# HG changeset patch # User korDen # Date 1256359326 -14400 # Node ID 10317f0c89a50785afec6f6fae44cb2467618e05 Initial commit diff -r 000000000000 -r 10317f0c89a5 bridge/bridge.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bridge/bridge.cpp Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,181 @@ +struct Symbol; +struct dt_t; +struct TYPE; +struct elem; +struct Blockx; +struct block; + +typedef TYPE type; + +int reftoident(int a, unsigned long b, Symbol* c, unsigned long d, int e); + +int reftoident(int a, unsigned int b, Symbol* c, unsigned int d, int e) +{ + return reftoident(a, (unsigned long)b, c, (unsigned long)d, e); +} + +dt_t** dtnzeros(dt_t**, unsigned long); + +dt_t** dtnzeros(dt_t** a, unsigned int b) +{ + return dtnzeros(a, (unsigned long)b); +} + +TYPE* type_fake(unsigned long a); + +TYPE* type_fake(unsigned int a) +{ + return type_fake((unsigned long)a); +} + +elem* el_long(unsigned long a, long long b); + +elem* el_long(unsigned int a, long long b) +{ + return el_long((unsigned long)a, b); +} + +type* type_alloc(unsigned long a); + +type* type_alloc(unsigned int a) +{ + return type_alloc((unsigned long)a); +} + +elem* el_bin(unsigned int a, unsigned long b, elem* c, elem* d); + +elem* el_bin(unsigned int a, unsigned int b, elem* c, elem* d) +{ + return el_bin(a, (unsigned long)b, c, d); +} + +dt_t** dtnbytes(dt_t** a, unsigned long b, const char* c); + +dt_t** dtnbytes(dt_t** a, unsigned int b, const char* c) +{ + return dtnbytes(a, (unsigned long)b, c); +} + +extern unsigned char tytab[]; +unsigned char* get_tytab() +{ + return tytab; +} + +extern unsigned char tytab2[]; +unsigned char* get_tytab2() +{ + return tytab2; +} + +extern signed char tysize[]; +signed char* get_tysize() +{ + return tysize; +} + +type* type_setcv(type** pt, unsigned long cv); + +type* type_setcv(type** pt, unsigned int cv) +{ + return type_setcv(pt, (unsigned long) cv); +} + +elem* el_una(unsigned int op, unsigned long ty, elem* e1); + +elem* el_una(unsigned int op, unsigned int ty, elem* e1) +{ + return el_una(op, (unsigned long) ty, e1); +} + +type* type_allocn(unsigned long a, type* b); + +type* type_allocn(unsigned int a, type* b) +{ + return type_allocn((unsigned long)a, b); +} + +void block_next(Blockx* bctx, enum BC bc, block* bn); + +void block_next(Blockx* bctx, int bc, block* bn) +{ + block_next(bctx, (enum BC)bc, bn); +} + +block* block_goto(Blockx* bctx, enum BC bc, block* bn); + +block* block_goto(Blockx* bctx, int bc, block* bn) +{ + return block_goto(bctx, (enum BC)bc, bn); +} + +dt_t** dtxoff(dt_t** pdtend, Symbol* s, unsigned long offset, unsigned long ty); + +dt_t** dtxoff(dt_t** pdtend, Symbol* s, unsigned int offset, unsigned int ty) +{ + return dtxoff(pdtend, s, (unsigned long)offset, (unsigned long)ty); +} + +dt_t** dtabytes(dt_t** pdtend, unsigned long ty, unsigned long offset, unsigned long size, const char* ptr); + +dt_t** dtabytes(dt_t** pdtend, unsigned int ty, unsigned int offset, unsigned int size, const char* ptr) +{ + return dtabytes(pdtend, (unsigned long)ty, (unsigned long)offset, (unsigned long)size, ptr); +} + +dt_t** dtdword(dt_t** pdtend, long value); + +dt_t** dtdword(dt_t** pdtend, int value) +{ + return dtdword(pdtend, (long)value); +} + +type* type_setty(type** a, long b); + +type* type_setty(type** a, int b) +{ + return type_setty(a, (long)b); +} + +elem* el_pair(unsigned long a, elem* b, elem* c); + +elem* el_pair(unsigned int a, elem* b, elem* c) +{ + return el_pair((unsigned long)a, b, c); +} + +extern unsigned char rel_not[]; +extern unsigned char rel_swap[]; +extern unsigned char rel_integral[]; +extern unsigned char rel_exception[]; +extern unsigned char rel_unord[]; + +unsigned char* get_rel_not() { return rel_not; } +unsigned char* get_rel_swap() { return rel_swap; } +unsigned char* get_rel_integral() { return rel_integral; } +unsigned char* get_rel_exception() { return rel_exception; } +unsigned char* get_rel_unord() { return rel_unord; } + +unsigned long type_paramsize(type* t); +unsigned int type_paramsize_i(type* t) +{ + return (unsigned int)type_paramsize(t); +} + +void cod3_thunk(Symbol* sthunk, Symbol* sfunc, unsigned int p, unsigned long thisty, unsigned long d, int i, unsigned long d2); +void cod3_thunk(Symbol* sthunk, Symbol* sfunc, unsigned int p, unsigned int thisty, unsigned int d, int i, unsigned int d2) +{ + return cod3_thunk(sthunk, sfunc, p, (unsigned long)thisty, (unsigned long)d, i, (unsigned long)d2); +} + +elem* el_const(unsigned long a, union eve* b); +elem* el_const(unsigned int a, union eve* b) +{ + return el_const((unsigned long)a, b); +} + +extern const unsigned long tytouns[]; +unsigned int* get_tytouns() +{ + return (unsigned int*)tytouns; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 build.bat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/build.bat Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,2 @@ +@echo off +cls && c:\dm\bin\dmc.exe bridge\bridge.cpp -c && c:\dmd_2.031\windows\bin\dmd.exe @commands.txt \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 commands.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/commands.txt Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,382 @@ +-g +-debug +-version=DMDV2 +-version=TX86 +-version=MARS +-version=TARGET_WINDOS +-version=_WIN32 +-version=WindowsXP +-version=DumbClone +-version=STRUCTTHISREF +-version=CCASTSYNTAX +-version=CARRAYDECL +-version=BREAKABI +-version=SEH +-version=OMFOBJ +-version=SNAN_DEFAULT_INIT +-ofc:\dmd_2.032\windows\bin\dmd.exe +bridge.obj +ddmd.def +c:\dmd_2.032\src\dmd\dmd.lib +main.d +win32\windef.d +win32\winuser.d +win32\wingdi.d +dlib\CrashHandler.d +dbg\ui\CrashWindow.d +dbg\Debug.d +dbg\symbol\CodeView.d +dbg\image\PE.d +dmd\AggregateDeclaration.d +dmd\VarExp.d +dmd\Tuple.d +dmd\UnrolledLoopStatement.d +dmd\SwitchErrorStatement.d +dmd\NewAnonClassExp.d +dmd\StructLiteralExp.d +dmd\StaticIfCondition.d +dmd\BoolExp.d +dmd\ShlAssignExp.d +dmd\ShrAssignExp.d +dmd\UshrAssignExp.d +dmd\CatAssignExp.d +dmd\Port.d +dmd\declaration\MATCH.d +dmd\expression\Util.d +dmd\expression\Add.d +dmd\expression\Xor.d +dmd\expression\Ptr.d +dmd\expression\Min.d +dmd\expression\And.d +dmd\expression\Shr.d +dmd\expression\Not.d +dmd\expression\Mod.d +dmd\expression\Mul.d +dmd\expression\Com.d +dmd\expression\Ushr.d +dmd\expression\Shl.d +dmd\expression\Div.d +dmd\expression\Cmp.d +dmd\expression\Identity.d +dmd\expression\ArrayLength.d +dmd\expression\Equal.d +dmd\expression\Or.d +dmd\expression\Neg.d +dmd\expression\Cat.d +dmd\expression\Slice.d +dmd\expression\Index.d +dmd\expression\shift_optimize.d +dmd\expression\util\arrayTypeCompatible.d +dmd\condition\util\findCondition.d +dmd\OverExp.d +dmd\Cast.d +dmd\TupleExp.d +dmd\ArrayLengthExp.d +dmd\TypeInfoConstDeclaration.d +dmd\TypeInfoInvariantDeclaration.d +dmd\TypeInfoSharedDeclaration.d +dmd\TypeInfoStructDeclaration.d +dmd\TypeInfoInterfaceDeclaration.d +dmd\TypeInfoEnumDeclaration.d +dmd\TypeInfoClassDeclaration.d +dmd\TypeInfoArrayDeclaration.d +dmd\TypeInfoDelegateDeclaration.d +dmd\TypeInfoTypedefDeclaration.d +dmd\TypeInfoPointerDeclaration.d +dmd\DsymbolExp.d +dmd\GlobalExpressions.d +dmd\NewExp.d +dmd\PeelStatement.d +dmd\HaltExp.d +dmd\SymOffExp.d +dmd\type\Util.d +dmd\SymbolExp.d +dmd\Optimize.d +dmd\DotVarExp.d +dmd\DeclarationExp.d +dmd\TraitsExp.d +dmd\ComplexExp.d +dmd\ErrorExp.d +dmd\AssignExp.d +dmd\DotExp.d +dmd\AliasDeclaration.d +dmd\DefaultInitExp.d +dmd\FileInitExp.d +dmd\LineInitExp.d +dmd\AnonDeclaration.d +dmd\AliasThis.d +dmd\AlignDeclaration.d +dmd\AnonymousAggregateDeclaration.d +dmd\Argument.d +dmd\FuncExp.d +dmd\ArrayLiteralExp.d +dmd\AssocArrayLiteralExp.d +dmd\AssertExp.d +dmd\IsExp.d +dmd\TypeExp.d +dmd\StringExp.d +dmd\NullExp.d +dmd\RealExp.d +dmd\ThisExp.d +dmd\ScopeExp.d +dmd\Array.d +dmd\DotIdExp.d +dmd\FileExp.d +dmd\SuperExp.d +dmd\TypeidExp.d +dmd\CompileExp.d +dmd\IdentifierExp.d +dmd\DollarExp.d +dmd\ArrayT.d +dmd\AndAndExp.d +dmd\DotTemplateInstanceExp.d +dmd\OrExp.d +dmd\PostExp.d +dmd\CallExp.d +dmd\SliceExp.d +dmd\ArrayExp.d +dmd\AddrExp.d +dmd\UAddExp.d +dmd\XorExp.d +dmd\CommaExp.d +dmd\BinExp.d +dmd\CondExp.d +dmd\OrOrExp.d +dmd\AndExp.d +dmd\InExp.d +dmd\EqualExp.d +dmd\CmpExp.d +dmd\ShlExp.d +dmd\AddExp.d +dmd\CatExp.d +dmd\MinExp.d +dmd\MulExp.d +dmd\ModExp.d +dmd\DivExp.d +dmd\ShrExp.d +dmd\UshrExp.d +dmd\CastExp.d +dmd\DeleteExp.d +dmd\ComExp.d +dmd\NotExp.d +dmd\UnaExp.d +dmd\NegExp.d +dmd\PtrExp.d +dmd\IntegerExp.d +dmd\AddAssignExp.d +dmd\AndAssignExp.d +dmd\DivAssignExp.d +dmd\MinAssignExp.d +dmd\ModAssignExp.d +dmd\MulAssignExp.d +dmd\OrAssignExp.d +dmd\XorAssignExp.d +dmd\IdentityExp.d +dmd\ArrayInitializer.d +dmd\ArrayScopeSymbol.d +dmd\ArrayTypes.d +dmd\AsmStatement.d +dmd\AttribDeclaration.d +dmd\BUILTIN.d +dmd\BaseClass.d +dmd\BreakStatement.d +dmd\CaseRangeStatement.d +dmd\CaseStatement.d +dmd\Catch.d +dmd\ClassDeclaration.d +dmd\ClassInfoDeclaration.d +dmd\CompileDeclaration.d +dmd\CompileStatement.d +dmd\CompoundDeclarationStatement.d +dmd\CompoundStatement.d +dmd\Condition.d +dmd\ConditionalDeclaration.d +dmd\ConditionalStatement.d +dmd\ContinueStatement.d +dmd\CppMangleState.d +dmd\CtorDeclaration.d +dmd\DVCondition.d +dmd\Dchar.d +dmd\DebugCondition.d +dmd\DebugSymbol.d +dmd\Declaration.d +dmd\DeclarationStatement.d +dmd\DefaultStatement.d +dmd\DeleteDeclaration.d +dmd\DoStatement.d +dmd\DocComment.d +dmd\Dsymbol.d +dmd\DsymbolTable.d +dmd\DtorDeclaration.d +dmd\EnumDeclaration.d +dmd\EnumMember.d +dmd\Escape.d +dmd\ExpInitializer.d +dmd\ExpStatement.d +dmd\Expression.d +dmd\File.d +dmd\FileName.d +dmd\ForStatement.d +dmd\ForeachRangeStatement.d +dmd\ForeachStatement.d +dmd\FuncAliasDeclaration.d +dmd\FuncDeclaration.d +dmd\FuncLiteralDeclaration.d +dmd\Global.d +dmd\GotoCaseStatement.d +dmd\GotoDefaultStatement.d +dmd\GotoStatement.d +dmd\HdrGenState.d +dmd\ILS.d +dmd\IRState.d +dmd\Id.d +dmd\Identifier.d +dmd\IfStatement.d +dmd\Import.d +dmd\Initializer.d +dmd\InlineCostState.d +dmd\InlineDoState.d +dmd\InlineScanState.d +dmd\IntRange.d +dmd\InterState.d +dmd\InterfaceDeclaration.d +dmd\InvariantDeclaration.d +dmd\LINK.d +dmd\LabelDsymbol.d +dmd\LabelStatement.d +dmd\Lexer.d +dmd\Library.d +dmd\LinkDeclaration.d +dmd\Loc.d +dmd\Lstring.d +dmd\MATCH.d +dmd\Macro.d +dmd\Module.d +dmd\ModuleDeclaration.d +dmd\ModuleInfoDeclaration.d +dmd\NewDeclaration.d +dmd\ObjModule.d +dmd\OnScopeStatement.d +dmd\OutBuffer.d +dmd\OverloadSet.d +dmd\PREC.d +dmd\PROT.d +dmd\Package.d +dmd\Param.d +dmd\Parser.d +dmd\PostBlitDeclaration.d +dmd\PragmaDeclaration.d +dmd\PragmaStatement.d +dmd\ProtDeclaration.d +dmd\RET.d +dmd\ReturnStatement.d +dmd\STC.d +dmd\Scope.d +dmd\ScopeDsymbol.d +dmd\ScopeStatement.d +dmd\Section.d +dmd\Statement.d +dmd\StaticAssert.d +dmd\StaticAssertStatement.d +dmd\StaticCtorDeclaration.d +dmd\StaticDtorDeclaration.d +dmd\StaticIfDeclaration.d +dmd\StorageClassDeclaration.d +dmd\String.d +dmd\StringEntry.d +dmd\StringTable.d +dmd\StringValue.d +dmd\StructDeclaration.d +dmd\StructInitializer.d +dmd\SwitchStatement.d +dmd\SymbolDeclaration.d +dmd\SynchronizedStatement.d +dmd\TOK.d +dmd\TY.d +dmd\TemplateAliasParameter.d +dmd\TemplateDeclaration.d +dmd\TemplateInstance.d +dmd\TemplateMixin.d +dmd\TemplateParameter.d +dmd\TemplateThisParameter.d +dmd\TemplateTupleParameter.d +dmd\TemplateTypeParameter.d +dmd\TemplateValueParameter.d +dmd\ThisDeclaration.d +dmd\ThrowStatement.d +dmd\Token.d +dmd\TryCatchStatement.d +dmd\TryFinallyStatement.d +dmd\TupleDeclaration.d +dmd\Type.d +dmd\TypeAArray.d +dmd\TypeArray.d +dmd\TypeBasic.d +dmd\TypeClass.d +dmd\TypeDArray.d +dmd\TypeDelegate.d +dmd\TypeEnum.d +dmd\TypeFunction.d +dmd\TypeIdentifier.d +dmd\TypeInfoDeclaration.d +dmd\TypeInstance.d +dmd\TypeNext.d +dmd\TypePointer.d +dmd\TypeQualified.d +dmd\TypeReference.d +dmd\TypeReturn.d +dmd\TypeSArray.d +dmd\EnumUtils.d +dmd\TypeSlice.d +dmd\TypeStruct.d +dmd\TypeTuple.d +dmd\TypeTypedef.d +dmd\TypeTypeof.d +dmd\TypedefDeclaration.d +dmd\UnionDeclaration.d +dmd\UnitTestDeclaration.d +dmd\Utf.d +dmd\Util.d +dmd\DotTemplateExp.d +dmd\DelegateExp.d +dmd\RemoveExp.d +dmd\TemplateExp.d +dmd\DotTypeExp.d +dmd\IndexExp.d +dmd\VarDeclaration.d +dmd\VersionCondition.d +dmd\VersionSymbol.d +dmd\VoidInitializer.d +dmd\VolatileStatement.d +dmd\WhileStatement.d +dmd\WithScopeSymbol.d +dmd\WithStatement.d +dmd\backend\Blockx.d +dmd\backend\enum_t.d +dmd\backend\Symbol.d +dmd\backend\Util.d +dmd\backend\TYPE.d +dmd\backend\TYM.d +dmd\backend\mTY.d +dmd\backend\block.d +dmd\backend\code.d +dmd\backend\glue.d +dmd\backend\dt_t.d +dmd\backend\elem.d +dmd\backend\func_t.d +dmd\backend\Cstate.d +dmd\backend\TYFL.d +dmd\backend\RTLSYM.d +dmd\backend\symtab_t.d +dmd\backend\Classsym.d +dmd\backend\con_t.d +dmd\backend\cse_t.d +dmd\backend\struct_t.d +dmd\backend\OPER.d +dmd\backend\StringTab.d +dmd\backend\DT.d +dmd\backend\Configv.d +dmd\backend\iasm.d +dmd\backend\rel.d +dmd\backend\LIST.d +dmd\codegen\Util.d \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dbg/Debug.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dbg/Debug.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,33 @@ +/** + Common interfaces for the debugging package. + + Authors: + Jeremie Pelletier +*/ +module dbg.Debug; + +interface IExecutableImage { + uint codeOffset() const; + + ISymbolicDebugInfo debugInfo(); +} + +interface ISymbolicDebugInfo { + SymbolInfo ResolveSymbol(size_t rva) const; + FileLineInfo ResolveFileLine(size_t rva) const; +} + +struct SymbolInfo { + string name; + uint offset; +} + +struct FileLineInfo { + string file; + uint line; +} + +void SystemException() +{ + throw new Exception("SystemException"); +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dbg/image/PE.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dbg/image/PE.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,361 @@ +/** + A simple PE/COFF image format reader. + + Authors: + Jeremie Pelletier + + References: + $(LINK http://www.csn.ul.ie/~caolan/publink/winresdump/winresdump/doc/pefile.html) + + License: + Public Domain +*/ +module dbg.image.PE; + +version(Windows) { + +import std.c.string : strncmp; +import dbg.Debug; +import dbg.symbol.CodeView; +//import dbg.symbol.COFF; +//import sys.windows.FileSystem; +//import sys.windows.Memory; +//import sys.windows.Security : GENERIC_READ; +//import sys.windows.Information : CloseHandle; +//import sys.windows.Image; + +import win32.windows; +import win32.winbase; + +enum IMAGE_SIZEOF_NT_OPTIONAL64_HEADER = 240; + +struct IMAGE_NT_HEADERS64 { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER64 OptionalHeader; +} + +auto IMAGE_FIRST_SECTION64( const(IMAGE_NT_HEADERS64*) ntheader ) { + return cast(PIMAGE_SECTION_HEADER) ((cast(UINT_PTR)ntheader) + IMAGE_NT_HEADERS64.OptionalHeader.offsetof + (cast(PIMAGE_NT_HEADERS64)(ntheader)).FileHeader.SizeOfOptionalHeader); +} + +auto IMAGE_FIRST_SECTION32( const(IMAGE_NT_HEADERS32*) ntheader ) { + return cast(PIMAGE_SECTION_HEADER)((cast(UINT_PTR)ntheader) + IMAGE_NT_HEADERS32.OptionalHeader.offsetof + (cast(PIMAGE_NT_HEADERS32)ntheader).FileHeader.SizeOfOptionalHeader); +} + +class PEImage : IExecutableImage { + /** + Loads and validate the image file. + + Params: + fileName = Path to the image file. + */ + this(string fileName) + in { + assert(fileName.length && fileName.ptr); + } + body { + _filename = fileName; + + // Create the file mapping + _file = CreateFileA((fileName ~ '\0').ptr, GENERIC_READ, FILE_SHARE_READ, + null, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, null); + if(_file == INVALID_HANDLE_VALUE) SystemException(); + + GetFileSizeEx(_file, &_fileSize); + + _map = CreateFileMapping(_file, null, PAGE_READONLY, 0, 0, null); + if(!_map) SystemException(); + + _view = cast(const(ubyte)*)MapViewOfFile(_map, FILE_MAP_READ, 0, 0, 0); + if(!_view) SystemException(); + + // Verify image headers + if(_dos.e_magic != IMAGE_DOS_SIGNATURE) goto Error; + CheckOffset(_dos.e_lfanew); + + _nt = cast(IMAGE_NT_HEADERS32*)(_view + _dos.e_lfanew); + if(_nt.Signature != IMAGE_NT_SIGNATURE) goto Error; + + _is64 = _nt.FileHeader.SizeOfOptionalHeader == IMAGE_SIZEOF_NT_OPTIONAL64_HEADER; + + if(_is64) { + if(_nt64.OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) + goto Error; + } + else { + if(_nt.OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) + goto Error; + } + + // Create the RVA lookup table + auto sections = this.sections; + RVAEntry* e = void; + _rvaTable.length = sections.length; + foreach(i, ref s; sections) with(s) { + e = &_rvaTable[i]; + e.start = VirtualAddress; + e.end = VirtualAddress + SizeOfRawData; + e.base = PointerToRawData; + } + + return; + + Error: + throw new PEInvalidException(this); + } + + /** + Unloads the PE file. + */ + ~this() { + if(_dos && !UnmapViewOfFile(cast(void*)_dos)) SystemException(); + if(_map && !CloseHandle(_map)) SystemException(); + if(_file && !CloseHandle(_file)) SystemException(); + } + + /** + Get the filename of the image + */ + string filename() const { + return _filename; + } + + /** + Get whether the image uses the 64bit structures or not + */ + bool is64() const { + return _is64; + } + + /** + Get the base address of the image + */ + long imageBase() const { + return _is64 ? _nt64.OptionalHeader.ImageBase : _nt.OptionalHeader.ImageBase; + } + + /** + Get the raw image data + */ + const(ubyte)[] data() const { + return _view[0 .. cast(size_t)_fileSize.QuadPart]; + } + + /** + Get the dos, nt or nt64 headers + */ + const(IMAGE_DOS_HEADER)* dosHeader() const { return _dos; } + const(IMAGE_NT_HEADERS32)* ntHeaders32() const { return _nt; } + const(IMAGE_NT_HEADERS64)* ntHeaders64() const { return _nt64; } + + /** + Get the array of data directories + */ + const(IMAGE_DATA_DIRECTORY)[] dataDirectory() const { + return _is64 ? _nt64.OptionalHeader.DataDirectory : _nt.OptionalHeader.DataDirectory; + } + + /** + Get the array of section headers + */ + const(IMAGE_SECTION_HEADER)[] sections() const { + return (_is64 ? IMAGE_FIRST_SECTION64(_nt64) : IMAGE_FIRST_SECTION32(_nt)) + [0 .. _nt.FileHeader.NumberOfSections]; + } + + /** + Translate the given Virtual Address to its corresponding data offset. + */ + long LookupVA(long va) const { + return LookupRVA(va - imageBase); + } + + /** + Translate the given Relative Virtual Address to its corresponding + data offset. + */ + long LookupRVA(long rva) const { + foreach(ref e; _rvaTable) with(e) { + if(rva >= start && rva < end) { + long offset = base + (rva - start); + CheckOffset(offset); + return offset; + } + } + + return 0; + } + + /** + Get a data structure in the image from its RVA + */ + const(T)* GetDataFromRVA(T : T*)(long rva) const { + long offset = LookupRVA(rva); + return offset ? cast(T*)(_view + offset) : null; + } + + /** + Get a data directory in the image from its ID + */ + const(T)* GetDirectory(T)(uint id) const { + const IMAGE_DATA_DIRECTORY* dir = &dataDirectory[id]; + return dir.VirtualAddress && dir.Size ? + GetDataFromRVA!(T*)(dir.VirtualAddress) : null; + } + + /** + Find the first section matching the given flags mask + */ + const(IMAGE_SECTION_HEADER)* FindSection(uint mask) const + in { + assert(mask); + } + body { + foreach(ref section; sections) + if(section.Characteristics & mask) + return §ion; + + return null; + } + + /** + Find a section by its name + */ + const(IMAGE_SECTION_HEADER)* FindSection(string name) const + in { + assert(name.length && name.ptr); + } + body { + foreach(ref section; sections) + if(strncmp(cast(char*)section.Name.ptr, name.ptr, section.Name.length) == 0) + return §ion; + + return null; + } + + /** + Get the offset to the code segment + */ + uint codeOffset() const { + const(IMAGE_SECTION_HEADER)* section = FindSection(IMAGE_SCN_MEM_EXECUTE); + return section ? section.VirtualAddress : 0; + } + + /** + Get the symbolic debug info object for this image + */ + ISymbolicDebugInfo debugInfo() { + uint va = _nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; + if(!va) return null; + + const(IMAGE_DEBUG_DIRECTORY)* dir = void; + uint size = _nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size; + uint offset = void; + + // Borland directory + const(IMAGE_SECTION_HEADER)* section = FindSection(".debug"); + if(section && section.VirtualAddress == va) { + CheckOffset(section.PointerToRawData); + + dir = cast(IMAGE_DEBUG_DIRECTORY*)(_view + section.PointerToRawData); + } + // Microsoft directory + else { + section = FindSection(".rdata"); + if(!section) goto NoDebug; + + offset = section.PointerToRawData + (va - section.VirtualAddress); + CheckOffset(offset); + + dir = cast(IMAGE_DEBUG_DIRECTORY*)(_view + offset); + } + + const(void)* end = cast(void*)dir + size; + Scan: for(; dir < end; dir++) { + switch(dir.Type) { + //case IMAGE_DEBUG_TYPE_COFF: + case IMAGE_DEBUG_TYPE_CODEVIEW: + // TODO: support more types + break Scan; + + default: + } + } + + if(dir >= end) goto NoDebug; + + offset = dir.PointerToRawData + dir.SizeOfData; + CheckOffset(offset); + auto debugView = _view[dir.PointerToRawData .. offset]; + + switch(dir.Type) { + //case IMAGE_DEBUG_TYPE_COFF: + // return new COFFDebugInfo(debugView); + case IMAGE_DEBUG_TYPE_CODEVIEW: + return new CodeViewDebugInfo(debugView); + default: + assert(0); + } + + NoDebug: + // TODO: we have no debug section or directory, but there csould still + // be external symbol files we can use. + return null; + } + +private: + + /** + Verify a file offset before accessing it + */ + void CheckOffset(long offset) const { + if(offset > _fileSize.QuadPart) throw new PECorruptedException(this); + } + + string _filename; + HANDLE _file; + HANDLE _map; + LARGE_INTEGER _fileSize; + bool _is64; + + union { + const(ubyte)* _view; + const(IMAGE_DOS_HEADER)* _dos; + } + union { + const(IMAGE_NT_HEADERS32)* _nt; + const(IMAGE_NT_HEADERS64)* _nt64; + } + + struct RVAEntry { + uint start; + uint end; + uint base; + } + + RVAEntry[] _rvaTable; +} + +/// Thrown if file open failed. +class PEException : Exception { + this(string msg) { + super("PEImage: " ~ msg); + } +} + +/// Thrown if not a valid module file +class PEInvalidException : PEException { + this(in PEImage img) { + super("Invalid PE file."); + } +} + +/// Thrown on corrupted module file. +class PECorruptedException : PEException { + this(in PEImage img) { + super("Corrupted PE file."); + } +} + +} // version(Windows) diff -r 000000000000 -r 10317f0c89a5 dbg/symbol/CodeView.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dbg/symbol/CodeView.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,1759 @@ +/** + This module is used to extract CodeView symbolic debugging information and to + perform queries upon that information. + + TODO: + * Add support for CodeView 5.0 and PDB formats. + * Add support to extract type information. + + Authors: + Jeremie Pelletier + + References: + $(LINK http://www.x86.org/ftp/manuals/tools/sym.pdf) + $(LINK http://undocumented.rawol.com/sbs-w2k-1-windows-2000-debugging-support.pdf) + $(LINK http://www.microsoft.com/msj/0399/hood/hood0399.aspx) + $(LINK http://source.winehq.org/source/include/wine/mscvpdb.h) + $(LINK http://www.digitalmars.com/d/2.0/abi.html) + + License: + Public Domain +*/ +module dbg.symbol.CodeView; + +import dbg.Debug; + +class CodeViewDebugInfo : ISymbolicDebugInfo { + /** + Load CodeView data from the given memory view. + */ + this(in void[] view) + in { + assert(view.length && view.ptr); + } + body { + _view = view; + + auto header = cast(CV_HEADER*)_view.ptr; + CheckOffset(header.offset); + + // TODO: Only supporting NB09 (CodeView 4.10) right now + if(!header.signature == CV_SIGNATURE_NB09) + throw new CodeViewUnsupportedException(this); + + auto dir = cast(CV_DIRECTORY*)(view.ptr + header.offset); + if(dir.dirSize != CV_DIRECTORY.sizeof || dir.entrySize != CV_ENTRY.sizeof) + throw new CodeViewCorruptedException(this); + + CvModule globalModule; + _modules ~= globalModule; + + foreach(ref e; dir.entries) { + CheckOffset(e.offset); + + switch(e.sst) { + case sstModule: ParseModule(&e); break; + case sstLibraries: ParseLibraries(&e); break; + case sstAlignSym: ParseAlignSymbols(&e); break; + case sstSrcModule: ParseSrcModule(&e); break; + case sstGlobalPub: + case sstStaticSym: + case sstGlobalSym: ParseHashSymbols(&e); break; + case sstGlobalTypes: ParseGlobalTypes(&e); break; + + // TODO: + /*case sstFileIndex: + case sstSegMap: + case sstSegName:*/ + + default: + } + } + } + + /** + Get the procedure symbol matching the given address. + */ + SymbolInfo ResolveSymbol(size_t rva) const + in { + assert(rva); + } + body { + SymbolInfo symbol; + + foreach(ref m; _modules[0 .. _maxSymModule + 1]) + if(m.symbols.QueryProc(rva, &symbol)) + goto Found; + + foreach(ref m; _modules[0 .. _maxSymModule + 1]) + if(m.symbols.QueryCodeData(rva, &symbol)) + goto Found; + + Found: + return symbol; + } + + /** + Get the file/line mapping corresponding to the given relative address. + */ + FileLineInfo ResolveFileLine(size_t rva) const + in { + assert(rva); + } + body { + FileLineInfo fileLine; + + if(_maxSrcModule) + foreach(m; _modules[1 .. _maxSrcModule + 1]) + if(m.src.Query(rva, &fileLine)) + break; + + return fileLine; + } + +private: + + void ParseModule(in CV_ENTRY* e) { + auto mod = cast(CV_MODULE*)(_view.ptr + e.offset); + + if(e.modIndex != _modules.length || mod.style != CV_MOD_STYLE) + throw new CodeViewCorruptedException(this); + + with(*mod) + _modules ~= CvModule(overlay, lib, segments, name.name); + } + + void ParseLibraries(in CV_ENTRY* e) { + if(e.modIndex != ushort.max) throw new CodeViewCorruptedException(this); + + auto name = cast(OMF_NAME*)(_view.ptr + e.offset); + auto end = cast(const(void)*)name + e.size; + + while(name < end) { + if(name.len) _libraries ~= name.name; + + name = cast(OMF_NAME*)(cast(void*)name + 1 + name.len); + } + } + + void ParseAlignSymbols(in CV_ENTRY* e) { + if(e.modIndex == ushort.max || e.modIndex <= 0 || e.modIndex >= _modules.length) + throw new CodeViewCorruptedException(this); + + if(e.modIndex > _maxSymModule) _maxSymModule = e.modIndex; + + auto sym = cast(CV_SYMBOL*)(_view.ptr + e.offset); + + if(sym.header.type == 0) sym = cast(CV_SYMBOL*)(cast(void*)sym + 4); + + _modules[e.modIndex].symbols.Init(sym, cast(void*)sym + e.size); + } + + void ParseHashSymbols(in CV_ENTRY* e) { + if(e.modIndex != ushort.max) throw new CodeViewCorruptedException(this); + + auto hash = cast(CV_SYMHASH*)(_view.ptr + e.offset); + auto p = cast(void*)hash + CV_SYMHASH.sizeof; + + _modules[0].symbols.Init(cast(CV_SYMBOL*)p, p + hash.symInfoSize); + } + + void ParseSrcModule(in CV_ENTRY* e) { + if(e.modIndex == ushort.max || e.modIndex <= 0 || e.modIndex >= _modules.length) + throw new CodeViewCorruptedException(this); + + if(e.modIndex > _maxSrcModule) _maxSrcModule = e.modIndex; + + auto src = cast(CV_SRCMODULE*)(_view.ptr + e.offset); + + with(_modules[e.modIndex].src) { + data = src; + fileOffsets = src.fileOffsets; + codeOffsets = src.codeOffsets; + segmentIds = src.segmentIds; + } + } + + void ParseGlobalTypes(in CV_ENTRY* e) { + if(e.modIndex != ushort.max) throw new CodeViewCorruptedException(this); + + // TODO: this currently crash stuff randomly + /*auto header = cast(CV_GLOBALTYPES*)(_view.ptr + e.offset); + _types.Init(header, cast(void*)header + e.size);*/ + } + + void CheckOffset(int offset) { + if(offset > _view.length) throw new CodeViewCorruptedException(this); + } + + const(void)[] _view; + + CvModule[] _modules; + uint _maxSymModule; + uint _maxSrcModule; + string[] _libraries; + CvTypes _types; +} + +abstract class CodeViewException : Exception { + this(string msg) { + super(msg); + } +} + +class CodeViewUnsupportedException : CodeViewException { + this(in CodeViewDebugInfo cv) { + super("CodeView version unsupported."); + } +} + +class CodeViewCorruptedException : CodeViewException { + this(in CodeViewDebugInfo cv) { + super("Corrupted CodeView data."); + } +} + +private: +alias int cmp_t; +uint BinarySearch(scope cmp_t delegate(uint i) dg, uint low, uint high) { + if(high < low) return uint.max; + + uint mid = low + ((high - low) / 2); + cmp_t cmp = dg(mid); + + if(cmp > 0) return BinarySearch(dg, low, mid - 1); + if(cmp < 0) return BinarySearch(dg, mid + 1, high); + return mid; +} + +uint BinarySearch(in uint[] a, uint value, uint low, uint high) { + if(high < low) return uint.max; + + uint mid = low + ((high - low) / 2); + + if(a[mid] > value) return BinarySearch(a, value, low, mid - 1); + if(a[mid] < value) return BinarySearch(a, value, mid + 1, high); + return mid; +} + +struct CvModule { + ushort overlay; + ushort lib; + CV_SEGMENT[] segments; + string name; + + CvSymbols symbols; + CvSrcModule src; +} + +struct CvSymbols { + ubyte compileMachine; + ubyte compileLanguage; + ushort compileFlags; + string compileName; + ushort segment; + + CvProc[] procSymbols; + CvData[] codeSymbols; + + void Init(const(CV_SYMBOL)* sym, in void* end) { + int i = 0; + while(sym < end && i < 100) { + ++i; + switch(sym.header.type) { + case S_COMPILE_V1: + with(sym.compile_v1) { + compileMachine = machine; + compileLanguage = language; + compileFlags = flags; + compileName = name.name; + } + break; + + case S_SSEARCH_V1: + if(!segment) segment = sym.ssearch.segment; + break; + + case S_UDT_V1: + break; + + case S_BPREL_V1: + break; + + case S_LDATA_V1: + case S_GDATA_V1: + case S_PUB_V1: + CvData data = void; + + with(sym.data_v1) { + // TODO: its bad to assume 2 to always be the only code segment! + if(segment != 2) break; + + data.offset = offset; + data.name = name.name; + } + + codeSymbols ~= data; + break; + + case S_LPROC_V1: + case S_GPROC_V1: + CvProc proc = void; + + with(sym.proc_v1) { + proc.offset = offset; + proc.length = procLength; + proc.name = name.name; + } + + procSymbols ~= proc; + break; + + case S_PROCREF_V1: + case S_DATAREF_V1: + case S_ALIGN_V1: + break; + + case S_END_V1: + case S_ENDARG_V1: + case S_RETURN_V1: + break; + + default: + } + + sym = cast(CV_SYMBOL*)(cast(void*)sym + sym.header.size + 2); + } + + codeSymbols.sort; + } + + bool QueryProc(uint rva, SymbolInfo* symbol) const { + if(!procSymbols.length) return false; + + cmp_t CmpProc(uint i) { + if(i >= procSymbols.length) return 0; + + uint offset = procSymbols[i].offset; + if(offset > rva) return 1; + if(offset + procSymbols[i].length < rva) return -1; + return 0; + } + + uint index = BinarySearch(&CmpProc, 0, procSymbols.length - 1); + + if(index < procSymbols.length) with(procSymbols[index]) { + symbol.name = name.idup; + symbol.offset = rva - offset; + return true; + } + + return false; + } + + bool QueryCodeData(uint rva, SymbolInfo* symbol) const { + if(!codeSymbols.length) return false; + + cmp_t CmpData(uint i) { + if(i >= codeSymbols.length) return 0; + + if(codeSymbols[i].offset > rva) return 1; + if(i + 1 != codeSymbols.length && codeSymbols[i + 1].offset < rva) return -1; + return 0; + } + + uint index = BinarySearch(&CmpData, 0, codeSymbols.length - 1); + + if(index < codeSymbols.length) with(codeSymbols[index]) { + symbol.name = name.idup; + symbol.offset = rva - offset; + return true; + } + + return false; + } +} + +struct CvProc { + uint offset; + uint length; + string name; +} + +struct CvData { + uint offset; + string name; + + cmp_t opCmp(ref const CvData data) const { + if(data.offset < offset) return -1; + return data.offset > offset; + } +} + +struct CvSrcModule { + bool Query(uint rva, FileLineInfo* fileLine) const { + if(!codeOffsets.length || rva < codeOffsets[0][0] || rva > codeOffsets[$ - 1][1]) + return false; + + uint fIndex; + + // Get the next CV_SRCFILE record having rva within it's code range + // The code offsets here may overlap over file records, we have to walk + // through them and possibly keep walking if the next section doesn't + // find a matching line record. + NextFile: + if(fIndex == fileOffsets.length) return false; + + CV_SRCFILE* srcFile = cast(CV_SRCFILE*)(data + fileOffsets[fIndex++]); + uint[2][] offsets = srcFile.codeOffsets; + + if(rva < offsets[0][0] || rva > offsets[$ - 1][1]) + goto NextFile; + + CV_SRCSEGMENT* srcSeg; + + // Address is possibly within this file, now get the CV_SEGMENT record. + cmp_t CmpFile(uint i) { + if(i >= offsets.length) return 0; + + if(offsets[i][0] > rva) return 1; + if(offsets[i][1] < rva) return -1; + + srcSeg = cast(CV_SRCSEGMENT*)(data + srcFile.lineOffsets[i]); + return 0; + } + + // Ignore the return value from BinarySearch, if CmpSegment matched, we + // already have srcSeg set. In some rare cases there may not be a + // matching segment record even if the file's segment range said so. + BinarySearch(&CmpFile, 0, offsets.length - 1); + if(!srcSeg) goto NextFile; + + // Finally look within the segment's offsets for a matching record. + uint[] segOffsets = srcSeg.offsets; + ushort[] lineNumbers = srcSeg.lineNumbers; + + cmp_t CmpSegment(uint i) { + if(i >= segOffsets.length) return 0; + + if(segOffsets[i] > rva) return 1; + if(i + 1 < segOffsets.length && segOffsets[i + 1] < rva) return -1; + + return 0; + } + + uint sIndex = BinarySearch(&CmpSegment, 0, segOffsets.length - 1); + if(sIndex >= lineNumbers.length) goto NextFile; + + // Found our record + fileLine.file = srcFile.name.name.idup; + fileLine.line = srcSeg.lineNumbers[sIndex]; + + return true; + } + + const(void)* data; + const(uint)[] fileOffsets; + const(uint[2])[] codeOffsets; + const(ushort)[] segmentIds; +} + +// TODO! +struct CvTypes { + void Init(in CV_GLOBALTYPES* gtypes, in void* end) { + debug(CodeView) TraceA("CvTypes[%p].Init(gtypes=%p, end=%p)", + &this, gtypes, end); + + offsets = gtypes.typeOffsets[0 .. gtypes.nTypes].idup; + + void* dataStart = gtypes.types; + data = dataStart[0 .. end - dataStart].idup; + } + + void GetType(ushort index) { + /+ + CheckOffset(typeOffsets[index]); + + CV_TYPE* type = cast(CV_TYPE*)(p + typeOffsets[i]); + + switch(type.header.type) { + case LF_MODIFIER_V1: + break; + + case LF_POINTER_V1: + break; + + case LF_ARRAY_V1: + break; + + case LF_CLASS_V1: + break; + + case LF_STRUCTURE_V1: + break; + + case LF_UNION_V1: + break; + + case LF_ENUM_V1: + break; + + case LF_PROCEDURE_V1: + break; + + case LF_MFUNCTION_V1: + break; + + case LF_VTSHAPE_V1: + break; + + case LF_OEM_V1: + with(type.oem_v1) { + // Ignore unknown OEMs + if(oem != OEM_DIGITALMARS || nIndices != 2) break; + + switch(rec) { + case D_DYN_ARRAY: + break; + + case D_ASSOC_ARRAY: + break; + + case D_DELEGATE: + break; + + default: + } + } + break; + + case LF_ARGLIST_V1: + break; + + case LF_FIELDLIST_V1: + break; + + case LF_DERIVED_V1: + break; + + case LF_METHODLIST_V1: + break; + + default: + TraceA("New leaf %x", cast(uint)type.header.type); + Pause; + } + +/ + } + + const(uint)[] offsets; + const(void)[] data; +} + +// ---------------------------------------------------------------------------- +// O M F S t r u c t u r e s +// ---------------------------------------------------------------------------- + +align(1): + +/** + Packed variant header +*/ +struct OMF_HEADER { + short size; + short type; +} + +/** + Packed name, may be 0 padded to maintain alignment +*/ +struct OMF_NAME { + ubyte len; + //char[1] name; + + string name() const { + return (cast(immutable(char)*)(&len + 1))[0 .. len]; + } +} + +// ---------------------------------------------------------------------------- +// C o d e V i e w C o m m o n S t r u c t u r e s +// ---------------------------------------------------------------------------- + +/** + Version signatures +*/ +enum : uint { + CV_SIGNATURE_NB09 = 0x3930424E, /// CodeView 4.10 + CV_SIGNATURE_NB11 = 0x3131424E, /// CodeView 5.0 + CV_SIGNATURE_NB10 = 0x3130424E, /// CodeView PDB 2.0 + CV_SIGNATURE_RSDS = 0x53445352 /// CodeView PDB 7.0 +} + +/** + SubSection Types +*/ +enum : ushort { + sstModule = 0x0120, + sstTypes = 0x0121, + sstPublic = 0x0122, + sstPublicSym = 0x0123, + sstSymbols = 0x0124, + sstAlignSym = 0x0125, + sstSrcLnSeg = 0x0126, + sstSrcModule = 0x0127, + sstLibraries = 0x0128, + sstGlobalSym = 0x0129, + sstGlobalPub = 0x012A, + sstGlobalTypes = 0x012B, + sstMPC = 0x012C, + sstSegMap = 0x012D, + sstSegName = 0x012E, + sstPreComp = 0x012F, + sstPreCompMap = 0x0130, + sstOffsetMap16 = 0x0131, + sstOffsetMap32 = 0x0132, + sstFileIndex = 0x0133, + sstStaticSym = 0x0134 +} + +/** + Header used with "NB09" and "NB11" +*/ +struct CV_HEADER { + uint signature; + int offset; +} + +/** + Header used with "NB10" +*/ +struct CV_HEADER_NB10 { + uint signature; + int offset; + uint timestamp; + uint age; + OMF_NAME name; +} + +/** + Header used with "RSDS" +*/ +/*struct CV_HEADER_RSDS { + uint signature; + GUID guid; + uint age; + OMF_NAME name; +}*/ + +/** + Directory header +*/ +struct CV_DIRECTORY { + ushort dirSize; + ushort entrySize; + uint nEntries; + int offset; + uint flags; + //CV_ENTRY[1] entries; + + CV_ENTRY[] entries() const { + return (cast(CV_ENTRY*)(&this + 1))[0 .. nEntries]; + } +} + +/** + Subsection record +*/ +struct CV_ENTRY { + ushort sst; + ushort modIndex; + int offset; + uint size; +} + +// ---------------------------------------------------------------------------- +// sstModule +// ---------------------------------------------------------------------------- + +/** + Module style, always "CV" +*/ +enum CV_MOD_STYLE = 0x5643; + +/** + Module +*/ +struct CV_MODULE { + ushort overlay; + ushort lib; + ushort nSegments; + ushort style; + //CV_SEGMENT[1] segments; + //OMF_NAME name; + + CV_SEGMENT[] segments() const { + return (cast(CV_SEGMENT*)(&style + 1))[0 .. nSegments]; + } + + OMF_NAME name() const { + return *cast(OMF_NAME*)(cast(void*)segments + nSegments * CV_SEGMENT.sizeof); + } +} + +/** + Module segment +*/ +struct CV_SEGMENT { + ushort segIndex; + ushort padding; + uint offset; + uint size; +} + +// ---------------------------------------------------------------------------- +// sstGlobalPub, sstStaticSym, sstGlobalSym, sstAlignSym +// ---------------------------------------------------------------------------- + +/** + Symbol IDs, used by CV_SYMBOL.header.type +*/ +enum : ushort { + S_COMPILE_V1 = 0x0001, + S_REGISTER_V1 = 0x0002, + S_CONSTANT_V1 = 0x0003, + S_UDT_V1 = 0x0004, + S_SSEARCH_V1 = 0x0005, + S_END_V1 = 0x0006, + S_SKIP_V1 = 0x0007, + S_CVRESERVE_V1 = 0x0008, + S_OBJNAME_V1 = 0x0009, + S_ENDARG_V1 = 0x000A, + S_COBOLUDT_V1 = 0x000B, + S_MANYREG_V1 = 0x000C, + S_RETURN_V1 = 0x000D, + S_ENTRYTHIS_V1 = 0x000E, + + S_BPREL_V1 = 0x0200, + S_LDATA_V1 = 0x0201, + S_GDATA_V1 = 0x0202, + S_PUB_V1 = 0x0203, + S_LPROC_V1 = 0x0204, + S_GPROC_V1 = 0x0205, + S_THUNK_V1 = 0x0206, + S_BLOCK_V1 = 0x0207, + S_WITH_V1 = 0x0208, + S_LABEL_V1 = 0x0209, + S_CEXMODEL_V1 = 0x020A, + S_VFTPATH_V1 = 0x020B, + S_REGREL_V1 = 0x020C, + S_LTHREAD_V1 = 0x020D, + S_GTHREAD_V1 = 0x020E, + + S_PROCREF_V1 = 0x0400, + S_DATAREF_V1 = 0x0401, + S_ALIGN_V1 = 0x0402, + S_LPROCREF_V1 = 0x0403, + + // Variants with 32bit type indices + S_REGISTER_V2 = 0x1001, /// CV_REGISTER_V2 + S_CONSTANT_V2 = 0x1002, /// CV_CONSTANT_V2 + S_UDT_V2 = 0x1003, /// CV_UDT_V2 + S_COBOLUDT_V2 = 0x1004, + S_MANYREG_V2 = 0x1005, + S_BPREL_V2 = 0x1006, /// CV_BPREL_V2 + S_LDATA_V2 = 0x1007, /// CV_DATA_V2 + S_GDATA_V2 = 0x1008, /// CV_DATA_V2 + S_PUB_V2 = 0x1009, /// CV_DATA_V2 + S_LPROC_V2 = 0x100A, /// CV_PROC_V2 + S_GPROC_V2 = 0x100B, /// CV_PROC_V2 + S_VFTTABLE_V2 = 0x100C, + S_REGREL_V2 = 0x100D, + S_LTHREAD_V2 = 0x100E, + S_GTHREAD_V2 = 0x100F, + S_FUNCINFO_V2 = 0x1012, + S_COMPILAND_V2 = 0x1013, /// CV_COMPILE_V2 + + S_COMPILAND_V3 = 0x1101, + S_THUNK_V3 = 0x1102, + S_BLOCK_V3 = 0x1103, + S_LABEL_V3 = 0x1105, + S_REGISTER_V3 = 0x1106, + S_CONSTANT_V3 = 0x1107, + S_UDT_V3 = 0x1108, + S_BPREL_V3 = 0x110B, + S_LDATA_V3 = 0x110C, + S_GDATA_V3 = 0x110D, + S_PUB_V3 = 0x110E, + S_LPROC_V3 = 0x110F, + S_GPROC_V3 = 0x1110, + S_BPREL_XXXX_V3 = 0x1111, /* not really understood, but looks like bprel... */ + S_MSTOOL_V3 = 0x1116, /* compiler command line options and build information */ + S_PUB_FUNC1_V3 = 0x1125, /* didn't get the difference between the two */ + S_PUB_FUNC2_V3 = 0x1127, + S_SECTINFO_V3 = 0x1136, + S_SUBSECTINFO_V3= 0x1137, + S_ENTRYPOINT_V3 = 0x1138, + S_SECUCOOKIE_V3 = 0x113A, + S_MSTOOLINFO_V3 = 0x113C, + S_MSTOOLENV_V3 = 0x113D +} + +/** + Packed symbols header +*/ +struct CV_SYMHASH { + ushort symIndex; + ushort addrIndex; + uint symInfoSize; + uint symHashSize; + uint addrHashSize; +} + +/** + Symbol variant record +*/ +struct CV_SYMBOL { + OMF_HEADER header; + union { + CV_COMPILE_V1 compile_v1; + CV_COMPILE_V2 compile_v2; + CV_REGISTER_V1 register_v1; + CV_REGISTER_V2 register_v2; + CV_CONSTANT_V1 constant_v1; + CV_CONSTANT_V2 constant_v2; + CV_UDT_V1 udt_v1; + CV_UDT_V2 udt_v2; + CV_SSEARCH ssearch; + CV_STACK_V1 stack_v1; + CV_STACK_V2 stack_v2; + CV_DATA_V1 data_v1; + CV_DATA_V2 data_v2; + CV_PROC_V1 proc_v1; + CV_PROC_V2 proc_v2; + CV_THUNK thunk; + CV_BLOCK block; + CV_LABEL label; + } +} + +/** + Compiler information symbol +*/ +struct CV_COMPILE_V1 { + ubyte machine; + ubyte language; + ushort flags; + OMF_NAME name; +} +struct CV_COMPILE_V2 { + uint[4] unknown1; + ushort unknown2; + OMF_NAME name; +} + +/** + Register data symbol +*/ +struct CV_REGISTER_V1 { + ushort typeIndex; + ushort reg; + OMF_NAME name; +} +struct CV_REGISTER_V2 { + uint typeIndex; + ushort reg; + OMF_NAME name; +} + +/** + Constant data symbol +*/ +struct CV_CONSTANT_V1 { + ushort typeIndex; + ushort value; + OMF_NAME name; +} +struct CV_CONSTANT_V2 { + uint typeIndex; + ushort value; + OMF_NAME name; +} + +/** + User defined type Symbol +*/ +struct CV_UDT_V1 { + ushort typeIndex; + OMF_NAME name; +} +struct CV_UDT_V2 { + uint typeIndex; + OMF_NAME name; +} + +/** + Start of Search symbol +*/ +struct CV_SSEARCH { + uint offset; + ushort segment; +} + +/** + Object name symbol +*/ +struct CV_OBJNAME { + uint signature; + OMF_NAME name; +} + +/** + Stack data symbol +*/ +struct CV_STACK_V1 { + uint offset; + ushort typeIndex; + OMF_NAME name; +} +struct CV_STACK_V2 { + uint offset; + uint typeIndex; + OMF_NAME name; +} + +/** + Data symbol +*/ +struct CV_DATA_V1 { + uint offset; + short segment; + short typeIndex; + OMF_NAME name; +} +struct CV_DATA_V2 { + uint typeIndex; + uint offset; + short segment; + OMF_NAME name; +} + +/** + Procedure symbol +*/ +struct CV_PROC_V1 { + uint parent; + uint end; + uint next; + uint procLength; + uint dbgStart; + uint dbgEnd; + uint offset; + ushort segment; + ushort procType; + ubyte flags; + OMF_NAME name; +} +struct CV_PROC_V2 { + uint parent; + uint end; + uint next; + uint procLength; + uint dbgStart; + uint dbgEnd; + uint procType; + uint offset; + ushort segment; + ubyte flags; + OMF_NAME name; +} + +/** + Thunk symbol +*/ +struct CV_THUNK { + uint parent; + uint end; + uint next; + uint offset; + ushort segment; + ushort size; + ubyte type; + OMF_NAME name; +} + +/** + Block symbol +*/ +struct CV_BLOCK { + uint parent; + uint end; + uint length; + uint offset; + ushort segment; + OMF_NAME name; +} + +/** + Label symbol +*/ +struct CV_LABEL { + uint offset; + ushort segment; + ubyte flags; + OMF_NAME name; +} + +// ---------------------------------------------------------------------------- +// sstSrcModule +// ---------------------------------------------------------------------------- + +/** + Source module header +*/ +struct CV_SRCMODULE { + ushort nFiles; /// number of CV_SRCFILE records + ushort nSegments; /// number of segments in module + //uint[] fileOffsets; + //uint[2][] codeOffsets; + //ushort[] segmentIds; + + /// array of offsets to every CV_SRCFILE record + uint[] fileOffsets() const { + return (cast(uint*)(&nSegments + 1))[0 .. nFiles]; + } + + /// array of segment start/end pairs, length = nSegments + uint[2][] codeOffsets() const { + return (cast(uint[2]*)(cast(void*)fileOffsets + nFiles * uint.sizeof))[0 .. nSegments]; + } + + /// array of linker indices, length = nSegments + ushort[] segmentIds() const { + return (cast(ushort*)(cast(void*)codeOffsets + nSegments * (uint[2]).sizeof))[0 .. nSegments]; + } +} + +/** + Source file record +*/ +struct CV_SRCFILE { + ushort nSegments; /// number of CV_SRCSEGMENT records + ushort reserved; + //uint[] lineOffsets; + //uint[2][] codeOffsets; + //OMF_NAME name; + + // array of offsets to every CV_SRCSEGMENT record, length = nSegments + uint[] lineOffsets() const { + return (cast(uint*)(&reserved + 1))[0 .. nSegments]; + } + + /// array of segment start/end pairs, length = nSegments + uint[2][] codeOffsets() const { + return (cast(uint[2]*)(cast(void*)lineOffsets + nSegments * uint.sizeof))[0 .. nSegments]; + } + + /// name of file padded to long boundary + OMF_NAME* name() const { + return cast(OMF_NAME*)(cast(void*)codeOffsets + nSegments * (uint[2]).sizeof); + } +} + +/** + Source segment record +*/ +struct CV_SRCSEGMENT { + ushort segment; /// linker segment index + ushort nPairs; /// count of line/offset pairs + //uint[] offsets; + //ushort[] lineNumbers; + + /// array of offsets in segment, length = nPairs + uint[] offsets() const { + return (cast(uint*)(&nPairs + 1))[0 .. nPairs]; + } + + /// array of line lumber in source, length = nPairs + ushort[] lineNumbers() const { + return (cast(ushort*)(cast(void*)offsets + nPairs * uint.sizeof))[0 .. nPairs]; + } +} + +// ---------------------------------------------------------------------------- +// sstGlobalTypes +// ---------------------------------------------------------------------------- + +/** + Basic types + + Official MS documentation says that type (< 0x4000, so 12 bits) is made of: + + +----------+------+------+----------+------+ + | 11 | 10-8 | 7-4 | 3 | 2-0 | + +----------+------+------+----------+------+ + | reserved | mode | type | reserved | size | + +----------+------+------+----------+------+ +*/ + +/** + Basic type: Type bits +*/ +enum : ubyte { + T_SPECIAL_BITS = 0x00, /// Special + T_SIGNED_BITS = 0x10, /// Signed integral value + T_UNSIGNED_BITS = 0x20, /// Unsigned integral value + T_BOOLEAN_BITS = 0x30, /// Boolean + T_REAL_BITS = 0x40, /// Real + T_COMPLEX_BITS = 0x50, /// Complex + T_SPECIAL2_BITS = 0x60, /// Special2 + T_INT_BITS = 0x70, /// Real int value +} + +/** + Basic type: Size bits +*/ +enum : ubyte { + // Special types + T_NOTYPE_BITS = 0x00, /// No type + T_ABS_BITS = 0x01, /// Absolute symbol + T_SEGMENT_BITS = 0x02, /// Segment + T_VOID_BITS = 0x03, /// Void + T_CURRENCY_BITS = 0x04, /// Basic 8-byte currency value + T_NBASICSTR_BITS = 0x05, /// Near Basic string + T_FBASICSTR_BITS = 0x06, /// Far Basic string + T_NOTRANS_BITS = 0x07, /// Untranslated type from previous Microsoft symbol formats + + // Signed/Unsigned/Boolean types + T_INT08_BITS = 0x00, /// 1 byte + T_INT16_BITS = 0x01, /// 2 byte + T_INT32_BITS = 0x02, /// 4 byte + T_INT64_BITS = 0x03, /// 8 byte + + // Real/Complex types + T_REAL32_BITS = 0x00, /// 32 bit + T_REAL64_BITS = 0x01, /// 64 bit + T_REAL80_BITS = 0x02, /// 80 bit + T_REAL128_BITS = 0x03, /// 128 bit + T_REAL48_BITS = 0x04, /// 48 bit + + // Special2 types + T_BIT_BITS = 0x00, /// Bit + T_PASCHAR_BITS = 0x01, /// Pascal CHAR + + // Real Int types + T_CHAR_BITS = 0x00, /// Char + T_WCHAR_BITS = 0x01, /// Wide character + T_INT2_BITS = 0x02, /// 2-byte signed integer + T_UINT2_BITS = 0x03, /// 2-byte unsigned integer + T_INT4_BITS = 0x04, /// 4-byte signed integer + T_UINT4_BITS = 0x05, /// 4-byte unsigned integer + T_INT8_BITS = 0x06, /// 8-byte signed integer + T_UINT8_BITS = 0x07, /// 8-byte unsigned integer + T_DCHAR_BITS = 0x08, /// dchar, DigitalMars D extension +} + +/** + Basic type: Mode bits +*/ +enum : ushort { + T_DIRECT_BITS = 0x0000, /// Direct; not a pointer + T_NEARPTR_BITS = 0x0100, /// Near pointer + T_FARPTR_BITS = 0x0200, /// Far pointer + T_HUGEPTR_BITS = 0x0300, /// Huge pointer + T_NEAR32PTR_BITS = 0x0400, /// 32-bit near pointer + T_FAR32PTR_BITS = 0x0500, /// 32-bit far pointer + T_NEAR64PTR_BITS = 0x0600, /// 64-bit near pointer +} + +/** + Basic type bit masks +*/ +enum : ushort { + T_TYPE_MASK = 0x00F0, /// type type mask (data treatment mode) + T_SIZE_MASK = 0x000F, /// type size mask (depends on 'type' value) + T_MODE_MASK = 0x0700, /// type mode mask (ptr/non-ptr) +} + +/** + Leaf types, used by CV_TYPE.header.type +*/ +enum : ushort { + // Can be referenced from symbols + LF_MODIFIER_V1 = 0x0001, + LF_POINTER_V1 = 0x0002, + LF_ARRAY_V1 = 0x0003, + LF_CLASS_V1 = 0x0004, + LF_STRUCTURE_V1 = 0x0005, + LF_UNION_V1 = 0x0006, + LF_ENUM_V1 = 0x0007, + LF_PROCEDURE_V1 = 0x0008, + LF_MFUNCTION_V1 = 0x0009, + LF_VTSHAPE_V1 = 0x000A, + LF_COBOL0_V1 = 0x000B, + LF_COBOL1_V1 = 0x000C, + LF_BARRAY_V1 = 0x000D, + LF_LABEL_V1 = 0x000E, + LF_NULL_V1 = 0x000F, + LF_NOTTRAN_V1 = 0x0010, + LF_DIMARRAY_V1 = 0x0011, + LF_VFTPATH_V1 = 0x0012, + LF_PRECOMP_V1 = 0x0013, + LF_ENDPRECOMP_V1 = 0x0014, + LF_OEM_V1 = 0x0015, + LF_TYPESERVER_V1 = 0x0016, + + LF_MODIFIER_V2 = 0x1001, + LF_POINTER_V2 = 0x1002, + LF_ARRAY_V2 = 0x1003, + LF_CLASS_V2 = 0x1004, + LF_STRUCTURE_V2 = 0x1005, + LF_UNION_V2 = 0x1006, + LF_ENUM_V2 = 0x1007, + LF_PROCEDURE_V2 = 0x1008, + LF_MFUNCTION_V2 = 0x1009, + LF_COBOL0_V2 = 0x100A, + LF_BARRAY_V2 = 0x100B, + LF_DIMARRAY_V2 = 0x100C, + LF_VFTPATH_V2 = 0x100D, + LF_PRECOMP_V2 = 0x100E, + LF_OEM_V2 = 0x100F, + + // Can be referenced from other type records + LF_SKIP_V1 = 0x0200, + LF_ARGLIST_V1 = 0x0201, + LF_DEFARG_V1 = 0x0202, + LF_LIST_V1 = 0x0203, + LF_FIELDLIST_V1 = 0x0204, + LF_DERIVED_V1 = 0x0205, + LF_BITFIELD_V1 = 0x0206, + LF_METHODLIST_V1 = 0x0207, + LF_DIMCONU_V1 = 0x0208, + LF_DIMCONLU_V1 = 0x0209, + LF_DIMVARU_V1 = 0x020A, + LF_DIMVARLU_V1 = 0x020B, + LF_REFSYM_V1 = 0x020C, + + LF_SKIP_V2 = 0x1200, + LF_ARGLIST_V2 = 0x1201, + LF_DEFARG_V2 = 0x1202, + LF_FIELDLIST_V2 = 0x1203, + LF_DERIVED_V2 = 0x1204, + LF_BITFIELD_V2 = 0x1205, + LF_METHODLIST_V2 = 0x1206, + LF_DIMCONU_V2 = 0x1207, + LF_DIMCONLU_V2 = 0x1208, + LF_DIMVARU_V2 = 0x1209, + LF_DIMVARLU_V2 = 0x120A, + + // Field lists + LF_BCLASS_V1 = 0x0400, + LF_VBCLASS_V1 = 0x0401, + LF_IVBCLASS_V1 = 0x0402, + LF_ENUMERATE_V1 = 0x0403, + LF_FRIENDFCN_V1 = 0x0404, + LF_INDEX_V1 = 0x0405, + LF_MEMBER_V1 = 0x0406, + LF_STMEMBER_V1 = 0x0407, + LF_METHOD_V1 = 0x0408, + LF_NESTTYPE_V1 = 0x0409, + LF_VFUNCTAB_V1 = 0x040A, + LF_FRIENDCLS_V1 = 0x040B, + LF_ONEMETHOD_V1 = 0x040C, + LF_VFUNCOFF_V1 = 0x040D, + LF_NESTTYPEEX_V1 = 0x040E, + LF_MEMBERMODIFY_V1 = 0x040F, + + LF_BCLASS_V2 = 0x1400, + LF_VBCLASS_V2 = 0x1401, + LF_IVBCLASS_V2 = 0x1402, + LF_FRIENDFCN_V2 = 0x1403, + LF_INDEX_V2 = 0x1404, + LF_MEMBER_V2 = 0x1405, + LF_STMEMBER_V2 = 0x1406, + LF_METHOD_V2 = 0x1407, + LF_NESTTYPE_V2 = 0x1408, + LF_VFUNCTAB_V2 = 0x1409, + LF_FRIENDCLS_V2 = 0x140A, + LF_ONEMETHOD_V2 = 0x140B, + LF_VFUNCOFF_V2 = 0x140C, + LF_NESTTYPEEX_V2 = 0x140D, + + LF_ENUMERATE_V3 = 0x1502, + LF_ARRAY_V3 = 0x1503, + LF_CLASS_V3 = 0x1504, + LF_STRUCTURE_V3 = 0x1505, + LF_UNION_V3 = 0x1506, + LF_ENUM_V3 = 0x1507, + LF_MEMBER_V3 = 0x150D, + LF_STMEMBER_V3 = 0x150E, + LF_METHOD_V3 = 0x150F, + LF_NESTTYPE_V3 = 0x1510, + LF_ONEMETHOD_V3 = 0x1511, + + // Numeric leaf types + LF_NUMERIC = 0x8000, + LF_CHAR = 0x8000, + LF_SHORT = 0x8001, + LF_USHORT = 0x8002, + LF_LONG = 0x8003, + LF_ULONG = 0x8004, + LF_REAL32 = 0x8005, + LF_REAL64 = 0x8006, + LF_REAL80 = 0x8007, + LF_REAL128 = 0x8008, + LF_QUADWORD = 0x8009, + LF_UQUADWORD = 0x800A, + LF_REAL48 = 0x800B, + LF_COMPLEX32 = 0x800C, + LF_COMPLEX64 = 0x800D, + LF_COMPLEX80 = 0x800E, + LF_COMPLEX128 = 0x800F, + LF_VARSTRING = 0x8010, + LF_DCHAR = 0x8011 +} + +/** + Global types header +*/ +struct CV_GLOBALTYPES { + ubyte[3] unused; + ubyte flags; + uint nTypes; + //uint[1] typeOffsets; + //CV_TYPE[1] types; + + /// array of offsets to CV_TYPE records + uint* typeOffsets() const { + return cast(uint*)(&nTypes + 1); + } + + // Get the first CV_TYPE record + CV_TYPE* types() const { + return cast(CV_TYPE*)(cast(void*)(&nTypes + 1) + nTypes * uint.sizeof); + } +} + +/** + Type variant record +*/ +struct CV_TYPE { + OMF_HEADER header; + union { + // Types + CV_MODIFIER_V1 modifier_v1; + CV_MODIFIER_V2 modifier_v2; + CV_POINTER_V1 pointer_v1; + CV_POINTER_V2 pointer_v2; + CV_ARRAY_V1 array_v1; + CV_ARRAY_V2 array_v2; + CV_STRUCT_V1 struct_v1; + CV_STRUCT_V2 struct_v2; + CV_UNION_V1 union_v1; + CV_UNION_V2 union_v2; + CV_ENUM_V1 enum_v1; + CV_ENUM_V2 enum_v2; + CV_PROCEDURE_V1 proc_v1; + CV_PROCEDURE_V2 proc_v2; + CV_MFUNCTION_V1 method_v1; + CV_MFUNCTION_V2 method_v2; + CV_OEM_V1 oem_v1; + CV_OEM_V2 oem_v2; + + // Referenced types + CV_FIELDLIST fieldlist; + CV_BITFIELD_V1 bitfield_v1; + CV_BITFIELD_V2 bitfield_v2; + CV_ARGLIST_V1 arglist_v1; + CV_ARGLIST_V2 arglist_v2; + CV_DERIVED_V1 derived_v1; + CV_DERIVED_V2 derived_v2; + + // Field types + } +} + +/** + Modifier type +*/ +struct CV_MODIFIER_V1 { + ushort attribute; + ushort type; +} +struct CV_MODIFIER_V2 { + uint type; + ushort attribute; +} + +/** + Pointer type +*/ +struct CV_POINTER_V1 { + ushort attribute; + ushort type; + OMF_NAME name; +} +struct CV_POINTER_V2 { + uint type; + uint attribute; + OMF_NAME name; +} + +/** + Array type +*/ +struct CV_ARRAY_V1 { + ushort elemType; + ushort indexType; + ushort length; /// numeric leaf + OMF_NAME name; +} +struct CV_ARRAY_V2 { + uint elemType; + uint indexType; + ushort length; /// numeric leaf + OMF_NAME name; +} + +/** + Struct type +*/ +struct CV_STRUCT_V1 { + ushort nElement; + ushort fieldlist; + ushort property; + ushort derived; + ushort vshape; + ushort length; /// numeric leaf + OMF_NAME name; +} +struct CV_STRUCT_V2 { + ushort nElement; + ushort property; + uint fieldlist; + uint derived; + uint vshape; + ushort length; /// numeric leaf + OMF_NAME name; +} + +/** + Union type +*/ +struct CV_UNION_V1 { + ushort count; + ushort fieldlist; + ushort property; + ushort length; /// numeric leaf + OMF_NAME name; +} +struct CV_UNION_V2 { + ushort count; + ushort property; + uint fieldlist; + ushort length; /// numeric leaf + OMF_NAME name; +} + +/** + Enumeration type +*/ +struct CV_ENUM_V1 { + ushort length; + ushort id; + ushort count; + ushort type; + ushort fieldlist; + ushort property; + OMF_NAME p_name; +} +struct CV_ENUM_V2 { + ushort length; + ushort id; + ushort count; + ushort property; + uint type; + uint fieldlist; + OMF_NAME p_name; +} + +/** + Procedure type +*/ +struct CV_PROCEDURE_V1 { + ushort retType; + ubyte call; + ubyte reserved; + ushort nParams; + ushort argList; +} +struct CV_PROCEDURE_V2 { + uint retType; + ubyte call; + ubyte reserved; + ushort nParams; + uint argList; +} + +/** + Method type +*/ +struct CV_MFUNCTION_V1 { + ushort retType; + ushort classType; + ushort thisType; + ubyte call; + ubyte reserved; + ushort nParams; + ushort arglist; + uint thisAdjust; +} +struct CV_MFUNCTION_V2 { + uint retType; + uint classType; + uint thisType; + ubyte call; + ubyte reserved; + ushort nParams; + uint arglist; + uint thisAdjust; +} + +/** + OEM type +*/ +struct CV_OEM_V1 { + ushort oem; + ushort rec; + ushort nIndices; + //ushort[1] indices; + + ushort* indices() const { + return cast(ushort*)(&nIndices + 1); + } +} +struct CV_OEM_V2 { + // UNKNOWN! +} + +enum { + OEM_DIGITALMARS = 0x0042, + D_DYN_ARRAY = 0x0001, + D_ASSOC_ARRAY = 0x0002, + D_DELEGATE = 0x0003 +} + +struct CV_D_DYNARRAY { + ushort indexType; + ushort elemType; +} + +struct CV_D_ASSOCARRAY { + ushort keyType; + ushort elemType; +} + +struct CV_D_DELEGATE { + ushort thisType; + ushort funcType; +} + +/** + Field list +*/ +struct CV_FIELDLIST { + ubyte[1] list; +} + +/** + Bit field +*/ +struct CV_BITFIELD_V1 { + ubyte nBits; + ubyte bitOffset; + ushort type; +} +struct CV_BITFIELD_V2 { + uint type; + ubyte nBits; + ubyte bitOffset; +} + +/** + Arguments list +*/ +struct CV_ARGLIST_V1 { + ushort count; + ushort[1] args; +} +struct CV_ARGLIST_V2 { + uint count; + uint[1] args; +} + +/** + Derived +*/ +struct CV_DERIVED_V1 { + ushort count; + ushort[1] derivedClasses; +} +struct CV_DERIVED_V2 { + uint count; + uint[1] derivedClasses; +} + +/** + Class type +*/ +struct CV_CLASS_V1 { + ushort type; + ushort attribute; + ushort offset; /// numeric leaf +} +struct CV_CLASS_V2 { + ushort attribute; + uint type; + ushort offset; /// numeric leaf +} + +struct CvTypeClass { + ushort count; + ushort fieldList; + ushort flags; + ushort dList; + ushort vShape; + // length + // name +} + +// ---------------------------------------------------------------------------- +// sstSegMap +// ---------------------------------------------------------------------------- + +struct CV_SEGMAP { + ushort total; + ushort logical; + //CV_SEGMAPDESC[1] descriptors; + + CV_SEGMAPDESC* descriptors() const { + return cast(CV_SEGMAPDESC*)(&logical + 1); + } +} + +struct CV_SEGMAPDESC { + ushort flags; + ushort overlay; + ushort group; + ushort frame; + ushort name; + ushort className; + uint offset; + uint size; +} + +// ---------------------------------------------------------------------------- +// sstPreCompMap +// ---------------------------------------------------------------------------- + +struct OMFPreCompMap { + ushort FirstType; // first precompiled type index + ushort cTypes; // number of precompiled types + uint signature; // precompiled types signature + ushort padding; + //CV_typ_t[] map; // mapping of precompiled types +} + +// ---------------------------------------------------------------------------- +// sstOffsetMap16, sstOffsetMap32 +// ---------------------------------------------------------------------------- + +struct OMFOffsetMap16 { + uint csegment; // Count of physical segments + + // The next six items are repeated for each segment + + //uint crangeLog; // Count of logical offset ranges + //ushort[] rgoffLog; // Array of logical offsets + //short[] rgbiasLog; // Array of logical->physical bias + //uint crangePhys; // Count of physical offset ranges + //ushort[] rgoffPhys; // Array of physical offsets + //short[] rgbiasPhys; // Array of physical->logical bias +} + +struct OMFOffsetMap32 { + uint csection; // Count of physical sections + + // The next six items are repeated for each section + + //uint crangeLog; // Count of logical offset ranges + //uint[] rgoffLog; // Array of logical offsets + //int[] rgbiasLog; // Array of logical->physical bias + //uint crangePhys; // Count of physical offset ranges + //uint[] rgoffPhys; // Array of physical offsets + //int[] rgbiasPhys; // Array of physical->logical bias +} + +// ---------------------------------------------------------------------------- +// sstFileIndex +// ---------------------------------------------------------------------------- + +struct OMFFileIndex { + ushort cmodules; // Number of modules + ushort cfilerefs; // Number of file references + //ushort[] modulelist; // Index to beginning of list of files + // for module i. (0 for module w/o files) + //ushort[] cfiles; // Number of file names associated + // with module i. + //uint[] ulNames; // Offsets from the beginning of this + // table to the file names + //char[] Names; // The length prefixed names of files +} + +struct OMFMpcDebugInfo { + ushort cSeg; // number of segments in module + //ushort[] mpSegFrame; // map seg (zero based) to frame +} + + + + + + + +// Procedure flags +enum { + PROC_FPO = 1 << 0, // Frame pointer omitted + PROC_INTERRUPT = 1 << 1, // Interrupt + PROC_RETURN = 1 << 2, // Far return + PROC_NEVER = 1 << 3, // Never returns +} + +// Procedure calling conventions +enum { + CALL_C_NEAR = 0x00, + CALL_C_FAR = 0x01, + CALL_PASCAL_NEAR = 0x02, + CALL_PASCAL_FAR = 0x03, + CALL_FASTCALL_NEAR = 0x04, + CALL_FASTCALL_FAR = 0x05, + CALL_STDCALL_NEAR = 0x07, + CALL_STDCALL_FAR = 0x08, + CALL_SYSCALL_NEAR = 0x09, + CALL_SYSCALL_FAR = 0x10, + CALL_THIS = 0x11, + CALL_MIPS = 0x12, + CALL_GENERIC = 0x13 +} + +enum { + STRUCT_PACKED = 1 << 0, + STRUCT_CTOR = 1 << 1, + STRUCT_OVERLOADS = 1 << 2, + STRUCT_IS_NESTED = 1 << 3, + STRUCT_HAS_NESTED = 1 << 4, + STRUCT_OPASSIGN = 1 << 5, + STRUCT_OPCAST = 1 << 6, + STRUCT_FWDREF = 1 << 7, + STRUCT_SCOPED = 1 << 8 +} diff -r 000000000000 -r 10317f0c89a5 dbg/ui/CrashWindow.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dbg/ui/CrashWindow.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,369 @@ +/** + A window used to display the data from a CrashInfo struct generated by the + runtime's crash handler. + + TODO: + * Send report - need SMTP implementation + * Save report + + Authors: + Jeremie Pelletier + + License: + Public Domain +*/ +module dbg.ui.CrashWindow; + +import std.c.string; +import dlib.CrashHandler; +import dbg.Debug : SystemException; + +import std.stdio; + +private enum { + ReportWindowWidth = 640, + ReportWindowHeight = 480, + ReportWindowMinWidth = 320, + ReportWindowMinHeight = 240, + ReportWindowTitle = "Unhandled exception!" +} + +// ---------------------------------------------------------------------------- +// W i n 3 2 +// ---------------------------------------------------------------------------- + +version(Windows) { + +import win32.windows; + +private enum { + ID_LABEL = 100, + ID_SAVE_BTN = 101, + ID_SEND_BTN = 102, + ID_CLOSE_BTN = 103, + ID_REPORT = 104 +} + +enum CLEARTYPE_QUALITY = 5; +enum LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x20; + +/** + Create the crash window for the given crash information, the routine will + return when the window is closed. +*/ +void ShowCrashWindow(CrashInfo* crashInfo) +in { + assert(crashInfo); +} +body { + try { + + HINSTANCE inst = GetModuleHandle(null); + + WNDCLASSEXA wc; + wc.cbSize = WNDCLASSEX.sizeof; + wc.lpfnWndProc = &ReportWndProc; + wc.hInstance = inst; + wc.hIcon = cast(HICON)LoadImage(HINSTANCE.init, MAKEINTRESOURCE(OIC_ERROR), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); + wc.hCursor = cast(HCURSOR)LoadImage(HINSTANCE.init, MAKEINTRESOURCE(OCR_NORMAL), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE); + wc.hbrBackground = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); + wc.lpszClassName = "CrashWindowClass"; + + if(!RegisterClassExA(&wc)) SystemException(); + scope(exit) if(!UnregisterClassA("CrashWindowClass", inst)) SystemException(); + + RECT rc = void; + GetClientRect(GetDesktopWindow(), &rc); + + writeln(crashInfo.toString); + + HWND wnd = CreateWindowExA( + WS_EX_WINDOWEDGE, + "CrashWindowClass", ReportWindowTitle, + WS_OVERLAPPEDWINDOW | WS_VISIBLE, + (rc.right >> 1) - (ReportWindowWidth >> 1), (rc.bottom >> 1) - (ReportWindowHeight >> 1), + ReportWindowWidth, ReportWindowHeight, + HWND.init, HMENU.init, inst, cast(void*)crashInfo.toString.ptr + ); + if(!wnd) SystemException(); + + MSG msg = void; + while(GetMessage(&msg, HWND.init, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + } // try + catch(Throwable e) { + MessageBoxA(HWND.init, (e.toString ~ '\0').ptr, "Crash Window Error!", MB_ICONERROR | MB_OK); + } +} + +private: + +__gshared HWND saveButton, sendButton, closeButton, reportField; + +extern(Windows) +LRESULT ReportWndProc(HWND wnd, uint msg, WPARAM w, LPARAM l) { + try { + + switch(msg) { + case WM_CREATE: + HINSTANCE inst = cast(HINSTANCE).GetModuleHandle(null); + CREATESTRUCT* cs = cast(CREATESTRUCT*)l; + + LOGFONTA lf; + lf.lfHeight = 15; + lf.lfWeight = FW_REGULAR; + lf.lfCharSet = DEFAULT_CHARSET; + lf.lfOutPrecision = OUT_DEFAULT_PRECIS; + lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; + lf.lfQuality = CLEARTYPE_QUALITY; + lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; + + HFONT font = .CreateFontIndirectA(&lf); + if(!font) SystemException(); + + HINSTANCE iconMod = LoadLibraryExA("shell32.dll", null, + DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE); + + HWND CreateButton(string caption, uint id, ushort iconId) { + HWND ret = CreateWindowExA( + 0, "BUTTON", caption.ptr, WS_CHILD | WS_VISIBLE, + 0, 0, 0, 0, wnd, cast(HMENU)id, inst, null + ); + if(!ret) SystemException(); + + SendMessageA(ret, WM_SETFONT, cast(WPARAM)font, 0); + + if(iconMod) { + HANDLE icon = LoadImage(iconMod, MAKEINTRESOURCE(iconId), IMAGE_ICON, 24, 24, 0); + if(icon) SendMessageA(ret, BM_SETIMAGE, IMAGE_ICON, cast(uint)icon); + } + + return ret; + } + + saveButton = CreateButton("Save Report", ID_SAVE_BTN, 7); + sendButton = CreateButton("Send Report", ID_SEND_BTN, 27); + closeButton = CreateButton("Close", ID_CLOSE_BTN, 28); + + if(iconMod) FreeLibrary(cast(HMODULE)iconMod); + + enum ReportFont = "Courier New\0"; + lf.lfHeight = 14; + lf.lfFaceName[0 .. ReportFont.length] = ReportFont; + + font = CreateFontIndirectA(&lf); + if(!font) SystemException(); + + reportField = CreateWindowExA( + WS_EX_CLIENTEDGE, "EDIT", null, + WS_CHILD | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE | + ES_READONLY | ES_MULTILINE | ES_AUTOVSCROLL, + 0, 0, 0, 0, wnd, cast(HMENU)ID_REPORT, inst, null + ); + if(!reportField) SystemException(); + + SendMessageA(reportField, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(5, 5)); + SendMessageA(reportField, WM_SETFONT, cast(WPARAM)font, 0); + SendMessageA(reportField, WM_SETTEXT, 0, cast(LPARAM)cs.lpCreateParams); + + break; + + case WM_DESTROY: + PostQuitMessage(0); + break; + + case WM_GETMINMAXINFO: + MINMAXINFO* mm = cast(MINMAXINFO*)l; + mm.ptMinTrackSize.x = ReportWindowMinWidth; + mm.ptMinTrackSize.y = ReportWindowMinHeight; + break; + + case WM_SIZE: + int width = LOWORD(l), halfWidth = width >> 1; + int height = HIWORD(l); + + enum { + BtnWidth = 125, + BtnHeight = 35, + NumBtns = 3, + Pad = 10, + ReportHPad = Pad * 2, + ReportVPad = BtnHeight + Pad * 3, + BtnVPad = BtnHeight + Pad, + BtnHalfWidth = (BtnWidth * NumBtns + (Pad * (NumBtns - 1))) >> 1 + } + + if(!MoveWindow(reportField, Pad, Pad, width - ReportHPad, height - ReportVPad, true)) + SystemException(); + + void Move(HWND wnd, int i) { + if(!MoveWindow(wnd, halfWidth - BtnHalfWidth + BtnWidth * i + Pad * i, + height - BtnVPad, BtnWidth, BtnHeight, true)) + SystemException(); + } + + Move(saveButton, 0); + Move(sendButton, 1); + Move(closeButton, 2); + + break; + + case WM_COMMAND: + if(HIWORD(w) != BN_CLICKED) break; + + int id = LOWORD(w); + + // GetSaveFileName fails on win7.. no idea why + if(id == ID_SAVE_BTN) { + /*char[256] path = void; + path[0 .. 11] = "Report.txt\0"; + + OPENFILENAMEA ofn; + ofn.lStructSize = OPENFILENAME.sizeof; + ofn.hwndOwner = wnd; + ofn.lpstrFilter = "Text File\0*.txt\0\0"; + ofn.lpstrFile = path.ptr; + ofn.nMaxFile = path.length; + ofn.Flags = OFN_OVERWRITEPROMPT; + + try { + if(!GetSaveFileNameA(&ofn)) SystemException(); + + uint len = strlen(path.ptr); + if(path[len-4 .. len] != ".txt") path[len .. len + 5] = ".txt\0"; + + HANDLE file = CreateFileA(path.ptr, GENERIC_WRITE, 0, + null, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, null); + + if(file == INVALID_HANDLE_VALUE) SystemException(); + scope(exit) if(!CloseHandle(file)) SystemException(); + + char* text; + SendMessageA(reportField, WM_GETTEXT, 0, cast(LPARAM)text); + len = strlen(text); + + uint written = void; + if(!WriteFile(file, text, len, &written, null)) + SystemException(); + + if(written != len) throw new SystemException("Couldn't write entire data."); + + id = ID_CLOSE_BTN; + } + catch(SystemException e) { + MessageBoxA(wnd, (e.toString ~ '\0').ptr, "Error!", MB_OK | MB_ICONERROR); + }*/ + + MessageBoxA(wnd, "TODO", "Error!", MB_OK | MB_ICONERROR); + } + + if(id == ID_SEND_BTN) + MessageBoxA(wnd, "TODO", "Error!", MB_OK | MB_ICONERROR); + + if(id == ID_CLOSE_BTN) + SendMessageA(wnd, WM_CLOSE, 0, 0); + + break; + + default: + return DefWindowProcA(wnd, msg, w, l); + } + + } // try + catch(Exception e) { + MessageBoxA(HWND.init, (e.toString ~ '\0').ptr, "Crash Window Handler Error!", MB_ICONERROR | MB_OK); + PostQuitMessage(0); + } + + return 0; +} + +} // version(Windows) + +else version(Gnome) { + +import std.c.stdio; + +import ext.Gnome.gtk; +import ext.Gnome.gobject; + +void ErrorGUI(in ErrorReport* report) { + int argc; + if(!gtk_init_check(&argc, null)) { + printf("gtk failed!\n"); + Pause; + } + + void SetSignal(A, B)(A* widget, string signal, B callback) { + g_signal_connect(cast(void*)widget, signal.ptr, cast(GCallback)callback, null); + } + + // Create the report window + GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(cast(GtkWindow*)window, ReportWindowTitle); + gtk_window_set_default_size(cast(GtkWindow*)window, ReportWindowWidth, ReportWindowHeight); + gtk_window_set_icon_name(cast(GtkWindow*)window, GTK_STOCK_DIALOG_ERROR); + + SetSignal(window, "destroy", >k_main_quit); + + // Create the root box + GtkWidget* vbox = gtk_vbox_new(false, 0); + gtk_container_add(cast(GtkContainer*)window, vbox); + + // Create the report edit + GtkWidget* view = gtk_text_view_new(); + gtk_text_view_set_editable(cast(GtkTextView*)view, false); + gtk_text_view_set_cursor_visible(cast(GtkTextView*)view, false); + + GtkTextBuffer* buffer = gtk_text_view_get_buffer(cast(GtkTextView*)view); + gtk_text_buffer_set_text(buffer, report.dumpText.ptr, -1); + + gtk_box_pack_start(cast(GtkBox*)vbox, view, true, true, 0); + + // Create the buttons box + GtkWidget* hbox = gtk_hbutton_box_new(); + gtk_box_set_spacing(cast(GtkBox*)hbox, 10); + gtk_button_box_set_layout(cast(GtkButtonBox*)hbox, GTK_BUTTONBOX_CENTER); + gtk_box_pack_start(cast(GtkBox*)vbox, hbox, false, true, 10); + + // Create the buttons + GtkWidget* CreateButton(B)(string label, string stockId, B callback) { + GtkWidget* button = gtk_button_new_with_label(label.ptr); + + GtkWidget* image = gtk_image_new_from_stock(stockId.ptr, GTK_ICON_SIZE_BUTTON); + gtk_button_set_image(cast(GtkButton*)button, image); + + gtk_container_add(cast(GtkContainer*)hbox, button); + + if(callback) SetSignal(button, "clicked", callback); + + return button; + } + + CreateButton("Save Report", GTK_STOCK_SAVE_AS, &OnClickSave); + CreateButton("Send Report", GTK_STOCK_CONNECT, &OnClickSend); + GtkWidget* close = CreateButton("Close", GTK_STOCK_CLOSE, null); + + g_signal_connect_swapped(cast(void*)close, "clicked", + cast(GCallback)(>k_widget_destroy), cast(void*)(window)); + + // Display the window and run the main loop + gtk_widget_show_all(window); + gtk_main(); +} + +extern(C): + +void OnClickSave(GtkButton* button, gpointer user_data) { + // TODO +} + +void OnClickSend(GtkButton* button, gpointer user_data) { + // TODO +} + +} // version(Gnome) +else static assert(0); \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 ddmd.def --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ddmd.def Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,8 @@ +EXETYPE NT + +IMPORTS +_EnumProcessModules@16 = psapi.EnumProcessModules +_GetFileVersionInfoSizeA@8 = version.GetFileVersionInfoSizeA +_GetFileVersionInfoA@16 = version.GetFileVersionInfoA +_VerQueryValueA@16 = version.VerQueryValueA +_CommandLineToArgvW@8 = shell32.CommandLineToArgvW diff -r 000000000000 -r 10317f0c89a5 ddmd.dice --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ddmd.dice Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,340 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DMDV2 + TX86 + MARS + TARGET_WINDOS + _WIN32 + WindowsXP + DumbClone + + + D:\Projects\ddmd\bridge.obj + D:\Projects\ddmd\ddmd.def + c:\dmd_2.032\src\dmd\dmd.lib + + + c:\dmd_2.032\windows\bin\ddmd.exe + + + \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dlib/CrashHandler.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dlib/CrashHandler.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,450 @@ +/** + A simple runtime crash handler which collects various informations about + the crash such as registers, stack traces, and loaded modules. + + TODO: + * Threading support + * Stack dumps + + Authors: + Jeremie Pelletier + + License: + Public Domain +*/ +module dlib.CrashHandler; + +debug = CrashHandler; + +import std.c.stdio; +import dbg.Debug; +import dbg.ui.CrashWindow; + +version(X86) {} +else static assert(0, "Unsupported architecture."); + +version(DigitalMars) { + //import dlib.dmd.ErrorHandling; +} +else static assert(0, "Unsupported compiler."); + +version(Windows) { + import win32.windows; + import win32.psapi; + //import sys.windows.Memory; + //import dlib.Module; + import dbg.image.PE; + import dbg.symbol.CodeView; +} +else version(Posix) { + import sys.posix.ucontext; + import std.c.signal; + import std.c.stdlib : free, exit, EXIT_FAILURE; +} +else static assert(0, "Unsupported platform."); + +/** + Register the crash handler +*/ +void CrashHandlerInit() { + version(Windows) { + //SetErrorMode(SetErrorMode(0) | SEM_FAILCRITICALERRORS); + SetErrorMode(0); + SetUnhandledExceptionFilter(&UnhandledExceptionHandler); + } + else version(Posix) { + sigaction_t sa; + sa.sa_handler = cast(sighandler_t)&SignalHandler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART | SA_SIGINFO; + + sigaction(SIGILL, &sa, null); + sigaction(SIGFPE, &sa, null); + sigaction(SIGSEGV, &sa, null); + } + else static assert(0); +} + +/** + Information collected by the crash handler +*/ +struct CrashInfo { + struct Registers { + version(X86) { + uint EAX, EBX, ECX, EDX; + uint EDI, ESI; + uint EBP, ESP; + } + else static assert(0); + } + + struct Module { + string fileName; + ushort[4] fileVersion; + } + + Throwable error; + string moduleName; + Registers registers; + size_t[] backtrace; + Module[] modules; + + void Dump() { + // TODO: support more dump methods + ShowCrashWindow(&this); + } + + /** + Formats the crash info as plain-text + */ + string toString() { + string text; + char[255] buffer = void; + uint len = void; + + text ~= error.toString(); + text ~= "\r\n\r\n"; + + version(X86) { + with(registers) len = snprintf(buffer.ptr, buffer.length, + " Registers:\r\n" ~ + "========================================\r\n" ~ + " EAX=0x%08X EBX=0x%08X ECX=0x%08X EDX=0x%08X\r\n" ~ + " EDI=0x%08X ESI=0x%08X EBP=0x%08X ESP=0x%08X\r\n", + EAX, EBX, ECX, EDX, EDI, ESI, EBP, ESP + ); + text ~= buffer[0 .. len] ~ "\r\n"; + } + else static assert(0); + + text ~= " Stack Trace:\r\n" ~ + "========================================\r\n"; + + scope auto frames = new StackFrameInfo[backtrace.length]; + ResolveStackFrames(frames); + + foreach(ref frame; frames) { + //len = snprintf(buffer.ptr, buffer.length, "%p", frame.va); + //text ~= " " ~ buffer[0 .. len] ~ ": " ~ frame.moduleName ~ "\r\n"; + + //with(frame.symbol) if(name.length) { + // len = snprintf(buffer.ptr, buffer.length, "%X", offset); + // text ~= " " ~ name ~ " @ 0x" ~ buffer[0 .. len] ~ "\r\n"; + //} + + with(frame.fileLine) if(line) { + len = snprintf(buffer.ptr, buffer.length, "%u", line); + text ~= " " ~ file ~ ":" ~ buffer[0 .. len] ~ "\r\n"; + } + + //text ~= "\r\n"; + } +/+ + text ~= " Loaded Modules:\r\n" ~ + "========================================\r\n"; + + foreach(mod; modules) { + len = snprintf(buffer.ptr, buffer.length, "%hu.%hu.%hu.%hu", + mod.fileVersion[0], mod.fileVersion[1], + mod.fileVersion[2], mod.fileVersion[3]); + + text ~= " " ~ mod.fileName ~ "\r\n " ~ buffer[0 .. len] ~ "\r\n"; + } ++/ + text ~= '\0'; + + return text; + } + +private: + + struct StackFrameInfo { + size_t va; + string moduleName; + SymbolInfo symbol; + FileLineInfo fileLine; + } + + struct DebugImage { + DebugImage* next; + string moduleName; + size_t baseAddress; + uint rvaOffset; + IExecutableImage exeModule; + ISymbolicDebugInfo debugInfo; + } + + version(X86) { + void ResolveStackFrames(StackFrameInfo[] frames) const { + StackFrameInfo* frame = void; + DebugImage* imageList, image = void; + char[255] buffer = void; + uint len = void; + uint rva = void; + + version(Windows) MEMORY_BASIC_INFORMATION mbi = void; + + foreach(i, va; backtrace) { + frame = &frames[i]; + frame.va = va; + + version(Windows) { + // mbi.Allocation base is the handle to stack frame's module + VirtualQuery(cast(void*)va, &mbi, MEMORY_BASIC_INFORMATION.sizeof); + if(!mbi.AllocationBase) break; + + image = imageList; + while(image) { + if(image.baseAddress == cast(size_t)mbi.AllocationBase) break; + image = image.next; + } + + if(!image) { + image = new DebugImage; + + with(*image) { + next = imageList; + imageList = image; + baseAddress = cast(size_t)mbi.AllocationBase; + + len = GetModuleFileNameA(cast(HMODULE)baseAddress, buffer.ptr, buffer.length); + moduleName = buffer[0 .. len].idup; + + exeModule = new PEImage(moduleName); + rvaOffset = baseAddress + exeModule.codeOffset; + debugInfo = exeModule.debugInfo; + } + } + } + else static assert(0); + + frame.moduleName = image.moduleName; + + if(!image.debugInfo) continue; + + rva = va - image.rvaOffset; + + with(image.debugInfo) { + frame.symbol = ResolveSymbol(rva); + frame.fileLine = ResolveFileLine(rva); + } + } + + while(imageList) { + image = imageList.next; + delete imageList.debugInfo; + delete imageList.exeModule; + delete imageList; + imageList = image; + } + } + } // version(X86) + else static assert(0); +} + +// ---------------------------------------------------------------------------- +// W i n d o w s C r a s h H a n d l e r +// ---------------------------------------------------------------------------- + +version(Windows) { + +extern(C) Throwable _d_translate_se_to_d_exception(EXCEPTION_RECORD* exception_record); + +/** + D exceptions are built on top of Windows' SEH, a simple registered callback + will catch any exceptions unwinding past a thread's entry point. +*/ +extern(Windows) +int UnhandledExceptionHandler(EXCEPTION_POINTERS* e) { + CrashInfo crashInfo = void; + char[256] buffer = void; + uint len = void; + size_t ip = void, bp = void; + + try { + with(crashInfo) { + + version(DigitalMars) + error = _d_translate_se_to_d_exception(e.ExceptionRecord); + else + static assert(0); + + len = GetModuleFileNameA(GetModuleHandle(null), buffer.ptr, buffer.length); + moduleName = buffer[0 .. len].idup; + + version(X86) with(*e.ContextRecord) { + with(registers) { + EAX = Eax, EBX = Ebx, ECX = Ecx, EDX = Edx; + EDI = Edi, ESI = Esi; + EBP = Ebp, ESP = Esp; + } + + ip = Eip; + bp = Ebp; + } + else static assert(0); + + backtrace = null; + while(ip) { + backtrace ~= ip; + + ip = cast(size_t)*(cast(void**)bp + 1); + bp = cast(size_t)*cast(void**)bp; + } + + HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, + 0, GetCurrentProcessId()); + + if(process == INVALID_HANDLE_VALUE) SystemException(); + scope(exit) if(!CloseHandle(process)) SystemException(); + + scope HMODULE[] hmodules = new HMODULE[64]; + uint size = HMODULE.sizeof * hmodules.length; + uint sizeNeeded = void; + uint nModules = void; + + GetModules: + if(!EnumProcessModules(process, hmodules.ptr, size, &sizeNeeded)) + SystemException(); + + nModules = sizeNeeded / HMODULE.sizeof; + + if(sizeNeeded > size) { + hmodules.length = nModules; + size = sizeNeeded; + goto GetModules; + } + + Module mod = void; + char[] versionInfo; + VS_FIXEDFILEINFO* fixedVersionInfo = void; + + modules = null; + foreach(i; 0 .. nModules) { + len = GetModuleFileNameA(hmodules[i], buffer.ptr, buffer.length); + mod.fileName = buffer[0 .. len].idup; + + sizeNeeded = GetFileVersionInfoSizeA(buffer.ptr, &size); + + if(sizeNeeded) { + if(versionInfo.length < sizeNeeded) versionInfo.length = sizeNeeded; + + if(!GetFileVersionInfoA(buffer.ptr, 0, versionInfo.length, versionInfo.ptr)) + SystemException(); + + if(!VerQueryValueA(versionInfo.ptr, cast(char*)"\\".ptr, cast(void**)&fixedVersionInfo, &size)) + SystemException(); + + with(*fixedVersionInfo) with(mod) { + fileVersion[0] = HIWORD(dwProductVersionMS); + fileVersion[1] = LOWORD(dwProductVersionMS); + fileVersion[2] = HIWORD(dwProductVersionLS); + fileVersion[3] = LOWORD(dwProductVersionLS); + } + } + else { + mod.fileVersion[] = 0; + } + + modules ~= mod; + } + + } // with(crashInfo) + + crashInfo.Dump(); + } + catch(Throwable e) { + debug MessageBoxA(HWND.init, (e.toString ~ '\0').ptr, "Exception Handler Error!", MB_ICONERROR | MB_OK); + } + + return EXCEPTION_EXECUTE_HANDLER; +} + +} // version(Windows) + +// ---------------------------------------------------------------------------- +// P o s i x C r a s h H a n d l e r +// ---------------------------------------------------------------------------- + +else version(Posix) { + +/** + This handler catches system signals and throws the appropriate D exception. + The exception will unwind down to the thread's entry point where it is catched + and sent to UnhandledExceptionHandler(). +*/ +extern(C) +void SignalHandler(int signum, siginfo_t* siginfo, ucontext_t* ucontext) { + string msg = void; + + switch(signum) { + case SIGILL: msg = "Illegal instruction"; break; + case SIGFPE: msg = "Floating-point exception"; break; + case SIGSEGV: msg = "Segmentation fault"; break; + default: msg = "Unknown signal"; + } + + SystemException e = new SystemException(msg); + + e._context = ucontext; + e.GetBackTrace(); + + // The kernel fixed the stack frame to make us believe we called this + // routine ourselves, with the nasty side effect of losing the faulty + // routine's address. The undocumented parameter ucontext contains our + // lost EIP. + version(X86) { + // It should be the 3rd frame: + // SignalHandler() -> GetBackTrace() -> backtrace() + if(e._backtrace.length > 2) + e._backtrace[2] = cast(void*)ucontext.uc_mcontext.gregs[REG_EIP]; + } + else static assert(0); + + throw e; +} + +/** + This handler is called when an exception unwinds down to the thread's entry + point, which should catch it and manually call this routine. +*/ +void UnhandledExceptionHandler(Throwable e) { + ErrorReport crashInfo = void; + + with(crashInfo) { +assert(0); + /+error = e; + + // Get the module filename + // TODO + + // Dump the general purpose registers + if(e._context) { + gregset_t gregs = e._context.uc_mcontext.gregs; + + version(X86) { + registers.Eax = gregs[REG_EAX]; + registers.Ebx = gregs[REG_EBX]; + registers.Ecx = gregs[REG_ECX]; + registers.Edx = gregs[REG_EDX]; + registers.Edi = gregs[REG_EDI]; + registers.Esi = gregs[REG_ESI]; + registers.Ebp = gregs[REG_EBP]; + registers.Esp = gregs[REG_ESP]; + } + else static assert(0); + } + + // Dump stack backtrace + addresses = e._backtrace; + + // Dump the loaded modules + // TODO+/ + + } // with(crashInfo) + + crashInfo.Dump(); +} + +} // version(Posix) +else static assert(0); diff -r 000000000000 -r 10317f0c89a5 dmd/AddAssignExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/AddAssignExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,175 @@ +module dmd.AddAssignExp; + +import dmd.BinExp; +import dmd.Loc; +import dmd.Expression; +import dmd.Scope; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.ArrayTypes; +import dmd.Identifier; +import dmd.IRState; +import dmd.TOK; +import dmd.Type; +import dmd.TY; +import dmd.AddExp; +import dmd.CastExp; +import dmd.AssignExp; +import dmd.Global; +import dmd.Id; + +import dmd.backend.OPER; +import dmd.backend.elem; + +class AddAssignExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKaddass, AddAssignExp.sizeof, e1, e2); + } + + Expression semantic(Scope sc) + { + Expression e; + + if (type) + return this; + + BinExp.semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + Type tb1 = e1.type.toBasetype(); + Type tb2 = e2.type.toBasetype(); + + if (e1.op == TOK.TOKslice) + { + typeCombine(sc); + type = e1.type; + return arrayOp(sc); + } + else + { + e1 = e1.modifiableLvalue(sc, e1); + } + + if ((tb1.ty == TY.Tarray || tb1.ty == TY.Tsarray) && (tb2.ty == TY.Tarray || tb2.ty == TY.Tsarray) && tb1.nextOf().equals(tb2.nextOf())) + { + type = e1.type; + typeCombine(sc); + e = this; + } + else + { + e1.checkScalar(); + e1.checkNoBool(); + if (tb1.ty == TY.Tpointer && tb2.isintegral()) + e = scaleFactor(sc); + else if (tb1.ty == TY.Tbit || tb1.ty == TY.Tbool) + { +static if (false) { + // Need to rethink this + if (e1.op != TOK.TOKvar) + { + // Rewrite e1+=e2 to (v=&e1),*v=*v+e2 + VarDeclaration v; + Expression ea; + Expression ex; + + Identifier id = Lexer.uniqueId("__name"); + + v = new VarDeclaration(loc, tb1.pointerTo(), id, null); + v.semantic(sc); + if (!sc.insert(v)) + assert(0); + + v.parent = sc.func; + + ea = new AddrExp(loc, e1); + ea = new AssignExp(loc, new VarExp(loc, v), ea); + + ex = new VarExp(loc, v); + ex = new PtrExp(loc, ex); + e = new AddExp(loc, ex, e2); + e = new CastExp(loc, e, e1.type); + e = new AssignExp(loc, ex.syntaxCopy(), e); + + e = new CommaExp(loc, ea, e); + } + else + { + // Rewrite e1+=e2 to e1=e1+e2 + // BUG: doesn't account for side effects in e1 + // BUG: other assignment operators for bits aren't handled at all + e = new AddExp(loc, e1, e2); + e = new CastExp(loc, e, e1.type); + e = new AssignExp(loc, e1.syntaxCopy(), e); + } +} else { + // Rewrite e1+=e2 to e1=e1+e2 + // BUG: doesn't account for side effects in e1 + // BUG: other assignment operators for bits aren't handled at all + e = new AddExp(loc, e1, e2); + e = new CastExp(loc, e, e1.type); + e = new AssignExp(loc, e1.syntaxCopy(), e); +} + e = e.semantic(sc); + } + else + { + type = e1.type; + typeCombine(sc); + e1.checkArithmetic(); + e2.checkArithmetic(); + + if (type.isreal() || type.isimaginary()) + { + assert(global.errors || e2.type.isfloating()); + e2 = e2.castTo(sc, e1.type); + } + e = this; + } + } + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void buildArrayIdent(OutBuffer buf, Expressions arguments) + { + assert(false); + } + + Expression buildArrayLoop(Arguments fparams) + { + assert(false); + } + + Identifier opId() /* For operator overloading */ + { + return Id.addass; + } + + elem* toElem(IRState* irs) + { + //printf("AddAssignExp::toElem() %s\n", toChars()); + elem *e; + Type tb1 = e1.type.toBasetype(); + Type tb2 = e2.type.toBasetype(); + + if ((tb1.ty == TY.Tarray || tb1.ty == TY.Tsarray) && (tb2.ty == TY.Tarray || tb2.ty == TY.Tsarray)) + { + error("Array operations not implemented"); + } + else + e = toElemBin(irs, OPER.OPaddass); + + return e; + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/AddExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/AddExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,161 @@ +module dmd.AddExp; + +import dmd.Expression; +import dmd.Identifier; +import dmd.backend.elem; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Id; +import dmd.Scope; +import dmd.IRState; +import dmd.ArrayTypes; +import dmd.BinExp; +import dmd.Type; +import dmd.TOK; +import dmd.TY; + +import dmd.expression.Add; +import dmd.backend.Util; +import dmd.backend.OPER; + +class AddExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKadd, AddExp.sizeof, e1, e2); + } + + Expression semantic(Scope sc) + { + Expression e; + +version (LOGSEMANTIC) { + printf("AddExp.semantic('%s')\n", toChars()); +} + if (!type) + { + BinExp.semanticp(sc); + + e = op_overload(sc); + if (e) + return e; + + Type tb1 = e1.type.toBasetype(); + Type tb2 = e2.type.toBasetype(); + + if ((tb1.ty == TY.Tarray || tb1.ty == TY.Tsarray) && + (tb2.ty == TY.Tarray || tb2.ty == TY.Tsarray) && + tb1.nextOf().equals(tb2.nextOf()) + ) + { + type = e1.type; + e = this; + } + else if (tb1.ty == TY.Tpointer && e2.type.isintegral() || + tb2.ty == TY.Tpointer && e1.type.isintegral()) + e = scaleFactor(sc); + else if (tb1.ty == TY.Tpointer && tb2.ty == TY.Tpointer) + { + incompatibleTypes(); + type = e1.type; + e = this; + } + else + { + typeCombine(sc); + if ((e1.type.isreal() && e2.type.isimaginary()) || + (e1.type.isimaginary() && e2.type.isreal())) + { + switch (type.toBasetype().ty) + { + case TY.Tfloat32: + case TY.Timaginary32: + type = Type.tcomplex32; + break; + + case TY.Tfloat64: + case TY.Timaginary64: + type = Type.tcomplex64; + break; + + case TY.Tfloat80: + case TY.Timaginary80: + type = Type.tcomplex80; + break; + } + } + e = this; + } + return e; + } + return this; + } + + Expression optimize(int result) + { + Expression e; + + //printf("AddExp::optimize(%s)\n", toChars()); + e1 = e1.optimize(result); + e2 = e2.optimize(result); + if (e1.isConst() && e2.isConst()) + { + if (e1.op == TOK.TOKsymoff && e2.op == TOK.TOKsymoff) + return this; + e = Add(type, e1, e2); + } + else + e = this; + + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void buildArrayIdent(OutBuffer buf, Expressions arguments) + { + assert(false); + } + + Expression buildArrayLoop(Arguments fparams) + { + assert(false); + } + + bool isCommutative() + { + return true; + } + + Identifier opId() + { + return Id.add; + } + + Identifier opId_r() + { + return Id.add_r; + } + + elem* toElem(IRState* irs) + { + elem *e; + Type tb1 = e1.type.toBasetype(); + Type tb2 = e2.type.toBasetype(); + + if ((tb1.ty == TY.Tarray || tb1.ty == TY.Tsarray) && (tb2.ty == TY.Tarray || tb2.ty == TY.Tsarray)) + { + error("Array operation %s not implemented", toChars()); + e = el_long(type.totym(), 0); // error recovery + } + else + e = toElemBin(irs, OPER.OPadd); + + return e; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/AddrExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/AddrExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,355 @@ +module dmd.AddrExp; + +import dmd.Expression; +import dmd.UnaExp; +import dmd.MATCH; +import dmd.Type; +import dmd.Loc; +import dmd.Scope; +import dmd.IRState; +import dmd.ErrorExp; +import dmd.DotVarExp; +import dmd.FuncDeclaration; +import dmd.DelegateExp; +import dmd.VarExp; +import dmd.VarDeclaration; +import dmd.ThisExp; +import dmd.TOK; +import dmd.WANT; +import dmd.CommaExp; +import dmd.STC; +import dmd.PtrExp; +import dmd.SymOffExp; +import dmd.IndexExp; +import dmd.OverExp; +import dmd.Dsymbol; +import dmd.ScopeDsymbol; +import dmd.TY; +import dmd.TypeSArray; + +import dmd.backend.elem; +import dmd.backend.Util; +import dmd.codegen.Util; + +class AddrExp : UnaExp +{ + this(Loc loc, Expression e) + { + super(loc, TOK.TOKaddress, AddrExp.sizeof, e); + } + + Expression semantic(Scope sc) + { + version (LOGSEMANTIC) { + printf("AddrExp.semantic('%s')\n", toChars()); + } + if (!type) + { + UnaExp.semantic(sc); + e1 = e1.toLvalue(sc, null); + if (!e1.type) + { + error("cannot take address of %s", e1.toChars()); + return new ErrorExp(); + } + if (!e1.type.deco) + { + /* No deco means semantic() was not run on the type. + * We have to run semantic() on the symbol to get the right type: + * auto x = &bar; + * pure: int bar() { return 1;} + * otherwise the 'pure' is missing from the type assigned to x. + */ + + error("forward reference to %s", e1.toChars()); + return new ErrorExp(); + } + + //printf("test3 deco = %p\n", e1.type.deco); + type = e1.type.pointerTo(); + + // See if this should really be a delegate + if (e1.op == TOKdotvar) + { + DotVarExp dve = cast(DotVarExp)e1; + FuncDeclaration f = dve.var.isFuncDeclaration(); + + if (f) + { + if (!dve.hasOverloads) + f.tookAddressOf++; + Expression e = new DelegateExp(loc, dve.e1, f, dve.hasOverloads); + e = e.semantic(sc); + return e; + } + } + else if (e1.op == TOKvar) + { + VarExp ve = cast(VarExp)e1; + + VarDeclaration v = ve.var.isVarDeclaration(); + if (v && !v.canTakeAddressOf()) + error("cannot take address of %s", e1.toChars()); + + FuncDeclaration f = ve.var.isFuncDeclaration(); + + if (f) + { + if (!ve.hasOverloads || + /* Because nested functions cannot be overloaded, + * mark here that we took its address because castTo() + * may not be called with an exact match. + */ + f.toParent2().isFuncDeclaration()) + f.tookAddressOf++; + + if (f.isNested()) + { + Expression e = new DelegateExp(loc, e1, f, ve.hasOverloads); + e = e.semantic(sc); + return e; + } + if (f.needThis() && hasThis(sc)) + { + /* Should probably supply 'this' after overload resolution, + * not before. + */ + Expression ethis = new ThisExp(loc); + Expression e = new DelegateExp(loc, ethis, f, ve.hasOverloads); + e = e.semantic(sc); + return e; + } + } + } + return optimize(WANTvalue); + } + return this; + } + + elem* toElem(IRState* irs) + { + elem* e; + + //printf("AddrExp.toElem('%s')\n", toChars()); + + e = e1.toElem(irs); + e = addressElem(e, e1.type); + L2: + e.Ety = type.totym(); + el_setLoc(e,loc); + return e; + } + + MATCH implicitConvTo(Type t) + { + static if (false) { + printf("AddrExp.implicitConvTo(this=%s, type=%s, t=%s)\n", + toChars(), type.toChars(), t.toChars()); + } + MATCH result; + + result = type.implicitConvTo(t); + //printf("\tresult = %d\n", result); + + if (result == MATCHnomatch) + { + // Look for pointers to functions where the functions are overloaded. + + t = t.toBasetype(); + + if (e1.op == TOKoverloadset && + (t.ty == Tpointer || t.ty == Tdelegate) && t.nextOf().ty == Tfunction) + { + OverExp eo = cast(OverExp)e1; + FuncDeclaration f = null; + for (int i = 0; i < eo.vars.a.dim; i++) + { + Dsymbol s = cast(Dsymbol)eo.vars.a.data[i]; + FuncDeclaration f2 = s.isFuncDeclaration(); + assert(f2); + if (f2.overloadExactMatch(t.nextOf())) + { + if (f) + /* Error if match in more than one overload set, + * even if one is a 'better' match than the other. + */ + ScopeDsymbol.multiplyDefined(loc, f, f2); + else + f = f2; + result = MATCHexact; + } + } + } + + if (type.ty == Tpointer && type.nextOf().ty == Tfunction && + t.ty == Tpointer && t.nextOf().ty == Tfunction && + e1.op == TOKvar) + { + /* I don't think this can ever happen - + * it should have been + * converted to a SymOffExp. + */ + assert(0); + VarExp ve = cast(VarExp)e1; + FuncDeclaration f = ve.var.isFuncDeclaration(); + if (f && f.overloadExactMatch(t.nextOf())) + result = MATCHexact; + } + } + + //printf("\tresult = %d\n", result); + return result; + } + + Expression castTo(Scope sc, Type t) + { + Type tb; + + static if (false) { + printf("AddrExp.castTo(this=%s, type=%s, t=%s)\n", toChars(), type.toChars(), t.toChars()); + } + Expression e = this; + + tb = t.toBasetype(); + type = type.toBasetype(); + if (tb != type) + { + // Look for pointers to functions where the functions are overloaded. + + if (e1.op == TOKoverloadset && + (t.ty == Tpointer || t.ty == Tdelegate) && t.nextOf().ty == Tfunction) + { + OverExp eo = cast(OverExp)e1; + FuncDeclaration f = null; + for (int i = 0; i < eo.vars.a.dim; i++) + { + Dsymbol s = cast(Dsymbol)eo.vars.a.data[i]; + FuncDeclaration f2 = s.isFuncDeclaration(); + assert(f2); + if (f2.overloadExactMatch(t.nextOf())) + { + if (f) + /* Error if match in more than one overload set, + * even if one is a 'better' match than the other. + */ + ScopeDsymbol.multiplyDefined(loc, f, f2); + else + f = f2; + } + } + if (f) + { + f.tookAddressOf++; + SymOffExp se = new SymOffExp(loc, f, 0, 0); + se.semantic(sc); + // Let SymOffExp.castTo() do the heavy lifting + return se.castTo(sc, t); + } + } + + + if (type.ty == Tpointer && type.nextOf().ty == Tfunction && + tb.ty == Tpointer && tb.nextOf().ty == Tfunction && + e1.op == TOKvar) + { + VarExp ve = cast(VarExp)e1; + FuncDeclaration f = ve.var.isFuncDeclaration(); + if (f) + { + assert(0); // should be SymOffExp instead + f = f.overloadExactMatch(tb.nextOf()); + if (f) + { + e = new VarExp(loc, f); + e.type = f.type; + e = new AddrExp(loc, e); + e.type = t; + return e; + } + } + } + e = Expression.castTo(sc, t); + } + e.type = t; + return e; + } + + Expression optimize(int result) + { + Expression e; + + //printf("AddrExp.optimize(result = %d) %s\n", result, toChars()); + + /* Rewrite &(a,b) as (a,&b) + */ + if (e1.op == TOKcomma) + { + CommaExp ce = cast(CommaExp)e1; + AddrExp ae = new AddrExp(loc, ce.e2); + ae.type = type; + e = new CommaExp(ce.loc, ce.e1, ae); + e.type = type; + return e.optimize(result); + } + + if (e1.op == TOKvar) + { + VarExp ve = cast(VarExp)e1; + if (ve.var.storage_class & STCmanifest) + e1 = e1.optimize(result); + } + else + e1 = e1.optimize(result); + + // Convert &*ex to ex + if (e1.op == TOKstar) + { + Expression ex; + + ex = (cast(PtrExp)e1).e1; + if (type.equals(ex.type)) + e = ex; + else + { + e = ex.copy(); + e.type = type; + } + return e; + } + if (e1.op == TOKvar) + { + VarExp ve = cast(VarExp)e1; + if (!ve.var.isOut() && !ve.var.isRef() && + !ve.var.isImportedSymbol()) + { + SymOffExp se = new SymOffExp(loc, ve.var, 0, ve.hasOverloads); + se.type = type; + return se; + } + } + if (e1.op == TOKindex) + { + // Convert &array[n] to &array+n + IndexExp ae = cast(IndexExp)e1; + + if (ae.e2.op == TOKint64 && ae.e1.op == TOKvar) + { + long index = ae.e2.toInteger(); + VarExp ve = cast(VarExp)ae.e1; + if (ve.type.ty == Tsarray + && !ve.var.isImportedSymbol()) + { + TypeSArray ts = cast(TypeSArray)ve.type; + long dim = ts.dim.toInteger(); + if (index < 0 || index >= dim) + error("array index %jd is out of bounds [0..%jd]", index, dim); + e = new SymOffExp(loc, ve.var, cast(uint)(index * ts.nextOf().size())); + e.type = type; + return e; + } + } + } + return this; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/AggregateDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/AggregateDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,643 @@ +module dmd.AggregateDeclaration; + +import dmd.ScopeDsymbol; +import dmd.Type; +import dmd.Id; +import dmd.ExpStatement; +import dmd.AddrExp; +import dmd.CastExp; +import dmd.TypeSArray; +import dmd.DotVarExp; +import dmd.TypeStruct; +import dmd.StructDeclaration; +import dmd.Declaration; +import dmd.TypeClass; +import dmd.TOK; +import dmd.ThisExp; +import dmd.PROT; +import dmd.Expression; +import dmd.STC; +import dmd.DotIdExp; +import dmd.CallExp; +import dmd.DtorDeclaration; +import dmd.Lexer; +import dmd.TY; +import dmd.Array; +import dmd.ArrayTypes; +import dmd.VarDeclaration; +import dmd.InvariantDeclaration; +import dmd.NewDeclaration; +import dmd.DeleteDeclaration; +import dmd.CtorDeclaration; +import dmd.FuncDeclaration; +import dmd.Identifier; +import dmd.Loc; +import dmd.Dsymbol; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.ClassDeclaration; +import dmd.BaseClass; +import dmd.Util; + +import dmd.backend.Symbol; +import dmd.backend.Classsym; +import dmd.backend.Util; +import dmd.backend.LIST; +import dmd.backend.SC; +import dmd.backend.FL; +import dmd.backend.SFL; +import dmd.codegen.Util; + +/**************************************** + * Determine if scope sc has package level access to s. + */ + +bool hasPackageAccess(Scope sc, Dsymbol s) +{ +version (LOG) { + printf("hasPackageAccess(s = '%s', sc = '%p')\n", s.toChars(), sc); +} + + for (; s; s = s.parent) + { + if (s.isPackage() && !s.isModule()) + break; + } +version (LOG) { + if (s) + printf("\tthis is in package '%s'\n", s.toChars()); +} + + if (s && s == sc.module_.parent) + { +version (LOG) { + printf("\ts is in same package as sc\n"); +} + return true; + } + + +version (LOG) { + printf("\tno package access\n"); +} + + return false; +} + +/******************************************************** + * Helper function for ClassDeclaration.accessCheck() + * Returns: + * 0 no access + * 1 access + */ + +bool accessCheckX(Dsymbol smember, Dsymbol sfunc, AggregateDeclaration dthis, AggregateDeclaration cdscope) +{ + assert(dthis); + +static if (false) { + writef("accessCheckX for %s.%s in function %s() in scope %s\n", dthis.toChars(), smember.toChars(), sfunc ? sfunc.toChars() : "null", cdscope ? cdscope.toChars() : "null"); +} + if (dthis.hasPrivateAccess(sfunc) || dthis.isFriendOf(cdscope)) + { + if (smember.toParent() == dthis) + return true; + else + { + ClassDeclaration cdthis = dthis.isClassDeclaration(); + if (cdthis) + { + for (int i = 0; i < cdthis.baseclasses.dim; i++) + { + BaseClass b = cast(BaseClass)cdthis.baseclasses.data[i]; + PROT access = b.base.getAccess(smember); + + if (access >= PROT.PROTprotected || accessCheckX(smember, sfunc, b.base, cdscope)) + return true; + } + } + } + } + else + { + if (smember.toParent() != dthis) + { + ClassDeclaration cdthis = dthis.isClassDeclaration(); + if (cdthis) + { + for (int i = 0; i < cdthis.baseclasses.dim; i++) + { + BaseClass b = cast(BaseClass)cdthis.baseclasses.data[i]; + + if (accessCheckX(smember, sfunc, b.base, cdscope)) + return true; + } + } + } + } + + return false; +} + +class AggregateDeclaration : ScopeDsymbol +{ + Type type; + uint storage_class; + PROT protection = PROT.PROTpublic; + Type handle; // 'this' type + uint structsize; // size of struct + uint alignsize; // size of struct for alignment purposes + uint structalign; // struct member alignment in effect + int hasUnions; // set if aggregate has overlapping fields + Array fields; // VarDeclaration fields + uint sizeok; // set when structsize contains valid data + // 0: no size + // 1: size is correct + // 2: cannot determine size; fwd referenced + bool isdeprecated; // true if deprecated + + bool isnested; // true if is nested + VarDeclaration vthis; // 'this' parameter if this aggregate is nested + + // Special member functions + InvariantDeclaration inv; // invariant + NewDeclaration aggNew; // allocator + DeleteDeclaration aggDelete; // deallocator + +version (DMDV2) { + //CtorDeclaration *ctor; + Dsymbol ctor; // CtorDeclaration or TemplateDeclaration + CtorDeclaration defaultCtor; // default constructor + Dsymbol aliasthis; // forward unresolved lookups to aliasthis +} + + FuncDeclarations dtors; // Array of destructors + FuncDeclaration dtor; // aggregate destructor + +version (IN_GCC) { + Array methods; // flat list of all methods for debug information +} + + this(Loc loc, Identifier id) + { + super(id); + this.loc = loc; + + fields = new Array(); /// + dtors = new FuncDeclarations(); + } + + void semantic2(Scope sc) + { + //printf("AggregateDeclaration.semantic2(%s)\n", toChars()); + if (scope_ && members) + { + error("has forward references"); + return; + } + if (members) + { + sc = sc.push(this); + for (size_t i = 0; i < members.dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + s.semantic2(sc); + } + sc.pop(); + } + } + + void semantic3(Scope sc) + { + int i; + + //printf("AggregateDeclaration.semantic3(%s)\n", toChars()); + if (members) + { + sc = sc.push(this); + for (i = 0; i < members.dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + s.semantic3(sc); + } + sc.pop(); + } + } + + void inlineScan() + { + int i; + + //printf("AggregateDeclaration.inlineScan(%s)\n", toChars()); + if (members) + { + for (i = 0; i < members.dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + //printf("inline scan aggregate symbol '%s'\n", s.toChars()); + s.inlineScan(); + } + } + } + + uint size(Loc loc) + { + //printf("AggregateDeclaration.size() = %d\n", structsize); + if (!members) + error(loc, "unknown size"); + + if (sizeok != 1) + { + error(loc, "no size yet for forward reference"); + //*(char*)0=0; + } + + return structsize; + } + + /**************************** + * Do byte or word alignment as necessary. + * Align sizes of 0, as we may not know array sizes yet. + */ + static void alignmember(uint salign, uint size, uint* poffset) + { + //printf("salign = %d, size = %d, offset = %d\n",salign,size,offset); + if (salign > 1) + { + assert(size != 3); + int sa = size; + if (sa == 0 || salign < sa) + sa = salign; + *poffset = (*poffset + sa - 1) & ~(sa - 1); + } + //printf("result = %d\n",offset); + } + + Type getType() + { + return type; + } + + void addField(Scope sc, VarDeclaration v) + { + uint memsize; // size of member + uint memalignsize; // size of member for alignment purposes + uint xalign; // alignment boundaries + + //printf("AggregateDeclaration.addField('%s') %s\n", v.toChars(), toChars()); + assert(!(v.storage_class & (STC.STCstatic | STC.STCextern | STC.STCparameter | STC.STCtls))); + + // Check for forward referenced types which will fail the size() call + Type t = v.type.toBasetype(); + if (v.storage_class & STC.STCref) + { // References are the size of a pointer + t = Type.tvoidptr; + } + if (t.ty == TY.Tstruct /*&& isStructDeclaration()*/) + { TypeStruct ts = cast(TypeStruct)t; +version (DMDV2) { + if (ts.sym == this) + { + error("cannot have field %s with same struct type", v.toChars()); + } +} + + if (ts.sym.sizeok != 1) + { + sizeok = 2; // cannot finish; flag as forward referenced + return; + } + } + if (t.ty == TY.Tident) + { + sizeok = 2; // cannot finish; flag as forward referenced + return; + } + + memsize = cast(uint)t.size(loc); /// + memalignsize = t.alignsize(); + xalign = t.memalign(sc.structalign); + alignmember(xalign, memalignsize, &sc.offset); + v.offset = sc.offset; + sc.offset += memsize; + if (sc.offset > structsize) + structsize = sc.offset; + if (sc.structalign < memalignsize) + memalignsize = sc.structalign; + if (alignsize < memalignsize) + alignsize = memalignsize; + //printf("\talignsize = %d\n", alignsize); + + v.storage_class |= STC.STCfield; + //printf(" addField '%s' to '%s' at offset %d, size = %d\n", v.toChars(), toChars(), v.offset, memsize); + fields.push(cast(void*)v); + } + + bool isDeprecated() // is aggregate deprecated? + { + return isdeprecated; + } + + /***************************************** + * Create inclusive destructor for struct/class by aggregating + * all the destructors in dtors[] with the destructors for + * all the members. + * Note the close similarity with StructDeclaration.buildPostBlit(), + * and the ordering changes (runs backward instead of forwards). + */ + FuncDeclaration buildDtor(Scope sc) + { + //printf("AggregateDeclaration.buildDtor() %s\n", toChars()); + Expression e = null; + +version (DMDV2) { + for (size_t i = 0; i < fields.dim; i++) + { + Dsymbol s = cast(Dsymbol)fields.data[i]; + VarDeclaration v = s.isVarDeclaration(); + assert(v && v.storage_class & STC.STCfield); + if (v.storage_class & STC.STCref) + continue; + Type tv = v.type.toBasetype(); + size_t dim = 1; + while (tv.ty == TY.Tsarray) + { TypeSArray ta = cast(TypeSArray)tv; + dim *= (cast(TypeSArray)tv).dim.toInteger(); + tv = tv.nextOf().toBasetype(); + } + if (tv.ty == TY.Tstruct) + { TypeStruct ts = cast(TypeStruct)tv; + StructDeclaration sd = ts.sym; + if (sd.dtor) + { + Expression ex; + + // this.v + ex = new ThisExp(Loc(0)); + ex = new DotVarExp(Loc(0), ex, v, 0); + + if (dim == 1) + { + // this.v.dtor() + ex = new DotVarExp(Loc(0), ex, sd.dtor, 0); + ex = new CallExp(Loc(0), ex); + } + else + { + // Typeinfo.destroy(cast(void*)&this.v); + Expression ea = new AddrExp(Loc(0), ex); + ea = new CastExp(Loc(0), ea, Type.tvoid.pointerTo()); + + Expression et = v.type.getTypeInfo(sc); + et = new DotIdExp(Loc(0), et, Id.destroy); + + ex = new CallExp(Loc(0), et, ea); + } + e = Expression.combine(ex, e); // combine in reverse order + } + } + } + + /* Build our own "destructor" which executes e + */ + if (e) + { + //printf("Building __fieldDtor()\n"); + DtorDeclaration dd = new DtorDeclaration(Loc(0), Loc(0), Lexer.idPool("__fieldDtor")); + dd.fbody = new ExpStatement(Loc(0), e); + dtors.shift(cast(void*)dd); + members.push(cast(void*)dd); + dd.semantic(sc); + } +} + + switch (dtors.dim) + { + case 0: + return null; + + case 1: + return cast(FuncDeclaration)dtors.data[0]; + + default: + e = null; + for (size_t i = 0; i < dtors.dim; i++) + { + FuncDeclaration fd = cast(FuncDeclaration)dtors.data[i]; + Expression ex = new ThisExp(Loc(0)); + ex = new DotVarExp(Loc(0), ex, fd, 0); + ex = new CallExp(Loc(0), ex); + e = Expression.combine(ex, e); + } + DtorDeclaration dd = new DtorDeclaration(Loc(0), Loc(0), Lexer.idPool("__aggrDtor")); + dd.fbody = new ExpStatement(Loc(0), e); + members.push(cast(void*)dd); + dd.semantic(sc); + return dd; + } + } + + /**************************************** + * Returns true if there's an extra member which is the 'this' + * pointer to the enclosing context (enclosing aggregate or function) + */ + bool isNested() + { + return isnested; + } + + void emitComment(Scope sc) + { + assert(false); + } + + void toDocBuffer(OutBuffer buf) + { + assert(false); + } + + // For access checking + PROT getAccess(Dsymbol smember) // determine access to smember + { + assert(false); + } + + /**************************************** + * Determine if this is the same or friend of cd. + */ + bool isFriendOf(AggregateDeclaration cd) + { +version (LOG) { + printf("AggregateDeclaration.isFriendOf(this = '%s', cd = '%s')\n", toChars(), cd ? cd.toChars() : "null"); +} + if (this is cd) + return true; + + // Friends if both are in the same module + //if (toParent() == cd.toParent()) + if (cd && getModule() == cd.getModule()) + { +version (LOG) { + printf("\tin same module\n"); +} + return true; + } + +version (LOG) { + printf("\tnot friend\n"); +} + return false; + } + + /********************************** + * Determine if smember has access to private members of this declaration. + */ + bool hasPrivateAccess(Dsymbol smember) // does smember have private access to members of this class? + { + if (smember) + { + AggregateDeclaration cd = null; + Dsymbol smemberparent = smember.toParent(); + if (smemberparent) + cd = smemberparent.isAggregateDeclaration(); + + version (LOG) { + printf("AggregateDeclaration::hasPrivateAccess(class %s, member %s)\n", toChars(), smember.toChars()); + } + + if (this == cd) // smember is a member of this class + { + version (LOG) { + printf("\tyes 1\n"); + } + return true; // so we get private access + } + + // If both are members of the same module, grant access + while (true) + { + Dsymbol sp = smember.toParent(); + if (sp.isFuncDeclaration() && smember.isFuncDeclaration()) + smember = sp; + else + break; + } + if (!cd && toParent() == smember.toParent()) + { + version (LOG) { + printf("\tyes 2\n"); + } + return true; + } + if (!cd && getModule() == smember.getModule()) + { + version (LOG) { + printf("\tyes 3\n"); + } + return true; + } + } + version (LOG) { + printf("\tno\n"); + } + return false; + } + + /******************************* + * Do access check for member of this class, this class being the + * type of the 'this' pointer used to access smember. + */ + void accessCheck(Loc loc, Scope sc, Dsymbol smember) + { + bool result; + + FuncDeclaration f = sc.func; + AggregateDeclaration cdscope = sc.getStructClassScope(); + PROT access; + +version (LOG) { + printf("AggregateDeclaration.accessCheck() for %s.%s in function %s() in scope %s\n", toChars(), smember.toChars(), f ? f.toChars() : null, cdscope ? cdscope.toChars() : null); +} + + Dsymbol smemberparent = smember.toParent(); + if (!smemberparent || !smemberparent.isAggregateDeclaration()) + { + version (LOG) { + printf("not an aggregate member\n"); + } + return; // then it is accessible + } + + // BUG: should enable this check + //assert(smember.parent.isBaseOf(this, null)); + + if (smemberparent == this) + { + PROT access2 = smember.prot(); + + result = access2 >= PROT.PROTpublic || + hasPrivateAccess(f) || + isFriendOf(cdscope) || + (access2 == PROT.PROTpackage && hasPackageAccess(sc, this)); + +version (LOG) { + printf("result1 = %d\n", result); +} + } + else if ((access = this.getAccess(smember)) >= PROT.PROTpublic) + { + result = true; +version (LOG) { + printf("result2 = %d\n", result); +} + } + else if (access == PROT.PROTpackage && hasPackageAccess(sc, this)) + { + result = true; +version (LOG) { + printf("result3 = %d\n", result); +} + } + else + { + result = accessCheckX(smember, f, this, cdscope); +version (LOG) { + printf("result4 = %d\n", result); +} + } + if (!result) + { + error(loc, "member %s is not accessible", smember.toChars()); + halt(); + } + } + + PROT prot() + { + assert(false); + } + + // Back end + Symbol* stag; // tag symbol for debug data + Symbol* sinit; + + Symbol* toInitializer() + { + Symbol* s; + Classsym* stag; + + if (!sinit) + { + stag = fake_classsym(Id.ClassInfo); + s = toSymbolX("__init", SC.SCextern, stag.Stype, "Z"); + s.Sfl = FL.FLextern; + s.Sflags |= SFL.SFLnodebug; + slist_add(s); + sinit = s; + } + + return sinit; + } + + AggregateDeclaration isAggregateDeclaration() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/AliasDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/AliasDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,233 @@ +module dmd.AliasDeclaration; + +import dmd.LINK; +import dmd.Declaration; +import dmd.TypedefDeclaration; +import dmd.VarDeclaration; +import dmd.FuncDeclaration; +import dmd.FuncAliasDeclaration; +import dmd.Dsymbol; +import dmd.ScopeDsymbol; +import dmd.Loc; +import dmd.Identifier; +import dmd.Type; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Scope; +import dmd.STC; +import dmd.Expression; +import dmd.Global; + +class AliasDeclaration : Declaration +{ + Dsymbol aliassym; + Dsymbol overnext; // next in overload list + int inSemantic; + + this(Loc loc, Identifier ident, Type type) + { + super(ident); + + //printf("AliasDeclaration(id = '%s', type = %p)\n", id.toChars(), type); + //printf("type = '%s'\n", type.toChars()); + this.loc = loc; + this.type = type; + this.aliassym = null; + version (_DH) { + this.htype = null; + this.haliassym = null; + } + + assert(type); + } + + this(Loc loc, Identifier id, Dsymbol s) + { + super(id); + + //printf("AliasDeclaration(id = '%s', s = %p)\n", id->toChars(), s); + assert(s !is this); /// huh? + this.loc = loc; + this.type = null; + this.aliassym = s; + version (_DH) { + this.htype = null; + this.haliassym = null; + } + assert(s); + } + + Dsymbol syntaxCopy(Dsymbol) + { + assert(false); + } + + void semantic(Scope sc) + { + //printf("AliasDeclaration.semantic() %s\n", toChars()); + if (aliassym) + { + if (aliassym.isTemplateInstance()) + aliassym.semantic(sc); + return; + } + this.inSemantic = 1; + + if (storage_class & STC.STCconst) + error("cannot be const"); + + storage_class |= sc.stc & STC.STCdeprecated; + + // Given: + // alias foo.bar.abc def; + // it is not knowable from the syntax whether this is an alias + // for a type or an alias for a symbol. It is up to the semantic() + // pass to distinguish. + // If it is a type, then type is set and getType() will return that + // type. If it is a symbol, then aliassym is set and type is null - + // toAlias() will return aliasssym. + + Dsymbol s; + Type t; + Expression e; + + /* This section is needed because resolve() will: + * const x = 3; + * alias x y; + * try to alias y to 3. + */ + s = type.toDsymbol(sc); + if (s && ((s.getType() && type.equals(s.getType())) || s.isEnumMember())) + goto L2; // it's a symbolic alias + +///version (DMDV2) { + if (storage_class & STC.STCref) + { // For 'ref' to be attached to function types, and picked + // up by Type.resolve(), it has to go into sc. + sc = sc.push(); + sc.stc |= STC.STCref; + type.resolve(loc, sc, &e, &t, &s); + sc = sc.pop(); + } + else +/// #endif + type.resolve(loc, sc, &e, &t, &s); + if (s) + { + goto L2; + } + else if (e) + { + // Try to convert Expression to Dsymbol + s = getDsymbol(e); + if (s) + goto L2; + + error("cannot alias an expression %s", e.toChars()); + t = e.type; + } + else if (t) + { + type = t; + } + if (overnext) + ScopeDsymbol.multiplyDefined(Loc(0), this, overnext); + this.inSemantic = 0; + return; + + L2: + //printf("alias is a symbol %s %s\n", s.kind(), s.toChars()); + type = null; + VarDeclaration v = s.isVarDeclaration(); + if (v && v.linkage == LINK.LINKdefault) + { + error("forward reference of %s", v.toChars()); + s = null; + } + else + { + FuncDeclaration f = s.toAlias().isFuncDeclaration(); + if (f) + { + if (overnext) + { + FuncAliasDeclaration fa = new FuncAliasDeclaration(f); + if (!fa.overloadInsert(overnext)) + ScopeDsymbol.multiplyDefined(Loc(0), f, overnext); + overnext = null; + s = fa; + s.parent = sc.parent; + } + } + if (overnext) + ScopeDsymbol.multiplyDefined(Loc(0), s, overnext); + if (s == this) + { + assert(global.errors); + s = null; + } + } + //printf("setting aliassym %p to %p\n", this, s); + aliassym = s; + this.inSemantic = 0; + } + + bool overloadInsert(Dsymbol s) + { + /* Don't know yet what the aliased symbol is, so assume it can + * be overloaded and check later for correctness. + */ + + //printf("AliasDeclaration.overloadInsert('%s')\n", s.toChars()); + if (overnext is null) + { + overnext = s; + return true; + } + else + { + return overnext.overloadInsert(s); + } + } + + string kind() + { + return "alias"; + } + + Type getType() + { + return type; + } + + Dsymbol toAlias() + { + //printf("AliasDeclaration::toAlias('%s', this = %p, aliassym = %p, kind = '%s')\n", toChars(), this, aliassym, aliassym ? aliassym->kind() : ""); + assert(this !is aliassym); + //static int count; if (++count == 10) *(char*)0=0; + if (inSemantic) + { + error("recursive alias declaration"); + aliassym = new TypedefDeclaration(loc, ident, Type.terror, null); + } + + Dsymbol s = aliassym ? aliassym.toAlias() : this; + return s; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + +version (_DH) { + Type htype; + Dsymbol haliassym; +} + void toDocBuffer(OutBuffer buf) + { + assert(false); + } + + AliasDeclaration isAliasDeclaration() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/AliasThis.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/AliasThis.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,41 @@ +module dmd.AliasThis; + +import dmd.Dsymbol; +import dmd.Identifier; +import dmd.Loc; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; + +class AliasThis : Dsymbol +{ + // alias Identifier this; + Identifier ident; + + this(Loc loc, Identifier ident) + { + assert(false); + } + + Dsymbol syntaxCopy(Dsymbol) + { + assert(false); + } + + void semantic(Scope sc) + { + assert(false); + } + + string kind() + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + AliasThis isAliasThis() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/AlignDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/AlignDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,47 @@ +module dmd.AlignDeclaration; + +import dmd.AttribDeclaration; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Scope; +import dmd.Dsymbol; +import dmd.Array; + +class AlignDeclaration : AttribDeclaration +{ + uint salign; + + this(uint sa, Array decl) + { + super(decl); + salign = sa; + } + + Dsymbol syntaxCopy(Dsymbol s) + { + assert(false); + } + + void setScope(Scope sc) + { + //printf("\tAlignDeclaration::setScope '%s'\n",toChars()); + if (decl) + { + setScopeNewSc(sc, sc.stc, sc.linkage, sc.protection, sc.explicitProtection, salign); + } + } + + void semantic(Scope sc) + { + //printf("\tAlignDeclaration::semantic '%s'\n",toChars()); + if (decl) + { + semanticNewSc(sc, sc.stc, sc.linkage, sc.protection, sc.explicitProtection, salign); + } + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/AndAndExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/AndAndExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,126 @@ +module dmd.AndAndExp; + +import dmd.Expression; +import dmd.InterState; +import dmd.Loc; +import dmd.Scope; +import dmd.IRState; +import dmd.CommaExp; +import dmd.Global; +import dmd.BoolExp; +import dmd.BinExp; +import dmd.TOK; +import dmd.WANT; +import dmd.IntegerExp; +import dmd.Type; +import dmd.TY; + +import dmd.backend.elem; +import dmd.backend.OPER; +import dmd.backend.Util; + +class AndAndExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKandand, AndAndExp.sizeof, e1, e2); + } + + Expression semantic(Scope sc) + { + uint cs1; + + // same as for OrOr + e1 = e1.semantic(sc); + e1 = resolveProperties(sc, e1); + e1 = e1.checkToPointer(); + e1 = e1.checkToBoolean(); + cs1 = sc.callSuper; + + if (sc.flags & SCOPE.SCOPEstaticif) + { + /* If in static if, don't evaluate e2 if we don't have to. + */ + e1 = e1.optimize(WANTflags); + if (e1.isBool(false)) + { + return new IntegerExp(loc, 0, Type.tboolean); + } + } + + e2 = e2.semantic(sc); + sc.mergeCallSuper(loc, cs1); + e2 = resolveProperties(sc, e2); + e2 = e2.checkToPointer(); + + type = Type.tboolean; + if (e2.type.ty == Tvoid) + type = Type.tvoid; + if (e2.op == TOKtype || e2.op == TOKimport) + error("%s is not an expression", e2.toChars()); + return this; + } + + Expression checkToBoolean() + { + e2 = e2.checkToBoolean(); + return this; + } + + int isBit() + { + assert(false); + } + + Expression optimize(int result) + { + //printf("AndAndExp::optimize(%d) %s\n", result, toChars()); + e1 = e1.optimize(WANTflags | (result & WANTinterpret)); + Expression e = this; + if (e1.isBool(false)) + { + e = new CommaExp(loc, e1, new IntegerExp(loc, 0, type)); + e.type = type; + e = e.optimize(result); + } + else + { + e2 = e2.optimize(WANTflags | (result & WANTinterpret)); + if (result && e2.type.toBasetype().ty == Tvoid && !global.errors) + error("void has no value"); + + if (e1.isConst()) + { + if (e2.isConst()) + { + int n1 = e1.isBool(1); + int n2 = e2.isBool(1); + + e = new IntegerExp(loc, n1 && n2, type); + } + else if (e1.isBool(true)) + e = new BoolExp(loc, e2, type); + } + } + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + bool checkSideEffect(int flag) + { + assert(false); + } + + elem* toElem(IRState* irs) + { + elem* e = toElemBin(irs, OPandand); + if (global.params.cov && e2.loc.linnum) + e.E2() = el_combine(incUsageElem(irs, e2.loc), e.E2); + return e; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/AndAssignExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/AndAssignExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,54 @@ +module dmd.AndAssignExp; + +import dmd.BinExp; +import dmd.Loc; +import dmd.Expression; +import dmd.Scope; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.ArrayTypes; +import dmd.Identifier; +import dmd.IRState; +import dmd.TOK; +import dmd.Id; + +import dmd.backend.elem; +import dmd.backend.OPER; + +class AndAssignExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKandass, AndAssignExp.sizeof, e1, e2); + } + + Expression semantic(Scope sc) + { + return commonSemanticAssignIntegral(sc); + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void buildArrayIdent(OutBuffer buf, Expressions arguments) + { + assert(false); + } + + Expression buildArrayLoop(Arguments fparams) + { + assert(false); + } + + Identifier opId() /* For operator overloading */ + { + return Id.andass; + } + + elem* toElem(IRState* irs) + { + return toElemBin(irs, OPER.OPandass); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/AndExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/AndExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,116 @@ +module dmd.AndExp; + +import dmd.Expression; +import dmd.Identifier; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.IntRange; +import dmd.IRState; +import dmd.BinExp; +import dmd.TOK; +import dmd.ArrayTypes; +import dmd.TY; +import dmd.Type; +import dmd.Id; +import dmd.Global; + +import dmd.backend.elem; +import dmd.backend.Util; +import dmd.backend.OPER; +import dmd.expression.Util; +import dmd.expression.And; + +class AndExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKand, AndExp.sizeof, e1, e2); + } + + Expression semantic(Scope sc) + { + Expression e; + + if (!type) + { + BinExp.semanticp(sc); + e = op_overload(sc); + + if (e) + return e; + + if (e1.type.toBasetype().ty == TY.Tbool && e2.type.toBasetype().ty == TY.Tbool) + { + type = e1.type; + e = this; + } + else + { + typeCombine(sc); + if (e1.op != TOK.TOKslice && e2.op != TOK.TOKslice) + { + e1.checkIntegral(); + e2.checkIntegral(); + } + } + } + return this; + } + + Expression optimize(int result) + { + Expression e; + + e1 = e1.optimize(result); + e2 = e2.optimize(result); + if (e1.isConst() == 1 && e2.isConst() == 1) + e = And(type, e1, e2); + else + e = this; + + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void buildArrayIdent(OutBuffer buf, Expressions arguments) + { + assert(false); + } + + Expression buildArrayLoop(Arguments fparams) + { + assert(false); + } + + IntRange getIntRange() + { + assert(false); + } + + bool isCommutative() + { + return true; + } + + Identifier opId() + { + return Id.iand; + } + + Identifier opId_r() + { + return Id.iand_r; + } + + elem* toElem(IRState* irs) + { + return toElemBin(irs, OPER.OPand); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/AnonDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/AnonDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,169 @@ +module dmd.AnonDeclaration; + +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.Array; +import dmd.AttribDeclaration; +import dmd.HdrGenState; +import dmd.Dsymbol; +import dmd.AggregateDeclaration; +import dmd.AnonymousAggregateDeclaration; +import dmd.STC; +import dmd.Module; +import dmd.VarDeclaration; + +class AnonDeclaration : AttribDeclaration +{ + int isunion; + int sem = 0; // 1 if successful semantic() + + this(Loc loc, int isunion, Array decl) + { + super(decl); + this.loc = loc; + this.isunion = isunion; + } + + Dsymbol syntaxCopy(Dsymbol s) + { + assert(false); + } + + void semantic(Scope sc) + { + //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this); + + Scope scx = null; + if (scope_) + { + sc = scope_; + scx = scope_; + scope_ = null; + } + + assert(sc.parent); + + Dsymbol parent = sc.parent.pastMixin(); + AggregateDeclaration ad = parent.isAggregateDeclaration(); + + if (!ad || (!ad.isStructDeclaration() && !ad.isClassDeclaration())) + { + error("can only be a part of an aggregate"); + return; + } + + if (decl) + { + AnonymousAggregateDeclaration aad = new AnonymousAggregateDeclaration(); + int adisunion; + + if (sc.anonAgg) + { + ad = sc.anonAgg; + adisunion = sc.inunion; + } + else + adisunion = ad.isUnionDeclaration() !is null; + + // printf("\tsc.anonAgg = %p\n", sc.anonAgg); + // printf("\tad = %p\n", ad); + // printf("\taad = %p\n", &aad); + + sc = sc.push(); + sc.anonAgg = aad; + sc.stc &= ~(STCauto | STCscope | STCstatic | STCtls | STCgshared); + sc.inunion = isunion; + sc.offset = 0; + sc.flags = cast(SCOPE)0; + aad.structalign = sc.structalign; + aad.parent = ad; + + for (uint i = 0; i < decl.dim; i++) + { + Dsymbol s = cast(Dsymbol)decl.data[i]; + + s.semantic(sc); + if (isunion) + sc.offset = 0; + if (aad.sizeok == 2) + break; + } + sc = sc.pop(); + + // If failed due to forward references, unwind and try again later + if (aad.sizeok == 2) + { + ad.sizeok = 2; + //printf("\tsetting ad.sizeok %p to 2\n", ad); + if (!sc.anonAgg) + { + scope_ = scx ? scx : new Scope(sc); ///< + scope_.setNoFree(); + scope_.module_.addDeferredSemantic(this); + } + //printf("\tforward reference %p\n", this); + return; + } + if (sem == 0) + { + Module.dprogress++; + sem = 1; + //printf("\tcompleted %p\n", this); + } + else { + ;//printf("\talready completed %p\n", this); + } + + // 0 sized structs are set to 1 byte + if (aad.structsize == 0) + { + aad.structsize = 1; + aad.alignsize = 1; + } + + // Align size of anonymous aggregate + //printf("aad.structalign = %d, aad.alignsize = %d, sc.offset = %d\n", aad.structalign, aad.alignsize, sc.offset); + ad.alignmember(aad.structalign, aad.alignsize, &sc.offset); + //ad.structsize = sc.offset; + //printf("sc.offset = %d\n", sc.offset); + + // Add members of aad to ad + //printf("\tadding members of aad to '%s'\n", ad.toChars()); + for (uint i = 0; i < aad.fields.dim; i++) + { + VarDeclaration v = cast(VarDeclaration)aad.fields.data[i]; + + v.offset += sc.offset; + ad.fields.push(cast(void*)v); + } + + // Add size of aad to ad + if (adisunion) + { + if (aad.structsize > ad.structsize) + ad.structsize = aad.structsize; + sc.offset = 0; + } + else + { + ad.structsize = sc.offset + aad.structsize; + sc.offset = ad.structsize; + } + + if (ad.alignsize < aad.alignsize) + ad.alignsize = aad.alignsize; + } + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + string kind() + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/AnonymousAggregateDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/AnonymousAggregateDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,14 @@ +module dmd.AnonymousAggregateDeclaration; + +import dmd.AggregateDeclaration; +import dmd.Loc; + +class AnonymousAggregateDeclaration : AggregateDeclaration +{ + this() + { + super(Loc(0), null); + } + + AnonymousAggregateDeclaration isAnonymousAggregateDeclaration() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/Argument.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Argument.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,278 @@ +module dmd.Argument; + +import dmd.Type; +import dmd.Identifier; +import dmd.TypeTuple; +import dmd.TY; +import dmd.Expression; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.ArrayTypes; +import dmd.StorageClassDeclaration; +import dmd.Global; +import dmd.MOD; +import dmd.CppMangleState; +import dmd.STC; + +class Argument +{ + //enum InOut inout; + STC storageClass; + Type type; + Identifier ident; + Expression defaultArg; + + this(STC storageClass, Type type, Identifier ident, Expression defaultArg) + { + this.type = type; + this.ident = ident; + this.storageClass = storageClass; + this.defaultArg = defaultArg; + } + + Argument clone() + { + return new Argument(storageClass, type, ident, defaultArg); + } + + Argument syntaxCopy() + { + return new Argument(storageClass, type ? type.syntaxCopy() : null, ident, defaultArg ? defaultArg.syntaxCopy() : null); + } + + Type isLazyArray() + { + assert(false); + } + + void toDecoBuffer(OutBuffer buf) + { + if (storageClass & STC.STCscope) + buf.writeByte('M'); + switch (storageClass & (STC.STCin | STC.STCout | STC.STCref | STC.STClazy)) + { + case STC.STCundefined: + case STC.STCin: + break; + case STC.STCout: + buf.writeByte('J'); + break; + case STC.STCref: + buf.writeByte('K'); + break; + case STC.STClazy: + buf.writeByte('L'); + break; + } +static if (false) { + int mod = 0x100; + if (type.toBasetype().ty == TY.Tclass) + mod = 0; + type.toDecoBuffer(buf, mod); +} else { + //type.toHeadMutable().toDecoBuffer(buf, 0); + type.toDecoBuffer(buf, 0); +} + } + + static Arguments arraySyntaxCopy(Arguments args) + { + Arguments a = null; + + if (args) + { + a = new Arguments(); + a.setDim(args.dim); + + for (size_t i = 0; i < a.dim; i++) + { + Argument arg = cast(Argument)args.data[i]; + + arg = arg.syntaxCopy(); + a.data[i] = cast(void*)arg; + } + } + + return a; + } + + static string argsTypesToChars(Arguments args, int varargs) + { + scope OutBuffer buf = new OutBuffer(); + + static if (true) { + HdrGenState hgs; + argsToCBuffer(buf, &hgs, args, varargs); + } else { + buf.writeByte('('); + if (args) + { + OutBuffer argbuf; + HdrGenState hgs; + + for (int i = 0; i < args.dim; i++) + { + if (i) + buf.writeByte(','); + Argument arg = cast(Argument)args.data[i]; + argbuf.reset(); + arg.type.toCBuffer2(&argbuf, &hgs, 0); + buf.write(&argbuf); + } + if (varargs) + { + if (i && varargs == 1) + buf.writeByte(','); + buf.writestring("..."); + } + } + buf.writeByte(')'); + } + return buf.toChars(); + } + + static void argsCppMangle(OutBuffer buf, CppMangleState* cms, Arguments arguments, int varargs) + { + assert(false); + } + + static void argsToCBuffer(OutBuffer buf, HdrGenState* hgs, Arguments arguments, int varargs) + { + buf.writeByte('('); + if (arguments) + { + int i; + scope OutBuffer argbuf = new OutBuffer(); + + for (i = 0; i < arguments.dim; i++) + { + if (i) + buf.writestring(", "); + Argument arg = cast(Argument)arguments.data[i]; + + if (arg.storageClass & STCout) + buf.writestring("out "); + else if (arg.storageClass & STCref) + buf.writestring((global.params.Dversion == 1) ? "inout " : "ref "); + else if (arg.storageClass & STCin) + buf.writestring("in "); + else if (arg.storageClass & STClazy) + buf.writestring("lazy "); + else if (arg.storageClass & STCalias) + buf.writestring("alias "); + else if (arg.storageClass & STCauto) + buf.writestring("auto "); + + uint stc = arg.storageClass; + if (arg.type && arg.type.mod & MODshared) + stc &= ~STCshared; + + StorageClassDeclaration.stcToCBuffer(buf, stc & (STCconst | STCimmutable | STCshared | STCscope)); + + argbuf.reset(); + if (arg.storageClass & STCalias) + { + if (arg.ident) + argbuf.writestring(arg.ident.toChars()); + } + else + arg.type.toCBuffer(argbuf, arg.ident, hgs); + if (arg.defaultArg) + { + argbuf.writestring(" = "); + arg.defaultArg.toCBuffer(argbuf, hgs); + } + buf.write(argbuf); + } + if (varargs) + { + if (i && varargs == 1) + buf.writeByte(','); + buf.writestring("..."); + } + } + buf.writeByte(')'); + } + + static void argsToDecoBuffer(OutBuffer buf, Arguments arguments) + { + //printf("Argument::argsToDecoBuffer()\n"); + + // Write argument types + if (arguments) + { + size_t dim = Argument.dim(arguments); + for (size_t i = 0; i < dim; i++) + { + Argument arg = Argument.getNth(arguments, i); + arg.toDecoBuffer(buf); + } + } + } + + static int isTPL(Arguments arguments) + { + assert(false); + } + + /*************************************** + * Determine number of arguments, folding in tuples. + */ + static size_t dim(Arguments args) + { + size_t n = 0; + if (args) + { + for (size_t i = 0; i < args.dim; i++) + { + Argument arg = cast(Argument)args.data[i]; + Type t = arg.type.toBasetype(); + + if (t.ty == TY.Ttuple) + { + TypeTuple tu = cast(TypeTuple)t; + n += dim(tu.arguments); + } + else + n++; + } + } + return n; + } + + /*************************************** + * Get nth Argument, folding in tuples. + * Returns: + * Argument nth Argument + * null not found, *pn gets incremented by the number + * of Arguments + */ + static Argument getNth(Arguments args, size_t nth, size_t* pn = null) + { + if (!args) + return null; + + size_t n = 0; + for (size_t i = 0; i < args.dim; i++) + { + Argument arg = cast(Argument)args.data[i]; + Type t = arg.type.toBasetype(); + + if (t.ty == TY.Ttuple) + { TypeTuple tu = cast(TypeTuple)t; + arg = getNth(tu.arguments, nth - n, &n); + if (arg) + return arg; + } + else if (n == nth) + return arg; + else + n++; + } + + if (pn) + *pn += n; + + return null; + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/Array.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Array.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,183 @@ +module dmd.Array; + +import std.contracts; +import core.stdc.stdlib; +import core.stdc.string; + +class Array +{ + uint dim = 0; + uint allocdim = 0; + void** data = null; + + ~this() + { + ///mem.free(data); + free(data); + } + + void mark() + { + ///unsigned u; + ///mem.mark(data); + ///for (u = 0; u < dim; u++) + ///mem.mark(data[u]); // BUG: what if arrays of Object's? + } + + string toString() + { + char *p; + + ///char **buf = cast(char**)alloca(dim * (char*).sizeof); + scope string[] buf = new string[dim]; + uint len = 2; + for (uint u = 0; u < dim; u++) { + buf[u] = (cast(Object)data[u]).toString(); + len += buf[u].length + 1; + } + + char* str = cast(char*)malloc(len); + + str[0] = '['; + p = str + 1; + + for (uint u = 0; u < dim; u++) + { + if (u != 0) { + *p++ = ','; + } + uint length = buf[u].length; + p[0..length] = buf[u][]; + + p += length; + } + + *p++ = ']'; + *p = 0; + + return assumeUnique(str[0..len]); + } + + final void reserve(uint nentries) + { + //printf("Array::reserve: size = %d, offset = %d, nbytes = %d\n", size, offset, nbytes); + if (allocdim - dim < nentries) { + allocdim = dim + nentries; + /// data = (void **)mem.realloc(data, allocdim * sizeof(*data)); + data = cast(void**)realloc(data, allocdim * (*data).sizeof); + } + } + + final void setDim(uint newdim) + { + if (dim < newdim) { + reserve(newdim - dim); + } + + dim = newdim; + } + + final void fixDim() + { + if (dim != allocdim) + { + ///data = (void**)mem.realloc(data, dim * sizeof(*data)); + data = cast(void**)realloc(data, dim * (*data).sizeof); + allocdim = dim; + } + } + + final void push(void* ptr) + { + reserve(1); + data[dim++] = ptr; + } + + final void* pop() + { + return data[--dim]; + } + + final void shift(void* ptr) + { + reserve(1); + memmove(data + 1, data, dim * (*data).sizeof); + data[0] = ptr; + dim++; + } + + final void insert(uint index, void* ptr) + { + reserve(1); + memmove(data + index + 1, data + index, (dim - index) * (*data).sizeof); + data[index] = ptr; + dim++; + } + + final void insert(uint index, Array a) + { + if (a !is null) { + uint d = a.dim; + reserve(d); + + if (dim != index) { + memmove(data + index + d, data + index, (dim - index) * (*data).sizeof); + } + + memcpy(data + index, a.data, d * (*data).sizeof); + dim += d; + } + } + + /*********************************** + * Append array a to this array. + */ + final void append(Array a) + { + insert(dim, a); + } + + final void remove(uint i) + { + memmove(data + i, data + i + 1, (dim - i) * (*data).sizeof); + dim--; + } + + final void zero() + { + memset(data, 0, dim * (*data).sizeof); + } + + final void* tos() + { + return dim ? data[dim - 1] : null; + } + + private static extern (C) int Array_sort_compare(const(void*) x, const(void*) y) + { + Object ox = *cast(Object *)x; + Object oy = *cast(Object *)y; + + return ox.opCmp(oy); + } + + final void sort() + { + if (dim) { + qsort(cast(void*)data, dim, Object.sizeof, &Array_sort_compare); + } + } + + final Array copyTo(Array a) + { + a.setDim(dim); + memcpy(a.data, data, dim * (*data).sizeof); + + return a; + } + + final Array copy() + { + return copyTo(new Array()); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ArrayExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ArrayExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,132 @@ +module dmd.ArrayExp; + +import dmd.Expression; +import dmd.Identifier; +import dmd.UnaExp; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.InlineCostState; +import dmd.InlineDoState; +import dmd.HdrGenState; +import dmd.InlineScanState; +import dmd.ArrayTypes; +import dmd.TOK; +import dmd.Type; +import dmd.TY; +import dmd.Id; +import dmd.IndexExp; + +import dmd.expression.Util; + +class ArrayExp : UnaExp +{ + Expressions arguments; + + this(Loc loc, Expression e1, Expressions args) + { + super(loc, TOK.TOKarray, ArrayExp.sizeof, e1); + arguments = args; + } + + Expression syntaxCopy() + { + assert(false); + } + + Expression semantic(Scope sc) + { + Expression e; + Type t1; + + version (LOGSEMANTIC) { + printf("ArrayExp::semantic('%s')\n", toChars()); + } + UnaExp.semantic(sc); + e1 = resolveProperties(sc, e1); + + t1 = e1.type.toBasetype(); + if (t1.ty != Tclass && t1.ty != Tstruct) + { + // Convert to IndexExp + if (arguments.dim != 1) + error("only one index allowed to index %s", t1.toChars()); + e = new IndexExp(loc, e1, cast(Expression)arguments.data[0]); + return e.semantic(sc); + } + + // Run semantic() on each argument + for (size_t i = 0; i < arguments.dim; i++) + { + e = cast(Expression)arguments.data[i]; + + e = e.semantic(sc); + if (!e.type) + error("%s has no value", e.toChars()); + arguments.data[i] = cast(void*)e; + } + + expandTuples(arguments); + assert(arguments && arguments.dim); + + e = op_overload(sc); + if (!e) + { + error("no [] operator overload for type %s", e1.type.toChars()); + e = e1; + } + return e; + } + + int isLvalue() + { + assert(false); + } + + Expression toLvalue(Scope sc, Expression e) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + void scanForNestedRef(Scope sc) + { + assert(false); + } + + Identifier opId() + { + return Id.index; + } + + int inlineCost(InlineCostState* ics) + { + return 1 + e1.inlineCost(ics) + arrayInlineCost(ics, arguments); + } + + Expression doInline(InlineDoState ids) + { + ArrayExp ce; + + ce = cast(ArrayExp)copy(); + ce.e1 = e1.doInline(ids); + ce.arguments = arrayExpressiondoInline(arguments, ids); + return ce; + } + + Expression inlineScan(InlineScanState* iss) + { + Expression e = this; + + //printf("ArrayExp.inlineScan()\n"); + e1 = e1.inlineScan(iss); + arrayInlineScan(iss, arguments); + + return e; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/ArrayInitializer.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ArrayInitializer.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,373 @@ +module dmd.ArrayInitializer; + +import dmd.ArrayTypes; +import dmd.Type; +import dmd.TypeNext; +import dmd.Array; +import dmd.Loc; +import dmd.Initializer; +import dmd.WANT; +import dmd.Util; +import dmd.TY; +import dmd.TypeSArray; +import dmd.IntegerExp; +import dmd.Expression; +import dmd.ArrayLiteralExp; +import dmd.Scope; +import dmd.ErrorExp; +import dmd.OutBuffer; +import dmd.HdrGenState; + +import dmd.backend.dt_t; +import dmd.backend.Util; +import dmd.codegen.Util; +import dmd.backend.TYM; +import dmd.backend.Symbol; + +class ArrayInitializer : Initializer +{ + Expressions index; // indices + Initializers value; // of Initializer *'s + uint dim = 0; // length of array being initialized + Type type = null; // type that array will be used to initialize + int sem = 0; // !=0 if semantic() is run + + this(Loc loc) + { + super(loc); + index = new Expressions(); + value = new Initializers(); + } + + Initializer syntaxCopy() + { + //printf("ArrayInitializer.syntaxCopy()\n"); + + ArrayInitializer ai = new ArrayInitializer(loc); + + assert(index.dim == value.dim); + ai.index.setDim(index.dim); + ai.value.setDim(value.dim); + for (int i = 0; i < ai.value.dim; i++) + { + Expression e = cast(Expression)index.data[i]; + if (e) + e = e.syntaxCopy(); + ai.index.data[i] = cast(void*)e; + + Initializer init = cast(Initializer)value.data[i]; + init = init.syntaxCopy(); + ai.value.data[i] = cast(void*)init; + } + return ai; + } + + void addInit(Expression index, Initializer value) + { + this.index.push(cast(void*)index); + this.value.push(cast(void*)value); + dim = 0; + type = null; + } + + Initializer semantic(Scope sc, Type t) + { + uint i; + uint length; + + //printf("ArrayInitializer.semantic(%s)\n", t.toChars()); + if (sem) // if semantic() already run + return this; + + sem = 1; + type = t; + t = t.toBasetype(); + switch (t.ty) + { + case Tpointer: + case Tsarray: + case Tarray: + break; + + default: + error(loc, "cannot use array to initialize %s", type.toChars()); + return this; + } + + length = 0; + for (i = 0; i < index.dim; i++) + { + Expression idx; + Initializer val; + + idx = cast(Expression)index.data[i]; + if (idx) + { + idx = idx.semantic(sc); + idx = idx.optimize(WANTvalue | WANTinterpret); + index.data[i] = cast(void*)idx; + length = cast(uint)idx.toInteger(); + } + + val = cast(Initializer)value.data[i]; + val = val.semantic(sc, t.nextOf()); + value.data[i] = cast(void*)val; + length++; + if (length == 0) + error(loc, "array dimension overflow"); + if (length > dim) + dim = length; + } + uint amax = 0x80000000; + if (cast(uint) (dim * t.nextOf().size()) >= amax) + error(loc, "array dimension %u exceeds max of %ju", dim, amax / t.nextOf().size()); + + return this; + } + + Type inferType(Scope sc) + { + //printf("ArrayInitializer.inferType() %s\n", toChars()); + type = Type.terror; + for (size_t i = 0; i < value.dim; i++) + { + if (index.data[i]) + goto Lno; + } + + for (size_t i = 0; i < value.dim; i++) + { + Initializer iz = cast(Initializer)value.data[i]; + if (iz) + { + Type t = iz.inferType(sc); + if (i == 0) + { + t = new TypeSArray(t, new IntegerExp(value.dim)); + t = t.semantic(loc, sc); + type = t; + } + } + } + return type; + + Lno: + error(loc, "cannot infer type from this array initializer"); + return Type.terror; + } + + /******************************** + * If possible, convert array initializer to array literal. + */ + Expression toExpression() + { + Expression e; + + //printf("ArrayInitializer.toExpression(), dim = %d\n", dim); + //static int i; if (++i == 2) halt(); + + size_t edim; + Type t = null; + if (type) + { + t = type.toBasetype(); + switch (t.ty) + { + case Tsarray: + edim = cast(uint)(cast(TypeSArray)t).dim.toInteger(); + break; + + case Tpointer: + case Tarray: + edim = dim; + break; + + default: + assert(0); + } + } + else + { + edim = value.dim; + for (size_t i = 0, j = 0; i < value.dim; i++, j++) + { + if (index.data[i]) + j = cast(uint)(cast(Expression)index.data[i]).toInteger(); + if (j >= edim) + edim = j + 1; + } + } + + Expressions elements = new Expressions(); + elements.setDim(edim); + for (size_t i = 0, j = 0; i < value.dim; i++, j++) + { + if (index.data[i]) + j = cast(uint)(cast(Expression)index.data[i]).toInteger(); + assert(j < edim); + Initializer iz = cast(Initializer)value.data[i]; + if (!iz) + goto Lno; + Expression ex = iz.toExpression(); + if (!ex) + { + goto Lno; + } + elements.data[j] = cast(void*)ex; + } + + /* Fill in any missing elements with the default initializer + */ + { + Expression init = null; + for (size_t i = 0; i < edim; i++) + { + if (!elements.data[i]) + { + if (!type) + goto Lno; + if (!init) + init = (cast(TypeNext)t).next.defaultInit(Loc(0)); + elements.data[i] = cast(void*)init; + } + } + + Expression e2 = new ArrayLiteralExp(loc, elements); + e2.type = type; + return e2; + } + + Lno: + delete elements; + error(loc, "array initializers as expressions are not allowed"); + return new ErrorExp(); + } + + Initializer toAssocArrayInitializer() + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + dt_t* toDt() + { + //printf("ArrayInitializer.toDt('%s')\n", toChars()); + Type tb = type.toBasetype(); + Type tn = tb.nextOf().toBasetype(); + + scope Array dts = new Array(); + uint size; + uint length; + uint i; + dt_t* dt; + dt_t* d; + dt_t** pdtend; + + //printf("\tdim = %d\n", dim); + dts.setDim(dim); + dts.zero(); + + size = cast(uint)tn.size(); + + length = 0; + for (i = 0; i < index.dim; i++) + { + Expression idx; + Initializer val; + + idx = cast(Expression)index.data[i]; + if (idx) + length = cast(uint)idx.toInteger(); + //printf("\tindex[%d] = %p, length = %u, dim = %u\n", i, idx, length, dim); + + assert(length < dim); + val = cast(Initializer)value.data[i]; + dt = val.toDt(); + if (dts.data[length]) + error(loc, "duplicate initializations for index %d", length); + dts.data[length] = cast(void*)dt; + length++; + } + + Expression edefault = tb.nextOf().defaultInit(Loc(0)); + + uint n = 1; + for (Type tbn = tn; tbn.ty == Tsarray; tbn = tbn.nextOf().toBasetype()) + { + TypeSArray tsa = cast(TypeSArray)tbn; + n *= tsa.dim.toInteger(); + } + + d = null; + pdtend = &d; + for (i = 0; i < dim; i++) + { + dt = cast(dt_t*)dts.data[i]; + if (dt) + pdtend = dtcat(pdtend, dt); + else + { + for (int j = 0; j < n; j++) + pdtend = edefault.toDt(pdtend); + } + } + switch (tb.ty) + { + case Tsarray: + { + uint tadim; + TypeSArray ta = cast(TypeSArray)tb; + + tadim = cast(uint)ta.dim.toInteger(); + if (dim < tadim) + { + if (edefault.isBool(false)) + // pad out end of array + pdtend = dtnzeros(pdtend, size * (tadim - dim)); + else + { + for (i = dim; i < tadim; i++) + { + for (int j = 0; j < n; j++) + pdtend = edefault.toDt(pdtend); + } + } + } + else if (dim > tadim) + { + debug writef("1: "); + error(loc, "too many initializers, %d, for array[%d]", dim, tadim); + } + break; + } + + case Tpointer: + case Tarray: + // Create symbol, and then refer to it + Symbol* s = static_sym(); + s.Sdt = d; + outdata(s); + + d = null; + if (tb.ty == Tarray) + dtdword(&d, dim); + dtxoff(&d, s, 0, TYnptr); + break; + + default: + assert(0); + } + return d; + } + + dt_t* toDtBit() // for bit arrays + { + assert(false); + } + + ArrayInitializer isArrayInitializer() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ArrayLengthExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ArrayLengthExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,75 @@ +module dmd.ArrayLengthExp; + +import dmd.Expression; +import dmd.backend.elem; +import dmd.UnaExp; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.IRState; +import dmd.HdrGenState; +import dmd.TOK; +import dmd.Type; +import dmd.WANT; + +import dmd.expression.ArrayLength; + +import dmd.backend.Util; +import dmd.backend.OPER; + +class ArrayLengthExp : UnaExp +{ + this(Loc loc, Expression e1) + { + super(loc, TOK.TOKarraylength, ArrayLengthExp.sizeof, e1); + } + + Expression semantic(Scope sc) + { + Expression e; + + version (LOGSEMANTIC) { + printf("ArrayLengthExp::semantic('%s')\n", toChars()); + } + if (!type) + { + UnaExp.semantic(sc); + e1 = resolveProperties(sc, e1); + + type = Type.tsize_t; + } + return this; + } + + Expression optimize(int result) + { + //printf("ArrayLengthExp::optimize(result = %d) %s\n", result, toChars()); + e1 = e1.optimize(WANTvalue | (result & WANTinterpret)); + Expression e = this; + if (e1.op == TOKstring || e1.op == TOKarrayliteral || e1.op == TOKassocarrayliteral) + { + e = ArrayLength(type, e1); + } + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + elem* toElem(IRState* irs) + { + elem *e = e1.toElem(irs); + e = el_una(OP64_32, type.totym(), e); + el_setLoc(e,loc); + return e; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/ArrayLiteralExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ArrayLiteralExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,363 @@ +module dmd.ArrayLiteralExp; + +import dmd.Expression; +import dmd.backend.elem; +import dmd.InterState; +import dmd.MATCH; +import dmd.Type; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.WANT; +import dmd.Scope; +import dmd.InlineCostState; +import dmd.IRState; +import dmd.InlineDoState; +import dmd.HdrGenState; +import dmd.backend.dt_t; +import dmd.InlineScanState; +import dmd.ArrayTypes; +import dmd.TOK; +import dmd.IntegerExp; +import dmd.TypeSArray; +import dmd.TY; +import dmd.StringExp; + +import dmd.expression.Util; +import dmd.backend.Util; +import dmd.backend.RTLSYM; +import dmd.backend.OPER; +import dmd.backend.TYM; +import dmd.backend.mTY; + +class ArrayLiteralExp : Expression +{ + Expressions elements; + + this(Loc loc, Expressions elements) + { + super(loc, TOK.TOKarrayliteral, ArrayLiteralExp.sizeof); + this.elements = elements; + } + + this(Loc loc, Expression e) + { + super(loc, TOK.TOKarrayliteral, ArrayLiteralExp.sizeof); + elements = new Expressions(); + elements.push(cast(void*)e); + } + + Expression syntaxCopy() + { + return new ArrayLiteralExp(loc, arraySyntaxCopy(elements)); + } + + Expression semantic(Scope sc) + { + Expression e; + Type t0 = null; + + version (LOGSEMANTIC) { + printf("ArrayLiteralExp.semantic('%s')\n", toChars()); + } + if (type) + return this; + + // Run semantic() on each element + for (int i = 0; i < elements.dim; i++) + { + e = cast(Expression)elements.data[i]; + e = e.semantic(sc); + assert(e.type); + elements.data[i] = cast(void*)e; + } + + expandTuples(elements); + + for (int i = 0; i < elements.dim; i++) + { + e = cast(Expression)elements.data[i]; + + if (!e.type) + error("%s has no value", e.toChars()); + + e = resolveProperties(sc, e); + + ubyte committed = 1; + if (e.op == TOKstring) + committed = (cast(StringExp)e).committed; + + if (!t0) + { + t0 = e.type; + // Convert any static arrays to dynamic arrays + if (t0.ty == Tsarray) + { + t0 = (cast(TypeSArray)t0).next.arrayOf(); + e = e.implicitCastTo(sc, t0); + } + } + else + e = e.implicitCastTo(sc, t0); + + if (!committed && e.op == TOKstring) + { + StringExp se = cast(StringExp)e; + se.committed = 0; + } + elements.data[i] = cast(void*)e; + } + + if (!t0) + t0 = Type.tvoid; + type = new TypeSArray(t0, new IntegerExp(elements.dim)); + type = type.semantic(loc, sc); + return this; + } + + bool isBool(bool result) + { + size_t dim = elements ? elements.dim : 0; + return result ? (dim != 0) : (dim == 0); + } + + elem* toElem(IRState* irs) + { + elem* e; + size_t dim; + + //printf("ArrayLiteralExp.toElem() %s\n", toChars()); + if (elements) + { + scope Expressions args = new Expressions(); + dim = elements.dim; + args.setDim(dim + 1); // +1 for number of args parameter + e = el_long(TYint, dim); + args.data[dim] = cast(void*)e; + for (size_t i = 0; i < dim; i++) + { + Expression el = cast(Expression)elements.data[i]; + elem* ep = el.toElem(irs); + + if (tybasic(ep.Ety) == TYstruct || tybasic(ep.Ety) == TYarray) + { + ep = el_una(OPstrpar, TYstruct, ep); + ep.Enumbytes = cast(uint)el.type.size(); + } + args.data[dim - (i + 1)] = cast(void *)ep; + } + + /* Because the number of parameters can get very large, produce + * a balanced binary tree so we don't blow up the stack in + * the subsequent tree walking code. + */ + e = el_params(args.data, dim + 1); + } + else + { + dim = 0; + e = el_long(TYint, 0); + } + Type tb = type.toBasetype(); + static if (true) { + e = el_param(e, type.getTypeInfo(null).toElem(irs)); + + // call _d_arrayliteralT(ti, dim, ...) + e = el_bin(OPcall,TYnptr,el_var(rtlsym[RTLSYM_ARRAYLITERALT]),e); + } else { + e = el_param(e, el_long(TYint, tb.next.size())); + + // call _d_arrayliteral(size, dim, ...) + e = el_bin(OPcall,TYnptr,el_var(rtlsym[RTLSYM_ARRAYLITERAL]),e); + } + if (tb.ty == Tarray) + { + e = el_pair(TYullong, el_long(TYint, dim), e); + } + else if (tb.ty == Tpointer) + { + } + else + { + e = el_una(OPind,TYstruct,e); + e.Enumbytes = cast(uint)type.size(); + } + + el_setLoc(e,loc); + return e; + } + + bool checkSideEffect(int flag) + { + bool f = false; + + for (size_t i = 0; i < elements.dim; i++) + { + Expression e = cast(Expression)elements.data[i]; + f |= e.checkSideEffect(2); + } + if (flag == 0 && f == false) + Expression.checkSideEffect(0); + + return f; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + buf.writeByte('['); + argsToCBuffer(buf, elements, hgs); + buf.writeByte(']'); + } + + void toMangleBuffer(OutBuffer buf) + { + size_t dim = elements ? elements.dim : 0; + buf.printf("A%u", dim); + for (size_t i = 0; i < dim; i++) + { + Expression e = cast(Expression)elements.data[i]; + e.toMangleBuffer(buf); + } + } + + void scanForNestedRef(Scope sc) + { + assert(false); + } + + Expression optimize(int result) + { + if (elements) + { + for (size_t i = 0; i < elements.dim; i++) + { + Expression e = cast(Expression)elements.data[i]; + + e = e.optimize(WANTvalue | (result & WANTinterpret)); + elements.data[i] = cast(void*)e; + } + } + + return this; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + MATCH implicitConvTo(Type t) + { + MATCH result = MATCHexact; + + static if (false) { + printf("ArrayLiteralExp.implicitConvTo(this=%s, type=%s, t=%s)\n", + toChars(), type.toChars(), t.toChars()); + } + Type typeb = type.toBasetype(); + Type tb = t.toBasetype(); + if ((tb.ty == Tarray || tb.ty == Tsarray) && + (typeb.ty == Tarray || typeb.ty == Tsarray)) + { + if (tb.ty == Tsarray) + { + TypeSArray tsa = cast(TypeSArray)tb; + if (elements.dim != tsa.dim.toInteger()) + result = MATCHnomatch; + } + + for (int i = 0; i < elements.dim; i++) + { + Expression e = cast(Expression)elements.data[i]; + MATCH m = cast(MATCH)e.implicitConvTo(tb.nextOf()); + if (m < result) + result = m; // remember worst match + if (result == MATCHnomatch) + break; // no need to check for worse + } + return result; + } + else + return Expression.implicitConvTo(t); + } + + Expression castTo(Scope sc, Type t) + { + static if (false) { + printf("ArrayLiteralExp.castTo(this=%s, type=%s, => %s)\n", + toChars(), type.toChars(), t.toChars()); + } + if (type == t) + return this; + ArrayLiteralExp e = this; + Type typeb = type.toBasetype(); + Type tb = t.toBasetype(); + if ((tb.ty == Tarray || tb.ty == Tsarray) && + (typeb.ty == Tarray || typeb.ty == Tsarray) && + // Not trying to convert non-void[] to void[] + !(tb.nextOf().toBasetype().ty == Tvoid && typeb.nextOf().toBasetype().ty != Tvoid)) + { + if (tb.ty == Tsarray) + { + TypeSArray tsa = cast(TypeSArray)tb; + if (elements.dim != tsa.dim.toInteger()) + goto L1; + } + + e = cast(ArrayLiteralExp)copy(); + e.elements = cast(Expressions)elements.copy(); + for (int i = 0; i < elements.dim; i++) + { + Expression ex = cast(Expression)elements.data[i]; + ex = ex.castTo(sc, tb.nextOf()); + e.elements.data[i] = cast(void*)ex; + } + e.type = t; + return e; + } + if (tb.ty == Tpointer && typeb.ty == Tsarray) + { + Type tp = typeb.nextOf().pointerTo(); + if (!tp.equals(e.type)) + { + e = cast(ArrayLiteralExp)copy(); + e.type = tp; + } + } + L1: + return e.Expression.castTo(sc, t); + } + + dt_t** toDt(dt_t** pdt) + { + assert(false); + } + +version (DMDV2) { + bool canThrow() + { + return 1; // because it can fail allocating memory + } +} + int inlineCost(InlineCostState* ics) + { + return 1 + arrayInlineCost(ics, elements); + } + + Expression doInline(InlineDoState ids) + { + ArrayLiteralExp ce = cast(ArrayLiteralExp)copy(); + ce.elements = arrayExpressiondoInline(elements, ids); + return ce; + } + + Expression inlineScan(InlineScanState* iss) + { + Expression e = this; + + //printf("ArrayLiteralExp.inlineScan()\n"); + arrayInlineScan(iss, elements); + + return e; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/ArrayScopeSymbol.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ArrayScopeSymbol.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,166 @@ +module dmd.ArrayScopeSymbol; + +import dmd.ScopeDsymbol; +import dmd.Expression; +import dmd.TypeTuple; +import dmd.TupleDeclaration; +import dmd.Scope; +import dmd.Dsymbol; +import dmd.Loc; +import dmd.TOK; +import dmd.Identifier; +import dmd.Id; +import dmd.TY; +import dmd.TupleExp; +import dmd.StringExp; +import dmd.WANT; +import dmd.TypeExp; +import dmd.Type; +import dmd.SliceExp; +import dmd.IndexExp; +import dmd.IntegerExp; +import dmd.STC; +import dmd.ExpInitializer; +import dmd.VarDeclaration; +import dmd.ArrayLiteralExp; +import dmd.expression.Util; + +class ArrayScopeSymbol : ScopeDsymbol +{ + Expression exp; // IndexExp or SliceExp + TypeTuple type; // for tuple[length] + TupleDeclaration td; // for tuples of objects + Scope sc; + + this(Scope sc, Expression e) + { + super(); + assert(e.op == TOKindex || e.op == TOKslice); + this.exp = e; + this.sc = sc; + } + + this(Scope sc, TypeTuple t) + { + assert(false); + } + + this(Scope sc, TupleDeclaration td) + { + assert(false); + } + + Dsymbol search(Loc loc, Identifier ident, int flags) + { + //printf("ArrayScopeSymbol.search('%s', flags = %d)\n", ident.toChars(), flags); + if (ident == Id.length || ident == Id.dollar) + { + VarDeclaration* pvar; + Expression ce; + + L1: + if (td) + { /* $ gives the number of elements in the tuple + */ + VarDeclaration v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null); + Expression e = new IntegerExp(Loc(0), td.objects.dim, Type.tsize_t); + v.init = new ExpInitializer(Loc(0), e); + v.storage_class |= STCstatic | STCconst; + v.semantic(sc); + return v; + } + + if (type) + { /* $ gives the number of type entries in the type tuple + */ + VarDeclaration v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null); + Expression e = new IntegerExp(Loc(0), type.arguments.dim, Type.tsize_t); + v.init = new ExpInitializer(Loc(0), e); + v.storage_class |= STCstatic | STCconst; + v.semantic(sc); + return v; + } + + if (exp.op == TOKindex) + { /* array[index] where index is some function of $ + */ + IndexExp ie = cast(IndexExp)exp; + + pvar = &ie.lengthVar; + ce = ie.e1; + } + else if (exp.op == TOKslice) + { /* array[lwr .. upr] where lwr or upr is some function of $ + */ + SliceExp se = cast(SliceExp)exp; + + pvar = &se.lengthVar; + ce = se.e1; + } + else + /* Didn't find $, look in enclosing scope(s). + */ + return null; + + /* If we are indexing into an array that is really a type + * tuple, rewrite this as an index into a type tuple and + * try again. + */ + if (ce.op == TOKtype) + { + Type t = (cast(TypeExp)ce).type; + if (t.ty == Ttuple) + { + type = cast(TypeTuple)t; + goto L1; + } + } + + /* *pvar is lazily initialized, so if we refer to $ + * multiple times, it gets set only once. + */ + if (!*pvar) // if not already initialized + { /* Create variable v and set it to the value of $, + * which will be a constant. + */ + VarDeclaration v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null); + + if (ce.op == TOKvar) + { // if ce is const, get its initializer + ce = fromConstInitializer(WANTvalue | WANTinterpret, ce); + } + + if (ce.op == TOKstring) + { /* It is for a string literal, so the + * length will be a const. + */ + Expression e = new IntegerExp(Loc(0), (cast(StringExp)ce).len, Type.tsize_t); + v.init = new ExpInitializer(Loc(0), e); + v.storage_class |= STCstatic | STCconst; + } + else if (ce.op == TOKarrayliteral) + { /* It is for an array literal, so the + * length will be a const. + */ + Expression e = new IntegerExp(Loc(0), (cast(ArrayLiteralExp)ce).elements.dim, Type.tsize_t); + v.init = new ExpInitializer(Loc(0), e); + v.storage_class |= STCstatic | STCconst; + } + else if (ce.op == TOKtuple) + { /* It is for an expression tuple, so the + * length will be a const. + */ + Expression e = new IntegerExp(Loc(0), (cast(TupleExp)ce).exps.dim, Type.tsize_t); + v.init = new ExpInitializer(Loc(0), e); + v.storage_class |= STCstatic | STCconst; + } + *pvar = v; + } + (*pvar).semantic(sc); + return (*pvar); + } + return null; + } + + ArrayScopeSymbol isArrayScopeSymbol() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ArrayT.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ArrayT.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,173 @@ +module dmd.ArrayT; + +import std.contracts; +import core.stdc.stdlib; +import core.stdc.string; + +class ArrayT(T) +{ + uint dim; + uint allocdim; + T* data; + + ~this() + { + free(data); + } + + void mark() + { + } + + string toString() + { + char *p; + + ///char **buf = cast(char**)alloca(dim * (char*).sizeof); + scope string[] buf = new string[dim]; + uint len = 2; + for (uint u = 0; u < dim; u++) { + buf[u] = (cast(Object)data[u]).toString(); + len += buf[u].length + 1; + } + + char* str = cast(char*)malloc(len); + + str[0] = '['; + p = str + 1; + + for (uint u = 0; u < dim; u++) + { + if (u != 0) { + *p++ = ','; + } + uint length = buf[u].length; + p[0..length] = buf[u][]; + + p += length; + } + + *p++ = ']'; + *p = 0; + + return assumeUnique(str[0..len]); + } + + final void reserve(uint nentries) + { + //printf("ArrayT::reserve: size = %d, offset = %d, nbytes = %d\n", size, offset, nbytes); + if (allocdim - dim < nentries) { + allocdim = dim + nentries; + data = cast(T*)realloc(data, allocdim * (*data).sizeof); + } + } + + final void setDim(uint newdim) + { + if (dim < newdim) { + reserve(newdim - dim); + } + + dim = newdim; + } + + final void fixDim() + { + if (dim != allocdim) + { + data = cast(T*)realloc(data, dim * (*data).sizeof); + allocdim = dim; + } + } + + final void push(void* ptr) + { + reserve(1); + data[dim++] = ptr; + } + + final void* pop() + { + return data[--dim]; + } + + final void shift(void* ptr) + { + reserve(1); + memmove(data + 1, data, dim * (*data).sizeof); + data[0] = ptr; + dim++; + } + + final void insert(uint index, void* ptr) + { + reserve(1); + memmove(data + index + 1, data + index, (dim - index) * (*data).sizeof); + data[index] = ptr; + dim++; + } + + final void insert(uint index, ArrayT a) + { + if (a !is null) { + uint d = a.dim; + reserve(d); + + if (dim != index) { + memmove(data + index + d, data + index, (dim - index) * (*data).sizeof); + } + + memcpy(data + index, a.data, d * (*data).sizeof); + dim += d; + } + } + + /*********************************** + * Append array a to this array. + */ + final void append(ArrayT a) + { + insert(dim, a); + } + + final void remove(uint i) + { + memmove(data + i, data + i + 1, (dim - i) * (*data).sizeof); + dim--; + } + + final void zero() + { + memset(data, 0, dim * (*data).sizeof); + } + + final void* tos() + { + return dim ? data[dim - 1] : null; + } + + private static extern (C) int Array_sort_compare(const(void*) x, const(void*) y) + { + Object ox = *cast(Object *)x; + Object oy = *cast(Object *)y; + + return ox.opCmp(oy); + } + + final void sort() + { + if (dim) { + qsort(cast(void*)data, dim, Object.sizeof, &ArrayT_sort_compare); + } + } + + final ArrayT copy() + { + ArrayT a = new TArray(); + a.setDim(dim); + + memcpy(a.data, data, dim * (*data).sizeof); + + return a; + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ArrayTypes.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ArrayTypes.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,25 @@ +module dmd.ArrayTypes; + +import dmd.Array; + +class TemplateParameters : Array { final typeof(this) copy() { auto a = new typeof(this); copyTo(a); return a; } } + +class Expressions : Array { final typeof(this) copy() { auto a = new typeof(this); copyTo(a); return a; } } + +class Statements : Array { final typeof(this) copy() { auto a = new typeof(this); copyTo(a); return a; } } + +class BaseClasses : Array { final typeof(this) copy() { auto a = new typeof(this); copyTo(a); return a; } } + +class ClassDeclarations : Array { final typeof(this) copy() { auto a = new typeof(this); copyTo(a); return a; } } + +class Dsymbols : Array { final typeof(this) copy() { auto a = new typeof(this); copyTo(a); return a; } } + +class Objects : Array { final typeof(this) copy() { auto a = new typeof(this); copyTo(a); return a; } } + +class FuncDeclarations : Array { final typeof(this) copy() { auto a = new typeof(this); copyTo(a); return a; } } + +class Arguments : Array { final typeof(this) copy() { auto a = new typeof(this); copyTo(a); return a; } } + +class Identifiers : Array { final typeof(this) copy() { auto a = new typeof(this); copyTo(a); return a; } } + +class Initializers : Array { final typeof(this) copy() { auto a = new typeof(this); copyTo(a); return a; } } \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/AsmStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/AsmStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,373 @@ +module dmd.AsmStatement; + +import dmd.Loc; +import dmd.Statement; +import dmd.Token; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.IRState; +import dmd.BE; +import dmd.LabelDsymbol; +import dmd.Dsymbol; +import dmd.Id; +import dmd.TOK; +import dmd.Global; +import dmd.FuncDeclaration; +import dmd.Declaration; +import dmd.LabelStatement; +import dmd.Util; + +import dmd.backend.code; +import dmd.backend.iasm; +import dmd.backend.block; +import dmd.backend.Blockx; +import dmd.backend.Util; +import dmd.codegen.Util; +import dmd.backend.BC; +import dmd.backend.FL; +import dmd.backend.SFL; +import dmd.backend.SC; +import dmd.backend.mTY; +import dmd.backend.Symbol; +import dmd.backend.LIST; + +import core.stdc.string : memset; +import core.stdc.stdlib : exit, EXIT_FAILURE; + +class AsmStatement : Statement +{ + Token* tokens; + code* asmcode; + uint asmalign; // alignment of this statement + bool refparam; // true if function parameter is referenced + bool naked; // true if function is to be naked + uint regs; // mask of registers modified + + this(Loc loc, Token* tokens) + { + super(loc); + this.tokens = tokens; + } + + Statement syntaxCopy() + { + assert(false); + } + + Statement semantic(Scope sc) + { + //printf("AsmStatement.semantic()\n"); + + if (global.params.safe && !sc.module_.safe) + { + error("inline assembler not allowed in safe mode"); + } + + OP* o; + OPND* o1 = null; + OPND* o2 = null; + OPND* o3 = null; + + PTRNTAB ptb; + uint usNumops; + ubyte uchPrefix = 0; + ubyte bAsmseen; + char* pszLabel = null; + code* c; + FuncDeclaration fd = sc.parent.isFuncDeclaration(); + + assert(fd); + fd.inlineAsm = 1; + + if (!tokens) + return null; + + memset(&asmstate, 0, asmstate.sizeof); + + asmstate.statement = this; + asmstate.sc = sc; + +static if (false) { + // don't use bReturnax anymore, and will fail anyway if we use return type inference + // Scalar return values will always be in AX. So if it is a scalar + // then asm block sets return value if it modifies AX, if it is non-scalar + // then always assume that the ASM block sets up an appropriate return + // value. + + asmstate.bReturnax = 1; + if (sc.func.type.nextOf().isscalar()) + asmstate.bReturnax = 0; +} + + // Assume assembler code takes care of setting the return value + sc.func.hasReturnExp |= 8; + + if (!asmstate.bInit) + { + asmstate.bInit = true; + init_optab(); + asmstate.psDollar = new LabelDsymbol(Id.__dollar); + //asmstate.psLocalsize = new VarDeclaration(0, Type.tint32, Id.__LOCAL_SIZE, null); + asmstate.psLocalsize = new Dsymbol(Id.__LOCAL_SIZE); + cod3_set386(); + } + + asmstate.loc = loc; + + asmtok = tokens; + asm_token_trans(asmtok); + if (setjmp(asmstate.env)) + { + asmtok = null; // skip rest of line + tok_value = TOK.TOKeof; + exit(EXIT_FAILURE); + goto AFTER_EMIT; + } + + switch (cast(int)tok_value) + { + case ASMTK.ASMTKnaked: + naked = true; + sc.func.naked = true; + asm_token(); + break; + + case ASMTK.ASMTKeven: + asm_token(); + asmalign = 2; + break; + + case TOK.TOKalign: + { + asm_token(); + uint align_ = asm_getnum(); + if (ispow2(align_) == -1) + asmerr(ASMERRMSGS.EM_align, align_); // power of 2 expected + else + asmalign = align_; + break; + } + + // The following three convert the keywords 'int', 'in', 'out' + // to identifiers, since they are x86 instructions. + case TOK.TOKint32: + o = asm_op_lookup(Id.__int.toChars()); + goto Lopcode; + + case TOK.TOKin: + o = asm_op_lookup(Id.___in.toChars()); + goto Lopcode; + + case TOK.TOKout: + o = asm_op_lookup(Id.___out.toChars()); + goto Lopcode; + + case TOK.TOKidentifier: + o = asm_op_lookup(asmtok.ident.toChars()); + if (!o) + goto OPCODE_EXPECTED; + + Lopcode: + asmstate.ucItype = o.usNumops & IT.ITMASK; + asm_token(); + if (o.usNumops > 3) + { + switch (asmstate.ucItype) + { + case IT.ITdata: + asmcode = asm_db_parse(o); + goto AFTER_EMIT; + + case IT.ITaddr: + asmcode = asm_da_parse(o); + goto AFTER_EMIT; + + default: + break; + } + } + // get the first part of an expr + o1 = asm_cond_exp(); + if (tok_value == TOK.TOKcomma) + { + asm_token(); + o2 = asm_cond_exp(); + } + if (tok_value == TOK.TOKcomma) + { + asm_token(); + o3 = asm_cond_exp(); + } + // match opcode and operands in ptrntab to verify legal inst and + // generate + + ptb = asm_classify(o, o1, o2, o3, &usNumops); + assert(ptb.pptb0); + + // + // The Multiply instruction takes 3 operands, but if only 2 are seen + // then the third should be the second and the second should + // be a duplicate of the first. + // + + if (asmstate.ucItype == IT.ITopt && + (usNumops == 2) && + (ASM_GET_aopty(o2.usFlags) == ASM_OPERAND_TYPE._imm) && + ((o.usNumops & IT.ITSIZE) == 3)) + { + o3 = o2; + o2 = opnd_calloc(); + *o2 = *o1; + + // Re-classify the opcode because the first classification + // assumed 2 operands. + + ptb = asm_classify(o, o1, o2, o3, &usNumops); + } + else + { +static if (false) { + if (asmstate.ucItype == IT.ITshift && (ptb.pptb2.usOp2 == 0 || + (ptb.pptb2.usOp2 & _cl))) { + opnd_free(o2); + o2 = null; + usNumops = 1; + } +} + } + + asmcode = asm_emit(loc, usNumops, ptb, o, o1, o2, o3); + break; + + default: + OPCODE_EXPECTED: + asmerr(ASMERRMSGS.EM_opcode_exp, asmtok.toChars()); // assembler opcode expected + break; + } + + AFTER_EMIT: + opnd_free(o1); + opnd_free(o2); + opnd_free(o3); + o1 = o2 = o3 = null; + + if (tok_value != TOK.TOKeof) + asmerr(ASMERRMSGS.EM_eol); // end of line expected + + //return asmstate.bReturnax; + return this; + } + + BE blockExit() + { + assert(false); + } + + bool comeFrom() + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + AsmStatement isAsmStatement() { return this; } + + void toIR(IRState *irs) + { + block* bpre; + block* basm; + Declaration d; + Symbol* s; + Blockx* blx = irs.blx; + +// dumpCode(asmcode); + + //printf("AsmStatement::toIR(asmcode = %x)\n", asmcode); + bpre = blx.curblock; + block_next(blx,BCgoto,null); + basm = blx.curblock; + list_append(&bpre.Bsucc, basm); + basm.Bcode = asmcode; + basm.Balign = cast(ubyte)asmalign; +static if (false) { + if (label) + { + block* b = labelToBlock(loc, blx, label); + printf("AsmStatement::toIR() %p\n", b); + if (b) + list_append(&basm.Bsucc, b); + } +} + // Loop through each instruction, fixing Dsymbols into Symbol's + for (code* c = asmcode; c; c = c.next) + { + LabelDsymbol label; + block* b; + + switch (c.IFL1) + { + case FLblockoff: + case FLblock: + // FLblock and FLblockoff have LabelDsymbol's - convert to blocks + label = c.IEVlsym1; + b = labelToBlock(loc, blx, label); + list_append(&basm.Bsucc, b); + c.IEV1.Vblock = b; + break; + + case FLdsymbol: + case FLfunc: + s = c.IEVdsym1.toSymbol(); + if (s.Sclass == SCauto && s.Ssymnum == -1) + symbol_add(s); + c.IEVsym1() = s; + c.IFL1 = s.Sfl ? s.Sfl : FLauto; + break; + default: + break; + } + + // Repeat for second operand + switch (c.IFL2) + { + case FLblockoff: + case FLblock: + label = c.IEVlsym2; + b = labelToBlock(loc, blx, label); + list_append(&basm.Bsucc, b); + c.IEV2.Vblock = b; + break; + + case FLdsymbol: + case FLfunc: + d = c.IEVdsym2; + s = d.toSymbol(); + if (s.Sclass == SCauto && s.Ssymnum == -1) + symbol_add(s); + c.IEVsym2() = s; + c.IFL2 = s.Sfl ? s.Sfl : FLauto; + if (d.isDataseg()) + s.Sflags |= SFLlivexit; + break; + default: + break; + } + //c.print(); + } + + basm.bIasmrefparam = refparam; // are parameters reference? + basm.usIasmregs = cast(ushort)regs; // registers modified + + block_next(blx,BCasm, null); + list_prepend(&basm.Bsucc, blx.curblock); + + if (naked) + { + blx.funcsym.Stype.Tty |= mTYnaked; + } + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/AssertExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/AssertExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,254 @@ +module dmd.AssertExp; + +import dmd.Expression; +import dmd.backend.elem; +import dmd.UnaExp; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.InlineCostState; +import dmd.InlineDoState; +import dmd.IRState; +import dmd.HdrGenState; +import dmd.InlineScanState; +import dmd.Type; +import dmd.Global; +import dmd.InvariantDeclaration; +import dmd.TOK; +import dmd.TY; +import dmd.TypeClass; +import dmd.Module; +import dmd.WANT; +import dmd.FuncDeclaration; +import dmd.HaltExp; +import dmd.TypeStruct; +import dmd.backend.Util; +import dmd.codegen.Util; +import dmd.backend.OPER; +import dmd.backend.TYM; +import dmd.backend.RTLSYM; +import dmd.backend.Symbol; +import dmd.backend.dt_t; +import dmd.backend.SC; +import dmd.backend.FL; + +import core.stdc.string; +import std.string : toStringz; + +static __gshared Symbol* assertexp_sfilename = null; +static __gshared string assertexp_name = null; +static __gshared Module assertexp_mn = null; + +class AssertExp : UnaExp +{ + Expression msg; + + this(Loc loc, Expression e, Expression msg = null) + { + super(loc, TOK.TOKassert, AssertExp.sizeof, e); + this.msg = msg; + } + + Expression syntaxCopy() + { + assert(false); + } + + Expression semantic(Scope sc) + { + version (LOGSEMANTIC) { + printf("AssertExp.semantic('%s')\n", toChars()); + } + UnaExp.semantic(sc); + e1 = resolveProperties(sc, e1); + // BUG: see if we can do compile time elimination of the Assert + e1 = e1.optimize(WANTvalue); + e1 = e1.checkToBoolean(); + if (msg) + { + msg = msg.semantic(sc); + msg = resolveProperties(sc, msg); + msg = msg.implicitCastTo(sc, Type.tchar.constOf().arrayOf()); + msg = msg.optimize(WANTvalue); + } + if (e1.isBool(false)) + { + FuncDeclaration fd = sc.parent.isFuncDeclaration(); + fd.hasReturnExp |= 4; + + if (!global.params.useAssert) + { + Expression e = new HaltExp(loc); + e = e.semantic(sc); + return e; + } + } + type = Type.tvoid; + return this; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + bool checkSideEffect(int flag) + { + return true; + } + +version (DMDV2) { + bool canThrow() + { + /* assert()s are non-recoverable errors, so functions that + * use them can be considered "nothrow" + */ + return 0; //(global.params.useAssert != 0); + } +} + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + int inlineCost(InlineCostState* ics) + { + return 1 + e1.inlineCost(ics) + (msg ? msg.inlineCost(ics) : 0); + } + + Expression doInline(InlineDoState ids) + { + AssertExp ae = cast(AssertExp)copy(); + + ae.e1 = e1.doInline(ids); + if (msg) + ae.msg = msg.doInline(ids); + return ae; + } + + Expression inlineScan(InlineScanState* iss) + { + e1 = e1.inlineScan(iss); + if (msg) + msg = msg.inlineScan(iss); + return this; + } + + static private void* castToVoid(int i) + { + return cast(void*)i; + } + + elem* toElem(IRState* irs) + { + elem* e; + elem* ea; + Type t1 = e1.type.toBasetype(); + + //printf("AssertExp.toElem() %s\n", toChars()); + if (global.params.useAssert) + { + e = e1.toElem(irs); + + InvariantDeclaration inv = cast(InvariantDeclaration)castToVoid(1); + + // If e1 is a class object, call the class invariant on it + if (global.params.useInvariants && t1.ty == Tclass && + !(cast(TypeClass)t1).sym.isInterfaceDeclaration()) + { + version (XXX) {///TARGET_LINUX || TARGET_FREEBSD || TARGET_SOLARIS + e = el_bin(OPcall, TYvoid, el_var(rtlsym[RTLSYM__DINVARIANT]), e); + } else { + e = el_bin(OPcall, TYvoid, el_var(rtlsym[RTLSYM_DINVARIANT]), e); + } + } + // If e1 is a struct object, call the struct invariant on it + else if (global.params.useInvariants && + t1.ty == Tpointer && + t1.nextOf().ty == Tstruct && + (inv = (cast(TypeStruct)t1.nextOf()).sym.inv) !is null) + { + e = callfunc(loc, irs, 1, inv.type.nextOf(), e, e1.type, inv, inv.type, null, null); + } + else + { + // Construct: (e1 || ModuleAssert(line)) + Symbol* sassert; + Module m = irs.blx.module_; + string mname = m.srcfile.toChars(); + + //printf("filename = '%s'\n", loc.filename); + //printf("module = '%s'\n", m.srcfile.toChars()); + + /* If the source file name has changed, probably due + * to a #line directive. + */ + if (loc.filename && (msg || loc.filename != mname)) + { + elem* efilename; + + /* Cache values. + */ + //static Symbol *assertexp_sfilename = null; + //static char *assertexp_name = null; + //static Module *assertexp_mn = null; + + if (!assertexp_sfilename || loc.filename != assertexp_name || assertexp_mn != m) + { + dt_t* dt = null; + + string id = loc.filename; + int len = id.length; + dtdword(&dt, len); + dtabytes(&dt,TYnptr, 0, len + 1, toStringz(id)); + + assertexp_sfilename = symbol_generate(SCstatic,type_fake(TYdarray)); + assertexp_sfilename.Sdt = dt; + assertexp_sfilename.Sfl = FLdata; + version (ELFOBJ) { + assertexp_sfilename.Sseg = CDATA; + } + version (MACHOBJ) { + assertexp_sfilename.Sseg = DATA; + } + outdata(assertexp_sfilename); + + assertexp_mn = m; + assertexp_name = id; + } + + efilename = el_var(assertexp_sfilename); + + if (msg) + { + elem* emsg = msg.toElem(irs); + ea = el_var(rtlsym[RTLSYM_DASSERT_MSG]); + ea = el_bin(OPcall, TYvoid, ea, el_params(el_long(TYint, loc.linnum), efilename, emsg, null)); + } + else + { + ea = el_var(rtlsym[RTLSYM_DASSERT]); + ea = el_bin(OPcall, TYvoid, ea, el_param(el_long(TYint, loc.linnum), efilename)); + } + } + else + { + sassert = m.toModuleAssert(); + ea = el_bin(OPcall,TYvoid,el_var(sassert), + el_long(TYint, loc.linnum)); + } + e = el_bin(OPoror,TYvoid,e,ea); + } + } + else + { + // BUG: should replace assert(0); with a HLT instruction + e = el_long(TYint, 0); + } + el_setLoc(e,loc); + + return e; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/AssignExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/AssignExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,857 @@ +module dmd.AssignExp; + +import dmd.Expression; +import dmd.Identifier; +import dmd.backend.elem; +import dmd.InterState; +import dmd.IndexExp; +import dmd.CallExp; +import dmd.TypeSArray; +import dmd.StructLiteralExp; +import dmd.ArrayLengthExp; +import dmd.TypeStruct; +import dmd.StructDeclaration; +import dmd.VarExp; +import dmd.TY; +import dmd.SliceExp; +import dmd.CommaExp; +import dmd.ArrayExp; +import dmd.AggregateDeclaration; +import dmd.CondExp; +import dmd.DotVarExp; +import dmd.WANT; +import dmd.Id; +import dmd.TypeClass; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.TupleExp; +import dmd.VarDeclaration; +import dmd.Scope; +import dmd.IRState; +import dmd.ArrayTypes; +import dmd.BinExp; +import dmd.TOK; +import dmd.Global; +import dmd.Declaration; +import dmd.TypeFunction; +import dmd.Type; +import dmd.RET; +import dmd.STC; +import dmd.DotIdExp; + +import dmd.backend.Util; +import dmd.backend.Symbol; +import dmd.backend.OPER; +import dmd.backend.TYM; +import dmd.backend.RTLSYM; +import dmd.codegen.Util; +import dmd.expression.Util; + +class AssignExp : BinExp +{ + int ismemset = 0; + + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKassign, AssignExp.sizeof, e1, e2); + } + + Expression semantic(Scope sc) + { + Expression e1old = e1; + +version (LOGSEMANTIC) { + printf("AssignExp.semantic('%s')\n", toChars()); +} + //printf("e1.op = %d, '%s'\n", e1.op, Token.toChars(e1.op)); + //printf("e2.op = %d, '%s'\n", e2.op, Token.toChars(e2.op)); + + if (type) + return this; + + if (e2.op == TOK.TOKcomma) + { + /* Rewrite to get rid of the comma from rvalue + */ + AssignExp ea = new AssignExp(loc, e1, (cast(CommaExp)e2).e2); + ea.op = op; + Expression e = new CommaExp(loc, (cast(CommaExp)e2).e1, ea); + return e.semantic(sc); + } + + /* Look for operator overloading of a[i]=value. + * Do it before semantic() otherwise the a[i] will have been + * converted to a.opIndex() already. + */ + if (e1.op == TOK.TOKarray) + { + ArrayExp ae = cast(ArrayExp)e1; + AggregateDeclaration ad; + Identifier id = Id.index; + + ae.e1 = ae.e1.semantic(sc); + Type t1 = ae.e1.type.toBasetype(); + if (t1.ty == TY.Tstruct) + { + ad = (cast(TypeStruct)t1).sym; + goto L1; + } + else if (t1.ty == TY.Tclass) + { + ad = (cast(TypeClass)t1).sym; + L1: + // Rewrite (a[i] = value) to (a.opIndexAssign(value, i)) + if (search_function(ad, Id.indexass)) + { + Expression e = new DotIdExp(loc, ae.e1, Id.indexass); + Expressions a = cast(Expressions)ae.arguments.copy(); + + a.insert(0, cast(void*)e2); + e = new CallExp(loc, e, a); + e = e.semantic(sc); + return e; + } + else + { + // Rewrite (a[i] = value) to (a.opIndex(i, value)) + if (search_function(ad, id)) + { + Expression e = new DotIdExp(loc, ae.e1, id); + + if (1 || !global.params.useDeprecated) + error("operator [] assignment overload with opIndex(i, value) illegal, use opIndexAssign(value, i)"); + + e = new CallExp(loc, e, cast(Expression)ae.arguments.data[0], e2); + e = e.semantic(sc); + return e; + } + } + } + } + /* Look for operator overloading of a[i..j]=value. + * Do it before semantic() otherwise the a[i..j] will have been + * converted to a.opSlice() already. + */ + if (e1.op == TOK.TOKslice) + { + Type t1; + SliceExp ae = cast(SliceExp)e1; + AggregateDeclaration ad; + Identifier id = Id.index; + + ae.e1 = ae.e1.semantic(sc); + ae.e1 = resolveProperties(sc, ae.e1); + t1 = ae.e1.type.toBasetype(); + if (t1.ty == TY.Tstruct) + { + ad = (cast(TypeStruct)t1).sym; + goto L2; + } + else if (t1.ty == TY.Tclass) + { + ad = (cast(TypeClass)t1).sym; + L2: + // Rewrite (a[i..j] = value) to (a.opIndexAssign(value, i, j)) + if (search_function(ad, Id.sliceass)) + { + Expression e = new DotIdExp(loc, ae.e1, Id.sliceass); + Expressions a = new Expressions(); + + a.push(cast(void*)e2); + if (ae.lwr) + { + a.push(cast(void*)ae.lwr); + assert(ae.upr); + a.push(cast(void*)ae.upr); + } + else + assert(!ae.upr); + + e = new CallExp(loc, e, a); + e = e.semantic(sc); + return e; + } + } + } + + BinExp.semantic(sc); + + if (e1.op == TOK.TOKdottd) + { + // Rewrite a.b=e2, when b is a template, as a.b(e2) + Expression e = new CallExp(loc, e1, e2); + e = e.semantic(sc); + return e; + } + + e2 = resolveProperties(sc, e2); + assert(e1.type); + + /* Rewrite tuple assignment as a tuple of assignments. + */ + if (e1.op == TOK.TOKtuple && e2.op == TOK.TOKtuple) + { + TupleExp tup1 = cast(TupleExp)e1; + TupleExp tup2 = cast(TupleExp)e2; + size_t dim = tup1.exps.dim; + if (dim != tup2.exps.dim) + { + error("mismatched tuple lengths, %d and %d", cast(int)dim, cast(int)tup2.exps.dim); + } + else + { + Expressions exps = new Expressions; + exps.setDim(dim); + + for (int i = 0; i < dim; i++) + { + Expression ex1 = cast(Expression)tup1.exps.data[i]; + Expression ex2 = cast(Expression)tup2.exps.data[i]; + exps.data[i] = cast(void*) new AssignExp(loc, ex1, ex2); + } + Expression e = new TupleExp(loc, exps); + e = e.semantic(sc); + return e; + } + } + + // Determine if this is an initialization of a reference + int refinit = 0; + if (op == TOK.TOKconstruct && e1.op == TOK.TOKvar) + { + VarExp ve = cast(VarExp)e1; + VarDeclaration v = ve.var.isVarDeclaration(); + if (v.storage_class & (STC.STCout | STC.STCref)) + refinit = 1; + } + + Type t1 = e1.type.toBasetype(); + + if (t1.ty == TY.Tfunction) + { + // Rewrite f=value to f(value) + Expression e = new CallExp(loc, e1, e2); + e = e.semantic(sc); + return e; + } + + /* If it is an assignment from a 'foreign' type, + * check for operator overloading. + */ + if (t1.ty == TY.Tstruct) + { + StructDeclaration sd = (cast(TypeStruct)t1).sym; + if (op == TOK.TOKassign) + { + Expression e = op_overload(sc); + if (e) + return e; + } + else if (op == TOK.TOKconstruct && !refinit) + { + Type t2 = e2.type.toBasetype(); + if (t2.ty == TY.Tstruct && sd == (cast(TypeStruct)t2).sym && sd.cpctor) + { + /* We have a copy constructor for this + */ + if (e2.op == TOK.TOKquestion) + { /* Write as: + * a ? e1 = b : e1 = c; + */ + CondExp ec = cast(CondExp)e2; + AssignExp ea1 = new AssignExp(ec.e1.loc, e1, ec.e1); + ea1.op = op; + AssignExp ea2 = new AssignExp(ec.e1.loc, e1, ec.e2); + ea2.op = op; + Expression e = new CondExp(loc, ec.econd, ea1, ea2); + return e.semantic(sc); + } + else if (e2.op == TOK.TOKvar || e2.op == TOK.TOKdotvar || e2.op == TOK.TOKstar || e2.op == TOK.TOKindex) + { /* Write as: + * e1.cpctor(e2); + */ + Expression e = new DotVarExp(loc, e1, sd.cpctor, 0); + e = new CallExp(loc, e, e2); + return e.semantic(sc); + } + } + } + } + else if (t1.ty == TY.Tclass) + { + // Disallow assignment operator overloads for same type + if (!e2.type.implicitConvTo(e1.type)) + { + Expression e = op_overload(sc); + if (e) + return e; + } + } + + if (t1.ty == TY.Tsarray && !refinit) + { + // Convert e1 to e1[] + Expression e = new SliceExp(e1.loc, e1, null, null); + e1 = e.semantic(sc); + t1 = e1.type.toBasetype(); + } + + e2.rvalue(); + + if (e1.op == TOK.TOKarraylength) + { + // e1 is not an lvalue, but we let code generator handle it + ArrayLengthExp ale = cast(ArrayLengthExp)e1; + ale.e1 = ale.e1.modifiableLvalue(sc, e1); + } + else if (e1.op == TOK.TOKslice) + { + Type tn = e1.type.nextOf(); + if (tn && !tn.isMutable() && op != TOK.TOKconstruct) + error("slice %s is not mutable", e1.toChars()); + } + else + { + // Try to do a decent error message with the expression + // before it got constant folded + if (e1.op != TOK.TOKvar) + e1 = e1.optimize(WANT.WANTvalue); + + if (op != TOK.TOKconstruct) + e1 = e1.modifiableLvalue(sc, e1old); + } + + Type t2 = e2.type; + if (e1.op == TOK.TOKslice && t1.nextOf() && e2.implicitConvTo(t1.nextOf())) + { + // memset + ismemset = 1; // make it easy for back end to tell what this is + e2 = e2.implicitCastTo(sc, t1.nextOf()); + } + else if (t1.ty == TY.Tsarray) + { + /* Should have already converted e1 => e1[] + */ + assert(op == TOK.TOKconstruct); + //error("cannot assign to static array %s", e1.toChars()); + } + else if (e1.op == TOK.TOKslice) + { + e2 = e2.implicitCastTo(sc, e1.type.constOf()); + } + else + { + e2 = e2.implicitCastTo(sc, e1.type); + } + + /* Look for array operations + */ + if (e1.op == TOK.TOKslice && !ismemset && + (e2.op == TOK.TOKadd || e2.op == TOK.TOKmin || + e2.op == TOK.TOKmul || e2.op == TOK.TOKdiv || + e2.op == TOK.TOKmod || e2.op == TOK.TOKxor || + e2.op == TOK.TOKand || e2.op == TOK.TOKor || + e2.op == TOK.TOKtilde || e2.op == TOK.TOKneg)) + { + type = e1.type; + return arrayOp(sc); + } + + type = e1.type; + assert(type); + return this; + } + + Expression checkToBoolean() + { + assert(false); + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + Identifier opId() + { + return Id.assign; + } + + void buildArrayIdent(OutBuffer buf, Expressions arguments) + { + assert(false); + } + + Expression buildArrayLoop(Arguments fparams) + { + assert(false); + } + + elem* toElem(IRState* irs) + { + elem* e; + IndexExp ae; + int r; + Type t1b; + + //printf("AssignExp.toElem('%s')\n", toChars()); + t1b = e1.type.toBasetype(); + + // Look for array.length = n + if (e1.op == TOK.TOKarraylength) + { + // Generate: + // _d_arraysetlength(e2, sizeelem, &ale.e1); + + ArrayLengthExp ale = cast(ArrayLengthExp)e1; + elem* p1; + elem* p2; + elem* p3; + elem* ep; + Type t1; + + p1 = e2.toElem(irs); + p3 = ale.e1.toElem(irs); + p3 = addressElem(p3, null); + t1 = ale.e1.type.toBasetype(); + +static if (true) { + // call _d_arraysetlengthT(ti, e2, &ale.e1); + p2 = t1.getTypeInfo(null).toElem(irs); + ep = el_params(p3, p1, p2, null); // c function + r = t1.nextOf().isZeroInit(Loc(0)) ? RTLSYM.RTLSYM_ARRAYSETLENGTHT : RTLSYM.RTLSYM_ARRAYSETLENGTHIT; +} else { + if (t1.next.isZeroInit()) + { + p2 = t1.getTypeInfo(null).toElem(irs); + ep = el_params(p3, p1, p2, null); // c function + r = RTLSYM.RTLSYM_ARRAYSETLENGTHT; + } + else + { + p2 = el_long(TYM.TYint, t1.next.size()); + ep = el_params(p3, p2, p1, null); // c function + Expression init = t1.next.defaultInit(); + ep = el_param(el_long(TYM.TYint, init.type.size()), ep); + elem* ei = init.toElem(irs); + ep = el_param(ei, ep); + r = RTLSYM.RTLSYM_ARRAYSETLENGTH3; + } +} + e = el_bin(OPER.OPcall, type.totym(), el_var(rtlsym[r]), ep); + el_setLoc(e, loc); + return e; + } + + // Look for array[]=n + if (e1.op == TOK.TOKslice) + { + Type t1 = t1b; + Type t2 = e2.type.toBasetype(); + + // which we do if the 'next' types match + if (ismemset) + { + // Do a memset for array[]=v + //printf("Lpair %s\n", toChars()); + SliceExp are = cast(SliceExp)e1; + elem* elwr; + elem* eupr; + elem* n1; + elem* evalue; + elem* enbytes; + elem* elength; + elem* einit; + long value; + Type ta = are.e1.type.toBasetype(); + Type tb = ta.nextOf().toBasetype(); + int sz = cast(uint)tb.size(); + tym_t tym = type.totym(); + + n1 = are.e1.toElem(irs); + elwr = are.lwr ? are.lwr.toElem(irs) : null; + eupr = are.upr ? are.upr.toElem(irs) : null; + + elem* n1x = n1; + + // Look for array[]=n + if (ta.ty == TY.Tsarray) + { + TypeSArray ts = cast(TypeSArray)ta; + n1 = array_toPtr(ta, n1); + enbytes = ts.dim.toElem(irs); + n1x = n1; + n1 = el_same(&n1x); + einit = resolveLengthVar(are.lengthVar, &n1, ta); + } + else if (ta.ty == TY.Tarray) + { + n1 = el_same(&n1x); + einit = resolveLengthVar(are.lengthVar, &n1, ta); + enbytes = el_copytree(n1); + n1 = array_toPtr(ta, n1); + enbytes = el_una(OPER.OP64_32, TYM.TYint, enbytes); + } + else if (ta.ty == TY.Tpointer) + { + n1 = el_same(&n1x); + enbytes = el_long(TYM.TYint, -1); // largest possible index + einit = null; + } + + // Enforce order of evaluation of n1[elwr..eupr] as n1,elwr,eupr + elem* elwrx = elwr; + if (elwr) elwr = el_same(&elwrx); + elem* euprx = eupr; + if (eupr) eupr = el_same(&euprx); + + static if (false) { + printf("sz = %d\n", sz); + printf("n1x\n"); + elem_print(n1x); + printf("einit\n"); + elem_print(einit); + printf("elwrx\n"); + elem_print(elwrx); + printf("euprx\n"); + elem_print(euprx); + printf("n1\n"); + elem_print(n1); + printf("elwr\n"); + elem_print(elwr); + printf("eupr\n"); + elem_print(eupr); + printf("enbytes\n"); + elem_print(enbytes); + } + einit = el_combine(n1x, einit); + einit = el_combine(einit, elwrx); + einit = el_combine(einit, euprx); + + evalue = this.e2.toElem(irs); + + static if (false) { + printf("n1\n"); + elem_print(n1); + printf("enbytes\n"); + elem_print(enbytes); + } + + if (global.params.useArrayBounds && eupr && ta.ty != TY.Tpointer) + { + elem *c1; + elem *c2; + elem *ea; + elem *eb; + elem *enbytesx; + + assert(elwr); + enbytesx = enbytes; + enbytes = el_same(&enbytesx); + c1 = el_bin(OPER.OPle, TYM.TYint, el_copytree(eupr), enbytesx); + c2 = el_bin(OPER.OPle, TYM.TYint, el_copytree(elwr), el_copytree(eupr)); + c1 = el_bin(OPER.OPandand, TYM.TYint, c1, c2); + + // Construct: (c1 || ModuleArray(line)) + Symbol *sassert; + + sassert = irs.blx.module_.toModuleArray(); + ea = el_bin(OPER.OPcall,TYM.TYvoid,el_var(sassert), el_long(TYM.TYint, loc.linnum)); + eb = el_bin(OPER.OPoror,TYM.TYvoid,c1,ea); + einit = el_combine(einit, eb); + } + + if (elwr) + { + elem *elwr2; + + el_free(enbytes); + elwr2 = el_copytree(elwr); + elwr2 = el_bin(OPER.OPmul, TYM.TYint, elwr2, el_long(TYM.TYint, sz)); + n1 = el_bin(OPER.OPadd, TYM.TYnptr, n1, elwr2); + enbytes = el_bin(OPER.OPmin, TYM.TYint, eupr, elwr); + elength = el_copytree(enbytes); + } + else + elength = el_copytree(enbytes); + + e = setArray(n1, enbytes, tb, evalue, irs, op); + Lpair: + e = el_pair(TYM.TYullong, elength, e); + Lret2: + e = el_combine(einit, e); + //elem_print(e); + goto Lret; + } +///static if (false) { +/// else if (e2.op == TOK.TOKadd || e2.op == TOK.TOKmin) +/// { +/// /* It's ea[] = eb[] +- ec[] +/// */ +/// BinExp e2a = cast(BinExp)e2; +/// Type t = e2.type.toBasetype().nextOf().toBasetype(); +/// if (t.ty != TY.Tfloat32 && t.ty != TY.Tfloat64 && t.ty != TY.Tfloat80) +/// { +/// e2.error("array add/min for %s not supported", t.toChars()); +/// return el_long(TYM.TYint, 0); +/// } +/// elem* ea = e1.toElem(irs); +/// ea = array_toDarray(e1.type, ea); +/// elem* eb = e2a.e1.toElem(irs); +/// eb = array_toDarray(e2a.e1.type, eb); +/// elem* ec = e2a.e2.toElem(irs); +/// ec = array_toDarray(e2a.e2.type, ec); +/// +/// int rtl = RTLSYM.RTLSYM_ARRAYASSADDFLOAT; +/// if (t.ty == Tfloat64) +/// rtl = RTLSYM.RTLSYM_ARRAYASSADDDOUBLE; +/// else if (t.ty == Tfloat80) +/// rtl = RTLSYM.RTLSYM_ARRAYASSADDREAL; +/// if (e2.op == TOK.TOKmin) +/// { +/// rtl = RTLSYM.RTLSYM_ARRAYASSMINFLOAT; +/// if (t.ty == Tfloat64) +/// rtl = RTLSYM.RTLSYM_ARRAYASSMINDOUBLE; +/// else if (t.ty == Tfloat80) +/// rtl = RTLSYM.RTLSYM_ARRAYASSMINREAL; +/// } +/// +/// /* Set parameters so the order of evaluation is eb, ec, ea +/// */ +/// elem* ep = el_params(eb, ec, ea, null); +/// e = el_bin(OPER.OPcall, type.totym(), el_var(rtlsym[rtl]), ep); +/// goto Lret; +/// } +///} + else + { + /* It's array1[]=array2[] + * which is a memcpy + */ + elem* eto; + elem* efrom; + elem* esize; + elem* ep; + + eto = e1.toElem(irs); + efrom = e2.toElem(irs); + + uint size = cast(uint)t1.nextOf().size(); + esize = el_long(TYM.TYint, size); + + /* Determine if we need to do postblit + */ + int postblit = 0; + if (needsPostblit(t1)) + postblit = 1; + + assert(e2.type.ty != TY.Tpointer); + + if (!postblit && !global.params.useArrayBounds) + { + elem* epto; + elem* epfr; + elem* elen; + elem* ex; + + ex = el_same(&eto); + + // Determine if elen is a constant + if (eto.Eoper == OPER.OPpair && eto.E1.Eoper == OPER.OPconst) + { + elen = el_copytree(eto.E1); + } + else + { + // It's not a constant, so pull it from the dynamic array + elen = el_una(OPER.OP64_32, TYM.TYint, el_copytree(ex)); + } + + esize = el_bin(OPER.OPmul, TYM.TYint, elen, esize); + epto = array_toPtr(e1.type, ex); + epfr = array_toPtr(e2.type, efrom); + static if (true) { + // memcpy() is faster, so if we can't beat 'em, join 'em + e = el_params(esize, epfr, epto, null); + e = el_bin(OPER.OPcall, TYM.TYnptr, el_var(rtlsym[RTLSYM.RTLSYM_MEMCPY]), e); + } else { + e = el_bin(OPER.OPmemcpy, TYM.TYnptr, epto, el_param(epfr, esize)); + } + e = el_pair(eto.Ety, el_copytree(elen), e); + e = el_combine(eto, e); + } +///version (DMDV2) { + else if (postblit && op != TOK.TOKblit) + { + /* Generate: + * _d_arrayassign(ti, efrom, eto) + * or: + * _d_arrayctor(ti, efrom, eto) + */ + el_free(esize); + Expression ti = t1.nextOf().toBasetype().getTypeInfo(null); + ep = el_params(eto, efrom, ti.toElem(irs), null); + int rtl = (op == TOK.TOKconstruct) ? RTLSYM.RTLSYM_ARRAYCTOR : RTLSYM.RTLSYM_ARRAYASSIGN; + e = el_bin(OPER.OPcall, type.totym(), el_var(rtlsym[rtl]), ep); + } +///} + else + { + // Generate: + // _d_arraycopy(eto, efrom, esize) + + ep = el_params(eto, efrom, esize, null); + e = el_bin(OPER.OPcall, type.totym(), el_var(rtlsym[RTLSYM.RTLSYM_ARRAYCOPY]), ep); + } + el_setLoc(e, loc); + return e; + } + } + + if (e1.op == TOK.TOKindex) + { + elem* eb; + elem* ei; + elem* ev; + TY ty; + Type ta; + + ae = cast(IndexExp)e1; + ta = ae.e1.type.toBasetype(); + ty = ta.ty; + } + +version (DMDV2) { + /* Look for reference initializations + */ + if (op == TOK.TOKconstruct && e1.op == TOK.TOKvar) + { + VarExp ve = cast(VarExp)e1; + Declaration s = ve.var; + if (s.storage_class & STC.STCref) + { +static if (false) { + Expression ae = e2.addressOf(null); + e = ae.toElem(irs); +} else { + e = e2.toElem(irs); + e = addressElem(e, e2.type); +} + elem* es = el_var(s.toSymbol()); + es.Ety = TYM.TYnptr; + e = el_bin(OPER.OPeq, TYM.TYnptr, es, e); + // BUG: type is struct, and e2 is TOKint64 + goto Lret; + } + } +} + +static if (true) { + /* This will work if we can distinguish an assignment from + * an initialization of the lvalue. It'll work if the latter. + * If the former, because of aliasing of the return value with + * function arguments, it'll fail. + */ + if (op == TOK.TOKconstruct && e2.op == TOK.TOKcall) + { + CallExp ce = cast(CallExp)e2; + + TypeFunction tf = cast(TypeFunction)ce.e1.type.toBasetype(); + if (tf.ty == TY.Tfunction && tf.retStyle() == RET.RETstack) + { + elem* ehidden = e1.toElem(irs); + ehidden = el_una(OPER.OPaddr, TYM.TYnptr, ehidden); + assert(!irs.ehidden); + irs.ehidden = ehidden; + e = e2.toElem(irs); + goto Lret; + } + } +} + //printf("test2 %d\n", op); + //if (op == TOK.TOKconstruct) printf("construct\n"); + if (t1b.ty == TY.Tstruct) + { + elem* eleft = e1.toElem(irs); + + if (e2.op == TOK.TOKint64) + { + /* Implement: + * (struct = 0) + * with: + * memset(&struct, 0, struct.sizeof) + */ + elem* ey = null; + int sz = cast(int)e1.type.size(); + StructDeclaration sd = (cast(TypeStruct)t1b).sym; + if (sd.isnested && op == TOK.TOKconstruct) + { + ey = el_una(OPER.OPaddr, TYM.TYnptr, eleft); + eleft = el_same(&ey); + ey = setEthis(loc, irs, ey, sd); + sz = sd.vthis.offset; + } + + elem *el = eleft; + elem *enbytes = el_long(TYM.TYint, sz); + elem *evalue = el_long(TYM.TYint, 0); + + if (!(sd.isnested && op == TOK.TOKconstruct)) + el = el_una(OPER.OPaddr, TYM.TYnptr, el); + + e = el_param(enbytes, evalue); + e = el_bin(OPER.OPmemset, TYM.TYnptr,el,e); + e = el_combine(ey, e); + el_setLoc(e, loc); + //e = el_una(OPER.OPind, TYM.TYstruct, e); + } + else + { + //printf("toElemBin() '%s'\n", toChars()); + + tym_t tym = type.totym(); + + elem* e1 = eleft; + elem* ex = e1; + if (e1.Eoper == OPER.OPind) + ex = e1.E1; + + if (this.e2.op == TOK.TOKstructliteral && ex.Eoper == OPER.OPvar && ex.EV.sp.Voffset == 0) + { + StructLiteralExp se = cast(StructLiteralExp)this.e2; + + Symbol* symSave = se.sym; + size_t soffsetSave = se.soffset; + int fillHolesSave = se.fillHoles; + + se.sym = ex.EV.sp.Vsym; + se.soffset = 0; + se.fillHoles = (op == TOK.TOKconstruct || op == TOK.TOKblit) ? 1 : 0; + + el_free(e1); + e = this.e2.toElem(irs); + + se.sym = symSave; + se.soffset = soffsetSave; + se.fillHoles = fillHolesSave; + } + else + { + elem* e2 = this.e2.toElem(irs); + e = el_bin(OPER.OPstreq,tym,e1,e2); + e.Enumbytes = cast(uint)this.e1.type.size(); + } + goto Lret; + } + } + else + e = toElemBin(irs,OPER.OPeq); + + return e; + + Lret: + el_setLoc(e,loc); + return e; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/AssocArrayLiteralExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/AssocArrayLiteralExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,111 @@ +module dmd.AssocArrayLiteralExp; + +import dmd.Expression; +import dmd.backend.elem; +import dmd.InterState; +import dmd.MATCH; +import dmd.Type; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.InlineCostState; +import dmd.IRState; +import dmd.InlineDoState; +import dmd.HdrGenState; +import dmd.InlineScanState; +import dmd.ArrayTypes; +import dmd.TOK; + +class AssocArrayLiteralExp : Expression +{ + Expressions keys; + + Expressions values; + + this(Loc loc, Expressions keys, Expressions values) + { + assert(false); + super(loc, TOK.init, 0); + } + + Expression syntaxCopy() + { + assert(false); + } + + Expression semantic(Scope sc) + { + assert(false); + } + + bool isBool(bool result) + { + assert(false); + } + + elem* toElem(IRState* irs) + { + assert(false); + } + + bool checkSideEffect(int flag) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + void toMangleBuffer(OutBuffer buf) + { + assert(false); + } + + void scanForNestedRef(Scope sc) + { + assert(false); + } + + Expression optimize(int result) + { + assert(false); + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + MATCH implicitConvTo(Type t) + { + assert(false); + } + + Expression castTo(Scope sc, Type t) + { + assert(false); + } + + bool canThrow() + { + assert(false); + } + + int inlineCost(InlineCostState* ics) + { + assert(false); + } + + Expression doInline(InlineDoState ids) + { + assert(false); + } + + Expression inlineScan(InlineScanState* iss) + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/AttribDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/AttribDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,265 @@ +module dmd.AttribDeclaration; + +import dmd.Dsymbol; +import dmd.Array; +import dmd.Scope; +import dmd.ScopeDsymbol; +import dmd.LINK; +import dmd.STC; +import dmd.PROT; +import dmd.ArrayTypes; +import dmd.OutBuffer; +import dmd.HdrGenState; + +class AttribDeclaration : Dsymbol +{ + Array decl; // array of Dsymbol's + + this(Array decl) + { + this.decl = decl; + } + + Array include(Scope sc, ScopeDsymbol sd) + { + return decl; + } + + bool addMember(Scope sc, ScopeDsymbol sd, int memnum) + { + bool m = false; + Array d = include(sc, sd); + + if (d) + { + for (uint i = 0; i < d.dim; i++) + { + Dsymbol s = cast(Dsymbol)d.data[i]; + m |= s.addMember(sc, sd, m | memnum); + } + } + + return m; + } + + void setScopeNewSc(Scope sc, STC stc, LINK linkage, PROT protection, int explicitProtection, uint structalign) + { + if (decl) + { + Scope newsc = sc; + if (stc != sc.stc || linkage != sc.linkage || protection != sc.protection || explicitProtection != sc.explicitProtection || structalign != sc.structalign) + { + // create new one for changes + newsc = new Scope(sc); + newsc.offset = sc.offset; + newsc.scopesym = sc.scopesym; + newsc.flags &= ~SCOPE.SCOPEfree; + newsc.stc = stc; + newsc.linkage = linkage; + newsc.protection = protection; + newsc.explicitProtection = explicitProtection; + newsc.structalign = structalign; + } + for (uint i = 0; i < decl.dim; i++) + { + Dsymbol s = cast(Dsymbol)decl.data[i]; + s.setScope(newsc); // yes, the only difference from semanticNewSc() + } + if (newsc != sc) + { + sc.offset = newsc.offset; + newsc.pop(); + } + } + } + + void semanticNewSc(Scope sc, STC stc, LINK linkage, PROT protection, int explicitProtection, uint structalign) + { + if (decl) + { + Scope newsc = sc; + if (stc != sc.stc || linkage != sc.linkage || protection != sc.protection || explicitProtection != sc.explicitProtection || structalign != sc.structalign) + { + // create new one for changes + newsc = new Scope(sc); + newsc.offset = sc.offset; + newsc.scopesym = sc.scopesym; + newsc.flags &= ~SCOPE.SCOPEfree; + newsc.stc = stc; + newsc.linkage = linkage; + newsc.protection = protection; + newsc.explicitProtection = explicitProtection; + newsc.structalign = structalign; + } + for (uint i = 0; i < decl.dim; i++) + { + Dsymbol s = cast(Dsymbol)decl.data[i]; + s.semantic(newsc); + } + if (newsc != sc) + { + sc.offset = newsc.offset; + newsc.pop(); + } + } + } + + void semantic(Scope sc) + { + Array d = include(sc, null); + + //printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d); + if (d) + { + for (uint i = 0; i < d.dim; i++) + { + Dsymbol s = cast(Dsymbol)d.data[i]; + + s.semantic(sc); + } + } + } + + void semantic2(Scope sc) + { + Array d = include(sc, null); + + if (d) + { + for (uint i = 0; i < d.dim; i++) + { Dsymbol s = cast(Dsymbol)d.data[i]; + s.semantic2(sc); + } + } + } + + void semantic3(Scope sc) + { + Array d = include(sc, null); + + if (d) + { + for (uint i = 0; i < d.dim; i++) + { + Dsymbol s = cast(Dsymbol)d.data[i]; + s.semantic3(sc); + } + } + } + + void inlineScan() + { + Array d = include(null, null); + + if (d) + { + for (uint i = 0; i < d.dim; i++) + { + Dsymbol s = cast(Dsymbol)d.data[i]; + //printf("AttribDeclaration.inlineScan %s\n", s.toChars()); + s.inlineScan(); + } + } + } + + void addComment(ubyte* comment) + { + if (comment !is null) + { + Array d = include(null, null); + if (d) + { + for (uint i = 0; i < d.dim; i++) + { + Dsymbol s = cast(Dsymbol)d.data[i]; + //printf("AttribDeclaration::addComment %s\n", s.toChars()); + s.addComment(comment); + } + } + } + } + + void emitComment(Scope sc) + { + assert(false); + } + + string kind() + { + assert(false); + } + + bool oneMember(Dsymbol* ps) + { + assert(false); + } + + bool hasPointers() + { + Array d = include(null, null); + + if (d) + { + for (size_t i = 0; i < d.dim; i++) + { + Dsymbol s = cast(Dsymbol)d.data[i]; + if (s.hasPointers()) + return true; + } + } + + return 0; + } + + void checkCtorConstInit() + { + Array d = include(null, null); + if (d) + { + for (uint i = 0; i < d.dim; i++) + { + Dsymbol s = cast(Dsymbol)d.data[i]; + s.checkCtorConstInit(); + } + } + } + + void addLocalClass(ClassDeclarations aclasses) + { + Array d = include(null, null); + if (d) + { + for (uint i = 0; i < d.dim; i++) + { + Dsymbol s = cast(Dsymbol)d.data[i]; + s.addLocalClass(aclasses); + } + } + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + AttribDeclaration isAttribDeclaration() { return this; } + + void toObjFile(int multiobj) // compile to .obj file + { + Array d = include(null, null); + + if (d) + { + for (uint i = 0; i < d.dim; i++) + { + Dsymbol s = cast(Dsymbol)d.data[i]; + s.toObjFile(multiobj); + } + } + } + + int cvMember(ubyte* p) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/BE.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/BE.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,16 @@ +module dmd.BE; + +/* How a statement exits; this is returned by blockExit() + */ +enum BE +{ + BEnone = 0, + BEfallthru = 1, + BEthrow = 2, + BEreturn = 4, + BEgoto = 8, + BEhalt = 0x10, + BEbreak = 0x20, + BEcontinue = 0x40, + BEany = (BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt), +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/BUILTIN.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/BUILTIN.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,12 @@ +module dmd.BUILTIN; + +enum BUILTIN +{ + BUILTINunknown = -1, // not known if this is a builtin + BUILTINnot, // this is not a builtin + BUILTINsin, // std.math.sin + BUILTINcos, // std.math.cos + BUILTINtan, // std.math.tan + BUILTINsqrt, // std.math.sqrt + BUILTINfabs, // std.math.fabs +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/BaseClass.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/BaseClass.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,138 @@ +module dmd.BaseClass; + +import dmd.Type; +import dmd.PROT; +import dmd.ClassDeclaration; +import dmd.Array; +import dmd.TY; +import dmd.TypeFunction; +import dmd.Dsymbol; +import dmd.FuncDeclaration; +import dmd.ArrayTypes; + +import core.stdc.stdlib; +import core.stdc.string; + +class BaseClass +{ + Type type; // (before semantic processing) + PROT protection; // protection for the base interface + + ClassDeclaration base; + int offset; // 'this' pointer offset + Array vtbl; // for interfaces: Array of FuncDeclaration's + // making up the vtbl[] + + //int baseInterfaces_dim; + BaseClass[] baseInterfaces; // if BaseClass is an interface, these + // are a copy of the InterfaceDeclaration::interfaces + + this() + { + vtbl = new Array(); + } + + this(Type type, PROT protection) + { + //printf("BaseClass(this = %p, '%s')\n", this, type->toChars()); + this.type = type; + this.protection = protection; + + vtbl = new Array(); + } + + /**************************************** + * Fill in vtbl[] for base class based on member functions of class cd. + * Input: + * vtbl if !=null, fill it in + * newinstance !=0 means all entries must be filled in by members + * of cd, not members of any base classes of cd. + * Returns: + * true if any entries were filled in by members of cd (not exclusively + * by base classes) + */ + bool fillVtbl(ClassDeclaration cd, Array vtbl, int newinstance) + { + ClassDeclaration id = base; + int j; + bool result = false; + + //printf("BaseClass.fillVtbl(this='%s', cd='%s')\n", base.toChars(), cd.toChars()); + if (vtbl) + vtbl.setDim(base.vtbl.dim); + + // first entry is ClassInfo reference + for (j = base.vtblOffset(); j < base.vtbl.dim; j++) + { + FuncDeclaration ifd = (cast(Dsymbol)base.vtbl.data[j]).isFuncDeclaration(); + FuncDeclaration fd; + TypeFunction tf; + + //printf(" vtbl[%d] is '%s'\n", j, ifd ? ifd.toChars() : "null"); + + assert(ifd); + // Find corresponding function in this class + tf = (ifd.type.ty == Tfunction) ? cast(TypeFunction)(ifd.type) : null; + fd = cd.findFunc(ifd.ident, tf); + if (fd && !fd.isAbstract()) + { + //printf(" found\n"); + // Check that calling conventions match + if (fd.linkage != ifd.linkage) + fd.error("linkage doesn't match interface function"); + + // Check that it is current + if (newinstance && + fd.toParent() != cd && + ifd.toParent() == base + ) + cd.error("interface function %s.%s is not implemented", + id.toChars(), ifd.ident.toChars()); + + if (fd.toParent() == cd) + result = true; + } + else + { + //printf(" not found\n"); + // BUG: should mark this class as abstract? + if (!cd.isAbstract()) + cd.error("interface function %s.%s isn't implemented", id.toChars(), ifd.ident.toChars()); + fd = null; + } + if (vtbl) + vtbl.data[j] = cast(void*)fd; + } + + return result; + } + + void copyBaseInterfaces(BaseClasses vtblInterfaces) + { + //printf("+copyBaseInterfaces(), %s\n", base.toChars()); + // if (baseInterfaces_dim) + // return; + + baseInterfaces.length = base.interfaces_dim; + + int size = BaseClass.classinfo.init.length; + + //printf("%s.copyBaseInterfaces()\n", base.toChars()); + for (int i = 0; i < baseInterfaces.length; i++) + { + BaseClass b2 = base.interfaces[i]; + assert(b2.vtbl.dim == 0); // should not be filled yet + + void* mem = malloc(size); + memcpy(mem, cast(void*)b2, size); + + BaseClass b = cast(BaseClass)mem; + baseInterfaces[i] = b; + + if (i) // single inheritance is i==0 + vtblInterfaces.push(cast(void*)b); // only need for M.I. + b.copyBaseInterfaces(vtblInterfaces); + } + //printf("-copyBaseInterfaces\n"); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/BinExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/BinExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,920 @@ +module dmd.BinExp; + +import dmd.Expression; +import dmd.Loc; +import dmd.ClassDeclaration; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.TOK; +import dmd.IRState; +import dmd.Scope; +import dmd.Type; +import dmd.InterState; +import dmd.InlineCostState; +import dmd.InlineScanState; +import dmd.InlineDoState; +import dmd.AggregateDeclaration; +import dmd.Identifier; +import dmd.MATCH; +import dmd.declaration.Match; +import dmd.ArrayTypes; +import dmd.TY; +import dmd.TypeClass; +import dmd.TypeStruct; +import dmd.Dsymbol; +import dmd.FuncDeclaration; +import dmd.TemplateDeclaration; +import dmd.DotIdExp; +import dmd.ErrorExp; +import dmd.WANT; +import dmd.IntegerExp; +import dmd.MulExp; +import dmd.Token; +import dmd.PREC; + +import dmd.expression.Util; + +import dmd.backend.elem; +import dmd.backend.Util; + +import std.stdio : writef; + +/************************************** + * Combine types. + * Output: + * *pt merged type, if *pt is not null + * *pe1 rewritten e1 + * *pe2 rewritten e2 + * Returns: + * !=0 success + * 0 failed + */ + +int typeMerge(Scope sc, Expression e, Type* pt, Expression* pe1, Expression* pe2) +{ + //printf("typeMerge() %s op %s\n", (*pe1).toChars(), (*pe2).toChars()); + //dump(0); + + Expression e1 = (*pe1).integralPromotions(sc); + Expression e2 = (*pe2).integralPromotions(sc); + + Type t1 = e1.type; + Type t2 = e2.type; + assert(t1); + Type t = t1; + + //if (t1) printf("\tt1 = %s\n", t1.toChars()); + //if (t2) printf("\tt2 = %s\n", t2.toChars()); +debug { + if (!t2) writef("\te2 = '%s'\n", e2.toChars()); +} + assert(t2); + + Type t1b = t1.toBasetype(); + Type t2b = t2.toBasetype(); + + TY ty = cast(TY)Type.impcnvResult[t1b.ty][t2b.ty]; + if (ty != TY.Terror) + { + TY ty1; + TY ty2; + + ty1 = cast(TY)Type.impcnvType1[t1b.ty][t2b.ty]; + ty2 = cast(TY)Type.impcnvType2[t1b.ty][t2b.ty]; + + if (t1b.ty == ty1) // if no promotions + { + if (t1 == t2) + { + t = t1; + goto Lret; + } + + if (t1b == t2b) + { + t = t1b; + goto Lret; + } + } + + t = Type.basic[ty]; + + t1 = Type.basic[ty1]; + t2 = Type.basic[ty2]; + + e1 = e1.castTo(sc, t1); + e2 = e2.castTo(sc, t2); + //printf("after typeCombine():\n"); + //dump(0); + //printf("ty = %d, ty1 = %d, ty2 = %d\n", ty, ty1, ty2); + goto Lret; + } + + t1 = t1b; + t2 = t2b; + +Lagain: + if (t1 == t2) + { + } + else if (t1.ty == TY.Tpointer && t2.ty == TY.Tpointer) + { + // Bring pointers to compatible type + Type t1n = t1.nextOf(); + Type t2n = t2.nextOf(); + + if (t1n == t2n) { + ; + } else if (t1n.ty == TY.Tvoid) {// pointers to void are always compatible + t = t2; + } else if (t2n.ty == TY.Tvoid) { + ; + } else if (t1n.mod != t2n.mod) { + t1 = t1n.mutableOf().constOf().pointerTo(); + t2 = t2n.mutableOf().constOf().pointerTo(); + t = t1; + goto Lagain; + } else if (t1n.ty == TY.Tclass && t2n.ty == TY.Tclass) { + ClassDeclaration cd1 = t1n.isClassHandle(); + ClassDeclaration cd2 = t2n.isClassHandle(); + int offset; + + if (cd1.isBaseOf(cd2, &offset)) + { + if (offset) + e2 = e2.castTo(sc, t); + } + else if (cd2.isBaseOf(cd1, &offset)) + { + t = t2; + if (offset) + e1 = e1.castTo(sc, t); + } + else + goto Lincompatible; + } else { + goto Lincompatible; + } + } + else if ((t1.ty == TY.Tsarray || t1.ty == TY.Tarray) && + e2.op == TOK.TOKnull && t2.ty == TY.Tpointer && t2.nextOf().ty == TY.Tvoid) + { /* (T[n] op void*) + * (T[] op void*) + */ + goto Lx1; + } + else if ((t2.ty == TY.Tsarray || t2.ty == TY.Tarray) && + e1.op == TOK.TOKnull && t1.ty == TY.Tpointer && t1.nextOf().ty == TY.Tvoid) + { /* (void* op T[n]) + * (void* op T[]) + */ + goto Lx2; + } + else if ((t1.ty == TY.Tsarray || t1.ty == TY.Tarray) && t1.implicitConvTo(t2)) + { + goto Lt2; + } + else if ((t2.ty == TY.Tsarray || t2.ty == TY.Tarray) && t2.implicitConvTo(t1)) + { + goto Lt1; + } + /* If one is mutable and the other invariant, then retry + * with both of them as const + */ + else if ((t1.ty == TY.Tsarray || t1.ty == TY.Tarray || t1.ty == TY.Tpointer) && + (t2.ty == TY.Tsarray || t2.ty == TY.Tarray || t2.ty == TY.Tpointer) && + t1.nextOf().mod != t2.nextOf().mod + ) + { + if (t1.ty == TY.Tpointer) + t1 = t1.nextOf().mutableOf().constOf().pointerTo(); + else + t1 = t1.nextOf().mutableOf().constOf().arrayOf(); + + if (t2.ty == TY.Tpointer) + t2 = t2.nextOf().mutableOf().constOf().pointerTo(); + else + t2 = t2.nextOf().mutableOf().constOf().arrayOf(); + t = t1; + goto Lagain; + } + else if (t1.ty == TY.Tclass || t2.ty == TY.Tclass) + { + while (1) + { + int i1 = e2.implicitConvTo(t1); + int i2 = e1.implicitConvTo(t2); + + if (i1 && i2) + { + // We have the case of class vs. void*, so pick class + if (t1.ty == TY.Tpointer) + i1 = 0; + else if (t2.ty == TY.Tpointer) + i2 = 0; + } + + if (i2) + { + goto Lt2; + } + else if (i1) + { + goto Lt1; + } + else if (t1.ty == TY.Tclass && t2.ty == TY.Tclass) + { + TypeClass tc1 = cast(TypeClass)t1; + TypeClass tc2 = cast(TypeClass)t2; + + /* Pick 'tightest' type + */ + ClassDeclaration cd1 = tc1.sym.baseClass; + ClassDeclaration cd2 = tc2.sym.baseClass; + + if (cd1 && cd2) + { t1 = cd1.type; + t2 = cd2.type; + } + else if (cd1) + t1 = cd1.type; + else if (cd2) + t2 = cd2.type; + else + goto Lincompatible; + } + else + goto Lincompatible; + } + } + else if (t1.ty == TY.Tstruct && t2.ty == TY.Tstruct) + { + if ((cast(TypeStruct)t1).sym != (cast(TypeStruct)t2).sym) + goto Lincompatible; + } + else if ((e1.op == TOK.TOKstring || e1.op == TOK.TOKnull) && e1.implicitConvTo(t2)) + { + goto Lt2; + } + else if ((e2.op == TOK.TOKstring || e2.op == TOK.TOKnull) && e2.implicitConvTo(t1)) + { + goto Lt1; + } + else if (t1.ty == TY.Tsarray && t2.ty == TY.Tsarray && + e2.implicitConvTo(t1.nextOf().arrayOf())) + { + Lx1: + t = t1.nextOf().arrayOf(); + e1 = e1.castTo(sc, t); + e2 = e2.castTo(sc, t); + } + else if (t1.ty == TY.Tsarray && t2.ty == TY.Tsarray && + e1.implicitConvTo(t2.nextOf().arrayOf())) + { + Lx2: + t = t2.nextOf().arrayOf(); + e1 = e1.castTo(sc, t); + e2 = e2.castTo(sc, t); + } + else if (t1.isintegral() && t2.isintegral()) + { + assert(0); + } + else if (e1.op == TOK.TOKslice && t1.ty == TY.Tarray && + e2.implicitConvTo(t1.nextOf())) + { // T[] op T + e2 = e2.castTo(sc, t1.nextOf()); + t = t1.nextOf().arrayOf(); + } + else if (e2.op == TOK.TOKslice && t2.ty == TY.Tarray && + e1.implicitConvTo(t2.nextOf())) + { // T op T[] + e1 = e1.castTo(sc, t2.nextOf()); + t = t2.nextOf().arrayOf(); + + //printf("test %s\n", e.toChars()); + e1 = e1.optimize(WANT.WANTvalue); + if (e && e.isCommutative() && e1.isConst()) + { /* Swap operands to minimize number of functions generated + */ + //printf("swap %s\n", e.toChars()); + Expression tmp = e1; + e1 = e2; + e2 = tmp; + } + } + else + { + Lincompatible: + return 0; + } +Lret: + if (!*pt) + *pt = t; + *pe1 = e1; + *pe2 = e2; +static if (false) { + printf("-typeMerge() %s op %s\n", e1.toChars(), e2.toChars()); + if (e1.type) printf("\tt1 = %s\n", e1.type.toChars()); + if (e2.type) printf("\tt2 = %s\n", e2.type.toChars()); + printf("\ttype = %s\n", t.toChars()); +} + //dump(0); + return 1; + + +Lt1: + e2 = e2.castTo(sc, t1); + t = t1; + goto Lret; + +Lt2: + e1 = e1.castTo(sc, t2); + t = t2; + goto Lret; +} + +class BinExp : Expression +{ + Expression e1; + Expression e2; + + this(Loc loc, TOK op, int size, Expression e1, Expression e2) + { + super(loc, op, size); + this.e1 = e1; + this.e2 = e2; + } + + Expression syntaxCopy() + { + BinExp e = cast(BinExp)copy(); + e.type = null; + e.e1 = e.e1.syntaxCopy(); + e.e2 = e.e2.syntaxCopy(); + + return e; + } + + Expression semantic(Scope sc) + { +version (LOGSEMANTIC) { + printf("BinExp.semantic('%s')\n", toChars()); +} + e1 = e1.semantic(sc); + if (!e1.type && !(op == TOK.TOKassign && e1.op == TOK.TOKdottd)) // a.template = e2 + { + error("%s has no value", e1.toChars()); + e1.type = Type.terror; + } + e2 = e2.semantic(sc); + if (!e2.type) + { + error("%s has no value", e2.toChars()); + e2.type = Type.terror; + } + return this; + } + + Expression semanticp(Scope sc) + { +version (LOGSEMANTIC) { + printf("BinExp.semantic('%s')\n", toChars()); +} + e1 = e1.semantic(sc); + if (!e1.type && + !(op == TOK.TOKassign && e1.op == TOK.TOKdottd)) // a.template = e2 + { + error("%s has no value", e1.toChars()); + e1.type = Type.terror; + } + e2 = e2.semantic(sc); + if (!e2.type) + { + error("%s has no value", e2.toChars()); + e2.type = Type.terror; + } + return this; + } + + Expression commonSemanticAssign(Scope sc) + { + assert(false); + } + + Expression commonSemanticAssignIntegral(Scope sc) + { + Expression e; + + if (!type) + { + BinExp.semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + if (e1.op == TOK.TOKslice) + { // T[] op= ... + typeCombine(sc); + type = e1.type; + return arrayOp(sc); + } + + e1 = e1.modifiableLvalue(sc, e1); + e1.checkScalar(); + type = e1.type; + if (type.toBasetype().ty == TY.Tbool) + { + e2 = e2.implicitCastTo(sc, type); + } + + typeCombine(sc); + e1.checkIntegral(); + e2.checkIntegral(); + } + + return this; + } + + bool checkSideEffect(int flag) + { + switch (op) { + case TOK.TOKplusplus: + case TOK.TOKminusminus: + case TOK.TOKassign: + case TOK.TOKconstruct: + case TOK.TOKblit: + case TOK.TOKaddass: + case TOK.TOKminass: + case TOK.TOKcatass: + case TOK.TOKmulass: + case TOK.TOKdivass: + case TOK.TOKmodass: + case TOK.TOKshlass: + case TOK.TOKshrass: + case TOK.TOKushrass: + case TOK.TOKandass: + case TOK.TOKorass: + case TOK.TOKxorass: + case TOK.TOKin: + case TOK.TOKremove: + return true; + + default: + return Expression.checkSideEffect(flag); + } + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + expToCBuffer(buf, hgs, e1, precedence[op]); + buf.writeByte(' '); + buf.writestring(Token.toChars(op)); + buf.writeByte(' '); + expToCBuffer(buf, hgs, e2, cast(PREC)(precedence[op] + 1)); + } + + /**************************************** + * Scale addition/subtraction to/from pointer. + */ + Expression scaleFactor(Scope sc) + { + ulong stride; + Type t1b = e1.type.toBasetype(); + Type t2b = e2.type.toBasetype(); + + if (t1b.ty == Tpointer && t2b.isintegral()) + { + // Need to adjust operator by the stride + // Replace (ptr + int) with (ptr + (int * stride)) + Type t = Type.tptrdiff_t; + + stride = t1b.nextOf().size(loc); + if (!t.equals(t2b)) + e2 = e2.castTo(sc, t); + e2 = new MulExp(loc, e2, new IntegerExp(Loc(0), stride, t)); + e2.type = t; + type = e1.type; + } + else if (t2b.ty == Tpointer && t1b.isintegral()) + { + // Need to adjust operator by the stride + // Replace (int + ptr) with (ptr + (int * stride)) + Type t = Type.tptrdiff_t; + Expression e; + + stride = t2b.nextOf().size(loc); + if (!t.equals(t1b)) + e = e1.castTo(sc, t); + else + e = e1; + e = new MulExp(loc, e, new IntegerExp(Loc(0), stride, t)); + e.type = t; + type = e2.type; + e1 = e2; + e2 = e; + } + return this; + } + + /************************************ + * Bring leaves to common type. + */ + Expression typeCombine(Scope sc) + { + Type t1 = e1.type.toBasetype(); + Type t2 = e2.type.toBasetype(); + + if (op == TOK.TOKmin || op == TOK.TOKadd) + { + if (t1.ty == TY.Tstruct) + { + if (t2.ty == TY.Tstruct && (cast(TypeStruct)t1).sym is (cast(TypeStruct)t2).sym) + goto Lerror; + } + else if (t1.ty == TY.Tclass) + { + if (t2.ty == TY.Tclass) + goto Lerror; + } + } + + if (!typeMerge(sc, this, &type, &e1, &e2)) + goto Lerror; + return this; + + Lerror: + incompatibleTypes(); + type = Type.terror; + e1 = new ErrorExp(); + e2 = new ErrorExp(); + return this; + } + + Expression optimize(int result) + { + //printf("BinExp.optimize(result = %d) %s\n", result, toChars()); + if (op != TOK.TOKconstruct && op != TOK.TOKblit) // don't replace const variable with its initializer + e1 = e1.optimize(result); + + e2 = e2.optimize(result); + if (op == TOK.TOKshlass || op == TOK.TOKshrass || op == TOK.TOKushrass) + { + if (e2.isConst() == 1) + { + long i2 = e2.toInteger(); + ulong sz = e1.type.size() * 8; + + if (i2 < 0 || i2 > sz) + { + error("shift assign by %jd is outside the range 0..%zu", i2, sz); + e2 = new IntegerExp(0); + } + } + } + + return this; + } + + bool isunsigned() + { + assert(false); + } + + void incompatibleTypes() + { + error("incompatible types for ((%s) %s (%s)): '%s' and '%s'", + e1.toChars(), Token.toChars(op), e2.toChars(), + e1.type.toChars(), e2.type.toChars()); + } + + void dump(int indent) + { + assert(false); + } + + void scanForNestedRef(Scope *sc) + { + assert(false); + } + + Expression interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *, Expression *)) + { + assert(false); + } + + Expression interpretCommon2(InterState *istate, Expression *(*fp)(TOK, Type *, Expression *, Expression *)) + { + assert(false); + } + + Expression interpretAssignCommon(InterState *istate, Expression *(*fp)(Type *, Expression *, Expression *), int post = 0) + { + assert(false); + } + + bool canThrow() + { + return e1.canThrow() || e2.canThrow(); + } + + Expression arrayOp(Scope sc) + { + assert(false); + } + + int inlineCost(InlineCostState* ics) + { + return 1 + e1.inlineCost(ics) + e2.inlineCost(ics); + } + + Expression doInline(InlineDoState ids) + { + BinExp be = cast(BinExp)copy(); + + be.e1 = e1.doInline(ids); + be.e2 = e2.doInline(ids); + return be; + } + + Expression inlineScan(InlineScanState* iss) + { + e1 = e1.inlineScan(iss); + e2 = e2.inlineScan(iss); + return this; + } + + Expression op_overload(Scope sc) + { + //printf("BinExp.op_overload() (%s)\n", toChars()); + + AggregateDeclaration ad; + Type t1 = e1.type.toBasetype(); + Type t2 = e2.type.toBasetype(); + Identifier id = opId(); + Identifier id_r = opId_r(); + + Match m; + scope Expressions args1 = new Expressions(); + scope Expressions args2 = new Expressions(); + int argsset = 0; + + AggregateDeclaration ad1; + if (t1.ty == TY.Tclass) + ad1 = (cast(TypeClass)t1).sym; + else if (t1.ty == TY.Tstruct) + ad1 = (cast(TypeStruct)t1).sym; + else + ad1 = null; + + AggregateDeclaration ad2; + if (t2.ty == TY.Tclass) + ad2 = (cast(TypeClass)t2).sym; + else if (t2.ty == TY.Tstruct) + ad2 = (cast(TypeStruct)t2).sym; + else + ad2 = null; + + Dsymbol s = null; + Dsymbol s_r = null; + FuncDeclaration fd = null; + TemplateDeclaration td = null; + if (ad1 && id) + { + s = search_function(ad1, id); + } + if (ad2 && id_r) + { + s_r = search_function(ad2, id_r); + } + + if (s || s_r) + { + /* Try: + * a.opfunc(b) + * b.opfunc_r(a) + * and see which is better. + */ + Expression e; + FuncDeclaration lastf; + + args1.setDim(1); + args1.data[0] = cast(void*) e1; + args2.setDim(1); + args2.data[0] = cast(void*) e2; + argsset = 1; + + ///memset(&m, 0, sizeof(m)); + m.last = MATCH.MATCHnomatch; + + if (s) + { + fd = s.isFuncDeclaration(); + if (fd) + { + overloadResolveX(&m, fd, null, args2); + } + else + { + td = s.isTemplateDeclaration(); + templateResolve(&m, td, sc, loc, null, null, args2); + } + } + + lastf = m.lastf; + + if (s_r) + { + fd = s_r.isFuncDeclaration(); + if (fd) + { + overloadResolveX(&m, fd, null, args1); + } + else + { + td = s_r.isTemplateDeclaration(); + templateResolve(&m, td, sc, loc, null, null, args1); + } + } + + if (m.count > 1) + { + // Error, ambiguous + error("overloads %s and %s both match argument list for %s", + m.lastf.type.toChars(), + m.nextf.type.toChars(), + m.lastf.toChars()); + } + else if (m.last == MATCH.MATCHnomatch) + { + m.lastf = m.anyf; + } + + if (op == TOK.TOKplusplus || op == TOK.TOKminusminus) + // Kludge because operator overloading regards e++ and e-- + // as unary, but it's implemented as a binary. + // Rewrite (e1 ++ e2) as e1.postinc() + // Rewrite (e1 -- e2) as e1.postdec() + e = build_overload(loc, sc, e1, null, id); + else if (lastf && m.lastf == lastf || m.last == MATCH.MATCHnomatch) + // Rewrite (e1 op e2) as e1.opfunc(e2) + e = build_overload(loc, sc, e1, e2, id); + else + // Rewrite (e1 op e2) as e2.opfunc_r(e1) + e = build_overload(loc, sc, e2, e1, id_r); + return e; + } + + if (isCommutative()) + { + s = null; + s_r = null; + if (ad1 && id_r) + { + s_r = search_function(ad1, id_r); + } + if (ad2 && id) + { + s = search_function(ad2, id); + } + + if (s || s_r) + { + /* Try: + * a.opfunc_r(b) + * b.opfunc(a) + * and see which is better. + */ + + if (!argsset) + { + args1.setDim(1); + args1.data[0] = cast(void*) e1; + args2.setDim(1); + args2.data[0] = cast(void*) e2; + } + + ///memset(&m, 0, sizeof(m)); + m.last = MATCH.MATCHnomatch; + + if (s_r) + { + fd = s_r.isFuncDeclaration(); + if (fd) + { + overloadResolveX(&m, fd, null, args2); + } + else + { td = s_r.isTemplateDeclaration(); + templateResolve(&m, td, sc, loc, null, null, args2); + } + } + FuncDeclaration lastf = m.lastf; + + if (s) + { + fd = s.isFuncDeclaration(); + if (fd) + { + overloadResolveX(&m, fd, null, args1); + } + else + { td = s.isTemplateDeclaration(); + templateResolve(&m, td, sc, loc, null, null, args1); + } + } + + if (m.count > 1) + { + // Error, ambiguous + error("overloads %s and %s both match argument list for %s", + m.lastf.type.toChars(), + m.nextf.type.toChars(), + m.lastf.toChars()); + } + else if (m.last == MATCH.MATCHnomatch) + { + m.lastf = m.anyf; + } + + Expression e; + if (lastf && m.lastf == lastf || id_r && m.last == MATCH.MATCHnomatch) + // Rewrite (e1 op e2) as e1.opfunc_r(e2) + e = build_overload(loc, sc, e1, e2, id_r); + else + // Rewrite (e1 op e2) as e2.opfunc(e1) + e = build_overload(loc, sc, e2, e1, id); + + // When reversing operands of comparison operators, + // need to reverse the sense of the op + switch (op) + { + case TOK.TOKlt: op = TOK.TOKgt; break; + case TOK.TOKgt: op = TOK.TOKlt; break; + case TOK.TOKle: op = TOK.TOKge; break; + case TOK.TOKge: op = TOK.TOKle; break; + + // Floating point compares + case TOK.TOKule: op = TOK.TOKuge; break; + case TOK.TOKul: op = TOK.TOKug; break; + case TOK.TOKuge: op = TOK.TOKule; break; + case TOK.TOKug: op = TOK.TOKul; break; + + // These are symmetric + case TOK.TOKunord: + case TOK.TOKlg: + case TOK.TOKleg: + case TOK.TOKue: + break; + } + + return e; + } + } + +version (DMDV2) { + // Try alias this on first operand + if (ad1 && ad1.aliasthis) + { + /* Rewrite (e1 op e2) as: + * (e1.aliasthis op e2) + */ + Expression e1 = new DotIdExp(loc, this.e1, ad1.aliasthis.ident); + Expression e = copy(); + (cast(BinExp)e).e1 = e1; + e = e.semantic(sc); + return e; + } + + // Try alias this on second operand + if (ad2 && ad2.aliasthis) + { + /* Rewrite (e1 op e2) as: + * (e1 op e2.aliasthis) + */ + Expression e2 = new DotIdExp(loc, this.e2, ad2.aliasthis.ident); + Expression e = copy(); + (cast(BinExp)e).e2 = e2; + e = e.semantic(sc); + return e; + } +} + return null; + } + + elem* toElemBin(IRState* irs, int op) + { + //printf("toElemBin() '%s'\n", toChars()); + + tym_t tym = type.totym(); + + elem* el = e1.toElem(irs); + elem* er = e2.toElem(irs); + elem* e = el_bin(op,tym,el,er); + el_setLoc(e,loc); + + return e; + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/BoolExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/BoolExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,54 @@ +module dmd.BoolExp; + +import dmd.Expression; +import dmd.backend.elem; +import dmd.UnaExp; +import dmd.InterState; +import dmd.Type; +import dmd.Loc; +import dmd.Scope; +import dmd.IRState; +import dmd.TOK; + +import dmd.backend.OPER; +import dmd.backend.Util; + +class BoolExp : UnaExp +{ + this(Loc loc, Expression e, Type t) + { + super(loc, TOK.init, 0, e); + type = t; + } + + Expression semantic(Scope sc) + { + UnaExp.semantic(sc); + e1 = resolveProperties(sc, e1); + e1 = e1.checkToBoolean(); + type = Type.tboolean; + return this; + } + + Expression optimize(int result) + { + assert(false); + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + int isBit() + { + return true; + } + + elem* toElem(IRState* irs) + { + elem* e1 = this.e1.toElem(irs); + return el_una(OPbool,type.totym(),e1); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/BreakStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/BreakStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,138 @@ +module dmd.BreakStatement; + +import dmd.Statement; +import dmd.Loc; +import dmd.Identifier; +import dmd.Scope; +import dmd.Expression; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.IRState; +import dmd.BE; +import dmd.FuncDeclaration; +import dmd.LabelStatement; +import dmd.ReturnStatement; +import dmd.IntegerExp; + +import dmd.backend.Util; +import dmd.backend.block; +import dmd.backend.Blockx; +import dmd.backend.BC; + +class BreakStatement : Statement +{ + Identifier ident; + + this(Loc loc, Identifier ident) + { + super(loc); + this.ident = ident; + } + + Statement syntaxCopy() + { + assert(false); + } + + Statement semantic(Scope sc) + { + //printf("BreakStatement::semantic()\n"); + // If: + // break Identifier; + if (ident) + { + Scope scx; + FuncDeclaration thisfunc = sc.func; + + for (scx = sc; scx; scx = scx.enclosing) + { + LabelStatement ls; + + if (scx.func != thisfunc) // if in enclosing function + { + if (sc.fes) // if this is the body of a foreach + { + /* Post this statement to the fes, and replace + * it with a return value that caller will put into + * a switch. Caller will figure out where the break + * label actually is. + * Case numbers start with 2, not 0, as 0 is continue + * and 1 is break. + */ + Statement s; + sc.fes.cases.push(cast(void*)this); + s = new ReturnStatement(Loc(0), new IntegerExp(sc.fes.cases.dim + 1)); + return s; + } + break; // can't break to it + } + + ls = scx.slabel; + if (ls && ls.ident == ident) + { + Statement s = ls.statement; + + if (!s.hasBreak()) + error("label '%s' has no break", ident.toChars()); + if (ls.tf != sc.tf) + error("cannot break out of finally block"); + return this; + } + } + error("enclosing label '%s' for break not found", ident.toChars()); + } + else if (!sc.sbreak) + { + if (sc.fes) + { + Statement s; + + // Replace break; with return 1; + s = new ReturnStatement(Loc(0), new IntegerExp(1)); + return s; + } + error("break is not inside a loop or switch"); + } + return this; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + BE blockExit() + { + //printf("BreakStatement::blockExit(%p) = x%x\n", this, ident ? BEgoto : BEbreak); + return ident ? BE.BEgoto : BE.BEbreak; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + void toIR(IRState* irs) + { + block* bbreak; + block* b; + Blockx* blx = irs.blx; + + bbreak = irs.getBreakBlock(ident); + assert(bbreak); + b = blx.curblock; + incUsage(irs, loc); + + // Adjust exception handler scope index if in different try blocks + if (b.Btry != bbreak.Btry) + { + //setScopeIndex(blx, b, bbreak.Btry ? bbreak.Btry.Bscope_index : -1); + } + + /* Nothing more than a 'goto' to the current break destination + */ + list_append(&b.Bsucc, bbreak); + block_next(blx, BCgoto, null); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/CSX.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/CSX.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,15 @@ +module dmd.CSX; + +enum CSX +{ + CSXthis_ctor = 1, // called this() + CSXsuper_ctor = 2, // called super() + CSXthis = 4, // referenced this + CSXsuper = 8, // referenced super + CSXlabel = 0x10, // seen a label + CSXreturn = 0x20, // seen a return statement + CSXany_ctor = 0x40, // either this() or super() was called +} + +import dmd.EnumUtils; +mixin(BringToCurrentScope!(CSX)); \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/CallExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/CallExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,1056 @@ +module dmd.CallExp; + +import dmd.Expression; +import dmd.WANT; +import dmd.BUILTIN; +import dmd.TypeFunction; +import dmd.ScopeDsymbol; +import dmd.CastExp; +import dmd.GlobalExpressions; +import dmd.TypePointer; +import dmd.ThisExp; +import dmd.OverExp; +import dmd.Dsymbol; +import dmd.CSX; +import dmd.AggregateDeclaration; +import dmd.TypeDelegate; +import dmd.ClassDeclaration; +import dmd.DsymbolExp; +import dmd.DotExp; +import dmd.TemplateExp; +import dmd.TypeStruct; +import dmd.TypeClass; +import dmd.Identifier; +import dmd.Lexer; +import dmd.VarDeclaration; +import dmd.DeclarationExp; +import dmd.CtorDeclaration; +import dmd.PtrExp; +import dmd.TemplateDeclaration; +import dmd.StructLiteralExp; +import dmd.StructDeclaration; +import dmd.DotTemplateExp; +import dmd.CommaExp; +import dmd.AggregateDeclaration; +import dmd.FuncDeclaration; +import dmd.Type; +import dmd.ScopeExp; +import dmd.VarExp; +import dmd.STC; +import dmd.LINK; +import dmd.Global; +import dmd.DotTemplateInstanceExp; +import dmd.TemplateInstance; +import dmd.DelegateExp; +import dmd.IdentifierExp; +import dmd.DotVarExp; +import dmd.DotIdExp; +import dmd.TY; +import dmd.Id; +import dmd.TypeAArray; +import dmd.RemoveExp; +import dmd.backend.elem; +import dmd.UnaExp; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.InlineCostState; +import dmd.IRState; +import dmd.InlineDoState; +import dmd.HdrGenState; +import dmd.InlineScanState; +import dmd.ArrayTypes; +import dmd.TOK; +import dmd.PREC; +import dmd.expression.Util; +import dmd.backend.Symbol; +import dmd.backend.TYPE; +import dmd.backend.Util; +import dmd.backend.TYM; +import dmd.codegen.Util; + +class CallExp : UnaExp +{ + Expressions arguments; + + this(Loc loc, Expression e, Expressions exps) + { + super(loc, TOK.TOKcall, CallExp.sizeof, e); + this.arguments = exps; + } + + this(Loc loc, Expression e) + { + super(loc, TOK.TOKcall, CallExp.sizeof, e); + } + + this(Loc loc, Expression e, Expression earg1) + { + super(loc, TOK.TOKcall, CallExp.sizeof, e); + + Expressions arguments = new Expressions(); + arguments.setDim(1); + arguments.data[0] = cast(void*)earg1; + + this.arguments = arguments; + } + + this(Loc loc, Expression e, Expression earg1, Expression earg2) + { + assert(false); + super(loc, TOK.init, 0, e); + } + + Expression syntaxCopy() + { + return new CallExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments)); + } + + Expression semantic(Scope sc) + { + TypeFunction tf; + FuncDeclaration f; + int i; + Type t1; + int istemp; + Objects targsi; // initial list of template arguments + TemplateInstance tierror; + +version (LOGSEMANTIC) { + printf("CallExp.semantic() %s\n", toChars()); +} + if (type) + return this; // semantic() already run + +static if (false) { + if (arguments && arguments.dim) + { + Expression earg = cast(Expression)arguments.data[0]; + earg.print(); + if (earg.type) earg.type.print(); + } +} + + if (e1.op == TOK.TOKdelegate) + { + DelegateExp de = cast(DelegateExp)e1; + + e1 = new DotVarExp(de.loc, de.e1, de.func); + return semantic(sc); + } + + /* Transform: + * array.id(args) into .id(array,args) + * aa.remove(arg) into delete aa[arg] + */ + if (e1.op == TOK.TOKdot) + { + // BUG: we should handle array.a.b.c.e(args) too + + DotIdExp dotid = cast(DotIdExp)(e1); + dotid.e1 = dotid.e1.semantic(sc); + assert(dotid.e1); + if (dotid.e1.type) + { + TY e1ty = dotid.e1.type.toBasetype().ty; + if (e1ty == TY.Taarray && dotid.ident == Id.remove) + { + if (!arguments || arguments.dim != 1) + { + error("expected key as argument to aa.remove()"); + goto Lagain; + } + Expression key = cast(Expression)arguments.data[0]; + key = key.semantic(sc); + key = resolveProperties(sc, key); + key.rvalue(); + + TypeAArray taa = cast(TypeAArray)dotid.e1.type.toBasetype(); + key = key.implicitCastTo(sc, taa.index); + + return new RemoveExp(loc, dotid.e1, key); + } + else if (e1ty == TY.Tarray || e1ty == TY.Tsarray || e1ty == TY.Taarray) + { + if (!arguments) + arguments = new Expressions(); + arguments.shift(cast(void*)dotid.e1); +version (DMDV2) { + e1 = new DotIdExp(dotid.loc, new IdentifierExp(dotid.loc, Id.empty), dotid.ident); +} else { + e1 = new IdentifierExp(dotid.loc, dotid.ident); +} + } + } + } + +static if (true) { + /* This recognizes: + * foo!(tiargs)(funcargs) + */ + if (e1.op == TOK.TOKimport && !e1.type) + { + ScopeExp se = cast(ScopeExp)e1; + TemplateInstance ti = se.sds.isTemplateInstance(); + if (ti && !ti.semanticRun) + { + /* Attempt to instantiate ti. If that works, go with it. + * If not, go with partial explicit specialization. + */ + ti.semanticTiargs(sc); + uint errors = global.errors; + global.gag++; + ti.semantic(sc); + global.gag--; + if (errors != global.errors) + { + /* Didn't work, go with partial explicit specialization + */ + global.errors = errors; + targsi = ti.tiargs; + tierror = ti; // for error reporting + e1 = new IdentifierExp(loc, ti.name); + } + } + } + + /* This recognizes: + * expr.foo!(tiargs)(funcargs) + */ + if (e1.op == TOK.TOKdotti && !e1.type) + { + DotTemplateInstanceExp se = cast(DotTemplateInstanceExp)e1; + TemplateInstance ti = se.ti; + if (!ti.semanticRun) + { + /* Attempt to instantiate ti. If that works, go with it. + * If not, go with partial explicit specialization. + */ + ti.semanticTiargs(sc); + Expression etmp = e1.trySemantic(sc); + if (etmp) + e1 = etmp; // it worked + else // didn't work + { + targsi = ti.tiargs; + tierror = ti; // for error reporting + e1 = new DotIdExp(loc, se.e1, ti.name); + } + } + } +} + + istemp = 0; + Lagain: + //printf("Lagain: %s\n", toChars()); + f = null; + if (e1.op == TOK.TOKthis || e1.op == TOK.TOKsuper) + { + // semantic() run later for these + } + else + { + UnaExp.semantic(sc); + + /* Look for e1 being a lazy parameter + */ + if (e1.op == TOK.TOKvar) + { + VarExp ve = cast(VarExp)e1; + + if (ve.var.storage_class & STC.STClazy) + { + TypeFunction tff = new TypeFunction(null, ve.var.type, 0, LINK.LINKd); + TypeDelegate t = new TypeDelegate(tff); + ve.type = t.semantic(loc, sc); + } + } + + if (e1.op == TOK.TOKimport) + { + // Perhaps this should be moved to ScopeExp.semantic() + ScopeExp se = cast(ScopeExp)e1; + e1 = new DsymbolExp(loc, se.sds); + e1 = e1.semantic(sc); + } +///static if (true) { // patch for #540 by Oskar Linde + else if (e1.op == TOK.TOKdotexp) + { + DotExp de = cast(DotExp)e1; + + if (de.e2.op == TOK.TOKimport) + { + // This should *really* be moved to ScopeExp.semantic() + ScopeExp se = cast(ScopeExp)de.e2; + de.e2 = new DsymbolExp(loc, se.sds); + de.e2 = de.e2.semantic(sc); + } + + if (de.e2.op == TOK.TOKtemplate) + { + TemplateExp te = cast(TemplateExp)de.e2; + e1 = new DotTemplateExp(loc,de.e1,te.td); + } + } +///} + } + + if (e1.op == TOK.TOKcomma) + { + CommaExp ce = cast(CommaExp)e1; + + e1 = ce.e2; + e1.type = ce.type; + ce.e2 = this; + ce.type = null; + return ce.semantic(sc); + } + + t1 = null; + if (e1.type) + t1 = e1.type.toBasetype(); + + // Check for call operator overload + if (t1) + { + AggregateDeclaration ad; + + if (t1.ty == TY.Tstruct) + { + ad = (cast(TypeStruct)t1).sym; +version (DMDV2) { + // First look for constructor + if (ad.ctor && arguments && arguments.dim) + { + // Create variable that will get constructed + Identifier idtmp = Lexer.uniqueId("__ctmp"); + VarDeclaration tmp = new VarDeclaration(loc, t1, idtmp, null); + Expression av = new DeclarationExp(loc, tmp); + av = new CommaExp(loc, av, new VarExp(loc, tmp)); + + Expression e; + CtorDeclaration cf = ad.ctor.isCtorDeclaration(); + if (cf) + e = new DotVarExp(loc, av, cf, 1); + else + { + TemplateDeclaration td = ad.ctor.isTemplateDeclaration(); + assert(td); + e = new DotTemplateExp(loc, av, td); + } + e = new CallExp(loc, e, arguments); + version (STRUCTTHISREF) { + } else { + /* Constructors return a pointer to the instance + */ + e = new PtrExp(loc, e); + } + e = e.semantic(sc); + return e; + } +} + // No constructor, look for overload of opCall + if (search_function(ad, Id.call)) + goto L1; // overload of opCall, therefore it's a call + + if (e1.op != TOK.TOKtype) + error("%s %s does not overload ()", ad.kind(), ad.toChars()); + + /* It's a struct literal + */ + Expression e = new StructLiteralExp(loc, cast(StructDeclaration)ad, arguments); + e = e.semantic(sc); + e.type = e1.type; // in case e1.type was a typedef + return e; + } + else if (t1.ty == TY.Tclass) + { + ad = (cast(TypeClass)t1).sym; + goto L1; + L1: + // Rewrite as e1.call(arguments) + Expression e = new DotIdExp(loc, e1, Id.call); + e = new CallExp(loc, e, arguments); + e = e.semantic(sc); + return e; + } + } + + arrayExpressionSemantic(arguments, sc); + preFunctionArguments(loc, sc, arguments); + + if (e1.op == TOK.TOKdotvar && t1.ty == TY.Tfunction || + e1.op == TOK.TOKdottd) + { + DotVarExp dve; + DotTemplateExp dte; + AggregateDeclaration ad; + UnaExp ue = cast(UnaExp)e1; + + if (e1.op == TOK.TOKdotvar) + { + // Do overload resolution + dve = cast(DotVarExp)e1; + + f = dve.var.isFuncDeclaration(); + assert(f); + f = f.overloadResolve(loc, ue.e1, arguments); + + ad = f.toParent().isAggregateDeclaration(); + } + else + { + dte = cast(DotTemplateExp)e1; + TemplateDeclaration td = dte.td; + assert(td); + + if (!arguments) + // Should fix deduceFunctionTemplate() so it works on null argument + arguments = new Expressions(); + + f = td.deduceFunctionTemplate(sc, loc, targsi, ue.e1, arguments); + if (!f) + { + type = Type.terror; + return this; + } + ad = td.toParent().isAggregateDeclaration(); + } + + if (f.needThis()) + { + ue.e1 = getRightThis(loc, sc, ad, ue.e1, f); + } + + /* Cannot call public functions from inside invariant + * (because then the invariant would have infinite recursion) + */ + if (sc.func && sc.func.isInvariantDeclaration() && + ue.e1.op == TOK.TOKthis && f.addPostInvariant()) + { + error("cannot call public/export function %s from invariant", f.toChars()); + } + + checkDeprecated(sc, f); + version (DMDV2) { + checkPurity(sc, f); + } + accessCheck(loc, sc, ue.e1, f); + if (!f.needThis()) + { + VarExp ve = new VarExp(loc, f); + e1 = new CommaExp(loc, ue.e1, ve); + e1.type = f.type; + } + else + { + if (e1.op == TOK.TOKdotvar) + dve.var = f; + else + e1 = new DotVarExp(loc, dte.e1, f); + + e1.type = f.type; +static if (false) { + printf("ue.e1 = %s\n", ue.e1.toChars()); + printf("f = %s\n", f.toChars()); + printf("t = %s\n", t.toChars()); + printf("e1 = %s\n", e1.toChars()); + printf("e1.type = %s\n", e1.type.toChars()); +} + // Const member function can take const/immutable/mutable this + if (!(f.type.isConst())) + { + // Check for const/immutable compatibility + Type tthis = ue.e1.type.toBasetype(); + if (tthis.ty == TY.Tpointer) + tthis = tthis.nextOf().toBasetype(); + + static if (false) { // this checking should have been already done + if (f.type.isInvariant()) + { + if (tthis.mod != MOD.MODinvariant) + error("%s can only be called with an immutable object", e1.toChars()); + } + else if (f.type.isShared()) + { + if (tthis.mod != MOD.MODinvariant && tthis.mod != MOD.MODshared && tthis.mod != (MOD.MODshared | MOD.MODconst)) + error("shared %s can only be called with a shared or immutable object", e1.toChars()); + } + else + { + if (tthis.mod != MOD.MODundefined) + { + //printf("mod = %x\n", tthis.mod); + error("%s can only be called with a mutable object, not %s", e1.toChars(), tthis.toChars()); + } + } + } + /* Cannot call mutable method on a final struct + */ + if (tthis.ty == TY.Tstruct && + ue.e1.op == TOK.TOKvar) + { + VarExp v = cast(VarExp)ue.e1; + if (v.var.storage_class & STC.STCfinal) + error("cannot call mutable method on final struct"); + } + } + + // See if we need to adjust the 'this' pointer + AggregateDeclaration add = f.isThis(); + ClassDeclaration cd = ue.e1.type.isClassHandle(); + if (add && cd && add.isClassDeclaration() && add != cd && ue.e1.op != TOK.TOKsuper) + { + ue.e1 = ue.e1.castTo(sc, add.type); //new CastExp(loc, ue.e1, add.type); + ue.e1 = ue.e1.semantic(sc); + } + } + t1 = e1.type; + } + else if (e1.op == TOK.TOKsuper) + { + // Base class constructor call + ClassDeclaration cd = null; + + if (sc.func) + cd = sc.func.toParent().isClassDeclaration(); + if (!cd || !cd.baseClass || !sc.func.isCtorDeclaration()) + { + error("super class constructor call must be in a constructor"); + type = Type.terror; + return this; + } + else + { + if (!cd.baseClass.ctor) + { + error("no super class constructor for %s", cd.baseClass.toChars()); + type = Type.terror; + return this; + } + else + { + if (!sc.intypeof) + { +static if (false) { + if (sc.callSuper & (CSX.CSXthis | CSX.CSXsuper)) + error("reference to this before super()"); +} + if (sc.noctor || sc.callSuper & CSX.CSXlabel) + error("constructor calls not allowed in loops or after labels"); + if (sc.callSuper & (CSX.CSXsuper_ctor | CSX.CSXthis_ctor)) + error("multiple constructor calls"); + sc.callSuper |= CSX.CSXany_ctor | CSX.CSXsuper_ctor; + } + + f = resolveFuncCall(sc, loc, cd.baseClass.ctor, null, null, arguments, 0); + checkDeprecated(sc, f); +version (DMDV2) { + checkPurity(sc, f); +} + e1 = new DotVarExp(e1.loc, e1, f); + e1 = e1.semantic(sc); + t1 = e1.type; + } + } + } + else if (e1.op == TOK.TOKthis) + { + // same class constructor call + AggregateDeclaration cd = null; + + if (sc.func) + cd = sc.func.toParent().isAggregateDeclaration(); + if (!cd || !sc.func.isCtorDeclaration()) + { + error("constructor call must be in a constructor"); + type = Type.terror; + return this; + } + else + { + if (!sc.intypeof) + { +static if (false) { + if (sc.callSuper & (CSXthis | CSXsuper)) + error("reference to this before super()"); +} + if (sc.noctor || sc.callSuper & CSX.CSXlabel) + error("constructor calls not allowed in loops or after labels"); + if (sc.callSuper & (CSX.CSXsuper_ctor | CSX.CSXthis_ctor)) + error("multiple constructor calls"); + sc.callSuper |= CSX.CSXany_ctor | CSX.CSXthis_ctor; + } + + f = resolveFuncCall(sc, loc, cd.ctor, null, null, arguments, 0); + checkDeprecated(sc, f); +version (DMDV2) { + checkPurity(sc, f); +} + e1 = new DotVarExp(e1.loc, e1, f); + e1 = e1.semantic(sc); + t1 = e1.type; + + // BUG: this should really be done by checking the static + // call graph + if (f == sc.func) + error("cyclic constructor call"); + } + } + else if (e1.op == TOK.TOKoverloadset) + { + OverExp eo = cast(OverExp)e1; + FuncDeclaration ff = null; + for (int j = 0; j < eo.vars.a.dim; j++) + { + Dsymbol s = cast(Dsymbol)eo.vars.a.data[j]; + FuncDeclaration f2 = s.isFuncDeclaration(); + if (f2) + { + f2 = f2.overloadResolve(loc, null, arguments, 1); + } + else + { + TemplateDeclaration td = s.isTemplateDeclaration(); + assert(td); + f2 = td.deduceFunctionTemplate(sc, loc, targsi, null, arguments, 1); + } + if (f2) + { + if (ff) + /* Error if match in more than one overload set, + * even if one is a 'better' match than the other. + */ + ScopeDsymbol.multiplyDefined(loc, ff, f2); + else + ff = f2; + } + } + if (!ff) + { + /* No overload matches, just set ff and rely on error + * message being generated later. + */ + ff = cast(FuncDeclaration)eo.vars.a.data[0]; + } + e1 = new VarExp(loc, ff); + goto Lagain; + } + else if (!t1) + { + error("function expected before (), not '%s'", e1.toChars()); + type = Type.terror; + return this; + } + else if (t1.ty != TY.Tfunction) + { + if (t1.ty == TY.Tdelegate) + { + TypeDelegate td = cast(TypeDelegate)t1; + assert(td.next.ty == TY.Tfunction); + tf = cast(TypeFunction)(td.next); + if (sc.func && sc.func.isPure() && !tf.ispure) + { + error("pure function '%s' cannot call impure delegate '%s'", sc.func.toChars(), e1.toChars()); + } + goto Lcheckargs; + } + else if (t1.ty == TY.Tpointer && (cast(TypePointer)t1).next.ty == TY.Tfunction) + { + Expression e = new PtrExp(loc, e1); + t1 = (cast(TypePointer)t1).next; + if (sc.func && sc.func.isPure() && !(cast(TypeFunction)t1).ispure) + { + error("pure function '%s' cannot call impure function pointer '%s'", sc.func.toChars(), e1.toChars()); + } + e.type = t1; + e1 = e; + } + else if (e1.op == TOK.TOKtemplate) + { + TemplateExp te = cast(TemplateExp)e1; + f = te.td.deduceFunctionTemplate(sc, loc, targsi, null, arguments); + if (!f) + { + if (tierror) + tierror.error("errors instantiating template"); // give better error message + type = Type.terror; + return this; + } + if (f.needThis() && hasThis(sc)) + { + // Supply an implicit 'this', as in + // this.ident + + e1 = new DotTemplateExp(loc, (new ThisExp(loc)).semantic(sc), te.td); + goto Lagain; + } + + e1 = new VarExp(loc, f); + goto Lagain; + } + else + { + error("function expected before (), not %s of type %s", e1.toChars(), e1.type.toChars()); + type = Type.terror; + return this; + } + } + else if (e1.op == TOK.TOKvar) + { + // Do overload resolution + VarExp ve = cast(VarExp)e1; + + f = ve.var.isFuncDeclaration(); + assert(f); + + if (ve.hasOverloads) + f = f.overloadResolve(loc, null, arguments); + + checkDeprecated(sc, f); +version (DMDV2) { + checkPurity(sc, f); +} + + if (f.needThis() && hasThis(sc)) + { + // Supply an implicit 'this', as in + // this.ident + + e1 = new DotVarExp(loc, new ThisExp(loc), f); + goto Lagain; + } + + accessCheck(loc, sc, null, f); + + ve.var = f; + // ve.hasOverloads = 0; + ve.type = f.type; + t1 = f.type; + } + assert(t1.ty == TY.Tfunction); + tf = cast(TypeFunction)t1; + + Lcheckargs: + assert(tf.ty == TY.Tfunction); + type = tf.next; + + if (!arguments) + arguments = new Expressions(); + + functionArguments(loc, sc, tf, arguments); + + if (!type) + { + error("forward reference to inferred return type of function call %s", toChars()); + type = Type.terror; + } + + if (f && f.tintro) + { + Type t = type; + int offset = 0; + TypeFunction tff = cast(TypeFunction)f.tintro; + + if (tff.next.isBaseOf(t, &offset) && offset) + { + type = tff.next; + return castTo(sc, t); + } + } + + return this; + } + + Expression optimize(int result) + { + //printf("CallExp::optimize(result = %d) %s\n", result, toChars()); + Expression e = this; + + // Optimize parameters + if (arguments) + { + for (size_t i = 0; i < arguments.dim; i++) + { + Expression ee = cast(Expression)arguments.data[i]; + + ee = ee.optimize(WANT.WANTvalue); + arguments.data[i] = cast(void*)ee; + } + } + + e1 = e1.optimize(result); + if (e1.op == TOK.TOKvar) + { + FuncDeclaration fd = (cast(VarExp)e1).var.isFuncDeclaration(); + if (fd) + { + BUILTIN b = fd.isBuiltin(); + if (b) + { + e = eval_builtin(b, arguments); + if (!e) // failed + e = this; // evaluate at runtime + } + else if (result & WANT.WANTinterpret) + { + Expression eresult = fd.interpret(null, arguments); + if (eresult && eresult !is EXP_VOID_INTERPRET) + e = eresult; + else + error("cannot evaluate %s at compile time", toChars()); + } + } + } + + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + bool checkSideEffect(int flag) + { +version (DMDV2) { + if (flag != 2) + return true; + + if (e1.checkSideEffect(2)) + return true; + + /* If any of the arguments have side effects, this expression does + */ + for (size_t i = 0; i < arguments.dim; i++) + { + Expression e = cast(Expression)arguments.data[i]; + + if (e.checkSideEffect(2)) + return true; + } + + /* If calling a function or delegate that is typed as pure, + * then this expression has no side effects. + */ + Type t = e1.type.toBasetype(); + if (t.ty == TY.Tfunction && (cast(TypeFunction)t).ispure) + return false; + if (t.ty == TY.Tdelegate && (cast(TypeFunction)(cast(TypeDelegate)t).next).ispure) + return false; +} + return true; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + int i; + expToCBuffer(buf, hgs, e1, precedence[op]); + buf.writeByte('('); + argsToCBuffer(buf, arguments, hgs); + buf.writeByte(')'); + } + + void dump(int indent) + { + assert(false); + } + + elem* toElem(IRState* irs) + { + //printf("CallExp::toElem('%s')\n", toChars()); + assert(e1.type); + elem* ec; + int directcall; + FuncDeclaration fd; + Type t1 = e1.type.toBasetype(); + Type ectype = t1; + + elem* ehidden = irs.ehidden; + irs.ehidden = null; + + directcall = 0; + fd = null; + if (e1.op == TOK.TOKdotvar && t1.ty != TY.Tdelegate) + { + DotVarExp dve = cast(DotVarExp)e1; + + fd = dve.var.isFuncDeclaration(); + Expression ex = dve.e1; + while (1) + { + switch (ex.op) + { + case TOK.TOKsuper: // super.member() calls directly + case TOK.TOKdottype: // type.member() calls directly + directcall = 1; + break; + + case TOK.TOKcast: + ex = (cast(CastExp)ex).e1; + continue; + + default: + //ex.dump(0); + break; + } + break; + } + ec = dve.e1.toElem(irs); + ectype = dve.e1.type.toBasetype(); + } + else if (e1.op == TOK.TOKvar) + { + fd = (cast(VarExp)e1).var.isFuncDeclaration(); + + if (fd && fd.ident == Id.alloca && !fd.fbody && fd.linkage == LINK.LINKc && arguments && arguments.dim == 1) + { + Expression arg = cast(Expression)arguments.data[0]; + arg = arg.optimize(WANT.WANTvalue); + if (arg.isConst() && arg.type.isintegral()) + { + long sz = arg.toInteger(); + if (sz > 0 && sz < 0x40000) + { + // It's an alloca(sz) of a fixed amount. + // Replace with an array allocated on the stack + // of the same size: char[sz] tmp; + + Symbol* stmp; + .type* t; + + assert(!ehidden); + t = type_allocn(TYM.TYarray, tschar); + t.Tdim = cast(uint)sz; + stmp = symbol_genauto(t); + ec = el_ptr(stmp); + el_setLoc(ec,loc); + return ec; + } + } + } + + ec = e1.toElem(irs); + } + else + { + ec = e1.toElem(irs); + } + ec = callfunc(loc, irs, directcall, type, ec, ectype, fd, t1, ehidden, arguments); + el_setLoc(ec,loc); + return ec; + } + + void scanForNestedRef(Scope sc) + { + assert(false); + } + +version (DMDV2) { + int isLvalue() + { + // if (type.toBasetype().ty == Tstruct) + // return 1; + Type tb = e1.type.toBasetype(); + if (tb.ty == Tfunction && (cast(TypeFunction)tb).isref) + return 1; // function returns a reference + return 0; + } +} + Expression toLvalue(Scope sc, Expression e) + { + if (isLvalue()) + return this; + return Expression.toLvalue(sc, e); + } + +version (DMDV2) { + bool canThrow() + { + //printf("CallExp::canThrow() %s\n", toChars()); + if (e1.canThrow()) + return true; + + /* If any of the arguments can throw, then this expression can throw + */ + for (size_t i = 0; i < arguments.dim; i++) + { + Expression e = cast(Expression)arguments.data[i]; + + if (e && e.canThrow()) + return true; + } + + if (global.errors && !e1.type) + return false; // error recovery + + /* If calling a function or delegate that is typed as nothrow, + * then this expression cannot throw. + * Note that pure functions can throw. + */ + Type t = e1.type.toBasetype(); + if (t.ty == TY.Tfunction && (cast(TypeFunction)t).isnothrow) + return false; + if (t.ty == TY.Tdelegate && (cast(TypeFunction)(cast(TypeDelegate)t).next).isnothrow) + return false; + + return true; + } +} + int inlineCost(InlineCostState* ics) + { + return 1 + e1.inlineCost(ics) + arrayInlineCost(ics, arguments); + } + + Expression doInline(InlineDoState ids) + { + CallExp ce = cast(CallExp)copy(); + ce.e1 = e1.doInline(ids); + ce.arguments = arrayExpressiondoInline(arguments, ids); + return ce; + } + + Expression inlineScan(InlineScanState* iss) + { + Expression e = this; + + //printf("CallExp.inlineScan()\n"); + e1 = e1.inlineScan(iss); + arrayInlineScan(iss, arguments); + + if (e1.op == TOKvar) + { + VarExp ve = cast(VarExp)e1; + FuncDeclaration fd = ve.var.isFuncDeclaration(); + + if (fd && fd != iss.fd && fd.canInline(0)) + { + e = fd.doInline(iss, null, arguments); + } + } + else if (e1.op == TOKdotvar) + { + DotVarExp dve = cast(DotVarExp)e1; + FuncDeclaration fd = dve.var.isFuncDeclaration(); + + if (fd && fd != iss.fd && fd.canInline(1)) + { + if (dve.e1.op == TOKcall && + dve.e1.type.toBasetype().ty == Tstruct) + { + /* To create ethis, we'll need to take the address + * of dve.e1, but this won't work if dve.e1 is + * a function call. + */ + ; + } + else + e = fd.doInline(iss, dve.e1, arguments); + } + } + + return e; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/CaseRangeStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/CaseRangeStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,37 @@ +module dmd.CaseRangeStatement; + +import dmd.Statement; +import dmd.Expression; +import dmd.Statement; +import dmd.Loc; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Scope; + +class CaseRangeStatement : Statement +{ + Expression first; + Expression last; + Statement statement; + + this(Loc loc, Expression first, Expression last, Statement s) + { + assert(false); + super(loc); + } + + Statement syntaxCopy() + { + assert(false); + } + + Statement semantic(Scope sc) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/CaseStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/CaseStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,177 @@ +module dmd.CaseStatement; + +import dmd.Statement; +import dmd.Expression; +import dmd.Statement; +import dmd.Scope; +import dmd.Loc; +import dmd.IRState; +import dmd.InlineScanState; +import dmd.HdrGenState; +import dmd.OutBuffer; +import dmd.InterState; +import dmd.BE; +import dmd.SwitchStatement; +import dmd.WANT; +import dmd.TOK; +import dmd.VarExp; +import dmd.VarDeclaration; +import dmd.Type; +import dmd.TY; +import dmd.IntegerExp; +import dmd.GotoCaseStatement; + +import dmd.backend.block; +import dmd.backend.Blockx; +import dmd.backend.Util; +import dmd.backend.BC; + +class CaseStatement : Statement +{ + Expression exp; + Statement statement; + + int index = 0; // which case it is (since we sort this) + block* cblock = null; // back end: label for the block + + this(Loc loc, Expression exp, Statement s) + { + super(loc); + + this.exp = exp; + this.statement = s; + } + + Statement syntaxCopy() + { + assert(false); + } + + Statement semantic(Scope sc) + { + SwitchStatement sw = sc.sw; + + //printf("CaseStatement.semantic() %s\n", toChars()); + exp = exp.semantic(sc); + if (sw) + { + exp = exp.implicitCastTo(sc, sw.condition.type); + exp = exp.optimize(WANTvalue | WANTinterpret); + + /* This is where variables are allowed as case expressions. + */ + if (exp.op == TOKvar) + { VarExp ve = cast(VarExp)exp; + VarDeclaration v = ve.var.isVarDeclaration(); + Type t = exp.type.toBasetype(); + if (v && (t.isintegral() || t.ty == Tclass)) + { + /* Flag that we need to do special code generation + * for this, i.e. generate a sequence of if-then-else + */ + sw.hasVars = 1; + if (sw.isFinal) + error("case variables not allowed in final switch statements"); + goto L1; + } + } + + if (exp.op != TOKstring && exp.op != TOKint64) + { + error("case must be a string or an integral constant, not %s", exp.toChars()); + exp = new IntegerExp(0); + } + + L1: + for (int i = 0; i < sw.cases.dim; i++) + { + CaseStatement cs = cast(CaseStatement)sw.cases.data[i]; + + //printf("comparing '%s' with '%s'\n", exp.toChars(), cs.exp.toChars()); + if (cs.exp.equals(exp)) + { + error("duplicate case %s in switch statement", exp.toChars()); + break; + } + } + + sw.cases.push(cast(void*)this); + + // Resolve any goto case's with no exp to this case statement + for (int i = 0; i < sw.gotoCases.dim; i++) + { + GotoCaseStatement gcs = cast(GotoCaseStatement)sw.gotoCases.data[i]; + + if (!gcs.exp) + { + gcs.cs = this; + sw.gotoCases.remove(i); // remove from array + } + } + + if (sc.sw.tf !is sc.tf) + error("switch and case are in different finally blocks"); + } + else + error("case not in switch statement"); + statement = statement.semantic(sc); + return this; + } + + int compare(Object obj) + { + assert(false); + } + + bool usesEH() + { + assert(false); + } + + BE blockExit() + { + return statement.blockExit(); + } + + bool comeFrom() + { + return true; + } + + Expression interpret(InterState *istate) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + Statement inlineScan(InlineScanState* iss) + { + //printf("CaseStatement.inlineScan()\n"); + exp = exp.inlineScan(iss); + if (statement) + statement = statement.inlineScan(iss); + return this; + } + + void toIR(IRState *irs) + { + Blockx* blx = irs.blx; + block* bcase = blx.curblock; + if (!cblock) + cblock = block_calloc(blx); + block_next(blx,BCgoto,cblock); + block* bsw = irs.getSwitchBlock(); + if (bsw.BC == BCswitch) + list_append(&bsw.Bsucc,cblock); // second entry in pair + list_append(&bcase.Bsucc,cblock); + if (blx.tryblock != bsw.Btry) + error("case cannot be in different try block level from switch"); + incUsage(irs, loc); + if (statement) + statement.toIR(irs); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/Cast.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Cast.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,142 @@ +module dmd.Cast; + +import dmd.Expression; +import dmd.Type; +import dmd.Loc; +import dmd.MATCH; +import dmd.IntegerExp; +import dmd.RealExp; +import dmd.ComplexExp; +import dmd.StructDeclaration; +import dmd.ArrayTypes; +import dmd.Dsymbol; +import dmd.VarDeclaration; +import dmd.StructLiteralExp; +import dmd.Util; +import dmd.TY; +import dmd.TOK; +import dmd.GlobalExpressions; + +import dmd.Complex; + +Expression expType(Type type, Expression e) +{ + if (type !is e.type) + { + e = e.copy(); + e.type = type; + } + return e; +} + +/* Also returns EXP_CANT_INTERPRET if cannot be computed. + * to: type to cast to + * type: type to paint the result + */ + +Expression Cast(Type type, Type to, Expression e1) +{ + Expression e = EXP_CANT_INTERPRET; + Loc loc = e1.loc; + + //printf("Cast(type = %s, to = %s, e1 = %s)\n", type.toChars(), to.toChars(), e1.toChars()); + //printf("\te1.type = %s\n", e1.type.toChars()); + if (e1.type.equals(type) && type.equals(to)) + return e1; + if (e1.type.implicitConvTo(to) >= MATCH.MATCHconst || to.implicitConvTo(e1.type) >= MATCH.MATCHconst) + return expType(to, e1); + + Type tb = to.toBasetype(); + Type typeb = type.toBasetype(); + + /* Allow casting from one string type to another + */ + if (e1.op == TOK.TOKstring) + { + if (tb.ty == TY.Tarray && typeb.ty == TY.Tarray && + tb.nextOf().size() == typeb.nextOf().size()) + { + return expType(to, e1); + } + } + + if (e1.isConst() != 1) + return EXP_CANT_INTERPRET; + + if (tb.ty == TY.Tbool) + e = new IntegerExp(loc, e1.toInteger() != 0, type); + else if (type.isintegral()) + { + if (e1.type.isfloating()) + { + long result; + real r = e1.toReal(); + + switch (typeb.ty) + { + case TY.Tint8: result = cast(byte)r; break; + case TY.Tchar: + case TY.Tuns8: result = cast(ubyte)r; break; + case TY.Tint16: result = cast(short)r; break; + case TY.Twchar: + case TY.Tuns16: result = cast(ushort)r; break; + case TY.Tint32: result = cast(int)r; break; + case TY.Tdchar: + case TY.Tuns32: result = cast(uint)r; break; + case TY.Tint64: result = cast(long)r; break; + case TY.Tuns64: result = cast(ulong)r; break; + } + + e = new IntegerExp(loc, result, type); + } + else if (type.isunsigned()) + e = new IntegerExp(loc, e1.toUInteger(), type); + else + e = new IntegerExp(loc, e1.toInteger(), type); + } + else if (tb.isreal()) + { + real value = e1.toReal(); + e = new RealExp(loc, value, type); + } + else if (tb.isimaginary()) + { + real value = e1.toImaginary(); + e = new RealExp(loc, value, type); + } + else if (tb.iscomplex()) + { + Complex!(real) value = e1.toComplex(); + e = new ComplexExp(loc, value, type); + } + else if (tb.isscalar()) + e = new IntegerExp(loc, e1.toInteger(), type); + else if (tb.ty == TY.Tvoid) + e = EXP_CANT_INTERPRET; + else if (tb.ty == TY.Tstruct && e1.op == TOK.TOKint64) + { + // Struct = 0; + StructDeclaration sd = tb.toDsymbol(null).isStructDeclaration(); + assert(sd); + Expressions elements = new Expressions; + for (size_t i = 0; i < sd.fields.dim; i++) + { Dsymbol s = cast(Dsymbol)sd.fields.data[i]; + VarDeclaration v = s.isVarDeclaration(); + assert(v); + + Expression exp = new IntegerExp(0); + exp = Cast(v.type, v.type, exp); + if (exp == EXP_CANT_INTERPRET) + return exp; + elements.push(cast(void*)exp); + } + e = new StructLiteralExp(loc, sd, elements); + e.type = type; + } + else + { + error(loc, "cannot cast %s to %s", e1.type.toChars(), type.toChars()); + e = new IntegerExp(loc, 0, Type.tint32); + } + return e; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/CastExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/CastExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,1201 @@ +module dmd.CastExp; + +import dmd.Expression; +import dmd.TY; +import dmd.TypeStruct; +import dmd.TypeExp; +import dmd.DotIdExp; +import dmd.CallExp; +import dmd.Global; +import dmd.Id; +import dmd.Identifier; +import dmd.BinExp; +import dmd.backend.elem; +import dmd.UnaExp; +import dmd.VarExp; +import dmd.Token; +import dmd.VarDeclaration; +import dmd.InterState; +import dmd.MATCH; +import dmd.Type; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.IntRange; +import dmd.IRState; +import dmd.ArrayTypes; +import dmd.HdrGenState; +import dmd.MOD; +import dmd.TOK; +import dmd.WANT; +import dmd.ClassDeclaration; + +import dmd.Optimize; +import dmd.PREC; +import dmd.Cast; + +import dmd.backend.Util; +import dmd.expression.Util; +import dmd.backend.TYM; +import dmd.backend.OPER; +import dmd.codegen.Util; +import dmd.backend.RTLSYM; + +class CastExp : UnaExp +{ + // Possible to cast to one type while painting to another type + Type to; // type to cast to + MOD mod; // MODxxxxx + + this(Loc loc, Expression e, Type t) + { + super(loc, TOK.TOKcast, CastExp.sizeof, e); + to = t; + this.mod = cast(MOD)~0; + } + + this(Loc loc, Expression e, MOD mod) + { + super(loc, TOK.TOKcast, CastExp.sizeof, e); + to = null; + this.mod = mod; + } + + Expression syntaxCopy() + { + return to ? new CastExp(loc, e1.syntaxCopy(), to.syntaxCopy()) + : new CastExp(loc, e1.syntaxCopy(), mod); + } + + Expression semantic(Scope sc) + { + Expression e; + BinExp b; + UnaExp u; + +version (LOGSEMANTIC) { + printf("CastExp.semantic('%s')\n", toChars()); +} + + //static int x; assert(++x < 10); + + if (type) + return this; + super.semantic(sc); + if (e1.type) // if not a tuple + { + e1 = resolveProperties(sc, e1); + + if (!to) + { + /* Handle cast(const) and cast(immutable), etc. + */ + to = e1.type.castMod(mod); + } + else + to = to.semantic(loc, sc); + + if (!to.equals(e1.type)) + { + e = op_overload(sc); + if (e) + { + return e.implicitCastTo(sc, to); + } + } + + Type t1b = e1.type.toBasetype(); + Type tob = to.toBasetype(); + if (tob.ty == TY.Tstruct && + !tob.equals(t1b) && + (cast(TypeStruct)tob).sym.search(Loc(0), Id.call, 0) + ) + { + /* Look to replace: + * cast(S)t + * with: + * S(t) + */ + + // Rewrite as to.call(e1) + e = new TypeExp(loc, to); + e = new DotIdExp(loc, e, Id.call); + e = new CallExp(loc, e, e1); + e = e.semantic(sc); + return e; + } + } + else if (!to) + { error("cannot cast tuple"); + to = Type.terror; + } + + if (global.params.safe && !sc.module_.safe && !sc.intypeof) + { // Disallow unsafe casts + Type tob = to.toBasetype(); + Type t1b = e1.type.toBasetype(); + if (!t1b.isMutable() && tob.isMutable()) + { // Cast not mutable to mutable + Lunsafe: + error("cast from %s to %s not allowed in safe mode", e1.type.toChars(), to.toChars()); + } + else if (t1b.isShared() && !tob.isShared()) + // Cast away shared + goto Lunsafe; + else if (tob.ty == TY.Tpointer) + { if (t1b.ty != TY.Tpointer) + goto Lunsafe; + Type tobn = tob.nextOf().toBasetype(); + Type t1bn = t1b.nextOf().toBasetype(); + + if (!t1bn.isMutable() && tobn.isMutable()) + // Cast away pointer to not mutable + goto Lunsafe; + + if (t1bn.isShared() && !tobn.isShared()) + // Cast away pointer to shared + goto Lunsafe; + + if (tobn.isTypeBasic() && tobn.size() < t1bn.size()) { + // Allow things like casting a long* to an int* + ; + } else if (tobn.ty != TY.Tvoid) { + // Cast to a pointer other than void* + goto Lunsafe; + } + } + + // BUG: Check for casting array types, such as void[] to int*[] + } + + e = e1.castTo(sc, to); + return e; + } + + MATCH implicitConvTo(Type t) + { + static if (false) { + printf("CastExp::implicitConvTo(this=%s, type=%s, t=%s)\n", toChars(), type.toChars(), t.toChars()); + } + MATCH result = type.implicitConvTo(t); + + if (result == MATCHnomatch) + { + if (t.isintegral() && + e1.type.isintegral() && + e1.implicitConvTo(t) != MATCHnomatch) + result = MATCHconvert; + else + result = Expression.implicitConvTo(t); + } + return result; + } + + IntRange getIntRange() + { + assert(false); + } + + Expression optimize(int result) + { + //printf("CastExp.optimize(result = %d) %s\n", result, toChars()); + //printf("from %s to %s\n", type.toChars(), to.toChars()); + //printf("from %s\n", type.toChars()); + //printf("e1.type %s\n", e1.type.toChars()); + //printf("type = %p\n", type); + assert(type); + TOK op1 = e1.op; + + Expression e1old = e1; + e1 = e1.optimize(result); + e1 = fromConstInitializer(result, e1); + + if (e1 == e1old && + e1.op == TOK.TOKarrayliteral && + type.toBasetype().ty == TY.Tpointer && + e1.type.toBasetype().ty != TY.Tsarray) + { + // Casting this will result in the same expression, and + // infinite loop because of Expression.implicitCastTo() + return this; // no change + } + + if ((e1.op == TOK.TOKstring || e1.op == TOK.TOKarrayliteral) && + (type.ty == TY.Tpointer || type.ty == TY.Tarray) && + e1.type.nextOf().size() == type.nextOf().size() + ) + { + Expression e = e1.castTo(null, type); + +static if (false) { + printf(" returning1 %s\n", e.toChars()); +} + return e; + } + + if (e1.op == TOK.TOKstructliteral && + e1.type.implicitConvTo(type) >= MATCH.MATCHconst) + { + e1.type = type; +static if (false) { + printf(" returning2 %s\n", e1.toChars()); +} + return e1; + } + + /* The first test here is to prevent infinite loops + */ + if (op1 != TOK.TOKarrayliteral && e1.op == TOK.TOKarrayliteral) + return e1.castTo(null, to); + if (e1.op == TOK.TOKnull && + (type.ty == TY.Tpointer || type.ty == TY.Tclass || type.ty == TY.Tarray)) + { + e1.type = type; +static if (false) { + printf(" returning3 %s\n", e1.toChars()); +} + return e1; + } + + if (result & WANT.WANTflags && type.ty == TY.Tclass && e1.type.ty == TY.Tclass) + { + // See if we can remove an unnecessary cast + ClassDeclaration cdfrom; + ClassDeclaration cdto; + int offset; + + cdfrom = e1.type.isClassHandle(); + cdto = type.isClassHandle(); + if (cdto.isBaseOf(cdfrom, &offset) && offset == 0) + { + e1.type = type; +static if (false) { + printf(" returning4 %s\n", e1.toChars()); +} + return e1; + } + } + + // We can convert 'head const' to mutable + if (to.constOf().equals(e1.type.constOf())) + // if (to.constConv(e1.type) >= MATCHconst) + { + e1.type = type; +static if (false) { + printf(" returning5 %s\n", e1.toChars()); +} + return e1; + } + + Expression e; + + if (e1.isConst()) + { + if (e1.op == TOK.TOKsymoff) + { + if (type.size() == e1.type.size() && + type.toBasetype().ty != TY.Tsarray) + { + e1.type = type; + return e1; + } + return this; + } + if (to.toBasetype().ty == TY.Tvoid) + e = this; + else + e = Cast(type, to, e1); + } + else + e = this; +static if (false) { + printf(" returning6 %s\n", e.toChars()); +} + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + bool checkSideEffect(int flag) + { + assert(false); + } + + void checkEscape() + { + Type tb = type.toBasetype(); + if (tb.ty == TY.Tarray && e1.op == TOK.TOKvar && e1.type.toBasetype().ty ==TY.Tsarray) + { + VarExp ve = cast(VarExp)e1; + VarDeclaration v = ve.var.isVarDeclaration(); + if (v) + { + if (!v.isDataseg() && !v.isParameter()) + error("escaping reference to local %s", v.toChars()); + } + } + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + buf.writestring("cast("); + version (DMDV1) { + to.toCBuffer(buf, null, hgs); + } else { + if (to) + to.toCBuffer(buf, null, hgs); + else + { + switch (mod) + { + case MODundefined: + break; + case MODconst: + buf.writestring(Token.tochars[TOKconst]); + break; + case MODinvariant: + buf.writestring(Token.tochars[TOKimmutable]); + break; + case MODshared: + buf.writestring(Token.tochars[TOKshared]); + break; + case MODshared | MODconst: + buf.writestring(Token.tochars[TOKshared]); + buf.writeByte(' '); + buf.writestring(Token.tochars[TOKconst]); + break; + default: + assert(0); + } + } + } + buf.writeByte(')'); + expToCBuffer(buf, hgs, e1, precedence[op]); + } + + void buildArrayIdent(OutBuffer buf, Expressions arguments) + { + assert(false); + } + + Expression buildArrayLoop(Arguments fparams) + { + assert(false); + } + + static int X(int fty, int tty) { + return ((fty) * TY.TMAX + (tty)); + } + + elem* toElem(IRState* irs) + { + elem* e; + TY fty; + TY tty; + tym_t ftym; + tym_t ttym; + OPER eop; + Type t; + Type tfrom; + +static if (false) { + printf("CastExp::toElem()\n"); + print(); + printf("\tfrom: %s\n", e1.type.toChars()); + printf("\tto : %s\n", to.toChars()); +} + + e = e1.toElem(irs); + tfrom = e1.type.toBasetype(); + t = to.toBasetype(); // skip over typedef's + if (t.equals(tfrom)) + goto Lret; + + fty = tfrom.ty; + //printf("fty = %d\n", fty); + tty = t.ty; + + if (tty == TY.Tpointer && fty == TY.Tarray +///static if (false) { +/// && (t.next.ty == Tvoid || t.next.equals(e1.type.next)) +///} + ) + { + if (e.Eoper == OPER.OPvar) + { + // e1 . *(&e1 + 4) + e = el_una(OPER.OPaddr, TYM.TYnptr, e); + e = el_bin(OPER.OPadd, TYM.TYnptr, e, el_long(TYM.TYint, 4)); + e = el_una(OPER.OPind, t.totym(),e); + } + else + { + // e1 . (unsigned)(e1 >> 32) + e = el_bin(OPER.OPshr, TYM.TYullong, e, el_long(TYM.TYint, 32)); + e = el_una(OPER.OP64_32, t.totym(), e); + } + goto Lret; + } + + if (tty == TY.Tpointer && fty == TY.Tsarray +///static if (false) { +/// && (t.next.ty == Tvoid || t.next.equals(e1.type.next)) +///} + ) + { + // e1 . &e1 + e = el_una(OPER.OPaddr, TYM.TYnptr, e); + goto Lret; + } + + // Convert from static array to dynamic array + if (tty == TY.Tarray && fty == TY.Tsarray) + { + e = sarray_toDarray(loc, tfrom, t, e); + goto Lret; + } + + // Convert from dynamic array to dynamic array + if (tty == TY.Tarray && fty == TY.Tarray) + { + uint fsize = cast(uint)tfrom.nextOf().size(); + uint tsize = cast(uint)t.nextOf().size(); + + if (fsize != tsize) + { + elem* ep = el_params(e, el_long(TYM.TYint, fsize), el_long(TYM.TYint, tsize), null); + e = el_bin(OPER.OPcall, type.totym(), el_var(rtlsym[RTLSYM.RTLSYM_ARRAYCAST]), ep); + } + goto Lret; + } + +static if (false) { + // Convert from dynamic array string literal to static array + if (tty == TY.Tsarray && fty == TY.Tarray && e1.op == TOK.TOKstring) + { + goto Lret; // treat as a 'paint' + } +} + + // Casting from base class to derived class requires a runtime check + if (fty == TY.Tclass && tty == TY.Tclass) + { + // Casting from derived class to base class is a no-op + ClassDeclaration cdfrom; + ClassDeclaration cdto; + int offset; + int rtl = RTLSYM.RTLSYM_DYNAMIC_CAST; + + cdfrom = tfrom.isClassHandle(); + cdto = t.isClassHandle(); + if (cdfrom.isInterfaceDeclaration()) + { + rtl = RTLSYM.RTLSYM_INTERFACE_CAST; + if (cdfrom.isCPPinterface()) + { + if (cdto.isCPPinterface()) + { + /* Casting from a C++ interface to a C++ interface + * is always a 'paint' operation + */ + goto Lret; // no-op + } + + /* Casting from a C++ interface to a class + * always results in null because there is no runtime + * information available to do it. + * + * Casting from a C++ interface to a non-C++ interface + * always results in null because there's no way one + * can be derived from the other. + */ + e = el_bin(OPER.OPcomma, TYM.TYnptr, e, el_long(TYM.TYnptr, 0)); + goto Lret; + } + } + if (cdto.isBaseOf(cdfrom, &offset) && offset != OFFSET_RUNTIME) + { + /* The offset from cdfrom=>cdto is known at compile time. + */ + + //printf("offset = %d\n", offset); + if (offset) + { + /* Rewrite cast as (e ? e + offset : null) + */ + elem* etmp; + elem* ex; + + if (e1.op == TOK.TOKthis) + { + // Assume 'this' is never null, so skip null check + e = el_bin(OPER.OPadd, TYM.TYnptr, e, el_long(TYM.TYint, offset)); + } + else + { + etmp = el_same(&e); + ex = el_bin(OPER.OPadd, TYM.TYnptr, etmp, el_long(TYM.TYint, offset)); + ex = el_bin(OPER.OPcolon, TYM.TYnptr, ex, el_long(TYM.TYnptr, 0)); + e = el_bin(OPER.OPcond, TYM.TYnptr, e, ex); + } + } + goto Lret; // no-op + } + + /* The offset from cdfrom=>cdto can only be determined at runtime. + */ + elem* ep; + + ep = el_param(el_ptr(cdto.toSymbol()), e); + e = el_bin(OPER.OPcall, TYM.TYnptr, el_var(rtlsym[rtl]), ep); + goto Lret; + } + + ftym = e.Ety; + ttym = t.totym(); + if (ftym == ttym) + goto Lret; + + switch (tty) + { + case TY.Tpointer: + if (fty == TY.Tdelegate) + goto Lpaint; + tty = TY.Tuns32; + break; + + case TY.Tchar: + tty = TY.Tuns8; + break; + case TY.Twchar: + tty = TY.Tuns16; + break; + case TY.Tdchar: + tty = TY.Tuns32; + break; + case TY.Tvoid: + goto Lpaint; + + case TY.Tbool: + { + // Construct e?true:false + elem* eq; + + e = el_una(OPER.OPbool, ttym, e); + goto Lret; + } + + default: + break; /// + } + + switch (fty) + { + case TY.Tpointer: fty = TY.Tuns32; break; + case TY.Tchar: fty = TY.Tuns8; break; + case TY.Twchar: fty = TY.Tuns16; break; + case TY.Tdchar: fty = TY.Tuns32; break; + default: break; /// + } + + Lagain: + switch (X(fty,tty)) + { +static if (false) { + case X(TY.Tbit,TY.Tint8): + case X(TY.Tbit,TY.Tuns8): + goto Lpaint; + case X(TY.Tbit,TY.Tint16): + case X(TY.Tbit,TY.Tuns16): + case X(TY.Tbit,TY.Tint32): + case X(TY.Tbit,TY.Tuns32): + eop = OPu8_16; + goto Leop; + case X(TY.Tbit,TY.Tint64): + case X(TY.Tbit,TY.Tuns64): + case X(TY.Tbit,TY.Tfloat32): + case X(TY.Tbit,TY.Tfloat64): + case X(TY.Tbit,TY.Tfloat80): + case X(TY.Tbit,TY.Tcomplex32): + case X(TY.Tbit,TY.Tcomplex64): + case X(TY.Tbit,TY.Tcomplex80): + e = el_una(OPER.OPu8_16, TYM.TYuint, e); + fty = TY.Tuns32; + goto Lagain; + case X(Tbit,Timaginary32): + case X(Tbit,Timaginary64): + case X(Tbit,Timaginary80): + goto Lzero; +} + /* ============================= */ + + case X(TY.Tbool,TY.Tint8): + case X(TY.Tbool,TY.Tuns8): + goto Lpaint; + case X(TY.Tbool,TY.Tint16): + case X(TY.Tbool,TY.Tuns16): + case X(TY.Tbool,TY.Tint32): + case X(TY.Tbool,TY.Tuns32): + eop = OPER.OPu8_16; + goto Leop; + case X(TY.Tbool,TY.Tint64): + case X(TY.Tbool,TY.Tuns64): + case X(TY.Tbool,TY.Tfloat32): + case X(TY.Tbool,TY.Tfloat64): + case X(TY.Tbool,TY.Tfloat80): + case X(TY.Tbool,TY.Tcomplex32): + case X(TY.Tbool,TY.Tcomplex64): + case X(TY.Tbool,TY.Tcomplex80): + e = el_una(OPER.OPu8_16, TYM.TYuint, e); + fty = TY.Tuns32; + goto Lagain; + case X(TY.Tbool,TY.Timaginary32): + case X(TY.Tbool,TY.Timaginary64): + case X(TY.Tbool,TY.Timaginary80): + goto Lzero; + + /* ============================= */ + + case X(TY.Tint8,TY.Tuns8): + goto Lpaint; + case X(TY.Tint8,TY.Tint16): + case X(TY.Tint8,TY.Tuns16): + case X(TY.Tint8,TY.Tint32): + case X(TY.Tint8,TY.Tuns32): + eop = OPER.OPs8_16; + goto Leop; + case X(TY.Tint8,TY.Tint64): + case X(TY.Tint8,TY.Tuns64): + case X(TY.Tint8,TY.Tfloat32): + case X(TY.Tint8,TY.Tfloat64): + case X(TY.Tint8,TY.Tfloat80): + case X(TY.Tint8,TY.Tcomplex32): + case X(TY.Tint8,TY.Tcomplex64): + case X(TY.Tint8,TY.Tcomplex80): + e = el_una(OPER.OPs8_16, TYM.TYint, e); + fty = TY.Tint32; + goto Lagain; + case X(TY.Tint8,TY.Timaginary32): + case X(TY.Tint8,TY.Timaginary64): + case X(TY.Tint8,TY.Timaginary80): + goto Lzero; + + /* ============================= */ + + case X(TY.Tuns8,TY.Tint8): + goto Lpaint; + case X(TY.Tuns8,TY.Tint16): + case X(TY.Tuns8,TY.Tuns16): + case X(TY.Tuns8,TY.Tint32): + case X(TY.Tuns8,TY.Tuns32): + eop = OPER.OPu8_16; + goto Leop; + case X(TY.Tuns8,TY.Tint64): + case X(TY.Tuns8,TY.Tuns64): + case X(TY.Tuns8,TY.Tfloat32): + case X(TY.Tuns8,TY.Tfloat64): + case X(TY.Tuns8,TY.Tfloat80): + case X(TY.Tuns8,TY.Tcomplex32): + case X(TY.Tuns8,TY.Tcomplex64): + case X(TY.Tuns8,TY.Tcomplex80): + e = el_una(OPER.OPu8_16, TYM.TYuint, e); + fty = TY.Tuns32; + goto Lagain; + case X(TY.Tuns8,TY.Timaginary32): + case X(TY.Tuns8,TY.Timaginary64): + case X(TY.Tuns8,TY.Timaginary80): + goto Lzero; + + /* ============================= */ + + case X(TY.Tint16,TY.Tint8): + case X(TY.Tint16,TY.Tuns8): + eop = OPER.OP16_8; + goto Leop; + case X(TY.Tint16,TY.Tuns16): + goto Lpaint; + case X(TY.Tint16,TY.Tint32): + case X(TY.Tint16,TY.Tuns32): + eop = OPER.OPs16_32; + goto Leop; + case X(TY.Tint16,TY.Tint64): + case X(TY.Tint16,TY.Tuns64): + e = el_una(OPER.OPs16_32, TYM.TYint, e); + fty = TY.Tint32; + goto Lagain; + case X(TY.Tint16,TY.Tfloat32): + case X(TY.Tint16,TY.Tfloat64): + case X(TY.Tint16,TY.Tfloat80): + case X(TY.Tint16,TY.Tcomplex32): + case X(TY.Tint16,TY.Tcomplex64): + case X(TY.Tint16,TY.Tcomplex80): + e = el_una(OPER.OPs16_d, TYM.TYdouble, e); + fty = TY.Tfloat64; + goto Lagain; + case X(TY.Tint16,TY.Timaginary32): + case X(TY.Tint16,TY.Timaginary64): + case X(TY.Tint16,TY.Timaginary80): + goto Lzero; + + /* ============================= */ + + case X(TY.Tuns16,TY.Tint8): + case X(TY.Tuns16,TY.Tuns8): + eop = OPER.OP16_8; + goto Leop; + case X(TY.Tuns16,TY.Tint16): + goto Lpaint; + case X(TY.Tuns16,TY.Tint32): + case X(TY.Tuns16,TY.Tuns32): + eop = OPER.OPu16_32; + goto Leop; + case X(TY.Tuns16,TY.Tint64): + case X(TY.Tuns16,TY.Tuns64): + case X(TY.Tuns16,TY.Tfloat64): + case X(TY.Tuns16,TY.Tfloat32): + case X(TY.Tuns16,TY.Tfloat80): + case X(TY.Tuns16,TY.Tcomplex32): + case X(TY.Tuns16,TY.Tcomplex64): + case X(TY.Tuns16,TY.Tcomplex80): + e = el_una(OPER.OPu16_32, TYM.TYuint, e); + fty = TY.Tuns32; + goto Lagain; + case X(TY.Tuns16,TY.Timaginary32): + case X(TY.Tuns16,TY.Timaginary64): + case X(TY.Tuns16,TY.Timaginary80): + goto Lzero; + + /* ============================= */ + + case X(TY.Tint32,TY.Tint8): + case X(TY.Tint32,TY.Tuns8): + e = el_una(OPER.OP32_16, TYM.TYshort, e); + fty = TY.Tint16; + goto Lagain; + case X(TY.Tint32,TY.Tint16): + case X(TY.Tint32,TY.Tuns16): + eop = OPER.OP32_16; + goto Leop; + case X(TY.Tint32,TY.Tuns32): + goto Lpaint; + case X(TY.Tint32,TY.Tint64): + case X(TY.Tint32,TY.Tuns64): + eop = OPER.OPs32_64; + goto Leop; + case X(TY.Tint32,TY.Tfloat32): + case X(TY.Tint32,TY.Tfloat64): + case X(TY.Tint32,TY.Tfloat80): + case X(TY.Tint32,TY.Tcomplex32): + case X(TY.Tint32,TY.Tcomplex64): + case X(TY.Tint32,TY.Tcomplex80): + e = el_una(OPER.OPs32_d, TYM.TYdouble, e); + fty = TY.Tfloat64; + goto Lagain; + case X(TY.Tint32,TY.Timaginary32): + case X(TY.Tint32,TY.Timaginary64): + case X(TY.Tint32,TY.Timaginary80): + goto Lzero; + + /* ============================= */ + + case X(TY.Tuns32,TY.Tint8): + case X(TY.Tuns32,TY.Tuns8): + e = el_una(OPER.OP32_16, TYM.TYshort, e); + fty = TY.Tuns16; + goto Lagain; + case X(TY.Tuns32,TY.Tint16): + case X(TY.Tuns32,TY.Tuns16): + eop = OPER.OP32_16; + goto Leop; + case X(TY.Tuns32,TY.Tint32): + goto Lpaint; + case X(TY.Tuns32,TY.Tint64): + case X(TY.Tuns32,TY.Tuns64): + eop = OPER.OPu32_64; + goto Leop; + case X(TY.Tuns32,TY.Tfloat32): + case X(TY.Tuns32,TY.Tfloat64): + case X(TY.Tuns32,TY.Tfloat80): + case X(TY.Tuns32,TY.Tcomplex32): + case X(TY.Tuns32,TY.Tcomplex64): + case X(TY.Tuns32,TY.Tcomplex80): + e = el_una(OPER.OPu32_d, TYM.TYdouble, e); + fty = TY.Tfloat64; + goto Lagain; + case X(TY.Tuns32,TY.Timaginary32): + case X(TY.Tuns32,TY.Timaginary64): + case X(TY.Tuns32,TY.Timaginary80): + goto Lzero; + + /* ============================= */ + + case X(TY.Tint64,TY.Tint8): + case X(TY.Tint64,TY.Tuns8): + case X(TY.Tint64,TY.Tint16): + case X(TY.Tint64,TY.Tuns16): + e = el_una(OPER.OP64_32, TYM.TYint, e); + fty = TY.Tint32; + goto Lagain; + case X(TY.Tint64,TY.Tint32): + case X(TY.Tint64,TY.Tuns32): + eop = OPER.OP64_32; + goto Leop; + case X(TY.Tint64,TY.Tuns64): + goto Lpaint; + case X(TY.Tint64,TY.Tfloat32): + case X(TY.Tint64,TY.Tfloat64): + case X(TY.Tint64,TY.Tfloat80): + case X(TY.Tint64,TY.Tcomplex32): + case X(TY.Tint64,TY.Tcomplex64): + case X(TY.Tint64,TY.Tcomplex80): + e = el_una(OPER.OPs64_d, TYM.TYdouble, e); + fty = TY.Tfloat64; + goto Lagain; + case X(TY.Tint64,TY.Timaginary32): + case X(TY.Tint64,TY.Timaginary64): + case X(TY.Tint64,TY.Timaginary80): + goto Lzero; + + /* ============================= */ + + case X(TY.Tuns64,TY.Tint8): + case X(TY.Tuns64,TY.Tuns8): + case X(TY.Tuns64,TY.Tint16): + case X(TY.Tuns64,TY.Tuns16): + e = el_una(OPER.OP64_32, TYM.TYint, e); + fty = TY.Tint32; + goto Lagain; + case X(TY.Tuns64,TY.Tint32): + case X(TY.Tuns64,TY.Tuns32): + eop = OPER.OP64_32; + goto Leop; + case X(TY.Tuns64,TY.Tint64): + goto Lpaint; + case X(TY.Tuns64,TY.Tfloat32): + case X(TY.Tuns64,TY.Tfloat64): + case X(TY.Tuns64,TY.Tfloat80): + case X(TY.Tuns64,TY.Tcomplex32): + case X(TY.Tuns64,TY.Tcomplex64): + case X(TY.Tuns64,TY.Tcomplex80): + e = el_una(OPER.OPu64_d, TYM.TYdouble, e); + fty = TY.Tfloat64; + goto Lagain; + case X(TY.Tuns64,TY.Timaginary32): + case X(TY.Tuns64,TY.Timaginary64): + case X(TY.Tuns64,TY.Timaginary80): + goto Lzero; + + /* ============================= */ + + case X(TY.Tfloat32,TY.Tint8): + case X(TY.Tfloat32,TY.Tuns8): + case X(TY.Tfloat32,TY.Tint16): + case X(TY.Tfloat32,TY.Tuns16): + case X(TY.Tfloat32,TY.Tint32): + case X(TY.Tfloat32,TY.Tuns32): + case X(TY.Tfloat32,TY.Tint64): + case X(TY.Tfloat32,TY.Tuns64): + case X(TY.Tfloat32,TY.Tfloat80): + e = el_una(OPER.OPf_d, TYM.TYdouble, e); + fty = TY.Tfloat64; + goto Lagain; + case X(TY.Tfloat32,TY.Tfloat64): + eop = OPER.OPf_d; + goto Leop; + case X(TY.Tfloat32,TY.Timaginary32): + goto Lzero; + case X(TY.Tfloat32,TY.Timaginary64): + goto Lzero; + case X(TY.Tfloat32,TY.Timaginary80): + goto Lzero; + case X(TY.Tfloat32,TY.Tcomplex32): + case X(TY.Tfloat32,TY.Tcomplex64): + case X(TY.Tfloat32,TY.Tcomplex80): + e = el_bin(OPER.OPadd,TYM.TYcfloat,el_long(TYM.TYifloat,0),e); + fty = TY.Tcomplex32; + goto Lagain; + + /* ============================= */ + + case X(TY.Tfloat64,TY.Tint8): + case X(TY.Tfloat64,TY.Tuns8): + e = el_una(OPER.OPd_s16, TYM.TYshort, e); + fty = TY.Tint16; + goto Lagain; + case X(TY.Tfloat64,TY.Tint16): + eop = OPER.OPd_s16; + goto Leop; + case X(TY.Tfloat64,TY.Tuns16): + eop = OPER.OPd_u16; + goto Leop; + case X(TY.Tfloat64,TY.Tint32): + eop = OPER.OPd_s32; + goto Leop; + case X(TY.Tfloat64,TY.Tuns32): + eop = OPER.OPd_u32; + goto Leop; + case X(TY.Tfloat64,TY.Tint64): + eop = OPER.OPd_s64; + goto Leop; + case X(TY.Tfloat64,TY.Tuns64): + eop = OPER.OPd_u64; + goto Leop; + case X(TY.Tfloat64,TY.Tfloat32): + eop = OPER.OPd_f; + goto Leop; + case X(TY.Tfloat64,TY.Tfloat80): + eop = OPER.OPd_ld; + goto Leop; + case X(TY.Tfloat64,TY.Timaginary32): + goto Lzero; + case X(TY.Tfloat64,TY.Timaginary64): + goto Lzero; + case X(TY.Tfloat64,TY.Timaginary80): + goto Lzero; + case X(TY.Tfloat64,TY.Tcomplex32): + case X(TY.Tfloat64,TY.Tcomplex64): + case X(TY.Tfloat64,TY.Tcomplex80): + e = el_bin(OPER.OPadd,TYM.TYcfloat,el_long(TYM.TYidouble,0),e); + fty = TY.Tcomplex64; + goto Lagain; + + /* ============================= */ + + case X(TY.Tfloat80,TY.Tint8): + case X(TY.Tfloat80,TY.Tuns8): + case X(TY.Tfloat80,TY.Tint16): + case X(TY.Tfloat80,TY.Tuns16): + case X(TY.Tfloat80,TY.Tint32): + case X(TY.Tfloat80,TY.Tuns32): + case X(TY.Tfloat80,TY.Tint64): + case X(TY.Tfloat80,TY.Tfloat32): + e = el_una(OPER.OPld_d, TYM.TYdouble, e); + fty = TY.Tfloat64; + goto Lagain; + case X(TY.Tfloat80,TY.Tuns64): + eop = OPER.OPld_u64; + goto Leop; + case X(TY.Tfloat80,TY.Tfloat64): + eop = OPER.OPld_d; + goto Leop; + case X(TY.Tfloat80,TY.Timaginary32): + goto Lzero; + case X(TY.Tfloat80,TY.Timaginary64): + goto Lzero; + case X(TY.Tfloat80,TY.Timaginary80): + goto Lzero; + case X(TY.Tfloat80,TY.Tcomplex32): + case X(TY.Tfloat80,TY.Tcomplex64): + case X(TY.Tfloat80,TY.Tcomplex80): + e = el_bin(OPER.OPadd,TYM.TYcldouble,e,el_long(TYM.TYildouble,0)); + fty = TY.Tcomplex80; + goto Lagain; + + /* ============================= */ + + case X(TY.Timaginary32,TY.Tint8): + case X(TY.Timaginary32,TY.Tuns8): + case X(TY.Timaginary32,TY.Tint16): + case X(TY.Timaginary32,TY.Tuns16): + case X(TY.Timaginary32,TY.Tint32): + case X(TY.Timaginary32,TY.Tuns32): + case X(TY.Timaginary32,TY.Tint64): + case X(TY.Timaginary32,TY.Tuns64): + case X(TY.Timaginary32,TY.Tfloat32): + case X(TY.Timaginary32,TY.Tfloat64): + case X(TY.Timaginary32,TY.Tfloat80): + goto Lzero; + case X(TY.Timaginary32,TY.Timaginary64): + eop = OPER.OPf_d; + goto Leop; + case X(TY.Timaginary32,TY.Timaginary80): + e = el_una(OPER.OPf_d, TYM.TYidouble, e); + fty = TY.Timaginary64; + goto Lagain; + case X(TY.Timaginary32,TY.Tcomplex32): + case X(TY.Timaginary32,TY.Tcomplex64): + case X(TY.Timaginary32,TY.Tcomplex80): + e = el_bin(OPER.OPadd,TYM.TYcfloat,el_long(TYM.TYfloat,0),e); + fty = TY.Tcomplex32; + goto Lagain; + + /* ============================= */ + + case X(TY.Timaginary64,TY.Tint8): + case X(TY.Timaginary64,TY.Tuns8): + case X(TY.Timaginary64,TY.Tint16): + case X(TY.Timaginary64,TY.Tuns16): + case X(TY.Timaginary64,TY.Tint32): + case X(TY.Timaginary64,TY.Tuns32): + case X(TY.Timaginary64,TY.Tint64): + case X(TY.Timaginary64,TY.Tuns64): + case X(TY.Timaginary64,TY.Tfloat32): + case X(TY.Timaginary64,TY.Tfloat64): + case X(TY.Timaginary64,TY.Tfloat80): + goto Lzero; + case X(TY.Timaginary64,TY.Timaginary32): + eop = OPER.OPd_f; + goto Leop; + case X(TY.Timaginary64,TY.Timaginary80): + eop = OPER.OPd_ld; + goto Leop; + case X(TY.Timaginary64,TY.Tcomplex32): + case X(TY.Timaginary64,TY.Tcomplex64): + case X(TY.Timaginary64,TY.Tcomplex80): + e = el_bin(OPER.OPadd, TYM.TYcdouble, el_long(TYM.TYdouble,0), e); + fty = TY.Tcomplex64; + goto Lagain; + + /* ============================= */ + + case X(TY.Timaginary80,TY.Tint8): + case X(TY.Timaginary80,TY.Tuns8): + case X(TY.Timaginary80,TY.Tint16): + case X(TY.Timaginary80,TY.Tuns16): + case X(TY.Timaginary80,TY.Tint32): + case X(TY.Timaginary80,TY.Tuns32): + case X(TY.Timaginary80,TY.Tint64): + case X(TY.Timaginary80,TY.Tuns64): + case X(TY.Timaginary80,TY.Tfloat32): + case X(TY.Timaginary80,TY.Tfloat64): + case X(TY.Timaginary80,TY.Tfloat80): + goto Lzero; + case X(TY.Timaginary80,TY.Timaginary32): + e = el_una(OPER.OPf_d, TYM.TYidouble, e); + fty = TY.Timaginary64; + goto Lagain; + case X(TY.Timaginary80,TY.Timaginary64): + eop = OPER.OPld_d; + goto Leop; + case X(TY.Timaginary80,TY.Tcomplex32): + case X(TY.Timaginary80,TY.Tcomplex64): + case X(TY.Timaginary80,TY.Tcomplex80): + e = el_bin(OPER.OPadd, TYM.TYcldouble, el_long(TYM.TYldouble,0), e); + fty = TY.Tcomplex80; + goto Lagain; + + /* ============================= */ + + case X(TY.Tcomplex32,TY.Tint8): + case X(TY.Tcomplex32,TY.Tuns8): + case X(TY.Tcomplex32,TY.Tint16): + case X(TY.Tcomplex32,TY.Tuns16): + case X(TY.Tcomplex32,TY.Tint32): + case X(TY.Tcomplex32,TY.Tuns32): + case X(TY.Tcomplex32,TY.Tint64): + case X(TY.Tcomplex32,TY.Tuns64): + case X(TY.Tcomplex32,TY.Tfloat32): + case X(TY.Tcomplex32,TY.Tfloat64): + case X(TY.Tcomplex32,TY.Tfloat80): + e = el_una(OPER.OPc_r, TYM.TYfloat, e); + fty = TY.Tfloat32; + goto Lagain; + case X(TY.Tcomplex32,TY.Timaginary32): + case X(TY.Tcomplex32,TY.Timaginary64): + case X(TY.Tcomplex32,TY.Timaginary80): + e = el_una(OPER.OPc_i, TYM.TYifloat, e); + fty = TY.Timaginary32; + goto Lagain; + case X(TY.Tcomplex32,TY.Tcomplex64): + case X(TY.Tcomplex32,TY.Tcomplex80): + e = el_una(OPER.OPf_d, TYM.TYcdouble, e); + fty = TY.Tcomplex64; + goto Lagain; + + /* ============================= */ + + case X(TY.Tcomplex64,TY.Tint8): + case X(TY.Tcomplex64,TY.Tuns8): + case X(TY.Tcomplex64,TY.Tint16): + case X(TY.Tcomplex64,TY.Tuns16): + case X(TY.Tcomplex64,TY.Tint32): + case X(TY.Tcomplex64,TY.Tuns32): + case X(TY.Tcomplex64,TY.Tint64): + case X(TY.Tcomplex64,TY.Tuns64): + case X(TY.Tcomplex64,TY.Tfloat32): + case X(TY.Tcomplex64,TY.Tfloat64): + case X(TY.Tcomplex64,TY.Tfloat80): + e = el_una(OPER.OPc_r, TYM.TYdouble, e); + fty = TY.Tfloat64; + goto Lagain; + case X(TY.Tcomplex64,TY.Timaginary32): + case X(TY.Tcomplex64,TY.Timaginary64): + case X(TY.Tcomplex64,TY.Timaginary80): + e = el_una(OPER.OPc_i, TYM.TYidouble, e); + fty = TY.Timaginary64; + goto Lagain; + case X(TY.Tcomplex64,TY.Tcomplex32): + eop = OPER.OPd_f; + goto Leop; + case X(TY.Tcomplex64,TY.Tcomplex80): + eop = OPER.OPd_ld; + goto Leop; + + /* ============================= */ + + case X(TY.Tcomplex80,TY.Tint8): + case X(TY.Tcomplex80,TY.Tuns8): + case X(TY.Tcomplex80,TY.Tint16): + case X(TY.Tcomplex80,TY.Tuns16): + case X(TY.Tcomplex80,TY.Tint32): + case X(TY.Tcomplex80,TY.Tuns32): + case X(TY.Tcomplex80,TY.Tint64): + case X(TY.Tcomplex80,TY.Tuns64): + case X(TY.Tcomplex80,TY.Tfloat32): + case X(TY.Tcomplex80,TY.Tfloat64): + case X(TY.Tcomplex80,TY.Tfloat80): + e = el_una(OPER.OPc_r, TYM.TYldouble, e); + fty = TY.Tfloat80; + goto Lagain; + case X(TY.Tcomplex80,TY.Timaginary32): + case X(TY.Tcomplex80,TY.Timaginary64): + case X(TY.Tcomplex80,TY.Timaginary80): + e = el_una(OPER.OPc_i, TYM.TYildouble, e); + fty = TY.Timaginary80; + goto Lagain; + case X(TY.Tcomplex80,TY.Tcomplex32): + case X(TY.Tcomplex80,TY.Tcomplex64): + e = el_una(OPER.OPld_d, TYM.TYcdouble, e); + fty = TY.Tcomplex64; + goto Lagain; + + /* ============================= */ + + default: + if (fty == tty) + goto Lpaint; + //dump(0); + //printf("fty = %d, tty = %d\n", fty, tty); + error("e2ir: cannot cast from %s to %s", e1.type.toChars(), t.toChars()); + goto Lzero; + + Lzero: + e = el_long(ttym, 0); + break; + + Lpaint: + e.Ety = ttym; + break; + + Leop: + e = el_una(eop, ttym, e); + break; + } + Lret: + // Adjust for any type paints + t = type.toBasetype(); + e.Ety = t.totym(); + + el_setLoc(e,loc); + return e; + } + + Identifier opId() + { + return Id.cast_; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/CatAssignExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/CatAssignExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,146 @@ +module dmd.CatAssignExp; + +import dmd.BinExp; +import dmd.Loc; +import dmd.Expression; +import dmd.Scope; +import dmd.InterState; +import dmd.SliceExp; +import dmd.Identifier; +import dmd.IRState; +import dmd.TOK; +import dmd.TY; +import dmd.Id; +import dmd.Type; +import dmd.backend.elem; +import dmd.backend.RTLSYM; +import dmd.backend.Util; +import dmd.backend.OPER; +import dmd.backend.TYM; +import dmd.backend.mTY; + +import dmd.expression.Util; + +class CatAssignExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKcatass, CatAssignExp.sizeof, e1, e2); + } + + Expression semantic(Scope sc) + { + Expression e; + + BinExp.semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + if (e1.op == TOKslice) + { + SliceExp se = cast(SliceExp)e1; + + if (se.e1.type.toBasetype().ty == Tsarray) + error("cannot append to static array %s", se.e1.type.toChars()); + } + + e1 = e1.modifiableLvalue(sc, e1); + + Type tb1 = e1.type.toBasetype(); + Type tb2 = e2.type.toBasetype(); + + e2.rvalue(); + + if ((tb1.ty == Tarray) && + (tb2.ty == Tarray || tb2.ty == Tsarray) && + (e2.implicitConvTo(e1.type) || + tb2.nextOf().implicitConvTo(tb1.nextOf())) + ) + { // Append array + e2 = e2.castTo(sc, e1.type); + type = e1.type; + e = this; + } + else if ((tb1.ty == Tarray) && + e2.implicitConvTo(tb1.nextOf()) + ) + { // Append element + e2 = e2.castTo(sc, tb1.nextOf()); + type = e1.type; + e = this; + } + else + { + error("cannot append type %s to type %s", tb2.toChars(), tb1.toChars()); + type = Type.tint32; + e = this; + } + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + Identifier opId() /* For operator overloading */ + { + return Id.catass; + } + + elem* toElem(IRState* irs) + { + //printf("CatAssignExp.toElem('%s')\n", toChars()); + elem* e; + Type tb1 = e1.type.toBasetype(); + Type tb2 = e2.type.toBasetype(); + + if (tb1.ty == Tarray || tb2.ty == Tsarray) + { elem* e1; + elem* e2; + elem* ep; + + e1 = this.e1.toElem(irs); + e1 = el_una(OPaddr, TYnptr, e1); + + e2 = this.e2.toElem(irs); + if (tybasic(e2.Ety) == TYstruct) + { + e2 = el_una(OPstrpar, TYstruct, e2); + e2.Enumbytes = e2.E1.Enumbytes; + assert(e2.Enumbytes); + } + + Type tb1n = tb1.nextOf().toBasetype(); + if ((tb2.ty == Tarray || tb2.ty == Tsarray) && + tb1n.equals(tb2.nextOf().toBasetype())) + { // Append array + static if (true) { + ep = el_params(e2, e1, this.e1.type.getTypeInfo(null).toElem(irs), null); + e = el_bin(OPcall, TYdarray, el_var(rtlsym[RTLSYM_ARRAYAPPENDT]), ep); + } else { + ep = el_params(el_long(TYint, tb1n.size()), e2, e1, null); + e = el_bin(OPcall, TYdarray, el_var(rtlsym[RTLSYM_ARRAYAPPEND]), ep); + } + } + else + { // Append element + static if (true) { + ep = el_params(e2, e1, this.e1.type.getTypeInfo(null).toElem(irs), null); + e = el_bin(OPcall, TYdarray, el_var(rtlsym[RTLSYM_ARRAYAPPENDCT]), ep); + } else { + ep = el_params(e2, el_long(TYint, tb1n.size()), e1, null); + e = el_bin(OPcall, TYdarray, el_var(rtlsym[RTLSYM_ARRAYAPPENDC]), ep); + } + } + el_setLoc(e,loc); + } + else + assert(0); + + return e; + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/CatExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/CatExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,255 @@ +module dmd.CatExp; + +import dmd.Expression; +import dmd.Identifier; +import dmd.InterState; +import dmd.Loc; +import dmd.Scope; +import dmd.IRState; +import dmd.BinExp; +import dmd.TOK; +import dmd.Type; +import dmd.TY; +import dmd.MATCH; +import dmd.ArrayLiteralExp; +import dmd.StringExp; +import dmd.WANT; +import dmd.Id; +import dmd.GlobalExpressions; + +import dmd.backend.elem; +import dmd.backend.Util; +import dmd.backend.TYM; +import dmd.backend.OPER; +import dmd.backend.RTLSYM; +import dmd.codegen.Util; +import dmd.expression.Cat; + +class CatExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKcat, CatExp.sizeof, e1, e2); + } + + Expression semantic(Scope sc) + { + Expression e; + + //printf("CatExp.semantic() %s\n", toChars()); + if (!type) + { + BinExp.semanticp(sc); + e = op_overload(sc); + if (e) + return e; + + Type tb1 = e1.type.toBasetype(); + Type tb2 = e2.type.toBasetype(); + + + /* BUG: Should handle things like: + * char c; + * c ~ ' ' + * ' ' ~ c; + */ + +static if (false) { + e1.type.print(); + e2.type.print(); +} + if ((tb1.ty == Tsarray || tb1.ty == Tarray) && + e2.type.implicitConvTo(tb1.nextOf()) >= MATCHconst) + { + type = tb1.nextOf().arrayOf(); + if (tb2.ty == Tarray) + { + // Make e2 into [e2] + e2 = new ArrayLiteralExp(e2.loc, e2); + e2.type = type; + } + return this; + } + else if ((tb2.ty == Tsarray || tb2.ty == Tarray) && + e1.type.implicitConvTo(tb2.nextOf()) >= MATCHconst) + { + type = tb2.nextOf().arrayOf(); + if (tb1.ty == Tarray) + { + // Make e1 into [e1] + e1 = new ArrayLiteralExp(e1.loc, e1); + e1.type = type; + } + return this; + } + + if ((tb1.ty == Tsarray || tb1.ty == Tarray) && + (tb2.ty == Tsarray || tb2.ty == Tarray) && + (tb1.nextOf().mod || tb2.nextOf().mod) && + (tb1.nextOf().mod != tb2.nextOf().mod) + ) + { + Type t1 = tb1.nextOf().mutableOf().constOf().arrayOf(); + Type t2 = tb2.nextOf().mutableOf().constOf().arrayOf(); + if (e1.op == TOKstring && !(cast(StringExp)e1).committed) + e1.type = t1; + else + e1 = e1.castTo(sc, t1); + if (e2.op == TOKstring && !(cast(StringExp)e2).committed) + e2.type = t2; + else + e2 = e2.castTo(sc, t2); + } + + typeCombine(sc); + type = type.toHeadMutable(); + + Type tb = type.toBasetype(); + if (tb.ty == Tsarray) + type = tb.nextOf().arrayOf(); + if (type.ty == Tarray && tb1.nextOf() && tb2.nextOf() && + tb1.nextOf().mod != tb2.nextOf().mod) + { + type = type.nextOf().toHeadMutable().arrayOf(); + } +static if (false) { + e1.type.print(); + e2.type.print(); + type.print(); + print(); +} + Type t1 = e1.type.toBasetype(); + Type t2 = e2.type.toBasetype(); + if (e1.op == TOKstring && e2.op == TOKstring) + e = optimize(WANTvalue); + else if ((t1.ty == Tarray || t1.ty == Tsarray) && + (t2.ty == Tarray || t2.ty == Tsarray)) + { + e = this; + } + else + { + //printf("(%s) ~ (%s)\n", e1.toChars(), e2.toChars()); + error("Can only concatenate arrays, not (%s ~ %s)", + e1.type.toChars(), e2.type.toChars()); + type = Type.tint32; + e = this; + } + e.type = e.type.semantic(loc, sc); + return e; + } + return this; + } + + Expression optimize(int result) + { + //printf("CatExp::optimize(%d) %s\n", result, toChars()); + e1 = e1.optimize(result); + e2 = e2.optimize(result); + Expression e = Cat(type, e1, e2); + if (e is EXP_CANT_INTERPRET) + e = this; + + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + Identifier opId() + { + return Id.cat; + } + + Identifier opId_r() + { + return Id.cat_r; + } + + elem* toElem(IRState* irs) + { + elem *e; + +static if (false) { + printf("CatExp::toElem()\n"); + print(); +} + + Type tb1 = e1.type.toBasetype(); + Type tb2 = e2.type.toBasetype(); + Type tn; + +///static if (false) { +/// if ((tb1.ty == Tarray || tb1.ty == Tsarray) && +/// (tb2.ty == Tarray || tb2.ty == Tsarray) +/// ) +///} + + Type ta = tb1.nextOf() ? e1.type : e2.type; + tn = tb1.nextOf() ? tb1.nextOf() : tb2.nextOf(); + { + if (e1.op == TOKcat) + { + elem* ep; + CatExp ce = this; + int n = 2; + + ep = eval_Darray(irs, ce.e2); + do + { + n++; + ce = cast(CatExp)ce.e1; + ep = el_param(ep, eval_Darray(irs, ce.e2)); + } while (ce.e1.op == TOKcat); + + ep = el_param(ep, eval_Darray(irs, ce.e1)); + static if (true) { + ep = el_params( + ep, + el_long(TYint, n), + ta.getTypeInfo(null).toElem(irs), + null); + e = el_bin(OPcall, TYdarray, el_var(rtlsym[RTLSYM_ARRAYCATNT]), ep); + } else { + ep = el_params( + ep, + el_long(TYint, n), + el_long(TYint, tn.size()), + null); + e = el_bin(OPcall, TYdarray, el_var(rtlsym[RTLSYM_ARRAYCATN]), ep); + } + } + else + { + elem *e1; + elem *e2; + elem *ep; + + e1 = eval_Darray(irs, this.e1); + e2 = eval_Darray(irs, this.e2); + static if (true) { + ep = el_params(e2, e1, ta.getTypeInfo(null).toElem(irs), null); + e = el_bin(OPcall, TYdarray, el_var(rtlsym[RTLSYM_ARRAYCATT]), ep); + } else { + ep = el_params(el_long(TYint, tn.size()), e2, e1, null); + e = el_bin(OPcall, TYdarray, el_var(rtlsym[RTLSYM_ARRAYCAT]), ep); + } + } + el_setLoc(e,loc); + } +/// static if (false) { +/// else if ((tb1.ty == Tarray || tb1.ty == Tsarray) && +/// e2.type.equals(tb1.next)) +/// { +/// error("array cat with element not implemented"); +/// e = el_long(TYint, 0); +/// } +/// else +/// assert(0); +/// } + return e; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/Catch.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Catch.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,88 @@ +module dmd.Catch; + +import dmd.Loc; +import dmd.Type; +import dmd.Scope; +import dmd.Identifier; +import dmd.VarDeclaration; +import dmd.Statement; +import dmd.OutBuffer; +import dmd.Id; +import dmd.TypeIdentifier; +import dmd.Util; +import dmd.ScopeDsymbol; +import dmd.HdrGenState; +import dmd.BE; + +class Catch +{ + Loc loc; + Type type; + Identifier ident; + VarDeclaration var = null; + Statement handler; + + this(Loc loc, Type t, Identifier id, Statement handler) + { + //printf("Catch(%s, loc = %s)\n", id.toChars(), loc.toChars()); + this.loc = loc; + this.type = t; + this.ident = id; + this.handler = handler; + } + + Catch syntaxCopy() + { + assert(false); + } + + void semantic(Scope sc) + { + ScopeDsymbol sym; + + //printf("Catch.semantic(%s)\n", ident.toChars()); + + version (IN_GCC) { + } else { + if (sc.tf) + { + /* This is because the _d_local_unwind() gets the stack munged + * up on this. The workaround is to place any try-catches into + * a separate function, and call that. + * To fix, have the compiler automatically convert the finally + * body into a nested function. + */ + error(loc, "cannot put catch statement inside finally block"); + } + } + + sym = new ScopeDsymbol(); + sym.parent = sc.scopesym; + sc = sc.push(sym); + + if (!type) + type = new TypeIdentifier(Loc(0), Id.Object_); + type = type.semantic(loc, sc); + if (!type.toBasetype().isClassHandle()) + error("can only catch class objects, not '%s'", type.toChars()); + else if (ident) + { + var = new VarDeclaration(loc, type, ident, null); + var.parent = sc.parent; + sc.insert(var); + } + handler = handler.semantic(sc); + + sc.pop(); + } + + BE blockExit() + { + return handler ? handler.blockExit() : BE.BEfallthru; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ClassDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ClassDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,1885 @@ +module dmd.ClassDeclaration; + +import dmd.AggregateDeclaration; +import dmd.InterfaceDeclaration; +import dmd.ThisDeclaration; +import dmd.CompoundStatement; +import dmd.DeleteDeclaration; +import dmd.NewDeclaration; +import dmd.CtorDeclaration; +import dmd.TypeIdentifier; +import dmd.STC; +import dmd.Argument; +import dmd.TypeTuple; +import dmd.TY; +import dmd.LINK; +import dmd.DsymbolTable; +import dmd.FuncDeclaration; +import dmd.Array; +import dmd.TypeClass; +import dmd.Module; +import dmd.Id; +import dmd.Type; +import dmd.OverloadSet; +import dmd.ArrayTypes; +import dmd.BaseClass; +import dmd.ClassInfoDeclaration; +import dmd.Loc; +import dmd.Identifier; +import dmd.Dsymbol; +import dmd.Scope; +import dmd.TypeFunction; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.VarDeclaration; +import dmd.Initializer; +import dmd.ExpInitializer; +import dmd.TypeSArray; +import dmd.ScopeDsymbol; +import dmd.PROT; +import dmd.Util; +import dmd.Global; + +import dmd.expression.Util; + +import dmd.backend.Symbol; +import dmd.backend.dt_t; +import dmd.backend.TYPE; +import dmd.backend.FL; +import dmd.backend.SFL; +import dmd.backend.mTY; +import dmd.backend.SC; +import dmd.backend.mTYman; +import dmd.backend.Util; +import dmd.backend.TYM; +import dmd.backend.Classsym; +import dmd.backend.glue; +import dmd.backend.RTLSYM; +import dmd.backend.LIST; + +import dmd.codegen.Util; + +import std.string; + +version (DMDV2) { + enum CLASSINFO_SIZE = (0x3C+16+4); // value of ClassInfo.size +} else { + enum CLASSINFO_SIZE = (0x3C+12+4); // value of ClassInfo.size +} + +enum OFFSET_RUNTIME = 0x76543210; + +struct Param +{ + int isf(FuncDeclaration fd2) + { + //printf("param = %p, fd = %p %s\n", param, fd, fd.toChars()); + return fd is fd2; + } + + FuncDeclaration fd; +} + +class ClassDeclaration : AggregateDeclaration +{ + static __gshared ClassDeclaration object; + static __gshared ClassDeclaration classinfo; + + ClassDeclaration baseClass; // null only if this is Object + FuncDeclaration staticCtor; + FuncDeclaration staticDtor; + Array vtbl; // Array of FuncDeclaration's making up the vtbl[] + Array vtblFinal; // More FuncDeclaration's that aren't in vtbl[] + + BaseClasses baseclasses; // Array of BaseClass's; first is super, + // rest are Interface's + + int interfaces_dim; + BaseClass* interfaces; // interfaces[interfaces_dim] for this class + // (does not include baseClass) + + BaseClasses vtblInterfaces; // array of base interfaces that have + // their own vtbl[] + + ClassInfoDeclaration vclassinfo; // the ClassInfo object for this ClassDeclaration + bool com; // true if this is a COM class (meaning + // it derives from IUnknown) + bool isauto; // true if this is an auto class + bool isabstract; // true if abstract class + + int inuse; // to prevent recursive attempts + + this(Loc loc, Identifier id, BaseClasses baseclasses) + { + super(loc, id); + + vtbl = new Array(); + vtblFinal = new Array(); + + enum msg = "only object.d can define this reserved class name"; + + if (baseclasses) { + this.baseclasses = baseclasses; + } else { + this.baseclasses = new BaseClasses(); + } + + //printf("ClassDeclaration(%s), dim = %d\n", id.toChars(), this.baseclasses.dim); + + // For forward references + type = new TypeClass(this); + + if (id) + { + // Look for special class names + + if (id is Id.__sizeof || id is Id.alignof_ || id is Id.mangleof_) + error("illegal class name"); + + // BUG: What if this is the wrong TypeInfo, i.e. it is nested? + if (id.toChars()[0] == 'T') + { + if (id is Id.TypeInfo) + { + if (Type.typeinfo) + Type.typeinfo.error("%s", msg); + Type.typeinfo = this; + } + + if (id is Id.TypeInfo_Class) + { + if (Type.typeinfoclass) + Type.typeinfoclass.error("%s", msg); + Type.typeinfoclass = this; + } + + if (id is Id.TypeInfo_Interface) + { + if (Type.typeinfointerface) + Type.typeinfointerface.error("%s", msg); + Type.typeinfointerface = this; + } + + if (id is Id.TypeInfo_Struct) + { + if (Type.typeinfostruct) + Type.typeinfostruct.error("%s", msg); + Type.typeinfostruct = this; + } + + if (id is Id.TypeInfo_Typedef) + { + if (Type.typeinfotypedef) + Type.typeinfotypedef.error("%s", msg); + Type.typeinfotypedef = this; + } + + if (id is Id.TypeInfo_Pointer) + { + if (Type.typeinfopointer) + Type.typeinfopointer.error("%s", msg); + Type.typeinfopointer = this; + } + + if (id is Id.TypeInfo_Array) + { + if (Type.typeinfoarray) + Type.typeinfoarray.error("%s", msg); + Type.typeinfoarray = this; + } + + if (id is Id.TypeInfo_StaticArray) + { //if (Type.typeinfostaticarray) + //Type.typeinfostaticarray.error("%s", msg); + Type.typeinfostaticarray = this; + } + + if (id is Id.TypeInfo_AssociativeArray) + { + if (Type.typeinfoassociativearray) + Type.typeinfoassociativearray.error("%s", msg); + Type.typeinfoassociativearray = this; + } + + if (id is Id.TypeInfo_Enum) + { + if (Type.typeinfoenum) + Type.typeinfoenum.error("%s", msg); + Type.typeinfoenum = this; + } + + if (id is Id.TypeInfo_Function) + { + if (Type.typeinfofunction) + Type.typeinfofunction.error("%s", msg); + Type.typeinfofunction = this; + } + + if (id is Id.TypeInfo_Delegate) + { + if (Type.typeinfodelegate) + Type.typeinfodelegate.error("%s", msg); + Type.typeinfodelegate = this; + } + + if (id is Id.TypeInfo_Tuple) + { + if (Type.typeinfotypelist) + Type.typeinfotypelist.error("%s", msg); + Type.typeinfotypelist = this; + } + + version (DMDV2) { + if (id is Id.TypeInfo_Const) + { + if (Type.typeinfoconst) + Type.typeinfoconst.error("%s", msg); + Type.typeinfoconst = this; + } + + if (id is Id.TypeInfo_Invariant) + { + if (Type.typeinfoinvariant) + Type.typeinfoinvariant.error("%s", msg); + Type.typeinfoinvariant = this; + } + + if (id is Id.TypeInfo_Shared) + { + if (Type.typeinfoshared) + Type.typeinfoshared.error("%s", msg); + Type.typeinfoshared = this; + } + } + } + + if (id is Id.Object_) + { + if (object) + object.error("%s", msg); + object = this; + } + + if (id is Id.ClassInfo) + { + if (classinfo) + classinfo.error("%s", msg); + classinfo = this; + } + + if (id is Id.ModuleInfo) + { + if (Module.moduleinfo) + Module.moduleinfo.error("%s", msg); + Module.moduleinfo = this; + } + } + + com = 0; + isauto = false; + isabstract = false; + inuse = 0; + } + + Dsymbol syntaxCopy(Dsymbol s) + { + assert(false); + } + + void semantic(Scope sc) + { + int i; + uint offset; + + //printf("ClassDeclaration.semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this); + //printf("\tparent = %p, '%s'\n", sc.parent, sc.parent ? sc.parent.toChars() : ""); + //printf("sc.stc = %x\n", sc.stc); + + //{ static int n; if (++n == 20) *(char*)0=0; } + + if (!ident) // if anonymous class + { + string id = "__anonclass"; + ident = Identifier.generateId(id); + } + + if (!sc) + sc = scope_; + + if (!parent && sc.parent && !sc.parent.isModule()) + parent = sc.parent; + + type = type.semantic(loc, sc); + handle = type; + + if (!members) // if forward reference + { + //printf("\tclass '%s' is forward referenced\n", toChars()); + return; + } + if (symtab) + { if (!scope_) + { //printf("\tsemantic for '%s' is already completed\n", toChars()); + return; // semantic() already completed + } + } + else + symtab = new DsymbolTable(); + + Scope scx = null; + if (scope_) + { sc = scope_; + scx = scope_; // save so we don't make redundant copies + scope_ = null; + } +version (IN_GCC) { + methods.setDim(0); +} + + if (sc.stc & STC.STCdeprecated) + { + isdeprecated = 1; + } + + if (sc.linkage == LINK.LINKcpp) + error("cannot create C++ classes"); + + // Expand any tuples in baseclasses[] + for (i = 0; i < baseclasses.dim; ) + { + BaseClass b = cast(BaseClass)baseclasses.data[i]; + //printf("test1 %s %s\n", toChars(), b.type.toChars()); + b.type = b.type.semantic(loc, sc); + //printf("test2\n"); + Type tb = b.type.toBasetype(); + + if (tb.ty == TY.Ttuple) + { + TypeTuple tup = cast(TypeTuple)tb; + enum PROT protection = b.protection; + baseclasses.remove(i); + size_t dim = Argument.dim(tup.arguments); + for (size_t j = 0; j < dim; j++) + { + Argument arg = Argument.getNth(tup.arguments, j); + b = new BaseClass(arg.type, protection); + baseclasses.insert(i + j, cast(void*)b); + } + } + else + i++; + } + + // See if there's a base class as first in baseclasses[] + if (baseclasses.dim) + { + TypeClass tc; + BaseClass b; + Type tb; + + b = cast(BaseClass)baseclasses.data[0]; + //b.type = b.type.semantic(loc, sc); + tb = b.type.toBasetype(); + if (tb.ty != TY.Tclass) + { error("base type must be class or interface, not %s", b.type.toChars()); + baseclasses.remove(0); + } + else + { + tc = cast(TypeClass)(tb); + + if (tc.sym.isDeprecated()) + { + if (!isDeprecated()) + { + // Deriving from deprecated class makes this one deprecated too + isdeprecated = 1; + + tc.checkDeprecated(loc, sc); + } + } + + if (tc.sym.isInterfaceDeclaration()) { + ; + } else { + for (ClassDeclaration cdb = tc.sym; cdb; cdb = cdb.baseClass) + { + if (cdb == this) + { + error("circular inheritance"); + baseclasses.remove(0); + goto L7; + } + } + if (!tc.sym.symtab || tc.sym.sizeok == 0) + { // Try to resolve forward reference + if (sc.mustsemantic && tc.sym.scope_) + tc.sym.semantic(null); + } + if (!tc.sym.symtab || tc.sym.scope_ || tc.sym.sizeok == 0) + { + //printf("%s: forward reference of base class %s\n", toChars(), tc.sym.toChars()); + //error("forward reference of base class %s", baseClass.toChars()); + // Forward reference of base class, try again later + //printf("\ttry later, forward reference of base class %s\n", tc.sym.toChars()); + scope_ = scx ? scx : new Scope(sc); + scope_.setNoFree(); + if (tc.sym.scope_) + tc.sym.scope_.module_.addDeferredSemantic(tc.sym); + scope_.module_.addDeferredSemantic(this); + return; + } + else + { baseClass = tc.sym; + b.base = baseClass; + } + L7: ; + } + } + } + + // Treat the remaining entries in baseclasses as interfaces + // Check for errors, handle forward references + for (i = (baseClass ? 1 : 0); i < baseclasses.dim; ) + { TypeClass tc; + BaseClass b; + Type tb; + + b = cast(BaseClass)baseclasses.data[i]; + b.type = b.type.semantic(loc, sc); + tb = b.type.toBasetype(); + if (tb.ty == TY.Tclass) + tc = cast(TypeClass)tb; + else + tc = null; + if (!tc || !tc.sym.isInterfaceDeclaration()) + { + error("base type must be interface, not %s", b.type.toChars()); + baseclasses.remove(i); + continue; + } + else + { + if (tc.sym.isDeprecated()) + { + if (!isDeprecated()) + { + // Deriving from deprecated class makes this one deprecated too + isdeprecated = 1; + + tc.checkDeprecated(loc, sc); + } + } + + // Check for duplicate interfaces + for (size_t j = (baseClass ? 1 : 0); j < i; j++) + { + BaseClass b2 = cast(BaseClass)baseclasses.data[j]; + if (b2.base == tc.sym) + error("inherits from duplicate interface %s", b2.base.toChars()); + } + + if (!tc.sym.symtab) + { // Try to resolve forward reference + if (sc.mustsemantic && tc.sym.scope_) + tc.sym.semantic(null); + } + + b.base = tc.sym; + if (!b.base.symtab || b.base.scope_) + { + //error("forward reference of base class %s", baseClass.toChars()); + // Forward reference of base, try again later + //printf("\ttry later, forward reference of base %s\n", baseClass.toChars()); + scope_ = scx ? scx : new Scope(sc); + scope_.setNoFree(); + if (tc.sym.scope_) + tc.sym.scope_.module_.addDeferredSemantic(tc.sym); + scope_.module_.addDeferredSemantic(this); + return; + } + } + i++; + } + + + // If no base class, and this is not an Object, use Object as base class + if (!baseClass && ident !is Id.Object_) + { + // BUG: what if Object is redefined in an inner scope? + Type tbase = new TypeIdentifier(Loc(0), Id.Object_); + BaseClass b; + TypeClass tc; + Type bt; + + if (!object) + { + error("missing or corrupt object.d"); + fatal(); + } + bt = tbase.semantic(loc, sc).toBasetype(); + b = new BaseClass(bt, PROT.PROTpublic); + baseclasses.shift(cast(void*)b); + assert(b.type.ty == TY.Tclass); + tc = cast(TypeClass)(b.type); + baseClass = tc.sym; + assert(!baseClass.isInterfaceDeclaration()); + b.base = baseClass; + } + + interfaces_dim = baseclasses.dim; + interfaces = cast(BaseClass*)baseclasses.data; + + if (baseClass) + { + if (baseClass.storage_class & STC.STCfinal) + error("cannot inherit from final class %s", baseClass.toChars()); + + interfaces_dim--; + interfaces++; + + // Copy vtbl[] from base class + vtbl.setDim(baseClass.vtbl.dim); + memcpy(vtbl.data, baseClass.vtbl.data, (void*).sizeof * vtbl.dim); + + // Inherit properties from base class + com = baseClass.isCOMclass(); + isauto = baseClass.isauto; + vthis = baseClass.vthis; + storage_class |= baseClass.storage_class & STC.STC_TYPECTOR; + } + else + { + // No base class, so this is the root of the class hierarchy + vtbl.setDim(0); + vtbl.push(cast(void*)this); // leave room for classinfo as first member + } + + protection = sc.protection; + storage_class |= sc.stc; + + if (sizeok == 0) + { + interfaceSemantic(sc); + + for (i = 0; i < members.dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + s.addMember(sc, this, 1); + } + + /* If this is a nested class, add the hidden 'this' + * member which is a pointer to the enclosing scope. + */ + if (vthis) // if inheriting from nested class + { // Use the base class's 'this' member + isnested = true; + if (storage_class & STC.STCstatic) + error("static class cannot inherit from nested class %s", baseClass.toChars()); + if (toParent2() != baseClass.toParent2()) + { + if (toParent2()) + { + error("is nested within %s, but super class %s is nested within %s", + toParent2().toChars(), + baseClass.toChars(), + baseClass.toParent2().toChars()); + } + else + { + error("is not nested, but super class %s is nested within %s", + baseClass.toChars(), + baseClass.toParent2().toChars()); + } + isnested = false; + } + } + else if (!(storage_class & STC.STCstatic)) + { + Dsymbol s = toParent2(); + if (s) + { + AggregateDeclaration ad = s.isClassDeclaration(); + FuncDeclaration fd = s.isFuncDeclaration(); + + if (ad || fd) + { isnested = true; + Type t; + if (ad) + t = ad.handle; + else if (fd) + { + AggregateDeclaration ad2 = fd.isMember2(); + if (ad2) + t = ad2.handle; + else + { + t = Type.tvoidptr; + } + } + else + assert(0); + if (t.ty == TY.Tstruct) // ref to struct + t = Type.tvoidptr; + assert(!vthis); + vthis = new ThisDeclaration(loc, t); + members.push(cast(void*)vthis); + } + } + } + } + + if (storage_class & (STC.STCauto | STC.STCscope)) + isauto = true; + if (storage_class & STC.STCabstract) + isabstract = true; + if (storage_class & STC.STCimmutable) + type = type.invariantOf(); + else if (storage_class & STC.STCconst) + type = type.constOf(); + else if (storage_class & STC.STCshared) + type = type.sharedOf(); + + sc = sc.push(this); + sc.stc &= ~(STC.STCfinal | STC.STCauto | STC.STCscope | STC.STCstatic | + STC.STCabstract | STC.STCdeprecated | STC.STC_TYPECTOR | STC.STCtls | STC.STCgshared); + sc.stc |= storage_class & STC.STC_TYPECTOR; + sc.parent = this; + sc.inunion = 0; + + if (isCOMclass()) + { +version (_WIN32) { + sc.linkage = LINK.LINKwindows; +} else { + /* This enables us to use COM objects under Linux and + * work with things like XPCOM + */ + sc.linkage = LINK.LINKc; +} + } + sc.protection = PROT.PROTpublic; + sc.explicitProtection = 0; + sc.structalign = 8; + structalign = sc.structalign; + if (baseClass) + { sc.offset = baseClass.structsize; + alignsize = baseClass.alignsize; + // if (isnested) + // sc.offset += PTRSIZE; // room for uplevel context pointer + } + else + { sc.offset = PTRSIZE * 2; // allow room for __vptr and __monitor + alignsize = PTRSIZE; + } + structsize = sc.offset; + Scope scsave = sc; /// a copy must be created? + int members_dim = members.dim; + sizeok = 0; + for (i = 0; i < members_dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + s.semantic(sc); + } + + if (sizeok == 2) + { // semantic() failed because of forward references. + // Unwind what we did, and defer it for later + fields.setDim(0); + structsize = 0; + alignsize = 0; + structalign = 0; + + sc = sc.pop(); + + scope_ = scx ? scx : new Scope(sc); + scope_.setNoFree(); + scope_.module_.addDeferredSemantic(this); + + //printf("\tsemantic('%s') failed due to forward references\n", toChars()); + return; + } + + //printf("\tsemantic('%s') successful\n", toChars()); + + structsize = sc.offset; + //members.print(); + + /* Look for special member functions. + * They must be in this class, not in a base class. + */ + ctor = cast(CtorDeclaration)search(Loc(0), Id.ctor, 0); + if (ctor && (ctor.toParent() != this || !ctor.isCtorDeclaration())) + ctor = null; + + // dtor = (DtorDeclaration *)search(Id.dtor, 0); + // if (dtor && dtor.toParent() != this) + // dtor = null; + + // inv = (InvariantDeclaration *)search(Id.classInvariant, 0); + // if (inv && inv.toParent() != this) + // inv = null; + + // Can be in base class + aggNew = cast(NewDeclaration)search(Loc(0), Id.classNew, 0); + aggDelete = cast(DeleteDeclaration)search(Loc(0), Id.classDelete, 0); + + // If this class has no constructor, but base class does, create + // a constructor: + // this() { } + if (!ctor && baseClass && baseClass.ctor) + { + //printf("Creating default this(){} for class %s\n", toChars()); + CtorDeclaration ctor = new CtorDeclaration(loc, Loc(0), null, 0); + ctor.fbody = new CompoundStatement(Loc(0), new Statements()); + members.push(cast(void*)ctor); + ctor.addMember(sc, this, 1); + sc = scsave; // why? What about sc.nofree? /// + sc.offset = structsize; + ctor.semantic(sc); + this.ctor = ctor; + defaultCtor = ctor; + } + +static if (false) { + if (baseClass) + { if (!aggDelete) + aggDelete = baseClass.aggDelete; + if (!aggNew) + aggNew = baseClass.aggNew; + } +} + + // Allocate instance of each new interface + for (i = 0; i < vtblInterfaces.dim; i++) + { + BaseClass b = cast(BaseClass)vtblInterfaces.data[i]; + uint thissize = PTRSIZE; + + alignmember(structalign, thissize, &sc.offset); + assert(b.offset == 0); + b.offset = sc.offset; + + // Take care of single inheritance offsets + while (b.baseInterfaces.length) + { + b = b.baseInterfaces[0]; + b.offset = sc.offset; + } + + sc.offset += thissize; + if (alignsize < thissize) + alignsize = thissize; + } + structsize = sc.offset; + sizeok = 1; + Module.dprogress++; + + dtor = buildDtor(sc); + + sc.pop(); + +static if (false) { // Do not call until toObjfile() because of forward references + // Fill in base class vtbl[]s + for (i = 0; i < vtblInterfaces.dim; i++) + { + BaseClass b = cast(BaseClass)vtblInterfaces.data[i]; + + //b.fillVtbl(this, &b.vtbl, 1); + } +} + //printf("-ClassDeclaration.semantic(%s), type = %p\n", toChars(), type); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + /********************************************* + * Determine if 'this' is a base class of cd. + * This is used to detect circular inheritance only. + */ + int isBaseOf2(ClassDeclaration cd) + { + if (!cd) + return 0; + //printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd.toChars()); + for (int i = 0; i < cd.baseclasses.dim; i++) + { + BaseClass b = cast(BaseClass)cd.baseclasses.data[i]; + + if (b.base is this || isBaseOf2(b.base)) + return 1; + } + return 0; + } + + /******************************************* + * Determine if 'this' is a base class of cd. + */ +/// #define OFFSET_RUNTIME 0x76543210 + bool isBaseOf(ClassDeclaration cd, int* poffset) + { + if (!cd) + return 0; + //printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd.toChars()); + for (int i = 0; i < cd.baseclasses.dim; i++) + { + BaseClass b = cast(BaseClass)cd.baseclasses.data[i]; + + if (b.base == this || isBaseOf2(b.base)) + return 1; + } + + return 0; + } + + Dsymbol search(Loc, Identifier ident, int flags) + { + Dsymbol s; + //printf("%s.ClassDeclaration.search('%s')\n", toChars(), ident.toChars()); + + if (scope_) + { + Scope sc = scope_; + sc.mustsemantic++; + semantic(sc); + sc.mustsemantic--; + } + + if (!members || !symtab || scope_) + { + error("is forward referenced when looking for '%s'", ident.toChars()); + //*(char*)0=0; + return null; + } + + s = ScopeDsymbol.search(loc, ident, flags); + if (!s) + { + // Search bases classes in depth-first, left to right order + + int i; + + for (i = 0; i < baseclasses.dim; i++) + { + BaseClass b = cast(BaseClass)baseclasses.data[i]; + + if (b.base) + { + if (!b.base.symtab) + error("base %s is forward referenced", b.base.ident.toChars()); + else + { + s = b.base.search(loc, ident, flags); + if (s is this) // happens if s is nested in this and derives from this + s = null; + else if (s) + break; + } + } + } + } + return s; + } + +version (DMDV2) { + bool isFuncHidden(FuncDeclaration fd) + { + //printf("ClassDeclaration::isFuncHidden(class = %s, fd = %s)\n", toChars(), fd.toChars()); + Dsymbol s = search(Loc(0), fd.ident, 4|2); + if (!s) + { + //printf("not found\n"); + /* Because, due to a hack, if there are multiple definitions + * of fd.ident, null is returned. + */ + return false; + } + + Param p; p.fd = fd; + + s = s.toAlias(); + OverloadSet os = s.isOverloadSet(); + if (os) + { + for (int i = 0; i < os.a.dim; i++) + { + Dsymbol s2 = cast(Dsymbol)os.a.data[i]; + FuncDeclaration f2 = s2.isFuncDeclaration(); + if (f2 && overloadApply(f2, &p.isf)) + return false; + } + return true; + } + else + { + FuncDeclaration fdstart = s.isFuncDeclaration(); + //printf("%s fdstart = %p\n", s.kind(), fdstart); + return !overloadApply(fdstart, &p.isf); + } + } +} + FuncDeclaration findFunc(Identifier ident, TypeFunction tf) + { + //printf("ClassDeclaration.findFunc(%s, %s) %s\n", ident.toChars(), tf.toChars(), toChars()); + + ClassDeclaration cd = this; + Array vtbl = cd.vtbl; + while (true) + { + for (size_t i = 0; i < vtbl.dim; i++) + { + FuncDeclaration fd = (cast(Dsymbol)vtbl.data[i]).isFuncDeclaration(); + if (!fd) + continue; // the first entry might be a ClassInfo + + //printf("\t[%d] = %s\n", i, fd.toChars()); + if (ident == fd.ident && + //tf.equals(fd.type) + fd.type.covariant(tf) == 1 + ) + { //printf("\t\tfound\n"); + return fd; + } + //else printf("\t\t%d\n", fd.type.covariant(tf)); + } + if (!cd) + break; + + vtbl = cd.vtblFinal; + cd = cd.baseClass; + } + + return null; + } + + void interfaceSemantic(Scope sc) + { + InterfaceDeclaration id = isInterfaceDeclaration(); + + vtblInterfaces = new BaseClasses(); + vtblInterfaces.reserve(interfaces_dim); + + for (size_t i = 0; i < interfaces_dim; i++) + { + BaseClass b = interfaces[i]; + + // If this is an interface, and it derives from a COM interface, + // then this is a COM interface too. + if (b.base.isCOMinterface()) + com = 1; + + if (b.base.isCPPinterface() && id) + id.cpp = 1; + + vtblInterfaces.push(cast(void*)b); + b.copyBaseInterfaces(vtblInterfaces); + } + } + + bool isCOMclass() + { + return com; + } + + bool isCOMinterface() + { + return false; + } + +version (DMDV2) { + bool isCPPinterface() + { + return false; + } +} + bool isAbstract() + { + if (isabstract) + return true; + + for (int i = 1; i < vtbl.dim; i++) + { + FuncDeclaration fd = (cast(Dsymbol)vtbl.data[i]).isFuncDeclaration(); + + //printf("\tvtbl[%d] = %p\n", i, fd); + if (!fd || fd.isAbstract()) + { + isabstract = true; + return true; + } + } + + return false; + } + + int vtblOffset() + { + assert(false); + } + + string kind() + { + return "class"; + } + + string mangle() + { + Dsymbol parentsave = parent; + + //printf("ClassDeclaration.mangle() %s.%s\n", parent.toChars(), toChars()); + + /* These are reserved to the compiler, so keep simple + * names for them. + */ + if (ident is Id.Exception) + { + if (parent.ident is Id.object) + parent = null; + } + else if (ident is Id.TypeInfo || + // ident is Id.Exception || + ident is Id.TypeInfo_Struct || + ident is Id.TypeInfo_Class || + ident is Id.TypeInfo_Typedef || + ident is Id.TypeInfo_Tuple || + this is object || + this is classinfo || + this is Module.moduleinfo || + ident.toChars().startsWith("TypeInfo_") + ) + { + parent = null; + } + + string id = Dsymbol.mangle(); + parent = parentsave; + return id; + } + + void toDocBuffer(OutBuffer buf) + { + assert(false); + } + + PROT getAccess(Dsymbol smember) // determine access to smember + { + PROT access_ret = PROT.PROTnone; + + version (LOG) { + printf("+ClassDeclaration::getAccess(this = '%s', smember = '%s')\n", + toChars(), smember.toChars()); + } + if (smember.toParent() is this) + { + access_ret = smember.prot(); + } + else + { + PROT access; + int i; + + if (smember.isDeclaration().isStatic()) + { + access_ret = smember.prot(); + } + + for (i = 0; i < baseclasses.dim; i++) + { + BaseClass b = cast(BaseClass)baseclasses.data[i]; + + access = b.base.getAccess(smember); + switch (access) + { + case PROT.PROTnone: + break; + + case PROT.PROTprivate: + access = PROT.PROTnone; // private members of base class not accessible + break; + + case PROT.PROTpackage: + case PROT.PROTprotected: + case PROT.PROTpublic: + case PROT.PROTexport: + // If access is to be tightened + if (b.protection < access) + access = b.protection; + + // Pick path with loosest access + if (access > access_ret) + access_ret = access; + break; + + default: + assert(0); + } + } + } + + version (LOG) { + printf("-ClassDeclaration::getAccess(this = '%s', smember = '%s') = %d\n", + toChars(), smember.toChars(), access_ret); + } + + return access_ret; + } + + void addLocalClass(ClassDeclarations aclasses) + { + aclasses.push(cast(void*)this); + } + + // Back end + void toObjFile(int multiobj) // compile to .obj file + { + uint i; + uint offset; + Symbol* sinit; + enum_SC scclass; + + //printf("ClassDeclaration.toObjFile('%s')\n", toChars()); + + if (!members) + return; + + if (multiobj) + { + obj_append(this); + return; + } + + if (global.params.symdebug) + toDebug(); + + assert(!scope_); // semantic() should have been run to completion + + scclass = SCglobal; + if (inTemplateInstance()) + scclass = SCcomdat; + + // Put out the members + for (i = 0; i < members.dim; i++) + { + Dsymbol member; + + member = cast(Dsymbol)members.data[i]; + member.toObjFile(0); + } + +static if (false) { + // Build destructor by aggregating dtors[] + Symbol* sdtor; + switch (dtors.dim) + { + case 0: + // No destructors for this class + sdtor = null; + break; + + case 1: + // One destructor, just use it directly + sdtor = (cast(DtorDeclaration)dtors.data[0]).toSymbol(); + break; + + default: + { + /* Build a destructor that calls all the + * other destructors in dtors[]. + */ + + elem* edtor = null; + + // Declare 'this' pointer for our new destructor + Symbol* sthis = symbol_calloc("this"); + sthis.Stype = type_fake(TYnptr); + sthis.Stype.Tcount++; + sthis.Sclass = SCfastpar; + sthis.Spreg = AX; + sthis.Sfl = FLauto; + + // Call each of the destructors in dtors[] + // in reverse order + for (i = 0; i < dtors.dim; i++) + { + DtorDeclaration d = cast(DtorDeclaration)dtors.data[i]; + Symbol* s = d.toSymbol(); + elem* e = el_bin(OPcall, TYvoid, el_var(s), el_var(sthis)); + edtor = el_combine(e, edtor); + } + + // Create type for the function + .type* t = type_alloc(TYjfunc); + t.Tflags |= TFprototype | TFfixed; + t.Tmangle = mTYman_d; + t.Tnext = tsvoid; + tsvoid.Tcount++; + + // Create the function, sdtor, and write it out + localgot = null; + sdtor = toSymbolX("__dtor", SCglobal, t, "FZv"); + block* b = block_calloc(); + b.BC = BCret; + b.Belem = edtor; + sdtor.Sfunc.Fstartblock = b; + cstate.CSpsymtab = &sdtor.Sfunc.Flocsym; + symbol_add(sthis); + writefunc(sdtor); + } + } +} + + // Generate C symbols + toSymbol(); + toVtblSymbol(); + sinit = toInitializer(); + + ////////////////////////////////////////////// + + // Generate static initializer + sinit.Sclass = scclass; + sinit.Sfl = FLdata; + version (ELFOBJ) { // Burton + sinit.Sseg = CDATA; + } + version (MACHOBJ) { + sinit.Sseg = DATA; + } + toDt(&sinit.Sdt); + outdata(sinit); + + ////////////////////////////////////////////// + + // Put out the TypeInfo + type.getTypeInfo(null); + type.vtinfo.toObjFile(multiobj); + + ////////////////////////////////////////////// + + // Put out the ClassInfo + csym.Sclass = scclass; + csym.Sfl = FLdata; + + /* The layout is: + { + void **vptr; + monitor_t monitor; + byte[] initializer; // static initialization data + char[] name; // class name + void *[] vtbl; + Interface[] interfaces; + ClassInfo *base; // base class + void *destructor; + void *invariant; // class invariant + uint flags; + void *deallocator; + OffsetTypeInfo[] offTi; + void *defaultConstructor; + const(MemberInfo[]) function(string) xgetMembers; // module getMembers() function + TypeInfo typeinfo; + } + */ + dt_t* dt = null; + offset = CLASSINFO_SIZE; // must be ClassInfo.size + if (classinfo) + { + if (classinfo.structsize != CLASSINFO_SIZE) + error("D compiler and phobos' object.d are mismatched"); + } + + if (classinfo) + dtxoff(&dt, classinfo.toVtblSymbol(), 0, TYnptr); // vtbl for ClassInfo + else + dtdword(&dt, 0); // BUG: should be an assert() + + dtdword(&dt, 0); // monitor + + // initializer[] + assert(structsize >= 8); + dtdword(&dt, structsize); // size + dtxoff(&dt, sinit, 0, TYnptr); // initializer + + // name[] + string name = ident.toChars(); + size_t namelen = name.length; + if (!(namelen > 9 && name[0..9] == "TypeInfo_")) + { + name = toPrettyChars(); + namelen = name.length; + } + dtdword(&dt, namelen); + dtabytes(&dt, TYnptr, 0, namelen + 1, toStringz(name)); + + // vtbl[] + dtdword(&dt, vtbl.dim); + dtxoff(&dt, vtblsym, 0, TYnptr); + + // interfaces[] + dtdword(&dt, vtblInterfaces.dim); + if (vtblInterfaces.dim) + dtxoff(&dt, csym, offset, TYnptr); // (*) + else + dtdword(&dt, 0); + + // base + if (baseClass) + dtxoff(&dt, baseClass.toSymbol(), 0, TYnptr); + else + dtdword(&dt, 0); + + // destructor + if (dtor) + dtxoff(&dt, dtor.toSymbol(), 0, TYnptr); + else + dtdword(&dt, 0); + + // invariant + if (inv) + dtxoff(&dt, inv.toSymbol(), 0, TYnptr); + else + dtdword(&dt, 0); + + // flags + int flags = 4 | isCOMclass(); + version (DMDV2) { + flags |= 16; + } + flags |= 32; + + if (ctor) + flags |= 8; + for (ClassDeclaration cd = this; cd; cd = cd.baseClass) + { + if (cd.members) + { + for (size_t j = 0; j < cd.members.dim; j++) + { + Dsymbol sm = cast(Dsymbol)cd.members.data[j]; + //printf("sm = %s %s\n", sm.kind(), sm.toChars()); + if (sm.hasPointers()) + goto L2; + } + } + } + flags |= 2; // no pointers + L2: + dtdword(&dt, flags); + + + // deallocator + if (aggDelete) + dtxoff(&dt, aggDelete.toSymbol(), 0, TYnptr); + else + dtdword(&dt, 0); + + // offTi[] + dtdword(&dt, 0); + dtdword(&dt, 0); // null for now, fix later + + // defaultConstructor + if (defaultCtor) + dtxoff(&dt, defaultCtor.toSymbol(), 0, TYnptr); + else + dtdword(&dt, 0); + + version (DMDV2) { + FuncDeclaration sgetmembers = findGetMembers(); + if (sgetmembers) + dtxoff(&dt, sgetmembers.toSymbol(), 0, TYnptr); + else + dtdword(&dt, 0); // module getMembers() function + } + + dtxoff(&dt, type.vtinfo.toSymbol(), 0, TYnptr); // typeinfo + //dtdword(&dt, 0); + + ////////////////////////////////////////////// + + // Put out vtblInterfaces.data[]. Must immediately follow csym, because + // of the fixup (*) + + offset += vtblInterfaces.dim * (4 * PTRSIZE); + for (i = 0; i < vtblInterfaces.dim; i++) + { + BaseClass b = cast(BaseClass)vtblInterfaces.data[i]; + ClassDeclaration id = b.base; + + /* The layout is: + * { + * ClassInfo *interface; + * void *[] vtbl; + * unsigned offset; + * } + */ + + // Fill in vtbl[] + b.fillVtbl(this, b.vtbl, 1); + + dtxoff(&dt, id.toSymbol(), 0, TYnptr); // ClassInfo + + // vtbl[] + dtdword(&dt, id.vtbl.dim); + dtxoff(&dt, csym, offset, TYnptr); + + dtdword(&dt, b.offset); // this offset + + offset += id.vtbl.dim * PTRSIZE; + } + + // Put out the vtblInterfaces.data[].vtbl[] + // This must be mirrored with ClassDeclaration.baseVtblOffset() + //printf("putting out %d interface vtbl[]s for '%s'\n", vtblInterfaces.dim, toChars()); + for (i = 0; i < vtblInterfaces.dim; i++) + { + BaseClass b = cast(BaseClass)vtblInterfaces.data[i]; + ClassDeclaration id = b.base; + int j; + + //printf(" interface[%d] is '%s'\n", i, id.toChars()); + j = 0; + if (id.vtblOffset()) + { + // First entry is ClassInfo reference + //dtxoff(&dt, id.toSymbol(), 0, TYnptr); + + // First entry is struct Interface reference + dtxoff(&dt, csym, CLASSINFO_SIZE + i * (4 * PTRSIZE), TYnptr); + j = 1; + } + + assert(id.vtbl.dim == b.vtbl.dim); + for (; j < id.vtbl.dim; j++) + { + FuncDeclaration fd; + + assert(j < b.vtbl.dim); + static if (false) { + Object o = cast(Object)b.vtbl.data[j]; + if (o) + { + printf("o = %p\n", o); + assert(o.dyncast() == DYNCAST_DSYMBOL); + Dsymbol s = cast(Dsymbol)o; + printf("s.kind() = '%s'\n", s.kind()); + } + } + fd = cast(FuncDeclaration)b.vtbl.data[j]; + if (fd) + dtxoff(&dt, fd.toThunkSymbol(b.offset), 0, TYnptr); + else + dtdword(&dt, 0); + } + } + + static if (true) { + // Put out the overriding interface vtbl[]s. + // This must be mirrored with ClassDeclaration.baseVtblOffset() + //printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset); + ClassDeclaration cd; + scope Array bvtbl = new Array(); + + for (cd = this.baseClass; cd; cd = cd.baseClass) + { + for (int k = 0; k < cd.vtblInterfaces.dim; k++) + { + BaseClass bs = cast(BaseClass)cd.vtblInterfaces.data[k]; + + if (bs.fillVtbl(this, bvtbl, 0)) + { + //printf("\toverriding vtbl[] for %s\n", bs.base.toChars()); + ClassDeclaration id = bs.base; + int j; + + j = 0; + if (id.vtblOffset()) + { + // First entry is ClassInfo reference + //dtxoff(&dt, id.toSymbol(), 0, TYnptr); + + // First entry is struct Interface reference + dtxoff(&dt, cd.toSymbol(), CLASSINFO_SIZE + k * (4 * PTRSIZE), TYnptr); + j = 1; + } + + for (; j < id.vtbl.dim; j++) + { + assert(j < bvtbl.dim); + FuncDeclaration fd = cast(FuncDeclaration)bvtbl.data[j]; + if (fd) + dtxoff(&dt, fd.toThunkSymbol(bs.offset), 0, TYnptr); + else + dtdword(&dt, 0); + } + } + } + } + } + + version (INTERFACE_VIRTUAL) { + // Put out the overriding interface vtbl[]s. + // This must be mirrored with ClassDeclaration.baseVtblOffset() + //printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset); + for (i = 0; i < vtblInterfaces.dim; i++) + { + BaseClass b = cast(BaseClass)vtblInterfaces.data[i]; + ClassDeclaration cd; + + for (cd = this.baseClass; cd; cd = cd.baseClass) + { + for (int k = 0; k < cd.vtblInterfaces.dim; k++) + { + BaseClass bs = cast(BaseClass)cd.vtblInterfaces.data[k]; + + if (b.base == bs.base) + { + //printf("\toverriding vtbl[] for %s\n", b.base.toChars()); + ClassDeclaration id = b.base; + int j; + + j = 0; + if (id.vtblOffset()) + { + // First entry is ClassInfo reference + //dtxoff(&dt, id.toSymbol(), 0, TYnptr); + + // First entry is struct Interface reference + dtxoff(&dt, cd.toSymbol(), CLASSINFO_SIZE + k * (4 * PTRSIZE), TYnptr); + j = 1; + } + + for (; j < id.vtbl.dim; j++) + { + assert(j < b.vtbl.dim); + FuncDeclaration fd = cast(FuncDeclaration)b.vtbl.data[j]; + if (fd) + dtxoff(&dt, fd.toThunkSymbol(bs.offset), 0, TYnptr); + else + dtdword(&dt, 0); + } + } + } + } + } + } + + + csym.Sdt = dt; + version (ELFOBJ_OR_MACHOBJ) { // Burton + // ClassInfo cannot be const data, because we use the monitor on it + csym.Sseg = DATA; + } + outdata(csym); + if (isExport()) + obj_export(csym,0); + + ////////////////////////////////////////////// + + // Put out the vtbl[] + //printf("putting out %s.vtbl[]\n", toChars()); + dt = null; + if (0) + i = 0; + else + { + dtxoff(&dt, csym, 0, TYnptr); // first entry is ClassInfo reference + i = 1; + } + for (; i < vtbl.dim; i++) + { + FuncDeclaration fd = (cast(Dsymbol)vtbl.data[i]).isFuncDeclaration(); + + //printf("\tvtbl[%d] = %p\n", i, fd); + if (fd && (fd.fbody || !isAbstract())) + { + Symbol* s = fd.toSymbol(); + + version (DMDV2) { + if (isFuncHidden(fd)) + { + /* fd is hidden from the view of this class. + * If fd overlaps with any function in the vtbl[], then + * issue 'hidden' error. + */ + for (int j = 1; j < vtbl.dim; j++) + { + if (j == i) + continue; + FuncDeclaration fd2 = (cast(Dsymbol)vtbl.data[j]).isFuncDeclaration(); + if (!fd2.ident.equals(fd.ident)) + continue; + if (fd.leastAsSpecialized(fd2) || fd2.leastAsSpecialized(fd)) + { + if (global.params.warnings) + { + TypeFunction tf = cast(TypeFunction)fd.type; + if (tf.ty == Tfunction) + warning("%s%s is hidden by %s\n", fd.toPrettyChars(), Argument.argsTypesToChars(tf.parameters, tf.varargs), toChars()); + else + warning("%s is hidden by %s\n", fd.toPrettyChars(), toChars()); + } + s = rtlsym[RTLSYM_DHIDDENFUNC]; + break; + } + } + } + } + dtxoff(&dt, s, 0, TYnptr); + } + else + dtdword(&dt, 0); + } + + vtblsym.Sdt = dt; + vtblsym.Sclass = scclass; + vtblsym.Sfl = FLdata; + version (ELFOBJ) { + vtblsym.Sseg = CDATA; + } + version (MACHOBJ) { + vtblsym.Sseg = DATA; + } + outdata(vtblsym); + if (isExport()) + obj_export(vtblsym,0); + } + + void toDebug() + { + assert(false); + } + + /****************************************** + * Get offset of base class's vtbl[] initializer from start of csym. + * Returns ~0 if not this csym. + */ + uint baseVtblOffset(BaseClass bc) + { + uint csymoffset; + int i; + + //printf("ClassDeclaration.baseVtblOffset('%s', bc = %p)\n", toChars(), bc); + csymoffset = CLASSINFO_SIZE; + csymoffset += vtblInterfaces.dim * (4 * PTRSIZE); + + for (i = 0; i < vtblInterfaces.dim; i++) + { + BaseClass b = cast(BaseClass)vtblInterfaces.data[i]; + + if (b == bc) + return csymoffset; + csymoffset += b.base.vtbl.dim * PTRSIZE; + } + + static if (true) { + // Put out the overriding interface vtbl[]s. + // This must be mirrored with ClassDeclaration.baseVtblOffset() + //printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset); + ClassDeclaration cd; + Array bvtbl; + + for (cd = this.baseClass; cd; cd = cd.baseClass) + { + for (int k = 0; k < cd.vtblInterfaces.dim; k++) + { + BaseClass bs = cast(BaseClass)cd.vtblInterfaces.data[k]; + + if (bs.fillVtbl(this, null, 0)) + { + if (bc == bs) + { + //printf("\tcsymoffset = x%x\n", csymoffset); + return csymoffset; + } + csymoffset += bs.base.vtbl.dim * PTRSIZE; + } + } + } + } + version (INTERFACE_VIRTUAL) { + for (i = 0; i < vtblInterfaces.dim; i++) + { + BaseClass b = cast(BaseClass)vtblInterfaces.data[i]; + ClassDeclaration cd; + + for (cd = this.baseClass; cd; cd = cd.baseClass) + { + //printf("\tbase class %s\n", cd.toChars()); + for (int k = 0; k < cd.vtblInterfaces.dim; k++) + { + BaseClass bs = cast(BaseClass)cd.vtblInterfaces.data[k]; + + if (bc == bs) + { + //printf("\tcsymoffset = x%x\n", csymoffset); + return csymoffset; + } + if (b.base == bs.base) + csymoffset += bs.base.vtbl.dim * PTRSIZE; + } + } + } + } + + return ~0; + } + + static private __gshared Classsym* scc; + + /************************************* + * Create the "ClassInfo" symbol + */ + Symbol* toSymbol() + { + if (!csym) + { + Symbol* s; + + if (!scc) + scc = fake_classsym(Id.ClassInfo); + + s = toSymbolX("__Class", SC.SCextern, scc.Stype, "Z"); + s.Sfl = FL.FLextern; + s.Sflags |= SFL.SFLnodebug; + csym = s; + slist_add(s); + } + + return csym; + } + + /************************************* + * This is accessible via the ClassData, but since it is frequently + * needed directly (like for rtti comparisons), make it directly accessible. + */ + Symbol* toVtblSymbol() + { + if (!vtblsym) + { + if (!csym) + toSymbol(); + + TYPE* t = type_alloc(TYM.TYnptr | mTY.mTYconst); + t.Tnext = tsvoid; + t.Tnext.Tcount++; + t.Tmangle = mTYman.mTYman_d; + + Symbol* s = toSymbolX("__vtbl", SC.SCextern, t, "Z"); + s.Sflags |= SFL.SFLnodebug; + s.Sfl = FL.FLextern; + vtblsym = s; + slist_add(s); + } + return vtblsym; + } + + // Generate the data for the static initializer. + void toDt(dt_t **pdt) + { + //printf("ClassDeclaration.toDt(this = '%s')\n", toChars()); + + // Put in first two members, the vtbl[] and the monitor + dtxoff(pdt, toVtblSymbol(), 0, TYnptr); + dtdword(pdt, 0); // monitor + + // Put in the rest + toDt2(pdt, this); + + //printf("-ClassDeclaration.toDt(this = '%s')\n", toChars()); + } + + void toDt2(dt_t** pdt, ClassDeclaration cd) + { + uint offset; + uint i; + dt_t* dt; + uint csymoffset; + + version (LOG) { + printf("ClassDeclaration.toDt2(this = '%s', cd = '%s')\n", toChars(), cd.toChars()); + } + if (baseClass) + { + baseClass.toDt2(pdt, cd); + offset = baseClass.structsize; + } + else + { + offset = 8; + } + + // Note equivalence of this loop to struct's + for (i = 0; i < fields.dim; i++) + { + VarDeclaration v = cast(VarDeclaration)fields.data[i]; + Initializer init; + + //printf("\t\tv = '%s' v.offset = %2d, offset = %2d\n", v.toChars(), v.offset, offset); + dt = null; + init = v.init; + if (init) + { + //printf("\t\t%s has initializer %s\n", v.toChars(), init.toChars()); + ExpInitializer ei = init.isExpInitializer(); + Type tb = v.type.toBasetype(); + if (ei && tb.ty == Tsarray) + (cast(TypeSArray)tb).toDtElem(&dt, ei.exp); + else + dt = init.toDt(); + } + else if (v.offset >= offset) + { //printf("\t\tdefault initializer\n"); + v.type.toDt(&dt); + } + if (dt) + { + if (v.offset < offset) + error("duplicated union initialization for %s", v.toChars()); + else + { + if (offset < v.offset) + dtnzeros(pdt, v.offset - offset); + dtcat(pdt, dt); + offset = v.offset + cast(uint)v.type.size(); + } + } + } + + // Interface vptr initializations + toSymbol(); // define csym + + for (i = 0; i < vtblInterfaces.dim; i++) + { + BaseClass b = cast(BaseClass)vtblInterfaces.data[i]; + +/// version (1 || INTERFACE_VIRTUAL) { + for (ClassDeclaration cd2 = cd; 1; cd2 = cd2.baseClass) + { + assert(cd2); + csymoffset = cd2.baseVtblOffset(b); + if (csymoffset != ~0) + { + if (offset < b.offset) + dtnzeros(pdt, b.offset - offset); + dtxoff(pdt, cd2.toSymbol(), csymoffset, TYnptr); + break; + } + } +/// } else { +/// csymoffset = baseVtblOffset(b); +/// assert(csymoffset != ~0); +/// dtxoff(pdt, csym, csymoffset, TYnptr); +/// } + offset = b.offset + 4; + } + + if (offset < structsize) + dtnzeros(pdt, structsize - offset); + } + + Symbol* vtblsym; + + ///ClassDeclaration isClassDeclaration() { return cast(ClassDeclaration)this; } /// huh? + ClassDeclaration isClassDeclaration() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ClassInfoDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ClassInfoDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,50 @@ +module dmd.ClassInfoDeclaration; + +import dmd.VarDeclaration; +import dmd.ClassDeclaration; +import dmd.Dsymbol; +import dmd.Scope; +import dmd.Loc; +import dmd.Id; +import dmd.STC; + +import dmd.backend.Symbol; +import dmd.backend.Classsym; +import dmd.backend.FL; +import dmd.backend.SFL; +import dmd.codegen.Util; +import dmd.backend.SC; +import dmd.backend.Util; + +class ClassInfoDeclaration : VarDeclaration +{ + ClassDeclaration cd; + + this(ClassDeclaration cd) + { + super(Loc(0), ClassDeclaration.classinfo.type, cd.ident, null); + + this.cd = cd; + storage_class = STC.STCstatic | STC.STCgshared; + } + + Dsymbol syntaxCopy(Dsymbol) + { + assert(false); + } + + void semantic(Scope sc) + { + assert(false); + } + + void emitComment(Scope sc) + { + assert(false); + } + + Symbol* toSymbol() + { + return cd.toSymbol(); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/CmpExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/CmpExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,245 @@ +module dmd.CmpExp; + +import dmd.Expression; +import dmd.Identifier; +import dmd.backend.elem; +import dmd.InterState; +import dmd.Loc; +import dmd.TOK; +import dmd.Scope; +import dmd.IRState; +import dmd.Type; +import dmd.Id; +import dmd.TY; +import dmd.ErrorExp; +import dmd.IntegerExp; +import dmd.MATCH; +import dmd.BinExp; +import dmd.WANT; +import dmd.GlobalExpressions; + +import dmd.expression.Util; +import dmd.codegen.Util; +import dmd.expression.Cmp; + +import dmd.backend.Util; +import dmd.backend.RTLSYM; +import dmd.backend.TYM; +import dmd.backend.OPER; +import dmd.backend.rel; + +class CmpExp : BinExp +{ + this(TOK op, Loc loc, Expression e1, Expression e2) + { + super(loc, op, CmpExp.sizeof, e1, e2); + } + + Expression semantic(Scope sc) + { + Expression e; + Type t1; + Type t2; + + version (LOGSEMANTIC) { + printf("CmpExp.semantic('%s')\n", toChars()); + } + if (type) + return this; + + BinExp.semanticp(sc); + + if (e1.type.toBasetype().ty == Tclass && e2.op == TOKnull || + e2.type.toBasetype().ty == Tclass && e1.op == TOKnull) + { + error("do not use null when comparing class types"); + } + + e = op_overload(sc); + if (e) + { + if (!e.type.isscalar() && e.type.equals(e1.type)) + { + error("recursive opCmp expansion"); + e = new ErrorExp(); + } + else + { + e = new CmpExp(op, loc, e, new IntegerExp(loc, 0, Type.tint32)); + e = e.semantic(sc); + } + return e; + } + + typeCombine(sc); + type = Type.tboolean; + + // Special handling for array comparisons + t1 = e1.type.toBasetype(); + t2 = e2.type.toBasetype(); + if ((t1.ty == Tarray || t1.ty == Tsarray || t1.ty == Tpointer) && + (t2.ty == Tarray || t2.ty == Tsarray || t2.ty == Tpointer)) + { + if (t1.nextOf().implicitConvTo(t2.nextOf()) < MATCHconst && + t2.nextOf().implicitConvTo(t1.nextOf()) < MATCHconst && + (t1.nextOf().ty != Tvoid && t2.nextOf().ty != Tvoid)) + error("array comparison type mismatch, %s vs %s", t1.nextOf().toChars(), t2.nextOf().toChars()); + e = this; + } + else if (t1.ty == Tstruct || t2.ty == Tstruct || + (t1.ty == Tclass && t2.ty == Tclass)) + { + if (t2.ty == Tstruct) + error("need member function opCmp() for %s %s to compare", t2.toDsymbol(sc).kind(), t2.toChars()); + else + error("need member function opCmp() for %s %s to compare", t1.toDsymbol(sc).kind(), t1.toChars()); + e = this; + } +/// static if (true) { + else if (t1.iscomplex() || t2.iscomplex()) + { + error("compare not defined for complex operands"); + e = new ErrorExp(); + } +/// } + else + { + e1.rvalue(); + e2.rvalue(); + e = this; + } + + //printf("CmpExp: %s, type = %s\n", e.toChars(), e.type.toChars()); + return e; + } + + Expression optimize(int result) + { + Expression e; + + //printf("CmpExp::optimize() %s\n", toChars()); + e1 = e1.optimize(WANTvalue | (result & WANTinterpret)); + e2 = e2.optimize(WANTvalue | (result & WANTinterpret)); + + Expression e1 = fromConstInitializer(result, this.e1); + Expression e2 = fromConstInitializer(result, this.e2); + + e = Cmp(op, type, e1, e2); + if (e is EXP_CANT_INTERPRET) + e = this; + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + int isBit() + { + assert(false); + } + + bool isCommutative() + { + return true; + } + + Identifier opId() + { + return Id.cmp; + } + + elem* toElem(IRState* irs) + { + elem *e; + OPER eop; + Type t1 = e1.type.toBasetype(); + Type t2 = e2.type.toBasetype(); + + switch (op) + { + case TOKlt: eop = OPlt; break; + case TOKgt: eop = OPgt; break; + case TOKle: eop = OPle; break; + case TOKge: eop = OPge; break; + case TOKequal: eop = OPeqeq; break; + case TOKnotequal: eop = OPne; break; + + // NCEG floating point compares + case TOKunord: eop = OPunord; break; + case TOKlg: eop = OPlg; break; + case TOKleg: eop = OPleg; break; + case TOKule: eop = OPule; break; + case TOKul: eop = OPul; break; + case TOKuge: eop = OPuge; break; + case TOKug: eop = OPug; break; + case TOKue: eop = OPue; break; + default: + dump(0); + assert(0); + } + if (!t1.isfloating()) + { + // Convert from floating point compare to equivalent + // integral compare + eop = cast(OPER)rel_integral(eop); + } + if (cast(int)eop > 1 && t1.ty == Tclass && t2.ty == Tclass) + { + static if (true) { + assert(0); + } else { + elem *ec1; + elem *ec2; + + ec1 = e1.toElem(irs); + ec2 = e2.toElem(irs); + e = el_bin(OPcall,TYint,el_var(rtlsym[RTLSYM_OBJ_CMP]),el_param(ec1, ec2)); + e = el_bin(eop, TYint, e, el_long(TYint, 0)); + } + } + else if (cast(int)eop > 1 && + (t1.ty == Tarray || t1.ty == Tsarray) && + (t2.ty == Tarray || t2.ty == Tsarray)) + { + elem* ea1; + elem* ea2; + elem* ep; + Type telement = t1.nextOf().toBasetype(); + int rtlfunc; + + ea1 = e1.toElem(irs); + ea1 = array_toDarray(t1, ea1); + ea2 = e2.toElem(irs); + ea2 = array_toDarray(t2, ea2); + + version (DMDV2) { + ep = el_params(telement.arrayOf().getInternalTypeInfo(null).toElem(irs), + ea2, ea1, null); + rtlfunc = RTLSYM_ARRAYCMP2; + } else { + ep = el_params(telement.getInternalTypeInfo(null).toElem(irs), ea2, ea1, null); + rtlfunc = RTLSYM_ARRAYCMP; + } + e = el_bin(OPcall, TYint, el_var(rtlsym[rtlfunc]), ep); + e = el_bin(eop, TYint, e, el_long(TYint, 0)); + el_setLoc(e,loc); + } + else + { + if (cast(int)eop <= 1) + { + /* The result is determinate, create: + * (e1 , e2) , eop + */ + e = toElemBin(irs,OPcomma); + e = el_bin(OPcomma,e.Ety,e,el_long(e.Ety,cast(int)eop)); + } + else + e = toElemBin(irs,eop); + } + return e; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/ComExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ComExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,98 @@ +module dmd.ComExp; + +import dmd.Expression; +import dmd.Identifier; +import dmd.backend.elem; +import dmd.UnaExp; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.IRState; +import dmd.ArrayTypes; +import dmd.TOK; +import dmd.TY; + +import dmd.backend.Util; +import dmd.backend.OPER; + +import dmd.expression.Util; +import dmd.expression.Com; + +class ComExp : UnaExp +{ + this(Loc loc, Expression e) + { + super(loc, TOKtilde, ComExp.sizeof, e); + } + + Expression semantic(Scope sc) + { + Expression e; + + if (!type) + { + UnaExp.semantic(sc); + e1 = resolveProperties(sc, e1); + e = op_overload(sc); + if (e) + return e; + + e1.checkNoBool(); + if (e1.op != TOKslice) + e1 = e1.checkIntegral(); + type = e1.type; + } + return this; + } + + Expression optimize(int result) + { + Expression e; + + e1 = e1.optimize(result); + if (e1.isConst() == 1) + { + e = Com(type, e1); + } + else + e = this; + + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void buildArrayIdent(OutBuffer buf, Expressions arguments) + { + assert(false); + } + + Expression buildArrayLoop(Arguments fparams) + { + assert(false); + } + + Identifier opId() + { + assert(false); + } + + elem* toElem(IRState* irs) + { + elem *e; + + elem *e1 = this.e1.toElem(irs); + tym_t ty = type.totym(); + if (this.e1.type.toBasetype().ty == Tbool) + e = el_bin(OPxor, ty, e1, el_long(ty, 1)); + else + e = el_una(OPcom,ty,e1); + el_setLoc(e,loc); + return e; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/CommaExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/CommaExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,123 @@ +module dmd.CommaExp; + +import dmd.Loc; +import dmd.BinExp; +import dmd.IRState; +import dmd.Scope; +import dmd.IntRange; +import dmd.Expression; +import dmd.MATCH; +import dmd.WANT; +import dmd.TOK; +import dmd.Type; +import dmd.InterState; + +import dmd.backend.elem; +import dmd.backend.Util; + +class CommaExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKcomma, CommaExp.sizeof, e1, e2); + } + + Expression semantic(Scope sc) + { + if (!type) + { + BinExp.semanticp(sc); + type = e2.type; + } + return this; + } + + void checkEscape() + { + e2.checkEscape(); + } + + IntRange getIntRange() + { + assert(false); + } + +version (DMDV2) { + int isLvalue() + { + return e2.isLvalue(); + } +} + Expression toLvalue(Scope sc, Expression e) + { + e2 = e2.toLvalue(sc, null); + return this; + } + + Expression modifiableLvalue(Scope sc, Expression e) + { + e2 = e2.modifiableLvalue(sc, e); + return this; + } + + bool isBool(bool result) + { + return e2.isBool(result); + } + + bool checkSideEffect(int flag) + { + if (flag == 2) + return e1.checkSideEffect(2) || e2.checkSideEffect(2); + else + { + // Don't check e1 until we cast(void) the a,b code generation + return e2.checkSideEffect(flag); + } + } + + MATCH implicitConvTo(Type t) + { + assert(false); + } + + Expression castTo(Scope sc, Type t) + { + assert(false); + } + + Expression optimize(int result) + { + Expression e; + + //printf("CommaExp.optimize(result = %d) %s\n", result, toChars()); + e1 = e1.optimize(result & WANTinterpret); + e2 = e2.optimize(result); + if (!e1 || e1.op == TOKint64 || e1.op == TOKfloat64 || !e1.checkSideEffect(2)) + { + e = e2; + if (e) + e.type = type; + } + else + e = this; + //printf("-CommaExp.optimize(result = %d) %s\n", result, e.toChars()); + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + elem* toElem(IRState* irs) + { + assert(e1 && e2); + elem* eleft = e1.toElem(irs); + elem* eright = e2.toElem(irs); + elem* e = el_combine(eleft, eright); + if (e) + el_setLoc(e, loc); + return e; + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/CompileDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/CompileDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,51 @@ +module dmd.CompileDeclaration; + +import dmd.AttribDeclaration; +import dmd.Expression; +import dmd.ScopeDsymbol; +import dmd.Dsymbol; +import dmd.Loc; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; + +// Mixin declarations + +class CompileDeclaration : AttribDeclaration +{ + Expression exp; + + ScopeDsymbol *sd; + int compiled; + + this(Loc loc, Expression exp) + { + assert(false); + super(null); + } + + Dsymbol syntaxCopy(Dsymbol s) + { + assert(false); + } + + bool addMember(Scope sc, ScopeDsymbol sd, int memnum) + { + assert(false); + } + + void compileIt(Scope sc) + { + assert(false); + } + + void semantic(Scope sc) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/CompileExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/CompileExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,29 @@ +module dmd.CompileExp; + +import dmd.Expression; +import dmd.UnaExp; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.HdrGenState; +import dmd.TOK; + +class CompileExp : UnaExp +{ + this(Loc loc, Expression e) + { + assert(false); + super(loc, TOK.init, 0, null); + } + + Expression semantic(Scope sc) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/CompileStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/CompileStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,40 @@ +module dmd.CompileStatement; + +import dmd.Statement; +import dmd.Expression; +import dmd.Loc; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.ArrayTypes; + +class CompileStatement : Statement +{ + Expression exp; + + this(Loc loc, Expression exp) + { + assert(false); + super(loc); + } + + Statement syntaxCopy() + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + Statements flatten(Scope sc) + { + assert(false); + } + + Statement semantic(Scope sc) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/Complex.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Complex.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,7 @@ +module dmd.Complex; + +struct Complex(T) +{ + T re; + T im; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ComplexExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ComplexExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,239 @@ +module dmd.ComplexExp; + +import dmd.Expression; +import dmd.InterState; +import dmd.Type; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.IRState; +import dmd.HdrGenState; +import dmd.Type; +import dmd.TOK; +import dmd.TY; +import dmd.Port; +import dmd.Complex; + +import dmd.backend.dt_t; +import dmd.backend.elem; +import dmd.backend.Util; +import dmd.backend.TYM; +import dmd.backend.mTY; + +class ComplexExp : Expression +{ + Complex!(real) value; + + this(Loc loc, Complex!(real) value, Type type) + { + super(loc, TOK.TOKcomplex80, ComplexExp.sizeof); + this.value = value; + this.type = type; + //printf("ComplexExp.ComplexExp(%s)\n", toChars()); + } + + int equals(Object o) + { + assert(false); + } + + Expression semantic(Scope sc) + { + if (!type) + type = Type.tcomplex80; + else + type = type.semantic(loc, sc); + return this; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + string toChars() + { + assert(false); + } + + ulong toInteger() + { + return cast(ulong) toReal(); + } + + ulong toUInteger() + { + return cast(long) toReal(); + } + + real toReal() + { + return value.re; + } + + real toImaginary() + { + return value.im; + } + + Complex!(real) toComplex() + { + return value; + } + + Expression castTo(Scope sc, Type t) + { + Expression e = this; + if (type != t) + { + if (type.iscomplex() && t.iscomplex()) + { + e = copy(); + e.type = t; + } + else + e = Expression.castTo(sc, t); + } + return e; + } + + int isConst() + { + assert(false); + } + + bool isBool(bool result) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + void toMangleBuffer(OutBuffer buf) + { + assert(false); + } +version (_DH) { + + OutBuffer hexp; +} + + elem* toElem(IRState* irs) + { + eve c; + tym_t ty; + + //printf("ComplexExp.toElem(%p) %s\n", this, toChars()); + + ///memset(&c, 0, c.sizeof); + + ty = type.totym(); + switch (tybasic(ty)) + { + case TYcfloat: + { + c.Vcfloat.re = cast(float) value.re; + if (Port.isSignallingNan(value.re)) { + (cast(uint*)&c.Vcfloat.re)[0] &= 0xFFBFFFFFL; + std.stdio.writeln("float.re is snan"); + } + c.Vcfloat.im = cast(float) value.im; + if (Port.isSignallingNan(value.im)) { + (cast(uint*)&c.Vcfloat.im)[0] &= 0xFFBFFFFFL; + std.stdio.writeln("float.im is snan"); + } + break; + } + + case TYcdouble: + { + c.Vcdouble.re = cast(double) value.re; + if (Port.isSignallingNan(value.re)) { + std.stdio.writeln("double.re is snan"); + (cast(uint*)&c.Vcdouble.re)[1] &= 0xFFF7FFFFL; + } + c.Vcdouble.im = cast(double) value.im; + if (Port.isSignallingNan(value.im)) { + (cast(uint*)&c.Vcdouble.im)[1] &= 0xFFF7FFFFL; + std.stdio.writeln("double.im is snan"); + } + break; + } + + case TYcldouble: + { + static if (true) { + c.Vcldouble = value; + } else { + { + ushort* p = cast(ushort*)&c.Vcldouble; + for (int i = 0; i < (LNGDBLSIZE*2)/2; i++) printf("%04x ", p[i]); + printf("\n"); + } + c.Vcldouble.im = im; + { + ushort* p = cast(ushort*)&c.Vcldouble; + for (int i = 0; i < (LNGDBLSIZE*2)/2; i++) printf("%04x ", p[i]); + printf("\n"); + } + c.Vcldouble.re = re; + { + ushort* p = cast(ushort*)&c.Vcldouble; + for (int i = 0; i < (LNGDBLSIZE*2)/2; i++) printf("%04x ", p[i]); + printf("\n"); + } + } + break; + } + + default: + assert(0); + } + return el_const(ty, &c); + } + + static private char[6] zeropad; + + dt_t** toDt(dt_t** pdt) + { + //printf("ComplexExp.toDt() '%s'\n", toChars()); + float fvalue; + double dvalue; + real evalue; + + switch (type.toBasetype().ty) + { + case Tcomplex32: + fvalue = value.re; + pdt = dtnbytes(pdt,4,cast(char*)&fvalue); + fvalue = value.im; + pdt = dtnbytes(pdt,4,cast(char*)&fvalue); + break; + + case Tcomplex64: + dvalue = value.re; + pdt = dtnbytes(pdt,8,cast(char*)&dvalue); + dvalue = value.im; + pdt = dtnbytes(pdt,8,cast(char*)&dvalue); + break; + + case Tcomplex80: + evalue = value.re; + pdt = dtnbytes(pdt,REALSIZE - REALPAD,cast(char*)&evalue); + pdt = dtnbytes(pdt,REALPAD,zeropad.ptr); + evalue = value.im; + pdt = dtnbytes(pdt,REALSIZE - REALPAD, cast(char*)&evalue); + pdt = dtnbytes(pdt,REALPAD,zeropad.ptr); + break; + + default: + assert(0); + break; + } + return pdt; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/CompoundDeclarationStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/CompoundDeclarationStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,27 @@ +module dmd.CompoundDeclarationStatement; + +import dmd.CompoundStatement; +import dmd.Loc; +import dmd.ArrayTypes; +import dmd.Statement; +import dmd.OutBuffer; +import dmd.HdrGenState; + +class CompoundDeclarationStatement : CompoundStatement +{ + this(Loc loc, Statements s) + { + super(loc, s); + ///statements = s; + } + + Statement syntaxCopy() + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/CompoundStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/CompoundStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,355 @@ +module dmd.CompoundStatement; + +import dmd.Loc; +import dmd.Statement; +import dmd.Array; +import dmd.TryCatchStatement; +import dmd.TryFinallyStatement; +import dmd.Catch; +import dmd.ScopeStatement; +import dmd.Identifier; +import dmd.Lexer; +import dmd.ThrowStatement; +import dmd.IdentifierExp; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.ArrayTypes; +import dmd.ReturnStatement; +import dmd.Expression; +import dmd.InterState; +import dmd.InlineDoState; +import dmd.InlineCostState; +import dmd.InlineScanState; +import dmd.IfStatement; +import dmd.IRState; +import dmd.BE; +import dmd.Util; + +class CompoundStatement : Statement +{ + Statements statements; + + this(Loc loc, Statements s) + { + super(loc); + statements = s; + } + + this(Loc loc, Statement s1, Statement s2) + { + super(loc); + + statements = new Statements(); + statements.reserve(2); + statements.push(cast(void*)s1); + statements.push(cast(void*)s2); + } + + Statement syntaxCopy() + { + Statements a = new Statements(); + a.setDim(statements.dim); + + for (size_t i = 0; i < statements.dim; i++) + { + Statement s = cast(Statement)statements.data[i]; + if (s) + s = s.syntaxCopy(); + a.data[i] = cast(void*)s; + } + + return new CompoundStatement(loc, a); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + static int indent = 0; + static int depth = 0; + + Statement semantic(Scope sc) + { + Statement s; + + //printf("CompoundStatement.semantic(this = %p, sc = %p)\n", this, sc); + + for (size_t i = 0; i < statements.dim; ) + { + s = cast(Statement) statements.data[i]; + if (s) + { + Statements a = s.flatten(sc); + + if (a) + { + statements.remove(i); + statements.insert(i, a); + continue; + } + + s = s.semantic(sc); + + statements.data[i] = cast(void*)s; + if (s) + { + Statement sentry; + Statement sexception; + Statement sfinally; + + s.scopeCode(sc, &sentry, &sexception, &sfinally); + if (sentry) + { + sentry = sentry.semantic(sc); + if (s.isDeclarationStatement()) + { + statements.insert(i, cast(void*)sentry); + i++; + } + else + statements.data[i] = cast(void*)sentry; + } + if (sexception) + { + if (i + 1 == statements.dim && !sfinally) + { + static if (true) { + sexception = sexception.semantic(sc); + } else { + statements.push(sexception); + if (sfinally) + // Assume sexception does not throw + statements.push(sfinally); + } + } + else + { + /* Rewrite: + * s; s1; s2; + * As: + * s; + * try { s1; s2; } + * catch (Object __o) + * { sexception; throw __o; } + */ + Statement body_; + Statements aa = new Statements(); + + for (int j = i + 1; j < statements.dim; j++) + { + aa.push(statements.data[j]); + } + body_ = new CompoundStatement(Loc(0), aa); + body_ = new ScopeStatement(Loc(0), body_); + + Identifier id = Lexer.uniqueId("__o"); + + Statement handler = new ThrowStatement(Loc(0), new IdentifierExp(Loc(0), id)); + handler = new CompoundStatement(Loc(0), sexception, handler); + + Array catches = new Array(); + Catch ctch = new Catch(Loc(0), null, id, handler); + catches.push(cast(void*)ctch); + s = new TryCatchStatement(Loc(0), body_, catches); + + if (sfinally) + s = new TryFinallyStatement(Loc(0), s, sfinally); + s = s.semantic(sc); + statements.setDim(i + 1); + statements.push(cast(void*)s); + break; + } + } + else if (sfinally) + { + if (0 && i + 1 == statements.dim) + { + statements.push(cast(void*)sfinally); + } + else + { + /* Rewrite: + * s; s1; s2; + * As: + * s; try { s1; s2; } finally { sfinally; } + */ + Statement body_; + Statements aa = new Statements(); + + for (int j = i + 1; j < statements.dim; j++) + { + aa.push(statements.data[j]); + } + body_ = new CompoundStatement(Loc(0), aa); + s = new TryFinallyStatement(Loc(0), body_, sfinally); + s = s.semantic(sc); + statements.setDim(i + 1); + statements.push(cast(void*)s); + break; + } + } + } + } + i++; + } + if (statements.dim == 1) + { + return cast(Statement)statements.data[0]; + } + return this; + } + + bool usesEH() + { + assert(false); + } + + BE blockExit() + { + //printf("CompoundStatement::blockExit(%p) %d\n", this, statements->dim); + BE result = BE.BEfallthru; + for (size_t i = 0; i < statements.dim; i++) + { Statement s = cast(Statement)statements.data[i]; + if (s) + { + //printf("result = x%x\n", result); + //printf("%s\n", s->toChars()); + if (!(result & BE.BEfallthru) && !s.comeFrom()) + { + if (s.blockExit() != BE.BEhalt) + s.warning("statement is not reachable"); + } + + result &= ~BE.BEfallthru; + result |= s.blockExit(); + } + } + + return result; + } + + bool comeFrom() + { + assert(false); + } + + bool isEmpty() + { + for (int i = 0; i < statements.dim; i++) + { + Statement s = cast(Statement) statements.data[i]; + if (s && !s.isEmpty()) + return false; + } + return true; + } + + Statements flatten(Scope sc) + { + return statements; + } + + ReturnStatement isReturnStatement() + { + ReturnStatement rs = null; + + for (int i = 0; i < statements.dim; i++) + { + Statement s = cast(Statement) statements.data[i]; + if (s) + { + rs = s.isReturnStatement(); + if (rs) + break; + } + } + return rs; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + int inlineCost(InlineCostState* ics) + { + int cost = 0; + + for (size_t i = 0; i < statements.dim; i++) + { + Statement s = cast(Statement)statements.data[i]; + if (s) + { + cost += s.inlineCost(ics); + if (cost >= COST_MAX) + break; + } + } + + return cost; + } + + Expression doInline(InlineDoState ids) + { + Expression e = null; + + //printf("CompoundStatement.doInline() %d\n", statements.dim); + for (size_t i = 0; i < statements.dim; i++) + { + Statement s = cast(Statement)statements.data[i]; + if (s) + { + Expression e2 = s.doInline(ids); + e = Expression.combine(e, e2); + if (s.isReturnStatement()) + break; + + /* Check for: + * if (condition) + * return exp1; + * else + * return exp2; + */ + IfStatement ifs = s.isIfStatement(); + if (ifs && ifs.elsebody && ifs.ifbody && + ifs.ifbody.isReturnStatement() && + ifs.elsebody.isReturnStatement() + ) + break; + } + } + return e; + } + + Statement inlineScan(InlineScanState* iss) + { + for (size_t i = 0; i < statements.dim; i++) + { + Statement s = cast(Statement) statements.data[i]; + if (s) + statements.data[i] = cast(void*)s.inlineScan(iss); + } + + return this; + } + + void toIR(IRState* irs) + { + if (statements) + { + size_t dim = statements.dim; + for (size_t i = 0 ; i < dim ; i++) + { + Statement s = cast(Statement)statements.data[i]; + if (s !is null) + { + s.toIR(irs); + } + } + } + } + + CompoundStatement isCompoundStatement() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/CondExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/CondExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,281 @@ +module dmd.CondExp; + +import dmd.BinExp; +import dmd.Loc; +import dmd.MATCH; +import dmd.Expression; +import dmd.Scope; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Type; +import dmd.InlineCostState; +import dmd.InlineDoState; +import dmd.InlineScanState; +import dmd.IRState; +import dmd.TOK; +import dmd.TY; +import dmd.WANT; +import dmd.Global; + +import dmd.backend.elem; +import dmd.backend.Util; +import dmd.backend.OPER; +import dmd.backend.mTY; +import dmd.backend.TYM; +import dmd.codegen.Util; + +class CondExp : BinExp +{ + Expression econd; + + this(Loc loc, Expression econd, Expression e1, Expression e2) + { + super(loc, TOK.TOKquestion, CondExp.sizeof, e1, e2); + this.econd = econd; + } + + Expression syntaxCopy() + { + assert(false); + } + + Expression semantic(Scope sc) + { + Type t1; + Type t2; + uint cs0; + uint cs1; + + version (LOGSEMANTIC) { + printf("CondExp.semantic('%s')\n", toChars()); + } + if (type) + return this; + + econd = econd.semantic(sc); + econd = resolveProperties(sc, econd); + econd = econd.checkToPointer(); + econd = econd.checkToBoolean(); + + static if (false) { + /* this cannot work right because the types of e1 and e2 + * both contribute to the type of the result. + */ + if (sc.flags & SCOPEstaticif) + { + /* If in static if, don't evaluate what we don't have to. + */ + econd = econd.optimize(WANTflags); + if (econd.isBool(TRUE)) + { + e1 = e1.semantic(sc); + e1 = resolveProperties(sc, e1); + return e1; + } + else if (econd.isBool(FALSE)) + { + e2 = e2.semantic(sc); + e2 = resolveProperties(sc, e2); + return e2; + } + } + } + + cs0 = sc.callSuper; + e1 = e1.semantic(sc); + e1 = resolveProperties(sc, e1); + cs1 = sc.callSuper; + sc.callSuper = cs0; + e2 = e2.semantic(sc); + e2 = resolveProperties(sc, e2); + sc.mergeCallSuper(loc, cs1); + + // If either operand is void, the result is void + t1 = e1.type; + t2 = e2.type; + if (t1.ty == Tvoid || t2.ty == Tvoid) + type = Type.tvoid; + else if (t1 == t2) + type = t1; + else + { + typeCombine(sc); + switch (e1.type.toBasetype().ty) + { + case Tcomplex32: + case Tcomplex64: + case Tcomplex80: + e2 = e2.castTo(sc, e1.type); + break; + default: + break; + } + switch (e2.type.toBasetype().ty) + { + case Tcomplex32: + case Tcomplex64: + case Tcomplex80: + e1 = e1.castTo(sc, e2.type); + break; + default: + break; + } + if (type.toBasetype().ty == Tarray) + { + e1 = e1.castTo(sc, type); + e2 = e2.castTo(sc, type); + } + } + static if (false) { + printf("res: %s\n", type.toChars()); + printf("e1 : %s\n", e1.type.toChars()); + printf("e2 : %s\n", e2.type.toChars()); + } + return this; + } + + Expression optimize(int result) + { + Expression e; + + econd = econd.optimize(WANTflags | (result & WANTinterpret)); + if (econd.isBool(true)) + e = e1.optimize(result); + else if (econd.isBool(false)) + e = e2.optimize(result); + else + { + e1 = e1.optimize(result); + e2 = e2.optimize(result); + e = this; + } + + return e; + } + + Expression interpret(InterState istate) + { + assert(false); + } + + void checkEscape() + { + e1.checkEscape(); + e2.checkEscape(); + } + + int isLvalue() + { + assert(false); + } + + Expression toLvalue(Scope sc, Expression e) + { + assert(false); + } + + Expression modifiableLvalue(Scope sc, Expression e) + { + assert(false); + } + + Expression checkToBoolean() + { + assert(false); + } + + bool checkSideEffect(int flag) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + MATCH implicitConvTo(Type t) + { + MATCH m1 = e1.implicitConvTo(t); + MATCH m2 = e2.implicitConvTo(t); + //printf("CondExp: m1 %d m2 %d\n", m1, m2); + + // Pick the worst match + return (m1 < m2) ? m1 : m2; + } + + Expression castTo(Scope sc, Type t) + { + Expression e = this; + + if (type !is t) + { + if (1 || e1.op == TOKstring || e2.op == TOKstring) + { + e = new CondExp(loc, econd, e1.castTo(sc, t), e2.castTo(sc, t)); + e.type = t; + } + else + e = Expression.castTo(sc, t); + } + return e; + } + + void scanForNestedRef(Scope sc) + { + assert(false); + } + + bool canThrow() + { + return econd.canThrow() || e1.canThrow() || e2.canThrow(); + } + + int inlineCost(InlineCostState* ics) + { + return 1 + e1.inlineCost(ics) + e2.inlineCost(ics) + econd.inlineCost(ics); + } + + Expression doInline(InlineDoState ids) + { + CondExp ce = cast(CondExp)copy(); + + ce.econd = econd.doInline(ids); + ce.e1 = e1.doInline(ids); + ce.e2 = e2.doInline(ids); + return ce; + } + + Expression inlineScan(InlineScanState* iss) + { + econd = econd.inlineScan(iss); + e1 = e1.inlineScan(iss); + e2 = e2.inlineScan(iss); + return this; + } + + elem* toElem(IRState* irs) + { + elem* eleft; + elem* eright; + + elem* ec = econd.toElem(irs); + + eleft = e1.toElem(irs); + tym_t ty = eleft.Ety; + if (global.params.cov && e1.loc.linnum) + eleft = el_combine(incUsageElem(irs, e1.loc), eleft); + + eright = e2.toElem(irs); + if (global.params.cov && e2.loc.linnum) + eright = el_combine(incUsageElem(irs, e2.loc), eright); + + elem* e = el_bin(OPcond, ty, ec, el_bin(OPcolon, ty, eleft, eright)); + if (tybasic(ty) == TYstruct) + e.Enumbytes = cast(uint)e1.type.size(); + + el_setLoc(e, loc); + return e; + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/Condition.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Condition.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,24 @@ +module dmd.Condition; + +import dmd.Loc; +import dmd.Scope; +import dmd.ScopeDsymbol; +import dmd.OutBuffer; +import dmd.HdrGenState; + +class Condition +{ + Loc loc; + int inc = 0;// 0: not computed yet + // 1: include + // 2: do not include + + this(Loc loc) + { + this.loc = loc; + } + + abstract Condition syntaxCopy(); + abstract bool include(Scope sc, ScopeDsymbol s); + abstract void toCBuffer(OutBuffer buf, HdrGenState* hgs); +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ConditionalDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ConditionalDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,81 @@ +module dmd.ConditionalDeclaration; + +import dmd.AttribDeclaration; +import dmd.Condition; +import dmd.Array; +import dmd.Dsymbol; +import dmd.Scope; +import dmd.ScopeDsymbol; +import dmd.OutBuffer; +import dmd.HdrGenState; + +class ConditionalDeclaration : AttribDeclaration +{ + Condition condition; + Array elsedecl; // array of Dsymbol's for else block + + this(Condition condition, Array decl, Array elsedecl) + { + super(decl); + //printf("ConditionalDeclaration::ConditionalDeclaration()\n"); + this.condition = condition; + this.elsedecl = elsedecl; + } + + Dsymbol syntaxCopy(Dsymbol s) + { + assert(false); + } + + bool oneMember(Dsymbol* ps) + { + assert(false); + } + + void emitComment(Scope sc) + { + assert(false); + } + + // Decide if 'then' or 'else' code should be included + + Array include(Scope sc, ScopeDsymbol sd) + { + //printf("ConditionalDeclaration::include()\n"); + assert(condition); + return condition.include(sc, sd) ? decl : elsedecl; + } + + void addComment(ubyte* comment) + { + /* Because addComment is called by the parser, if we called + * include() it would define a version before it was used. + * But it's no problem to drill down to both decl and elsedecl, + * so that's the workaround. + */ + + if (comment) + { + Array d = decl; + + for (int j = 0; j < 2; j++) + { + if (d) + { + for (uint i = 0; i < d.dim; i++) + { + Dsymbol s = cast(Dsymbol)d.data[i]; + //printf("ConditionalDeclaration::addComment %s\n", s->toChars()); + s.addComment(comment); + } + } + d = elsedecl; + } + } + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ConditionalStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ConditionalStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,65 @@ +module dmd.ConditionalStatement; + +import dmd.Statement; +import dmd.Condition; +import dmd.Loc; +import dmd.OutBuffer; +import dmd.Scope; +import dmd.HdrGenState; +import dmd.ArrayTypes; +import dmd.BE; + +class ConditionalStatement : Statement +{ + Condition condition; + Statement ifbody; + Statement elsebody; + + this(Loc loc, Condition condition, Statement ifbody, Statement elsebody) + { + super(loc); + this.condition = condition; + this.ifbody = ifbody; + this.elsebody = elsebody; + } + + Statement syntaxCopy() + { + assert(false); + } + + Statement semantic(Scope sc) + { + assert(false); + } + + Statements flatten(Scope sc) + { + Statement s; + + if (condition.include(sc, null)) + s = ifbody; + else + s = elsebody; + + Statements a = new Statements(); + a.push(cast(void*)s); + + return a; + } + + bool usesEH() + { + assert(false); + } + + BE blockExit() + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ContinueStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ContinueStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,154 @@ +module dmd.ContinueStatement; + +import dmd.Statement; +import dmd.FuncDeclaration; +import dmd.IntegerExp; +import dmd.ReturnStatement; +import dmd.LabelStatement; +import dmd.Identifier; +import dmd.Loc; +import dmd.Scope; +import dmd.Expression; +import dmd.InterState; +import dmd.HdrGenState; +import dmd.OutBuffer; +import dmd.IRState; +import dmd.BE; + +import dmd.backend.Util; +import dmd.backend.BC; +import dmd.backend.block; +import dmd.backend.Blockx; + +class ContinueStatement : Statement +{ + Identifier ident; + + this(Loc loc, Identifier ident) + { + super(loc); + this.ident = ident; + } + + Statement syntaxCopy() + { + ContinueStatement s = new ContinueStatement(loc, ident); + return s; + } + + Statement semantic(Scope sc) + { + //printf("ContinueStatement.semantic() %p\n", this); + if (ident) + { + Scope scx; + FuncDeclaration thisfunc = sc.func; + + for (scx = sc; scx; scx = scx.enclosing) + { + LabelStatement ls; + + if (scx.func != thisfunc) // if in enclosing function + { + if (sc.fes) // if this is the body of a foreach + { + for (; scx; scx = scx.enclosing) + { + ls = scx.slabel; + if (ls && ls.ident == ident && ls.statement == sc.fes) + { + // Replace continue ident; with return 0; + return new ReturnStatement(Loc(0), new IntegerExp(0)); + } + } + + /* Post this statement to the fes, and replace + * it with a return value that caller will put into + * a switch. Caller will figure out where the break + * label actually is. + * Case numbers start with 2, not 0, as 0 is continue + * and 1 is break. + */ + Statement s; + sc.fes.cases.push(cast(void*)this); + s = new ReturnStatement(Loc(0), new IntegerExp(sc.fes.cases.dim + 1)); + return s; + } + break; // can't continue to it + } + + ls = scx.slabel; + if (ls && ls.ident == ident) + { + Statement s = ls.statement; + + if (!s.hasContinue()) + error("label '%s' has no continue", ident.toChars()); + if (ls.tf != sc.tf) + error("cannot continue out of finally block"); + return this; + } + } + error("enclosing label '%s' for continue not found", ident.toChars()); + } + else if (!sc.scontinue) + { + if (sc.fes) + { + Statement s; + + // Replace continue; with return 0; + s = new ReturnStatement(Loc(0), new IntegerExp(0)); + return s; + } + error("continue is not inside a loop"); + } + return this; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + BE blockExit() + { + return ident ? BE.BEgoto : BE.BEcontinue; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + buf.writestring("continue"); + if (ident) + { + buf.writebyte(' '); + buf.writestring(ident.toChars()); + } + buf.writebyte(';'); + buf.writenl(); + } + + void toIR(IRState* irs) + { + block* bcont; + block* b; + Blockx* blx = irs.blx; + + //printf("ContinueStatement.toIR() %p\n", this); + bcont = irs.getContBlock(ident); + assert(bcont); + b = blx.curblock; + incUsage(irs, loc); + + // Adjust exception handler scope index if in different try blocks + if (b.Btry != bcont.Btry) + { + //setScopeIndex(blx, b, bcont.Btry ? bcont.Btry.Bscope_index : -1); + } + + /* Nothing more than a 'goto' to the current continue destination + */ + list_append(&b.Bsucc, bcont); + block_next(blx, BCgoto, null); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/CppMangleState.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/CppMangleState.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,14 @@ +module dmd.CppMangleState; + +import dmd.Array; +import dmd.OutBuffer; + +struct CppMangleState +{ + static __gshared Array components; + + int substitute(OutBuffer buf, void* p) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/CtorDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/CtorDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,140 @@ +module dmd.CtorDeclaration; + +import dmd.FuncDeclaration; +import dmd.ArrayTypes; +import dmd.Loc; +import dmd.Dsymbol; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.STC; +import dmd.AggregateDeclaration; +import dmd.TypeFunction; +import dmd.Type; +import dmd.Global; +import dmd.LINK; +import dmd.Expression; +import dmd.ThisExp; +import dmd.Statement; +import dmd.ReturnStatement; +import dmd.CompoundStatement; +import dmd.Argument; +import dmd.Id; + +class CtorDeclaration : FuncDeclaration +{ + Arguments arguments; + int varargs; + + this(Loc loc, Loc endloc, Arguments arguments, int varargs) + { + super(loc, endloc, Id.ctor, STC.STCundefined, null); + + this.arguments = arguments; + this.varargs = varargs; + //printf("CtorDeclaration(loc = %s) %s\n", loc.toChars(), toChars()); + } + + Dsymbol syntaxCopy(Dsymbol) + { + assert(false); + } + + void semantic(Scope sc) + { + AggregateDeclaration ad; + Type tret; + + //printf("CtorDeclaration.semantic() %s\n", toChars()); + if (type) + return; + + sc = sc.push(); + sc.stc &= ~STCstatic; // not a static constructor + + parent = sc.parent; + Dsymbol parent = toParent2(); + ad = parent.isAggregateDeclaration(); + if (!ad || parent.isUnionDeclaration()) + { + error("constructors are only for class or struct definitions"); + tret = Type.tvoid; + } + else + { + tret = ad.handle; + assert(tret); + } + type = new TypeFunction(arguments, tret, varargs, LINKd); + +version (STRUCTTHISREF) { + if (ad && ad.isStructDeclaration()) + (cast(TypeFunction)type).isref = true; +} + if (!originalType) + originalType = type; + + sc.flags |= SCOPE.SCOPEctor; + type = type.semantic(loc, sc); + sc.flags &= ~SCOPE.SCOPEctor; + + // Append: + // return this; + // to the function body + if (fbody) + { + Expression e = new ThisExp(loc); + Statement s = new ReturnStatement(loc, e); + fbody = new CompoundStatement(loc, fbody, s); + } + + FuncDeclaration.semantic(sc); + + sc.pop(); + + // See if it's the default constructor + if (ad && varargs == 0 && Argument.dim(arguments) == 0) + { if (ad.isStructDeclaration()) + error("default constructor not allowed for structs"); + else + ad.defaultCtor = this; + } + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + string kind() + { + return "constructor"; + } + + string toChars() + { + return "this"; + } + + bool isVirtual() + { + return false; + } + + bool addPreInvariant() + { + return false; + } + + bool addPostInvariant() + { + return (isThis() && vthis && global.params.useInvariants); + } + + void toDocBuffer(OutBuffer buf) + { + assert(false); + } + + CtorDeclaration isCtorDeclaration() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/DVCondition.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/DVCondition.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,26 @@ +module dmd.DVCondition; + +import dmd.Condition; +import dmd.Identifier; +import dmd.Module; +import dmd.Loc; + +class DVCondition : Condition +{ + uint level; + Identifier ident; + Module mod; + + this(Module mod, uint level, Identifier ident) + { + super(Loc(0)); + this.mod = mod; + this.level = level; + this.ident = ident; + } + + Condition syntaxCopy() + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/DYNCAST.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/DYNCAST.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,11 @@ +module dmd.DYNCAST; + +enum DYNCAST +{ + DYNCAST_OBJECT, + DYNCAST_EXPRESSION, + DYNCAST_DSYMBOL, + DYNCAST_TYPE, + DYNCAST_IDENTIFIER, + DYNCAST_TUPLE, +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/Dchar.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Dchar.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,271 @@ +module dmd.Dchar; + +import core.stdc.wchar_; +import core.stdc.string; +import core.stdc.ctype; + +version (M_UNICODE) { + alias wchat dchar_t; + + struct Dchar + { + static dchar_t* inc(dchar_t* p) { return p + 1; } + static dchar_t* dec(dchar_t* pstart, dchar_t* p) { return p - 1; } + static int len(const(dchar_t)* p) { return wcslen(p); } + static dchar_t get(dchar_t* p) { return *p; } + static dchar_t getprev(dchar_t* pstart, dchar_t* p) { return p[-1]; } + static dchar_t* put(dchar_t* p, dchar_t c) { *p = c; return p + 1; } + static int cmp(dchar_t* s1, dchar_t* s2) + { +version (__DMC__) { + if (!*s1 && !*s2) // wcscmp is broken + return 0; +} + return wcscmp(s1, s2); +version (disabled) { + return (*s1 == *s2) + ? wcscmp(s1, s2) + : (cast(int)*s1 - cast(int)*s2); +} + } + static int memcmp(const(dchar_t)*s1, const(dchar_t)* s2, int nchars) { return .memcmp(s1, s2, nchars * dchar_t.sizeof); } + static int isDigit(dchar_t c) { return '0' <= c && c <= '9'; } + static int isAlpha(dchar_t c) { return iswalpha(c); } + static int isUpper(dchar_t c) { return iswupper(c); } + static int isLower(dchar_t c) { return iswlower(c); } + static int isLocaleUpper(dchar_t c) { return isUpper(c); } + static int isLocaleLower(dchar_t c) { return isLower(c); } + static int toLower(dchar_t c) { return isUpper(c) ? towlower(c) : c; } + static int toLower(dchar_t* p) { return toLower(*p); } + static int toUpper(dchar_t c) { return isLower(c) ? towupper(c) : c; } + static dchar_t* dup(dchar_t* p) { return ._wcsdup(p); } // BUG: out of memory? + + static dchar_t* dup(char* p) + { + assert(false); + } + + static dchar_t* chr(dchar_t *p, uint c) { return wcschr(p, cast(dchar_t)c); } + static dchar_t* rchr(dchar_t *p, uint c) { return wcsrchr(p, cast(dchar_t)c); } + + static dchar_t* memchr(dchar_t* p, int c, int count) + { + assert(false); + } + + static dchar_t* cpy(dchar_t* s1, dchar_t* s2) { return wcscpy(s1, s2); } + static dchar_t* str(dchar_t* s1, dchar_t* s2) { return wcsstr(s1, s2); } + + static hash_t calcHash(const(dchar_t)* str, size_t len) + { + assert(false); + } + + // Case insensitive versions + static int icmp(dchar_t* s1, dchar_t* s2) { return wcsicmp(s1, s2); } + static int memicmp(const(dchar_t)* s1, const(dchar_t)* s2, int nchars) { return .wcsnicmp(s1, s2, nchars); } + + static hash_t icalcHash(const(dchar_t)* str, size_t len) + { + assert(false); + } + } +} else version (UTF8) { + alias char dchar_t; + + struct Dchar + { + static char mblen[256]; + + static dchar_t* inc(dchar_t* p) { return p + mblen[*p & 0xFF]; } + + static dchar_t* dec(dchar_t* pstart, dchar_t* p) + { + assert(false); + } + + static int len(const(dchar_t)* p) { return strlen(p); } + + static int get(dchar_t* p) + { + assert(false); + } + + static int getprev(dchar_t* pstart, dchar_t* p) + { + return *dec(pstart, p) & 0xFF; + } + + static dchar_t* put(dchar_t* p, uint c) + { + assert(false); + } + + static int cmp(dchar_t* s1, dchar_t* s2) { return strcmp(s1, s2); } + + static int memcmp(const(dchar_t)* s1, const(dchar_t)* s2, int nchars) { return .memcmp(s1, s2, nchars); } + + static int isDigit(dchar_t c) { return '0' <= c && c <= '9'; } + + static int isAlpha(dchar_t c) { return c <= 0x7F ? isalpha(c) : 0; } + + static int isUpper(dchar_t c) { return c <= 0x7F ? isupper(c) : 0; } + + static int isLower(dchar_t c) { return c <= 0x7F ? islower(c) : 0; } + + static int isLocaleUpper(dchar_t c) { return isUpper(c); } + + static int isLocaleLower(dchar_t c) { return isLower(c); } + + static int toLower(dchar_t c) { return isUpper(c) ? tolower(c) : c; } + + static int toLower(dchar_t* p) { return toLower(*p); } + + static int toUpper(dchar_t c) { return isLower(c) ? toupper(c) : c; } + + static dchar_t* dup(dchar_t* p) { return .strdup(p); } // BUG: out of memory? + + static dchar_t* chr(dchar_t* p, int c) { return strchr(p, c); } + + static dchar_t* rchr(dchar_t* p, int c) { return strrchr(p, c); } + + static dchar_t* memchr(dchar_t* p, int c, int count) + { + return cast(dchar_t*).memchr(p, c, count); + } + + static dchar_t* cpy(dchar_t* s1, dchar_t* s2) { return strcpy(s1, s2); } + + static dchar_t* str(dchar_t* s1, dchar_t* s2) { return strstr(s1, s2); } + + static hash_t calcHash(const(dchar_t)* str, size_t len) + { + assert(false); + } + + // Case insensitive versions + static int icmp(dchar_t* s1, dchar_t* s2) { return _mbsicmp(s1, s2); } + + static int memicmp(const(dchar_t)* s1, const(dchar_t)* s2, int nchars) { return ._mbsnicmp(s1, s2, nchars); } + } +} else { + alias char dchar_t; + + struct Dchar + { + static dchar_t* inc(dchar_t* p) { return p + 1; } + + static dchar_t* dec(dchar_t* pstart, dchar_t* p) { return p - 1; } + + static int len(const(dchar_t)* p) { return strlen(p); } + + static int get(dchar_t* p) { return *p & 0xFF; } + + static int getprev(dchar_t* pstart, dchar_t* p) { return p[-1] & 0xFF; } + + static dchar_t* put(dchar_t* p, uint c) { *p = cast(dchar_t)c; return p + 1; } + + static int cmp(dchar_t* s1, dchar_t* s2) { return strcmp(s1, s2); } + + static int memcmp(const(dchar_t)* s1, const(dchar_t)* s2, int nchars) { return .memcmp(s1, s2, nchars); } + + static int isDigit(dchar_t c) { return '0' <= c && c <= '9'; } + +version (GCC_SAFE_DMD) { +} else { + static int isAlpha(dchar_t c) { return isalpha(c); } + + static int isUpper(dchar_t c) { return isupper(c); } + + static int isLower(dchar_t c) { return islower(c); } + + static int isLocaleUpper(dchar_t c) { return isupper(c); } + + static int isLocaleLower(dchar_t c) { return islower(c); } + + static int toLower(dchar_t c) { return isupper(c) ? tolower(c) : c; } + + static int toLower(dchar_t* p) { return toLower(*p); } + + static int toUpper(dchar_t c) { return islower(c) ? toupper(c) : c; } + + static dchar_t* dup(dchar_t* p) { /*return .strdup(p);*/ assert(false); } // BUG: out of memory? +} + static dchar_t* chr(dchar_t *p, int c) { return strchr(p, c); } + + static dchar_t* rchr(dchar_t *p, int c) { return strrchr(p, c); } + + static dchar_t* memchr(dchar_t *p, int c, int count) + { + return cast(dchar_t*).memchr(p, c, count); + } + + static dchar_t* cpy(dchar_t* s1, dchar_t* s2) { return strcpy(s1, s2); } + + static dchar_t* str(dchar_t* s1, dchar_t* s2) { return strstr(s1, s2); } + + static hash_t calcHash(const(dchar_t)* str, size_t len) + { + hash_t hash = 0; + + while (1) + { + switch (len) + { + case 0: + return hash; + + case 1: + hash *= 37; + hash += *cast(const(uint8_t)*)str; + return hash; + + case 2: + hash *= 37; +version (__I86__) { + hash += *cast(const(uint16_t)*)str; +} else { + hash += str[0] * 256 + str[1]; +} + return hash; + + case 3: + hash *= 37; +version (__I86__) { + hash += (*cast(const(uint16_t)*)str << 8) + + (cast(const(uint8_t)*)str)[2]; +} else { + hash += (str[0] * 256 + str[1]) * 256 + str[2]; +} + return hash; + + default: + hash *= 37; +version (__I86__) { + hash += *cast(const(uint32_t)*)str; +} else { + hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3]; +} + str += 4; + len -= 4; + break; + } + } + + assert(false); + } + + // Case insensitive versions +version (__GNUC__) { + static int icmp(dchar_t* s1, dchar_t* s2) { return strcasecmp(s1, s2); } +} else { + static int icmp(dchar_t* s1, dchar_t* s2) { /*return stricmp(s1, s2);*/ assert(false); } +} + static int memicmp(const(dchar_t)* s1, const(dchar_t)* s2, int nchars) { /*return .memicmp(s1, s2, nchars);*/ assert(false); } + static hash_t icalcHash(const(dchar_t)* str, size_t len) + { + assert(false); + } + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/DebugCondition.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/DebugCondition.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,70 @@ +module dmd.DebugCondition; + +import dmd.DVCondition; +import dmd.Module; +import dmd.Identifier; +import dmd.Scope; +import dmd.ScopeDsymbol; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Array; +import dmd.String; +import dmd.Global; + +import dmd.condition.util.findCondition; + +class DebugCondition : DVCondition +{ + static void setGlobalLevel(uint level) + { + assert(false); + } + + static void addGlobalIdent(const(char)* ident) + { + assert(false); + } + + static void addPredefinedGlobalIdent(const(char)* ident) + { + assert(false); + } + + this(Module mod, uint level, Identifier ident) + { + super(mod, level, ident); + } + + bool include(Scope sc, ScopeDsymbol s) + { + //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel); + if (inc == 0) + { + inc = 2; + + if (ident) + { + if (findCondition(mod.debugids, ident)) + inc = 1; + else if (findCondition(global.params.debugids, ident)) + inc = 1; + else + { + if (!mod.debugidsNot) + mod.debugidsNot = new Array(); + + mod.debugidsNot.push(cast(void*)new String(ident.toChars())); + } + } + else if (level <= global.params.debuglevel || level <= mod.debuglevel) + inc = 1; + } + + return (inc == 1); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/DebugSymbol.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/DebugSymbol.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,49 @@ +module dmd.DebugSymbol; + +import dmd.Dsymbol; +import dmd.Identifier; +import dmd.Loc; +import dmd.Scope; +import dmd.ScopeDsymbol; +import dmd.HdrGenState; +import dmd.OutBuffer; + +class DebugSymbol : Dsymbol +{ + uint level; + + this(Loc loc, Identifier ident) + { + assert(false); + } + + this(Loc loc, uint level) + { + assert(false); + } + + Dsymbol syntaxCopy(Dsymbol s) + { + assert(false); + } + + bool addMember(Scope sc, ScopeDsymbol s, int memnum) + { + assert(false); + } + + void semantic(Scope sc) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + string kind() + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/Declaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Declaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,311 @@ +module dmd.Declaration; + +import dmd.Dsymbol; +import dmd.Type; +import dmd.PROT; +import dmd.LINK; +import dmd.Identifier; +import dmd.Scope; +import dmd.Loc; +import dmd.STC; +import dmd.FuncDeclaration; +import dmd.VarDeclaration; +import dmd.OutBuffer; + +import std.stdio : writef; + +import core.stdc.ctype; +import core.stdc.stdio : sprintf; + +string mangle(Declaration sthis) +{ + scope OutBuffer buf = new OutBuffer(); + + string id; + Dsymbol s = sthis; + + //printf(".mangle(%s)\n", sthis.toChars()); + do + { + //printf("mangle: s = %p, '%s', parent = %p\n", s, s.toChars(), s.parent); + if (s.ident) + { + FuncDeclaration fd = s.isFuncDeclaration(); + if (s !is sthis && fd) + { + id = mangle(fd); + buf.prependstring(id); + goto L1; + } + else + { + id = s.ident.toChars(); + int len = id.length; + char tmp[len.sizeof * 3 + 1]; + buf.prependstring(id); + len = sprintf(tmp.ptr, "%d".ptr, len); + buf.prependstring(tmp[0..len]); + } + } + else + buf.prependstring("0"); + s = s.parent; + } while (s); + +// buf.prependstring("_D"); +L1: + //printf("deco = '%s'\n", sthis.type.deco ? sthis.type.deco : "null"); + //printf("sthis.type = %s\n", sthis.type.toChars()); + FuncDeclaration fd = sthis.isFuncDeclaration(); + if (fd && (fd.needThis() || fd.isNested())) + buf.writeByte(Type.needThisPrefix()); + if (sthis.type.deco) + buf.writestring(sthis.type.deco); + else + { +debug { + if (!fd.inferRetType) + writef("%s\n", fd.toChars()); +} + assert(fd.inferRetType); + } + + id = buf.extractString(); + return id; +} + +class Declaration : Dsymbol +{ + Type type; + Type originalType; // before semantic analysis + STC storage_class = STC.STCundefined; + PROT protection = PROT.PROTundefined; + LINK linkage = LINK.LINKdefault; + int inuse; // used to detect cycles + + this(Identifier id) + { + super(id); + } + + void semantic(Scope sc) + { + assert(false); + } + + string kind() + { + assert(false); + } + + uint size(Loc loc) + { + assert(false); + } + + /************************************* + * Check to see if declaration can be modified in this context (sc). + * Issue error if not. + */ + void checkModify(Loc loc, Scope sc, Type t) + { + if (sc.incontract && isParameter()) + error(loc, "cannot modify parameter '%s' in contract", toChars()); + + if (isCtorinit()) + { + // It's only modifiable if inside the right constructor + Dsymbol s = sc.func; + while (true) + { + FuncDeclaration fd = null; + if (s) + fd = s.isFuncDeclaration(); + if (fd && ((fd.isCtorDeclaration() && storage_class & STC.STCfield) || + (fd.isStaticCtorDeclaration() && !(storage_class & STC.STCfield))) && + fd.toParent() == toParent() + ) + { + VarDeclaration v = isVarDeclaration(); + assert(v); + v.ctorinit = 1; + //printf("setting ctorinit\n"); + } + else + { + if (s) + { + s = s.toParent2(); + continue; + } + else + { + string p = isStatic() ? "static " : ""; + error(loc, "can only initialize %sconst %s inside %sconstructor", p, toChars(), p); + } + } + break; + } + } + else + { + VarDeclaration v = isVarDeclaration(); + if (v && v.canassign == 0) + { + string p = null; + if (isConst()) + p = "const"; + else if (isInvariant()) + p = "immutable"; + else if (storage_class & STC.STCmanifest) + p = "enum"; + else if (!t.isAssignable()) + p = "struct with immutable members"; + if (p) + { + error(loc, "cannot modify %s", p); + } + } + } + } + + void emitComment(Scope sc) + { + assert(false); + } + + void toDocBuffer(OutBuffer buf) + { + assert(false); + } + + string mangle() + out (result) + { + try + { + int len = result.length; + + assert(len > 0); + //printf("mangle: '%s' => '%s'\n", toChars(), result); + for (int i = 0; i < len; i++) + { + assert(result[i] == '_' || result[i] == '@' || isalnum(result[i]) || result[i] & 0x80); + } + } catch { + writef("Incorrect mangle: '%s'\n", result); + assert(false); + } + } + body + { + //writef("Declaration.mangle(this = %p, '%s', parent = '%s', linkage = %d)\n", this, toChars(), parent ? parent.toChars() : "null", linkage); + if (!parent || parent.isModule() || linkage == LINK.LINKcpp) // if at global scope + { + // If it's not a D declaration, no mangling + switch (linkage) + { + case LINK.LINKd: + break; + + case LINK.LINKc: + case LINK.LINKwindows: + case LINK.LINKpascal: + return ident.toChars(); + + case LINK.LINKcpp: +version (CPP_MANGLE) { + return cpp_mangle(this); +} else { + // Windows C++ mangling is done by C++ back end + return ident.toChars(); +} + + case LINK.LINKdefault: + assert(false); + error("forward declaration"); + return ident.toChars(); + + default: + writef("'%s', linkage = %d\n", toChars(), linkage); + assert(0); + } + } + + string p = .mangle(this); + scope OutBuffer buf = new OutBuffer(); + buf.writestring("_D"); + buf.writestring(p); + p = buf.toChars(); + buf.data = null; + //writef("Declaration.mangle(this = %p, '%s', parent = '%s', linkage = %d) = %s\n", this, toChars(), parent ? parent.toChars() : "null", linkage, p); + return p; + } + + int isStatic() { return storage_class & STC.STCstatic; } + + bool isStaticConstructor() + { + return false; + } + + bool isStaticDestructor() + { + return false; + } + + bool isDelete() + { + return false; + } + + bool isDataseg() + { + return false; + } + + bool isThreadlocal() + { + assert(false); + } + + bool isCodeseg() + { + return false; + } + + int isCtorinit() { return storage_class & STC.STCctorinit; } + + int isFinal() { return storage_class & STC.STCfinal; } + + bool isAbstract() { return (storage_class & STC.STCabstract) != 0; } + + bool isConst() { return (storage_class & STC.STCconst) != 0; } + + int isInvariant() { return storage_class & STC.STCinvariant; } + + int isAuto() { return storage_class & STC.STCauto; } + + int isScope() { return storage_class & (STC.STCscope | STC.STCauto); } + + int isSynchronized() { return storage_class & STC.STCsynchronized; } + + int isParameter() { return storage_class & STC.STCparameter; } + + bool isDeprecated() { return (storage_class & STC.STCdeprecated) != 0; } + + int isOverride() { return storage_class & STC.STCoverride; } + + int isIn() { return storage_class & STC.STCin; } + + int isOut() { return storage_class & STC.STCout; } + + int isRef() { return storage_class & STC.STCref; } + + PROT prot() + { + return protection; + } + + Declaration isDeclaration() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/DeclarationExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/DeclarationExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,291 @@ +module dmd.DeclarationExp; + +import dmd.Expression; +import dmd.backend.elem; +import dmd.InterState; +import dmd.ExpInitializer; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.InlineCostState; +import dmd.IRState; +import dmd.InlineDoState; +import dmd.HdrGenState; +import dmd.TupleDeclaration; +import dmd.InlineScanState; +import dmd.Dsymbol; +import dmd.AttribDeclaration; +import dmd.VarDeclaration; +import dmd.Global; +import dmd.TOK; +import dmd.VoidInitializer; +import dmd.Type; +import dmd.codegen.Util; + +// Declaration of a symbol + +class DeclarationExp : Expression +{ + Dsymbol declaration; + + this(Loc loc, Dsymbol declaration) + { + super(loc, TOK.TOKdeclaration, DeclarationExp.sizeof); + this.declaration = declaration; + } + + Expression syntaxCopy() + { + return new DeclarationExp(loc, declaration.syntaxCopy(null)); + } + + Expression semantic(Scope sc) + { + if (type) + return this; + +version (LOGSEMANTIC) { + printf("DeclarationExp.semantic() %s\n", toChars()); +} + + /* This is here to support extern(linkage) declaration, + * where the extern(linkage) winds up being an AttribDeclaration + * wrapper. + */ + Dsymbol s = declaration; + + AttribDeclaration ad = declaration.isAttribDeclaration(); + if (ad) + { + if (ad.decl && ad.decl.dim == 1) + s = cast(Dsymbol)ad.decl.data[0]; + } + + if (s.isVarDeclaration()) + { + // Do semantic() on initializer first, so: + // int a = a; + // will be illegal. + declaration.semantic(sc); + s.parent = sc.parent; + } + + //printf("inserting '%s' %p into sc = %p\n", s.toChars(), s, sc); + // Insert into both local scope and function scope. + // Must be unique in both. + if (s.ident) + { + if (!sc.insert(s)) + error("declaration %s is already defined", s.toPrettyChars()); + else if (sc.func) + { + VarDeclaration v = s.isVarDeclaration(); + if (s.isFuncDeclaration() && !sc.func.localsymtab.insert(s)) + error("declaration %s is already defined in another scope in %s", s.toPrettyChars(), sc.func.toChars()); + else if (!global.params.useDeprecated) + { + // Disallow shadowing + + for (Scope scx = sc.enclosing; scx && scx.func is sc.func; scx = scx.enclosing) + { + Dsymbol s2; + + if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s !is s2) + { + error("shadowing declaration %s is deprecated", s.toPrettyChars()); + } + } + } + } + } + if (!s.isVarDeclaration()) + { + declaration.semantic(sc); + s.parent = sc.parent; + } + if (!global.errors) + { + declaration.semantic2(sc); + if (!global.errors) + { + declaration.semantic3(sc); + + if (!global.errors && global.params.useInline) + declaration.inlineScan(); + } + } + + type = Type.tvoid; + return this; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + bool checkSideEffect(int flag) + { + return true; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + declaration.toCBuffer(buf, hgs); + } + + elem* toElem(IRState* irs) + { + //printf("DeclarationExp::toElem() %s\n", toChars()); + elem* e = Dsymbol_toElem(declaration, irs); + return e; + } + + void scanForNestedRef(Scope sc) + { + assert(false); + } + +version (DMDV2) { + bool canThrow() + { + VarDeclaration v = declaration.isVarDeclaration(); + if (v && v.init) + { + ExpInitializer ie = v.init.isExpInitializer(); + return ie && ie.exp.canThrow(); + } + + return false; + } +} + int inlineCost(InlineCostState* ics) + { + int cost = 0; + VarDeclaration vd; + + //printf("DeclarationExp.inlineCost()\n"); + vd = declaration.isVarDeclaration(); + if (vd) + { + TupleDeclaration td = vd.toAlias().isTupleDeclaration(); + if (td) + { + static if (true) { + return COST_MAX; // finish DeclarationExp.doInline + } else { + for (size_t i = 0; i < td.objects.dim; i++) + { + Object o = cast(Object)td.objects.data[i]; + Expression eo = cast(Expression)o; + if (eo is null) + return COST_MAX; + + if (eo.op != TOKdsymbol) + return COST_MAX; + } + + return td.objects.dim; + } + } + if (!ics.hdrscan && vd.isDataseg()) + return COST_MAX; + + cost += 1; + + // Scan initializer (vd.init) + if (vd.init) + { + ExpInitializer ie = vd.init.isExpInitializer(); + + if (ie) + { + cost += ie.exp.inlineCost(ics); + } + } + } + + // These can contain functions, which when copied, get output twice. + if (declaration.isStructDeclaration() || + declaration.isClassDeclaration() || + declaration.isFuncDeclaration() || + declaration.isTypedefDeclaration() || + declaration.isTemplateMixin() + ) + return COST_MAX; + + //printf("DeclarationExp.inlineCost('%s')\n", toChars()); + return cost; + } + + Expression doInline(InlineDoState ids) + { + DeclarationExp de = cast(DeclarationExp)copy(); + VarDeclaration vd; + + //printf("DeclarationExp.doInline(%s)\n", toChars()); + vd = declaration.isVarDeclaration(); + if (vd) + { + static if (false) { + // Need to figure this out before inlining can work for tuples + TupleDeclaration td = vd.toAlias().isTupleDeclaration(); + if (td) + { + for (size_t i = 0; i < td.objects.dim; i++) + { + DsymbolExp se = cast(DsymbolExp)td.objects.data[i]; + assert(se.op == TOKdsymbol); + se.s; + } + return st.objects.dim; + } + } + if (vd.isStatic()) + { + ; + } + else + { + VarDeclaration vto = new VarDeclaration(vd.loc, vd.type, vd.ident, vd.init); + + ///*vto = *vd; + memcpy(cast(void*)vto, cast(void*)vd, VarDeclaration.classinfo.init.length); + + vto.parent = ids.parent; + vto.csym = null; + vto.isym = null; + + ids.from.push(cast(void*)vd); + ids.to.push(cast(void*)vto); + + if (vd.init) + { + if (vd.init.isVoidInitializer()) + { + vto.init = new VoidInitializer(vd.init.loc); + } + else + { + Expression e = vd.init.toExpression(); + assert(e); + vto.init = new ExpInitializer(e.loc, e.doInline(ids)); + } + } + de.declaration = vto; + } + } + /* This needs work, like DeclarationExp.toElem(), if we are + * to handle TemplateMixin's. For now, we just don't inline them. + */ + return de; + } + + Expression inlineScan(InlineScanState* iss) + { + //printf("DeclarationExp.inlineScan()\n"); + scanVar(declaration, iss); + return this; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/DeclarationStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/DeclarationStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,92 @@ +module dmd.DeclarationStatement; + +import dmd.Loc; +import dmd.ExpStatement; +import dmd.Dsymbol; +import dmd.Expression; +import dmd.Statement; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Scope; +import dmd.DeclarationExp; +import dmd.TOK; +import dmd.VarDeclaration; + +class DeclarationStatement : ExpStatement +{ + // Doing declarations as an expression, rather than a statement, + // makes inlining functions much easier. + + this(Loc loc, Dsymbol declaration) + { + super(loc, new DeclarationExp(loc, declaration)); + } + + this(Loc loc, Expression exp) + { + super(loc, exp); + } + + Statement syntaxCopy() + { + DeclarationStatement ds = new DeclarationStatement(loc, exp.syntaxCopy()); + return ds; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + exp.toCBuffer(buf, hgs); + } + + void scopeCode(Scope sc, Statement* sentry, Statement* sexception, Statement* sfinally) + { + //printf("DeclarationStatement.scopeCode()\n"); + //print(); + + *sentry = null; + *sexception = null; + *sfinally = null; + + if (exp) + { + if (exp.op == TOK.TOKdeclaration) + { + DeclarationExp de = cast(DeclarationExp)exp; + VarDeclaration v = de.declaration.isVarDeclaration(); + if (v) + { + Expression e; + + e = v.callAutoDtor(sc); + if (e) + { + //printf("dtor is: "); e.print(); +static if (false) { + if (v.type.toBasetype().ty == Tstruct) + { + /* Need a 'gate' to turn on/off destruction, + * in case v gets moved elsewhere. + */ + Identifier id = Lexer.uniqueId("__runDtor"); + ExpInitializer ie = new ExpInitializer(loc, new IntegerExp(1)); + VarDeclaration rd = new VarDeclaration(loc, Type.tint32, id, ie); + *sentry = new DeclarationStatement(loc, rd); + v.rundtor = rd; + + /* Rewrite e as: + * rundtor && e + */ + Expression ve = new VarExp(loc, v.rundtor); + e = new AndAndExp(loc, ve, e); + e.type = Type.tbool; + } +} + *sfinally = new ExpStatement(loc, e); + } + } + } + } + } + + DeclarationStatement isDeclarationStatement() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/DefaultInitExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/DefaultInitExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,30 @@ +module dmd.DefaultInitExp; + +import dmd.Expression; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.HdrGenState; +import dmd.TOK; + +class DefaultInitExp : Expression +{ + TOK subop; + + this(Loc loc, TOK subop, int size) + { + assert(false); + super(loc, subop, size); + } + + Expression resolve(Loc loc, Scope sc) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/DefaultStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/DefaultStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,106 @@ +module dmd.DefaultStatement; + +import dmd.Statement; +import dmd.Loc; +import dmd.Scope; +import dmd.Expression; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.InlineScanState; +import dmd.IRState; +import dmd.BE; + +import dmd.backend.Util; +import dmd.backend.OPER; +import dmd.backend.Blockx; +import dmd.backend.block; +import dmd.backend.BC; + +class DefaultStatement : Statement +{ + Statement statement; +version (IN_GCC) { + block* cblock = null; // back end: label for the block +} + + this(Loc loc, Statement s) + { + super(loc); + this.statement = s; + } + + Statement syntaxCopy() + { + assert(false); + } + + Statement semantic(Scope sc) + { + //printf("DefaultStatement.semantic()\n"); + if (sc.sw) + { + if (sc.sw.sdefault) + { + error("switch statement already has a default"); + } + sc.sw.sdefault = this; + + if (sc.sw.tf !is sc.tf) + error("switch and default are in different finally blocks"); + + if (sc.sw.isFinal) + error("default statement not allowed in final switch statement"); + } + else + error("default not in switch statement"); + statement = statement.semantic(sc); + return this; + } + + bool usesEH() + { + assert(false); + } + + BE blockExit() + { + return statement.blockExit(); + } + + bool comeFrom() + { + return true; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + Statement inlineScan(InlineScanState* iss) + { + if (statement) + statement = statement.inlineScan(iss); + return this; + } + + void toIR(IRState* irs) + { + Blockx* blx = irs.blx; + block* bcase = blx.curblock; + block* bdefault = irs.getDefaultBlock(); + block_next(blx,BCgoto,bdefault); + list_append(&bcase.Bsucc,blx.curblock); + if (blx.tryblock != irs.getSwitchBlock().Btry) + error("default cannot be in different try block level from switch"); + incUsage(irs, loc); + if (statement) + statement.toIR(irs); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/DelegateExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/DelegateExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,218 @@ +module dmd.DelegateExp; + +import dmd.Expression; +import dmd.backend.elem; +import dmd.AggregateDeclaration; +import dmd.UnaExp; +import dmd.TypeDelegate; +import dmd.FuncDeclaration; +import dmd.MATCH; +import dmd.Type; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.TY; +import dmd.Scope; +import dmd.InlineCostState; +import dmd.IRState; +import dmd.PREC; +import dmd.HdrGenState; +import dmd.TOK; + +import dmd.expression.Util; +import dmd.codegen.Util; +import dmd.backend.Util; +import dmd.backend.Symbol; +import dmd.backend.TYM; +import dmd.backend.OPER; + +class DelegateExp : UnaExp +{ + FuncDeclaration func; + int hasOverloads; + + this(Loc loc, Expression e, FuncDeclaration f, int hasOverloads = 0) + { + super(loc, TOK.TOKdelegate, DelegateExp.sizeof, e); + this.func = f; + this.hasOverloads = hasOverloads; + } + + Expression semantic(Scope sc) + { + version (LOGSEMANTIC) { + printf("DelegateExp.semantic('%s')\n", toChars()); + } + if (!type) + { + e1 = e1.semantic(sc); + type = new TypeDelegate(func.type); + type = type.semantic(loc, sc); + AggregateDeclaration ad = func.toParent().isAggregateDeclaration(); + if (func.needThis()) + e1 = getRightThis(loc, sc, ad, e1, func); + } + return this; + } + + MATCH implicitConvTo(Type t) + { + static if (false) { + printf("DelegateExp.implicitConvTo(this=%s, type=%s, t=%s)\n", + toChars(), type.toChars(), t.toChars()); + } + MATCH result; + + result = type.implicitConvTo(t); + + if (result == MATCHnomatch) + { + // Look for pointers to functions where the functions are overloaded. + FuncDeclaration f; + + t = t.toBasetype(); + if (type.ty == Tdelegate && type.nextOf().ty == Tfunction && + t.ty == Tdelegate && t.nextOf().ty == Tfunction) + { + if (func && func.overloadExactMatch(t.nextOf())) + result = MATCHexact; + } + } + return result; + } + + Expression castTo(Scope sc, Type t) + { + static if (false) { + printf("DelegateExp.castTo(this=%s, type=%s, t=%s)\n", + toChars(), type.toChars(), t.toChars()); + } + static string msg = "cannot form delegate due to covariant return type"; + + Expression e = this; + Type tb = t.toBasetype(); + Type typeb = type.toBasetype(); + if (tb != typeb) + { + // Look for delegates to functions where the functions are overloaded. + FuncDeclaration f; + + if (typeb.ty == Tdelegate && typeb.nextOf().ty == Tfunction && + tb.ty == Tdelegate && tb.nextOf().ty == Tfunction) + { + if (func) + { + f = func.overloadExactMatch(tb.nextOf()); + if (f) + { + int offset; + if (f.tintro && f.tintro.nextOf().isBaseOf(f.type.nextOf(), &offset) && offset) + error("%s", msg); + f.tookAddressOf++; + e = new DelegateExp(loc, e1, f); + e.type = t; + return e; + } + if (func.tintro) + error("%s", msg); + } + } + e = Expression.castTo(sc, t); + } + else + { + int offset; + + func.tookAddressOf++; + if (func.tintro && func.tintro.nextOf().isBaseOf(func.type.nextOf(), &offset) && offset) + error("%s", msg); + e = copy(); + e.type = t; + } + return e; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + buf.writeByte('&'); + if (!func.isNested()) + { + expToCBuffer(buf, hgs, e1, PREC.PREC_primary); + buf.writeByte('.'); + } + buf.writestring(func.toChars()); + } + + void dump(int indent) + { + assert(false); + } + + int inlineCost(InlineCostState* ics) + { + assert(false); + } + + elem* toElem(IRState* irs) + { + elem* e; + elem* ethis; + elem* ep; + Symbol* sfunc; + int directcall = 0; + + //printf("DelegateExp.toElem() '%s'\n", toChars()); + sfunc = func.toSymbol(); + if (func.isNested()) + { + ep = el_ptr(sfunc); + ethis = getEthis(loc, irs, func); + } + else + { + ethis = e1.toElem(irs); + if (e1.type.ty != Tclass && e1.type.ty != Tpointer) + ethis = addressElem(ethis, e1.type); + + if (e1.op == TOKsuper) + directcall = 1; + + if (!func.isThis()) + error("delegates are only for non-static functions"); + + if (!func.isVirtual() || + directcall || + func.isFinal()) + { + ep = el_ptr(sfunc); + } + else + { + // Get pointer to function out of virtual table + assert(ethis); + ep = el_same(ðis); + ep = el_una(OPind, TYnptr, ep); + uint vindex = func.vtblIndex; + + // Build *(ep + vindex * 4) + ep = el_bin(OPadd,TYnptr,ep,el_long(TYint, vindex * 4)); + ep = el_una(OPind,TYnptr,ep); + } + + // if (func.tintro) + // func.error(loc, "cannot form delegate due to covariant return type"); + } + + if (ethis.Eoper == OPcomma) + { + ethis.E2() = el_pair(TYullong, ethis.E2, ep); + ethis.Ety = TYullong; + e = ethis; + } + else + e = el_pair(TYullong, ethis, ep); + + el_setLoc(e,loc); + + return e; + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/DeleteDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/DeleteDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,65 @@ +module dmd.DeleteDeclaration; + +import dmd.FuncDeclaration; +import dmd.ArrayTypes; +import dmd.Loc; +import dmd.Dsymbol; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.STC; + +class DeleteDeclaration : FuncDeclaration +{ + Arguments arguments; + + this(Loc loc, Loc endloc, Arguments arguments) + { + assert(false); + super(loc, endloc, null, STC.init, null); + } + + Dsymbol syntaxCopy(Dsymbol) + { + assert(false); + } + + void semantic(Scope sc) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + string kind() + { + assert(false); + } + + bool isDelete() + { + assert(false); + } + + bool isVirtual() + { + assert(false); + } + + bool addPreInvariant() + { + assert(false); + } + + bool addPostInvariant() + { + assert(false); + } + +version (_DH) { + DeleteDeclaration isDeleteDeclaration() { return this; } +} +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/DeleteExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/DeleteExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,273 @@ +module dmd.DeleteExp; + +import dmd.Expression; +import dmd.backend.elem; +import dmd.UnaExp; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.IRState; +import dmd.HdrGenState; +import dmd.Type; +import dmd.IndexExp; +import dmd.Global; +import dmd.VarExp; +import dmd.Identifier; +import dmd.StructDeclaration; +import dmd.Lexer; +import dmd.FuncDeclaration; +import dmd.TypeStruct; +import dmd.CallExp; +import dmd.DotVarExp; +import dmd.DeclarationExp; +import dmd.ExpInitializer; +import dmd.VarDeclaration; +import dmd.TypePointer; +import dmd.ClassDeclaration; +import dmd.TypeClass; +import dmd.TY; +import dmd.TOK; +import dmd.TypeAArray; +import dmd.TypeSArray; + +import dmd.codegen.Util; +import dmd.backend.Util; +import dmd.backend.OPER; +import dmd.backend.RTLSYM; +import dmd.backend.mTY; +import dmd.backend.Symbol; +import dmd.backend.TYM; + +class DeleteExp : UnaExp +{ + this(Loc loc, Expression e) + { + super(loc, TOK.TOKdelete, DeleteExp.sizeof, e); + } + + Expression semantic(Scope sc) + { + Type tb; + + UnaExp.semantic(sc); + e1 = resolveProperties(sc, e1); + e1 = e1.toLvalue(sc, null); + type = Type.tvoid; + + tb = e1.type.toBasetype(); + switch (tb.ty) + { + case Tclass: + { + TypeClass tc = cast(TypeClass)tb; + ClassDeclaration cd = tc.sym; + + if (cd.isCOMinterface()) + { /* Because COM classes are deleted by IUnknown.Release() + */ + error("cannot delete instance of COM interface %s", cd.toChars()); + } + break; + } + case Tpointer: + tb = (cast(TypePointer)tb).next.toBasetype(); + if (tb.ty == Tstruct) + { + TypeStruct ts = cast(TypeStruct)tb; + StructDeclaration sd = ts.sym; + FuncDeclaration f = sd.aggDelete; + FuncDeclaration fd = sd.dtor; + + if (!f && !fd) + break; + + /* Construct: + * ea = copy e1 to a tmp to do side effects only once + * eb = call destructor + * ec = call deallocator + */ + Expression ea = null; + Expression eb = null; + Expression ec = null; + VarDeclaration v; + + if (fd && f) + { + Identifier id = Lexer.idPool("__tmp"); + v = new VarDeclaration(loc, e1.type, id, new ExpInitializer(loc, e1)); + v.semantic(sc); + v.parent = sc.parent; + ea = new DeclarationExp(loc, v); + ea.type = v.type; + } + + if (fd) + { + Expression e = ea ? new VarExp(loc, v) : e1; + e = new DotVarExp(Loc(0), e, fd, 0); + eb = new CallExp(loc, e); + eb = eb.semantic(sc); + } + + if (f) + { + Type tpv = Type.tvoid.pointerTo(); + Expression e = ea ? new VarExp(loc, v) : e1.castTo(sc, tpv); + e = new CallExp(loc, new VarExp(loc, f), e); + ec = e.semantic(sc); + } + ea = combine(ea, eb); + ea = combine(ea, ec); + assert(ea); + return ea; + } + break; + + case Tarray: + /* BUG: look for deleting arrays of structs with dtors. + */ + break; + + default: + if (e1.op == TOKindex) + { + IndexExp ae = cast(IndexExp)e1; + Type tb1 = ae.e1.type.toBasetype(); + if (tb1.ty == Taarray) + break; + } + error("cannot delete type %s", e1.type.toChars()); + break; + } + + if (e1.op == TOKindex) + { + IndexExp ae = cast(IndexExp)e1; + Type tb1 = ae.e1.type.toBasetype(); + if (tb1.ty == Taarray) + { + if (!global.params.useDeprecated) + error("delete aa[key] deprecated, use aa.remove(key)"); + } + } + + return this; + } + + Expression checkToBoolean() + { + assert(false); + } + + bool checkSideEffect(int flag) + { + return true; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + elem* toElem(IRState* irs) + { + elem* e; + int rtl; + Type tb; + + //printf("DeleteExp.toElem()\n"); + if (e1.op == TOKindex) + { + IndexExp ae = cast(IndexExp)e1; + tb = ae.e1.type.toBasetype(); + if (tb.ty == Taarray) + { + TypeAArray taa = cast(TypeAArray)tb; + elem* ea = ae.e1.toElem(irs); + elem* ekey = ae.e2.toElem(irs); + elem* ep; + elem* keyti; + + if (tybasic(ekey.Ety) == TYstruct) + { + ekey = el_una(OPstrpar, TYstruct, ekey); + ekey.Enumbytes = ekey.E1.Enumbytes; + assert(ekey.Enumbytes); + } + + Symbol *s = taa.aaGetSymbol("Del", 0); + keyti = taa.index.getInternalTypeInfo(null).toElem(irs); + ep = el_params(ekey, keyti, ea, null); + e = el_bin(OPcall, TYnptr, el_var(s), ep); + goto Lret; + } + } + //e1.type.print(); + e = e1.toElem(irs); + tb = e1.type.toBasetype(); + switch (tb.ty) + { + case Tarray: + { + e = addressElem(e, e1.type); + rtl = RTLSYM_DELARRAYT; + + /* See if we need to run destructors on the array contents + */ + elem *et = null; + Type tv = tb.nextOf().toBasetype(); + while (tv.ty == Tsarray) + { + TypeSArray ta = cast(TypeSArray)tv; + tv = tv.nextOf().toBasetype(); + } + if (tv.ty == Tstruct) + { + TypeStruct ts = cast(TypeStruct)tv; + StructDeclaration sd = ts.sym; + if (sd.dtor) + et = tb.nextOf().getTypeInfo(null).toElem(irs); + } + if (!et) // if no destructors needed + et = el_long(TYnptr, 0); // pass null for TypeInfo + e = el_params(et, e, null); + // call _d_delarray_t(e, et); + e = el_bin(OPcall, TYvoid, el_var(rtlsym[rtl]), e); + goto Lret; + } + case Tclass: + if (e1.op == TOKvar) + { + VarExp ve = cast(VarExp)e1; + if (ve.var.isVarDeclaration() && + ve.var.isVarDeclaration().onstack) + { + rtl = RTLSYM_CALLFINALIZER; + if (tb.isClassHandle().isInterfaceDeclaration()) + rtl = RTLSYM_CALLINTERFACEFINALIZER; + break; + } + } + e = addressElem(e, e1.type); + rtl = RTLSYM_DELCLASS; + if (tb.isClassHandle().isInterfaceDeclaration()) + rtl = RTLSYM_DELINTERFACE; + break; + + case Tpointer: + e = addressElem(e, e1.type); + rtl = RTLSYM_DELMEMORY; + break; + + default: + assert(0); + break; + } + e = el_bin(OPcall, TYvoid, el_var(rtlsym[rtl]), e); + + Lret: + el_setLoc(e,loc); + return e; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/DivAssignExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/DivAssignExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,118 @@ +module dmd.DivAssignExp; + +import dmd.BinExp; +import dmd.Loc; +import dmd.Expression; +import dmd.Scope; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.ArrayTypes; +import dmd.Identifier; +import dmd.IRState; +import dmd.TOK; +import dmd.Type; +import dmd.TY; +import dmd.Id; +import dmd.CommaExp; +import dmd.RealExp; +import dmd.AssignExp; + +import dmd.backend.elem; +import dmd.backend.OPER; +import dmd.backend.Util; +import dmd.expression.Util; + +class DivAssignExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKdivass, DivAssignExp.sizeof, e1, e2); + } + + Expression semantic(Scope sc) + { + Expression e; + + BinExp.semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + if (e1.op == TOKslice) + { // T[] -= ... + typeCombine(sc); + type = e1.type; + return arrayOp(sc); + } + + e1 = e1.modifiableLvalue(sc, e1); + e1.checkScalar(); + e1.checkNoBool(); + type = e1.type; + typeCombine(sc); + e1.checkArithmetic(); + e2.checkArithmetic(); + if (e2.type.isimaginary()) + { + Type t1; + Type t2; + + t1 = e1.type; + if (t1.isreal()) + { + // x/iv = i(-x/v) + // Therefore, the result is 0 + e2 = new CommaExp(loc, e2, new RealExp(loc, 0, t1)); + e2.type = t1; + e = new AssignExp(loc, e1, e2); + e.type = t1; + return e; + } + else if (t1.isimaginary()) + { + Expression e3; + + switch (t1.ty) + { + case Timaginary32: t2 = Type.tfloat32; break; + case Timaginary64: t2 = Type.tfloat64; break; + case Timaginary80: t2 = Type.tfloat80; break; + default: + assert(0); + } + e2 = e2.castTo(sc, t2); + e3 = new AssignExp(loc, e1, e2); + e3.type = t1; + return e3; + } + } + return this; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void buildArrayIdent(OutBuffer buf, Expressions arguments) + { + assert(false); + } + + Expression buildArrayLoop(Arguments fparams) + { + assert(false); + } + + Identifier opId() /* For operator overloading */ + { + return Id.divass; + } + + elem* toElem(IRState* irs) + { + return toElemBin(irs,OPdivass); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/DivExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/DivExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,143 @@ +module dmd.DivExp; + +import dmd.Expression; +import dmd.Identifier; +import dmd.backend.elem; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.IntRange; +import dmd.IRState; +import dmd.ArrayTypes; +import dmd.BinExp; +import dmd.TOK; +import dmd.Type; +import dmd.NegExp; +import dmd.TY; +import dmd.Id; + +import dmd.expression.Div; +import dmd.backend.OPER; +import dmd.backend.Util; + +class DivExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKdiv, DivExp.sizeof, e1, e2); + } + + Expression semantic(Scope sc) + { + Expression e; + + if (type) + return this; + + super.semanticp(sc); + e = op_overload(sc); + if (e) + return e; + + typeCombine(sc); + if (e1.op != TOK.TOKslice && e2.op != TOK.TOKslice) + { + e1.checkArithmetic(); + e2.checkArithmetic(); + } + if (type.isfloating()) + { + Type t1 = e1.type; + Type t2 = e2.type; + + if (t1.isreal()) + { + type = t2; + if (t2.isimaginary()) + { + // x/iv = i(-x/v) + e2.type = t1; + Expression ee = new NegExp(loc, this); + ee = ee.semantic(sc); + return e; + } + } + else if (t2.isreal()) + { + type = t1; + } + else if (t1.isimaginary()) + { + if (t2.isimaginary()) { + switch (t1.ty) + { + case TY.Timaginary32: type = Type.tfloat32; break; + case TY.Timaginary64: type = Type.tfloat64; break; + case TY.Timaginary80: type = Type.tfloat80; break; + default: assert(0); + } + } else { + type = t2; // t2 is complex + } + } + else if (t2.isimaginary()) + { + type = t1; // t1 is complex + } + } + return this; + } + + Expression optimize(int result) + { + Expression e; + + //printf("DivExp.optimize(%s)\n", toChars()); + e1 = e1.optimize(result); + e2 = e2.optimize(result); + if (e1.isConst() == 1 && e2.isConst() == 1) + { + e = Div(type, e1, e2); + } + else + e = this; + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void buildArrayIdent(OutBuffer buf, Expressions arguments) + { + assert(false); + } + + Expression buildArrayLoop(Arguments fparams) + { + assert(false); + } + + IntRange getIntRange() + { + assert(false); + } + + Identifier opId() + { + return Id.div; + } + + Identifier opId_r() + { + return Id.div_r; + } + + elem* toElem(IRState* irs) + { + return toElemBin(irs,OPdiv); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/DoStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/DoStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,141 @@ +module dmd.DoStatement; + +import dmd.Statement; +import dmd.Expression; +import dmd.Loc; +import dmd.Scope; +import dmd.InterState; +import dmd.HdrGenState; +import dmd.OutBuffer; +import dmd.InlineScanState; +import dmd.IRState; +import dmd.BE; +import dmd.WANT; + +import dmd.backend.block; +import dmd.backend.Blockx; +import dmd.backend.Util; +import dmd.backend.BC; + +class DoStatement : Statement +{ + Statement body_; + Expression condition; + + this(Loc loc, Statement b, Expression c) + { + super(loc); + body_ = b; + condition = c; + } + + Statement syntaxCopy() + { + DoStatement s = new DoStatement(loc, body_ ? body_.syntaxCopy() : null, condition.syntaxCopy()); + return s; + } + + Statement semantic(Scope sc) + { + sc.noctor++; + if (body_) + body_ = body_.semanticScope(sc, this, this); + sc.noctor--; + condition = condition.semantic(sc); + condition = resolveProperties(sc, condition); + condition = condition.optimize(WANTvalue); + + condition = condition.checkToBoolean(); + + return this; + } + + bool hasBreak() + { + return true; + } + + bool hasContinue() + { + return true; + } + + bool usesEH() + { + return body_ ? body_.usesEH() : false; + } + + BE blockExit() + { + BE result; + + if (body_) + { + result = body_.blockExit(); + if (result == BE.BEbreak) + return BE.BEfallthru; + if (result & BE.BEcontinue) + result |= BE.BEfallthru; + } + else + result = BE.BEfallthru; + + if (result & BE.BEfallthru) + { + if (condition.canThrow()) + result |= BE.BEthrow; + if (!(result & BE.BEbreak) && condition.isBool(true)) + result &= ~BE.BEfallthru; + } + result &= ~(BE.BEbreak | BE.BEcontinue); + + return result; + } + + bool comeFrom() + { + assert(false); + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + Statement inlineScan(InlineScanState* iss) + { + body_ = body_ ? body_.inlineScan(iss) : null; + condition = condition.inlineScan(iss); + return this; + } + + void toIR(IRState* irs) + { + Blockx *blx = irs.blx; + + IRState mystate = IRState(irs,this); + mystate.breakBlock = block_calloc(blx); + mystate.contBlock = block_calloc(blx); + + block* bpre = blx.curblock; + block_next(blx, BCgoto, null); + list_append(&bpre.Bsucc, blx.curblock); + + list_append(&mystate.contBlock.Bsucc, blx.curblock); + list_append(&mystate.contBlock.Bsucc, mystate.breakBlock); + + if (body_) + body_.toIR(&mystate); + list_append(&blx.curblock.Bsucc, mystate.contBlock); + + block_next(blx, BCgoto, mystate.contBlock); + incUsage(irs, condition.loc); + block_appendexp(mystate.contBlock, condition.toElem(&mystate)); + block_next(blx, BCiftrue, mystate.breakBlock); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/DocComment.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/DocComment.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,50 @@ +module dmd.DocComment; + +import dmd.Array; +import dmd.Section; +import dmd.Macro; +import dmd.Escape; +import dmd.Scope; +import dmd.Dsymbol; +import dmd.OutBuffer; + +class DocComment +{ + Array sections; // Section*[] + + Section summary; + Section copyright; + Section macros; + Macro** pmacrotable; + Escape** pescapetable; + + this() + { + assert(false); + } + + static DocComment parse(Scope sc, Dsymbol s, ubyte* comment) + { + assert(false); + } + + static void parseMacros(Escape** pescapetable, Macro** pmacrotable, ubyte* m, uint mlen) + { + assert(false); + } + + static void parseEscapes(Escape** pescapetable, ubyte* textstart, uint textlen) + { + assert(false); + } + + void parseSections(ubyte* comment) + { + assert(false); + } + + void writeSections(Scope sc, Dsymbol s, OutBuffer buf) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/DollarExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/DollarExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,16 @@ +module dmd.DollarExp; + +import dmd.IdentifierExp; +import dmd.Loc; +import dmd.Identifier; +import dmd.TOK; +import dmd.Id; + +class DollarExp : IdentifierExp +{ + this(Loc loc) + { + super(loc, Id.dollar); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/DotExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/DotExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,22 @@ +module dmd.DotExp; + +import dmd.Expression; +import dmd.Loc; +import dmd.Scope; +import dmd.BinExp; +import dmd.TOK; + +class DotExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + assert(false); + super(loc, TOK.init, 0, e1, e2); + } + + Expression semantic(Scope sc) + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/DotIdExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/DotIdExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,373 @@ +module dmd.DotIdExp; + +import dmd.Expression; +import dmd.Identifier; +import dmd.IntegerExp; +import dmd.Type; +import dmd.TY; +import dmd.ScopeExp; +import dmd.StringExp; +import dmd.PtrExp; +import dmd.TypePointer; +import dmd.Dsymbol; +import dmd.EnumMember; +import dmd.VarDeclaration; +import dmd.ThisExp; +import dmd.DotVarExp; +import dmd.VarExp; +import dmd.CommaExp; +import dmd.FuncDeclaration; +import dmd.OverloadSet; +import dmd.OverExp; +import dmd.TypeExp; +import dmd.TupleDeclaration; +import dmd.ScopeDsymbol; +import dmd.Import; +import dmd.Id; +import dmd.TupleExp; +import dmd.ArrayTypes; +import dmd.UnaExp; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.TOK; +import dmd.HdrGenState; +import dmd.ClassDeclaration; +import dmd.StructDeclaration; +import dmd.AggregateDeclaration; +import dmd.DotExp; +import dmd.Global; +import dmd.IdentifierExp; +import dmd.CallExp; +import dmd.PREC; + +import dmd.expression.Util; + +class DotIdExp : UnaExp +{ + Identifier ident; + + this(Loc loc, Expression e, Identifier ident) + { + super(loc, TOK.TOKdot, DotIdExp.sizeof, e); + this.ident = ident; + } + + Expression semantic(Scope sc) + { + Expression e; + Expression eleft; + Expression eright; + +version (LOGSEMANTIC) { + printf("DotIdExp.semantic(this = %p, '%s')\n", this, toChars()); + //printf("e1.op = %d, '%s'\n", e1.op, Token.toChars(e1.op)); +} + + //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; } + +static if (false) { + /* Don't do semantic analysis if we'll be converting + * it to a string. + */ + if (ident == Id.stringof) + { + char *s = e1.toChars(); + e = new StringExp(loc, s, strlen(s), 'c'); + e = e.semantic(sc); + return e; + } +} + + /* Special case: rewrite this.id and super.id + * to be classtype.id and baseclasstype.id + * if we have no this pointer. + */ + if ((e1.op == TOK.TOKthis || e1.op == TOK.TOKsuper) && !hasThis(sc)) + { + ClassDeclaration cd; + StructDeclaration sd; + AggregateDeclaration ad; + + ad = sc.getStructClassScope(); + if (ad) + { + cd = ad.isClassDeclaration(); + if (cd) + { + if (e1.op == TOK.TOKthis) + { + e = typeDotIdExp(loc, cd.type, ident); + return e.semantic(sc); + } + else if (cd.baseClass && e1.op == TOK.TOKsuper) + { + e = typeDotIdExp(loc, cd.baseClass.type, ident); + return e.semantic(sc); + } + } + else + { + sd = ad.isStructDeclaration(); + if (sd) + { + if (e1.op == TOK.TOKthis) + { + e = typeDotIdExp(loc, sd.type, ident); + return e.semantic(sc); + } + } + } + } + } + + UnaExp.semantic(sc); + + if (e1.op == TOK.TOKdotexp) + { + DotExp de = cast(DotExp)e1; + eleft = de.e1; + eright = de.e2; + } + else + { + e1 = resolveProperties(sc, e1); + eleft = null; + eright = e1; + } + +version (DMDV2) { + if (e1.op == TOK.TOKtuple && ident == Id.offsetof) + { + /* 'distribute' the .offsetof to each of the tuple elements. + */ + TupleExp te = cast(TupleExp)e1; + Expressions exps = new Expressions(); + exps.setDim(te.exps.dim); + for (int i = 0; i < exps.dim; i++) + { + Expression ee = cast(Expression)te.exps.data[i]; + ee = ee.semantic(sc); + ee = new DotIdExp(e.loc, ee, Id.offsetof); + exps.data[i] = cast(void*)ee; + } + e = new TupleExp(loc, exps); + e = e.semantic(sc); + return e; + } +} + + if (e1.op == TOK.TOKtuple && ident == Id.length) + { + TupleExp te = cast(TupleExp)e1; + e = new IntegerExp(loc, te.exps.dim, Type.tsize_t); + return e; + } + + if (e1.op == TOK.TOKdottd) + { + error("template %s does not have property %s", e1.toChars(), ident.toChars()); + return e1; + } + + if (!e1.type) + { + error("expression %s does not have property %s", e1.toChars(), ident.toChars()); + return e1; + } + + Type t1b = e1.type.toBasetype(); + + if (eright.op == TOK.TOKimport) // also used for template alias's + { + ScopeExp ie = cast(ScopeExp)eright; + + /* Disable access to another module's private imports. + * The check for 'is sds our current module' is because + * the current module should have access to its own imports. + */ + Dsymbol s = ie.sds.search(loc, ident, + (ie.sds.isModule() && ie.sds != sc.module_) ? 1 : 0); + if (s) + { + s = s.toAlias(); + checkDeprecated(sc, s); + + EnumMember em = s.isEnumMember(); + if (em) + { + e = em.value; + e = e.semantic(sc); + return e; + } + + VarDeclaration v = s.isVarDeclaration(); + if (v) + { + //printf("DotIdExp. Identifier '%s' is a variable, type '%s'\n", toChars(), v.type.toChars()); + if (v.inuse) + { + error("circular reference to '%s'", v.toChars()); + type = Type.tint32; + return this; + } + type = v.type; + if (v.needThis()) + { + if (!eleft) + eleft = new ThisExp(loc); + e = new DotVarExp(loc, eleft, v); + e = e.semantic(sc); + } + else + { + e = new VarExp(loc, v); + if (eleft) + { + e = new CommaExp(loc, eleft, e); + e.type = v.type; + } + } + return e.deref(); + } + + FuncDeclaration f = s.isFuncDeclaration(); + if (f) + { + //printf("it's a function\n"); + if (f.needThis()) + { + if (!eleft) + eleft = new ThisExp(loc); + e = new DotVarExp(loc, eleft, f); + e = e.semantic(sc); + } + else + { + e = new VarExp(loc, f, 1); + if (eleft) + { e = new CommaExp(loc, eleft, e); + e.type = f.type; + } + } + return e; + } +version (DMDV2) { + OverloadSet o = s.isOverloadSet(); + if (o) + { + //printf("'%s' is an overload set\n", o.toChars()); + return new OverExp(o); + } +} + + Type t = s.getType(); + if (t) + { + return new TypeExp(loc, t); + } + + TupleDeclaration tup = s.isTupleDeclaration(); + if (tup) + { + if (eleft) + error("cannot have e.tuple"); + e = new TupleExp(loc, tup); + e = e.semantic(sc); + return e; + } + + ScopeDsymbol sds = s.isScopeDsymbol(); + if (sds) + { + //printf("it's a ScopeDsymbol\n"); + e = new ScopeExp(loc, sds); + e = e.semantic(sc); + if (eleft) + e = new DotExp(loc, eleft, e); + return e; + } + + Import imp = s.isImport(); + if (imp) + { + ScopeExp iee = new ScopeExp(loc, imp.pkg); + return iee.semantic(sc); + } + + // BUG: handle other cases like in IdentifierExp.semantic() +version (DEBUG) { + printf("s = '%s', kind = '%s'\n", s.toChars(), s.kind()); +} + assert(0); + } + else if (ident is Id.stringof_) + { + string ss = ie.toChars(); + e = new StringExp(loc, ss, 'c'); + e = e.semantic(sc); + return e; + } + error("undefined identifier %s", toChars()); + type = Type.tvoid; + return this; + } + else if (t1b.ty == TY.Tpointer && + ident !is Id.init_ && ident !is Id.__sizeof && + ident !is Id.alignof_ && ident !is Id.offsetof && + ident !is Id.mangleof_ && ident !is Id.stringof_) + { /* Rewrite: + * p.ident + * as: + * (*p).ident + */ + e = new PtrExp(loc, e1); + e.type = (cast(TypePointer)t1b).next; + return e.type.dotExp(sc, e, ident); + } +///version (DMDV2) { + else if (t1b.ty == TY.Tarray || + t1b.ty == TY.Tsarray || + t1b.ty == TY.Taarray) + { + /* If ident is not a valid property, rewrite: + * e1.ident + * as: + * .ident(e1) + */ + uint errors = global.errors; + global.gag++; + e = e1.type.dotExp(sc, e1, ident); + global.gag--; + if (errors != global.errors) // if failed to find the property + { + global.errors = errors; + e = new DotIdExp(loc, new IdentifierExp(loc, Id.empty), ident); + e = new CallExp(loc, e, e1); + } + e = e.semantic(sc); + return e; + } +///} + else + { + e = e1.type.dotExp(sc, e1, ident); + e = e.semantic(sc); + return e; + } + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + //printf("DotIdExp.toCBuffer()\n"); + expToCBuffer(buf, hgs, e1, PREC.PREC_primary); + buf.writeByte('.'); + buf.writestring(ident.toChars()); + } + + void dump(int i) + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/DotTemplateExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/DotTemplateExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,26 @@ +module dmd.DotTemplateExp; + +import dmd.Expression; +import dmd.UnaExp; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.TOK; +import dmd.HdrGenState; +import dmd.TemplateDeclaration; + +class DotTemplateExp : UnaExp +{ + TemplateDeclaration td; + + this(Loc loc, Expression e, TemplateDeclaration td) + { + assert(false); + super(loc, TOK.init, 0, e); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/DotTemplateInstanceExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/DotTemplateInstanceExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,42 @@ +module dmd.DotTemplateInstanceExp; + +import dmd.Expression; +import dmd.UnaExp; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.TemplateInstance; +import dmd.HdrGenState; +import dmd.TOK; + +class DotTemplateInstanceExp : UnaExp +{ + TemplateInstance ti; + + this(Loc loc, Expression e, TemplateInstance ti) + { + assert(false); + super(loc, TOK.init, 0, e); + } + + Expression syntaxCopy() + { + assert(false); + } + + Expression semantic(Scope sc) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + void dump(int indent) + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/DotTypeExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/DotTypeExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,48 @@ +module dmd.DotTypeExp; + +import dmd.Expression; +import dmd.backend.elem; +import dmd.UnaExp; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.IRState; +import dmd.HdrGenState; +import dmd.Dsymbol; +import dmd.TOK; +import dmd.PREC; +import dmd.expression.Util; + +class DotTypeExp : UnaExp +{ + Dsymbol sym; + + this(Loc loc, Expression e, Dsymbol s) + { + super(loc, TOK.TOKdottype, DotTypeExp.sizeof, e); + this.sym = s; + this.type = s.getType(); + } + + Expression semantic(Scope sc) + { + version (LOGSEMANTIC) { + printf("DotTypeExp.semantic('%s')\n", toChars()); + } + UnaExp.semantic(sc); + return this; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + expToCBuffer(buf, hgs, e1, PREC.PREC_primary); + buf.writeByte('.'); + buf.writestring(sym.toChars()); + } + + elem* toElem(IRState* irs) + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/DotVarExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/DotVarExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,281 @@ +module dmd.DotVarExp; + +import dmd.Expression; +import dmd.Declaration; +import dmd.backend.elem; +import dmd.UnaExp; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.IRState; +import dmd.HdrGenState; +import dmd.TOK; +import dmd.TupleDeclaration; +import dmd.ArrayTypes; +import dmd.DsymbolExp; +import dmd.TupleExp; +import dmd.Global; +import dmd.Type; +import dmd.Dsymbol; +import dmd.AggregateDeclaration; +import dmd.VarDeclaration; +import dmd.WANT; +import dmd.TY; +import dmd.ErrorExp; +import dmd.FuncDeclaration; +import dmd.STC; +import dmd.GlobalExpressions; +import dmd.VarExp; +import dmd.StructLiteralExp; +import dmd.PREC; + +import dmd.expression.Util; +import dmd.codegen.Util; +import dmd.backend.Util; +import dmd.backend.mTY; +import dmd.backend.OPER; +import dmd.backend.TYM; + +class DotVarExp : UnaExp +{ + Declaration var; + + int hasOverloads; + + this(Loc loc, Expression e, Declaration var, int hasOverloads = 0) + { + super(loc, TOK.TOKdotvar, DotVarExp.sizeof, e); + //printf("DotVarExp()\n"); + this.var = var; + this.hasOverloads = hasOverloads; + } + + Expression semantic(Scope sc) + { +version (LOGSEMANTIC) { + printf("DotVarExp.semantic('%s')\n", toChars()); +} + if (!type) + { + var = var.toAlias().isDeclaration(); + + TupleDeclaration tup = var.isTupleDeclaration(); + if (tup) + { + /* Replace: + * e1.tuple(a, b, c) + * with: + * tuple(e1.a, e1.b, e1.c) + */ + Expressions exps = new Expressions; + + exps.reserve(tup.objects.dim); + for (size_t i = 0; i < tup.objects.dim; i++) + { + Object o = cast(Object)tup.objects.data[i]; + if (auto e = cast(Expression)o) + { + if (e.op != TOK.TOKdsymbol) + error("%s is not a member", e.toChars()); + else + { + DsymbolExp ve = cast(DsymbolExp)e; + e = new DotVarExp(loc, e1, ve.s.isDeclaration()); + exps.push(cast(void*)e); + } + } else { + error("%s is not an expression", o.toString()); + } + } + Expression e = new TupleExp(loc, exps); + e = e.semantic(sc); + return e; + } + + e1 = e1.semantic(sc); + type = var.type; + if (!type && global.errors) + { + // var is goofed up, just return 0 + return new ErrorExp(); + } + assert(type); + + if (!var.isFuncDeclaration()) // for functions, do checks after overload resolution + { + Type t1 = e1.type; + if (t1.ty == TY.Tpointer) + t1 = t1.nextOf(); + + type = type.addMod(t1.mod); + + Dsymbol vparent = var.toParent(); + AggregateDeclaration ad = vparent ? vparent.isAggregateDeclaration() : null; + e1 = getRightThis(loc, sc, ad, e1, var); + if (!sc.noaccesscheck) + accessCheck(loc, sc, e1, var); + + VarDeclaration v = var.isVarDeclaration(); + Expression e = expandVar(WANT.WANTvalue, v); + if (e) + return e; + } + } + //printf("-DotVarExp.semantic('%s')\n", toChars()); + return this; + } + + int isLvalue() + { + assert(false); + } + + Expression toLvalue(Scope sc, Expression e) + { + //printf("DotVarExp::toLvalue(%s)\n", toChars()); + return this; + } + + Expression modifiableLvalue(Scope sc, Expression e) + { +static if (false) { + printf("DotVarExp::modifiableLvalue(%s)\n", toChars()); + printf("e1.type = %s\n", e1.type.toChars()); + printf("var.type = %s\n", var.type.toChars()); +} + + if (var.isCtorinit()) + { + // It's only modifiable if inside the right constructor + Dsymbol s = sc.func; + while (true) + { + FuncDeclaration fd = null; + if (s) + fd = s.isFuncDeclaration(); + if (fd && ((fd.isCtorDeclaration() && var.storage_class & STC.STCfield) || + (fd.isStaticCtorDeclaration() && !(var.storage_class & STC.STCfield))) && + fd.toParent() == var.toParent() && e1.op == TOK.TOKthis) + { + VarDeclaration v = var.isVarDeclaration(); + assert(v); + v.ctorinit = 1; + //printf("setting ctorinit\n"); + } + else + { + if (s) + { + s = s.toParent2(); + continue; + } + else + { + string p = var.isStatic() ? "static " : ""; + error("can only initialize %sconst member %s inside %sconstructor", p, var.toChars(), p); + } + } + break; + } + } + else + { +version (DMDV2) { + Type t1 = e1.type.toBasetype(); + + if (!t1.isMutable() || (t1.ty == TY.Tpointer && !t1.nextOf().isMutable()) || + !var.type.isMutable() || !var.type.isAssignable() || var.storage_class & STC.STCmanifest) + { + error("cannot modify const/immutable expression %s", toChars()); + } +} + } + + return this; + } + + Expression optimize(int result) + { + //printf("DotVarExp.optimize(result = x%x) %s\n", result, toChars()); + e1 = e1.optimize(result); + + if (e1.op == TOK.TOKvar) + { + VarExp ve = cast(VarExp)e1; + VarDeclaration v = ve.var.isVarDeclaration(); + Expression e = expandVar(result, v); + if (e && e.op == TOK.TOKstructliteral) + { + StructLiteralExp sle = cast(StructLiteralExp)e; + VarDeclaration vf = var.isVarDeclaration(); + if (vf) + { + e = sle.getField(type, vf.offset); + if (e && e !is EXP_CANT_INTERPRET) + return e; + } + } + } + else if (e1.op == TOK.TOKstructliteral) + { + StructLiteralExp sle = cast(StructLiteralExp)e1; + VarDeclaration vf = var.isVarDeclaration(); + if (vf) + { + Expression e = sle.getField(type, vf.offset); + if (e && e !is EXP_CANT_INTERPRET) + return e; + } + } + + return this; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + expToCBuffer(buf, hgs, e1, PREC.PREC_primary); + buf.writeByte('.'); + buf.writestring(var.toChars()); + } + + void dump(int indent) + { + assert(false); + } + + elem* toElem(IRState* irs) + { + // *(&e + offset) + //printf("DotVarExp.toElem('%s')\n", toChars()); + + VarDeclaration v = var.isVarDeclaration(); + if (!v) + { + error("%s is not a field, but a %s", var.toChars(), var.kind()); + } + + elem* e = e1.toElem(irs); + Type tb1 = e1.type.toBasetype(); + + if (tb1.ty != TY.Tclass && tb1.ty != TY.Tpointer) + //e = el_una(OPaddr, TYnptr, e); + e = addressElem(e, tb1); + + e = el_bin(OPER.OPadd, TYM.TYnptr, e, el_long(TYM.TYint, v ? v.offset : 0)); + e = el_una(OPER.OPind, type.totym(), e); + if (tybasic(e.Ety) == TYM.TYstruct) + { + e.Enumbytes = cast(uint)type.size(); + } + el_setLoc(e,loc); + + return e; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/Dsymbol.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Dsymbol.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,862 @@ +module dmd.Dsymbol; + +import dmd.Loc; +import dmd.STC; +import dmd.Scope; +import dmd.Lexer; +import dmd.Module; +import dmd.Array; +import dmd.ScopeDsymbol; +import dmd.OutBuffer; +import dmd.Id; +import dmd.Identifier; +import dmd.TemplateInstance; +import dmd.HdrGenState; +import dmd.AggregateDeclaration; +import dmd.ClassDeclaration; +import dmd.LabelDsymbol; +import dmd.Type; +import dmd.PROT; +import dmd.ArrayTypes; +import dmd.Package; +import dmd.EnumMember; +import dmd.TemplateDeclaration; +import dmd.TemplateMixin; +import dmd.Declaration; +import dmd.ThisDeclaration; +import dmd.TupleDeclaration; +import dmd.TypedefDeclaration; +import dmd.AliasDeclaration; +import dmd.FuncDeclaration; +import dmd.FuncAliasDeclaration; +import dmd.FuncLiteralDeclaration; +import dmd.CtorDeclaration; +import dmd.PostBlitDeclaration; +import dmd.DtorDeclaration; +import dmd.StaticCtorDeclaration; +import dmd.StaticDtorDeclaration; +import dmd.InvariantDeclaration; +import dmd.UnitTestDeclaration; +import dmd.NewDeclaration; +import dmd.VarDeclaration; +import dmd.StructDeclaration; +import dmd.UnionDeclaration; +import dmd.InterfaceDeclaration; +import dmd.WithScopeSymbol; +import dmd.ArrayScopeSymbol; +import dmd.Import; +import dmd.EnumDeclaration; +import dmd.DeleteDeclaration; +import dmd.SymbolDeclaration; +import dmd.AttribDeclaration; +import dmd.OverloadSet; +import dmd.DYNCAST; +import dmd.Global; +import dmd.Expression; +import dmd.TOK; +import dmd.VarExp; +import dmd.FuncExp; + +import dmd.backend.Symbol; +import dmd.backend.TYPE; +import dmd.backend.Util; +import dmd.backend.mTYman; +import dmd.backend.TYFL; +import dmd.backend.TYM; +import dmd.backend.mTY; +import dmd.backend.SC; +import dmd.backend.FL; +import dmd.backend.LIST; + +import core.stdc.string : strcmp, memcpy, strlen; +import core.stdc.stdlib : alloca; + +import std.stdio; + +// TODO: remove dependencies on these +Expression isExpression(Object o) +{ + return cast(Expression)o; +} + +Dsymbol isDsymbol(Object o) +{ + return cast(Dsymbol)o; +} + +Type isType(Object o) +{ + return cast(Type)o; +} + +Dsymbol getDsymbol(Object oarg) +{ + Dsymbol sa; + Expression ea = isExpression(oarg); + if (ea) + { // Try to convert Expression to symbol + if (ea.op == TOK.TOKvar) + sa = (cast(VarExp)ea).var; + else if (ea.op == TOK.TOKfunction) + sa = (cast(FuncExp)ea).fd; + else + sa = null; + } + else + { // Try to convert Type to symbol + Type ta = isType(oarg); + if (ta) + sa = ta.toDsymbol(null); + else + sa = isDsymbol(oarg); // if already a symbol + } + return sa; +} + +class Dsymbol +{ + Identifier ident; + Identifier c_ident; + Dsymbol parent; + Symbol* csym; // symbol for code generator + Symbol* isym; // import version of csym + ubyte* comment; // documentation comment for this Dsymbol + Loc loc; // where defined + Scope scope_; // !=null means context to use for semantic() + + this() + { + // do nothing + } + + this(Identifier ident) + { + this.ident = ident; + } + + string toChars() + { + return ident ? ident.toChars() : "__anonymous"; + } + + string locToChars() + { + scope OutBuffer buf = new OutBuffer(); + Module m = getModule(); + + if (m && m.srcfile) + loc.filename = m.srcfile.toChars(); + + return loc.toChars(); + } + + int equals(Object o) + { + assert(false); + } + + bool isAnonymous() + { + return ident ? 0 : 1; + } + + void error(T...)(Loc loc, string format, T t) + { + if (!global.gag) + { + string p = loc.toChars(); + if (p.length == 0) + p = locToChars(); + + if (p.length != 0) { + writef("%s: ", p); + } + + write("Error: "); + writef("%s %s ", kind(), toPrettyChars()); + + writefln(format, t); + } + + global.errors++; + + //fatal(); + } + + void error(T...)(string format, T t) + { + //printf("Dsymbol.error()\n"); + if (!global.gag) + { + string p = loc.toChars(); + + if (p.length != 0) { + writef("%s: ", p); + } + + write("Error: "); + if (isAnonymous()) { + writef("%s ", kind()); + } else { + writef("%s %s ", kind(), toPrettyChars()); + } + + writefln(format, t); + } + global.errors++; + + //fatal(); + } + + void checkDeprecated(Loc loc, Scope sc) + { + if (!global.params.useDeprecated && isDeprecated()) + { + // Don't complain if we're inside a deprecated symbol's scope + for (Dsymbol sp = sc.parent; sp; sp = sp.parent) + { + if (sp.isDeprecated()) + return; + } + + for (; sc; sc = sc.enclosing) + { + if (sc.scopesym && sc.scopesym.isDeprecated()) + return; + + // If inside a StorageClassDeclaration that is deprecated + if (sc.stc & STC.STCdeprecated) + return; + } + + error(loc, "is deprecated"); + } + } + + Module getModule() + { + //printf("Dsymbol.getModule()\n"); + Dsymbol s = this; + while (s) + { + //printf("\ts = '%s'\n", s.toChars()); + Module m = s.isModule(); + if (m) + return m; + s = s.parent; + } + + return null; + } + + Dsymbol pastMixin() + { + Dsymbol s = this; + //printf("Dsymbol::pastMixin() %s\n", toChars()); + while (s && s.isTemplateMixin()) + s = s.parent; + return s; + } + + Dsymbol toParent() + { + return parent ? parent.pastMixin() : null; + } + + /********************************** + * Use this instead of toParent() when looking for the + * 'this' pointer of the enclosing function/class. + */ + Dsymbol toParent2() + { + Dsymbol s = parent; + while (s && s.isTemplateInstance()) + s = s.parent; + return s; + } + + TemplateInstance inTemplateInstance() + { + for (Dsymbol parent = this.parent; parent; parent = parent.parent) + { + TemplateInstance ti = parent.isTemplateInstance(); + if (ti) + return ti; + } + + return null; + } + + DYNCAST dyncast() { return DYNCAST.DYNCAST_DSYMBOL; } // kludge for template.isSymbol() + + /************************************* + * Do syntax copy of an array of Dsymbol's. + */ + static Array arraySyntaxCopy(Array a) + { + Array b = null; + if (a) + { + b = a.copy(); + for (int i = 0; i < b.dim; i++) + { + Dsymbol s = cast(Dsymbol)b.data[i]; + + s = s.syntaxCopy(null); + b.data[i] = cast(void*)s; + } + } + return b; + } + + string toPrettyChars() + { + //printf("Dsymbol.toPrettyChars() '%s'\n", toChars()); + if (!parent) { + return toChars(); + } + + size_t len = 0; + for (Dsymbol p = this; p; p = p.parent) { + len += p.toChars().length + 1; + } + --len; + + char* s = cast(char*)alloca(len); + char* q = s + len; + + for (Dsymbol p = this; p; p = p.parent) + { + string t = p.toChars(); + size_t length = t.length; + q -= length; + + memcpy(q, t.ptr, length); + if (q is s) + break; + + q--; + version (TARGET_NET) { + if (AggregateDeclaration ad = p.isAggregateDeclaration()) + { + if (ad.isNested() && p.parent && p.parent.isAggregateDeclaration()) + { + *q = '/'; + continue; + } + } + } + *q = '.'; + } + + return s[0..len].idup; + } + + string kind() + { + assert(false); + } + + /********************************* + * If this symbol is really an alias for another, + * return that other. + */ + Dsymbol toAlias() // resolve real symbol + { + return this; + } + + bool addMember(Scope sc, ScopeDsymbol sd, int memnum) + { + //printf("Dsymbol.addMember('%s')\n", toChars()); + //printf("Dsymbol.addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sd.toChars()); + assert(sd !is null); + parent = sd; + if (!isAnonymous()) // no name, so can't add it to symbol table + { + if (!sd.symtab.insert(this)) // if name is already defined + { + Dsymbol s2 = sd.symtab.lookup(ident); + if (!s2.overloadInsert(this)) + { + sd.multiplyDefined(Loc(0), this, s2); + } + } + if (sd.isAggregateDeclaration() || sd.isEnumDeclaration()) + { + if (ident is Id.__sizeof || ident is Id.alignof_ || ident is Id.mangleof_) + error(".%s property cannot be redefined", ident.toChars()); + } + return true; + } + + return false; + } + + void setScope(Scope sc) + { + //printf("Dsymbol.setScope() %p %s\n", this, toChars()); + if (!sc.nofree) + sc.setNoFree(); // may need it even after semantic() finishes + scope_ = sc; + } + + void semantic(Scope sc) + { + assert(false); + } + + /************************************* + * Does semantic analysis on initializers and members of aggregates. + */ + void semantic2(Scope sc) + { + // Most Dsymbols have no further semantic analysis needed + } + + /************************************* + * Does semantic analysis on function bodies. + */ + void semantic3(Scope sc) + { + // Most Dsymbols have no further semantic analysis needed + } + + /************************************* + * Look for function inlining possibilities. + */ + void inlineScan() + { + // Most Dsymbols aren't functions + } + + Dsymbol search(Loc loc, Identifier ident, int flags) + { + assert(false); + } + + /*************************************** + * Search for identifier id as a member of 'this'. + * id may be a template instance. + * Returns: + * symbol found, null if not + */ + Dsymbol searchX(Loc loc, Scope sc, Identifier id) + { + //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars()); + Dsymbol s = toAlias(); + Dsymbol sm; + + /// HUH???? + switch (id.dyncast()) + { + case DYNCAST.DYNCAST_IDENTIFIER: + sm = s.search(loc, id, 0); + break; + + case DYNCAST.DYNCAST_DSYMBOL: + { + assert(false); /// how can it happen? + // It's a template instance + //printf("\ttemplate instance id\n"); + Dsymbol st = cast(Dsymbol)id; + TemplateInstance ti = st.isTemplateInstance(); + id = ti.name; + sm = s.search(loc, id, 0); + if (!sm) + { + error("template identifier %s is not a member of %s %s", id.toChars(), s.kind(), s.toChars()); + return null; + } + sm = sm.toAlias(); + TemplateDeclaration td = sm.isTemplateDeclaration(); + if (!td) + { + error("%s is not a template, it is a %s", id.toChars(), sm.kind()); + return null; + } + + ti.tempdecl = td; + if (!ti.semanticRun) + ti.semantic(sc); + + sm = ti.toAlias(); + break; + } + + default: + assert(0); + } + return sm; + } + + bool overloadInsert(Dsymbol s) + { + assert(false); + } + +version (_DH) { + char* toHChars() + { + assert(false); + } + + void toHBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } +} + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + void toDocBuffer(OutBuffer buf) + { + assert(false); + } + + uint size(Loc loc) + { + assert(false); + } + + int isforwardRef() + { + assert(false); + } + + void defineRef(Dsymbol s) + { + assert(false); + } + + AggregateDeclaration isThis() // is a 'this' required to access the member + { + assert(false); + } + + ClassDeclaration isClassMember() // are we a member of a class? + { + Dsymbol parent = toParent(); + if (parent && parent.isClassDeclaration()) + return cast(ClassDeclaration)parent; + return null; + } + + bool isExport() // is Dsymbol exported? + { + return false; + } + + bool isImportedSymbol() // is Dsymbol imported? + { + return false; + } + + bool isDeprecated() // is Dsymbol deprecated? + { + return false; + } + +version (DMDV2) { + bool isOverloadable() + { + return false; + } +} + + LabelDsymbol isLabel() // is this a LabelDsymbol? + { + return null; + } + + AggregateDeclaration isMember() // is this symbol a member of an AggregateDeclaration? + { + //printf("Dsymbol::isMember() %s\n", toChars()); + Dsymbol parent = toParent(); + //printf("parent is %s %s\n", parent.kind(), parent.toChars()); + return parent ? parent.isAggregateDeclaration() : null; + } + + Type getType() // is this a type? + { + return null; + } + + string mangle() + { + OutBuffer buf = new OutBuffer(); + string id; + +static if (false) { + printf("Dsymbol::mangle() '%s'", toChars()); + if (parent) + printf(" parent = %s %s", parent.kind(), parent.toChars()); + printf("\n"); +} + id = ident ? ident.toChars() : toChars(); + if (parent) + { + string p = parent.mangle(); + if (p[0] == '_' && p[1] == 'D') + p = p[2..$]; + buf.writestring(p); + } + ///buf.printf("%zu%s", id.length, id); + buf.printf("%d%s", id.length, id); + id = buf.toChars(); + buf.data = null; + //printf("Dsymbol::mangle() %s = %s\n", toChars(), id); + return id; + } + + bool needThis() // need a 'this' pointer? + { + return false; + } + + PROT prot() + { + assert(false); + } + + Dsymbol syntaxCopy(Dsymbol s) // copy only syntax trees + { + assert(false); + } + + /************************************** + * Determine if this symbol is only one. + * Returns: + * false, *ps = null: There are 2 or more symbols + * true, *ps = null: There are zero symbols + * true, *ps = symbol: The one and only one symbol + */ + bool oneMember(Dsymbol* ps) + { + //printf("Dsymbol::oneMember()\n"); + *ps = this; + return true; + } + + /***************************************** + * Same as Dsymbol::oneMember(), but look at an array of Dsymbols. + */ + static bool oneMembers(Array members, Dsymbol* ps) + { + //printf("Dsymbol::oneMembers() %d\n", members ? members->dim : 0); + Dsymbol s = null; + + if (members) + { + for (int i = 0; i < members.dim; i++) + { + Dsymbol sx = cast(Dsymbol)members.data[i]; + + bool x = sx.oneMember(ps); + //printf("\t[%d] kind %s = %d, s = %p\n", i, sx->kind(), x, *ps); + if (!x) + { + //printf("\tfalse 1\n"); + assert(*ps is null); + return false; + } + if (*ps) + { + if (s) // more than one symbol + { + *ps = null; + //printf("\tfalse 2\n"); + return false; + } + s = *ps; + } + } + } + + *ps = s; // s is the one symbol, null if none + //printf("\ttrue\n"); + return true; + } + + /***************************************** + * Is Dsymbol a variable that contains pointers? + */ + bool hasPointers() + { + //printf("Dsymbol::hasPointers() %s\n", toChars()); + return 0; + } + + void addLocalClass(ClassDeclarations) { } + void checkCtorConstInit() { } + + void addComment(ubyte* comment) + { + //if (comment) + //printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars()); + + if (this.comment is null) { + this.comment = comment; + } else { +static if (true) { + if (comment !is null && strcmp(cast(char*)comment, cast(char*)this.comment) != 0) + { // Concatenate the two + this.comment = Lexer.combineComments(this.comment, comment); + } +} + } + } + + void emitComment(Scope sc) + { + assert(false); + } + + void emitDitto(Scope sc) + { + assert(false); + } + + // Backend + + Symbol* toSymbol() // to backend symbol + { + assert(false); + } + + void toObjFile(int multiobj) // compile to .obj file + { + //printf("Dsymbol::toObjFile('%s')\n", toChars()); + // ignore + } + + int cvMember(ubyte* p) // emit cv debug info for member + { + assert(false); + } + + /********************************* + * Generate import symbol from symbol. + */ + Symbol* toImport() // to backend import symbol + { + if (!isym) + { + if (!csym) + csym = toSymbol(); + isym = toImport(csym); + } + + return isym; + } + + static Symbol* toImport(Symbol* sym) // to backend import symbol + { + char* id; + char* n; + Symbol* s; + type* t; + + //printf("Dsymbol::toImport('%s')\n", sym->Sident); + n = sym.Sident.ptr; + id = cast(char*) alloca(6 + strlen(n) + 1 + (type_paramsize_i(sym.Stype)).sizeof*3 + 1); + if (sym.Stype.Tmangle == mTYman_std && tyfunc(sym.Stype.Tty)) + { + sprintf(id, "_imp__%s@%lu", n, type_paramsize_i(sym.Stype)); + } + else if (sym.Stype.Tmangle == mTYman_d) + sprintf(id,"_imp_%s",n); + else + sprintf(id,"_imp__%s",n); + t = type_alloc(TYnptr | mTYconst); + t.Tnext = sym.Stype; + t.Tnext.Tcount++; + t.Tmangle = mTYman_c; + t.Tcount++; + s = symbol_calloc(id); + s.Stype = t; + s.Sclass = SCextern; + s.Sfl = FLextern; + slist_add(s); + + return s; + } + + Symbol* toSymbolX(string prefix, int sclass, TYPE* t, string suffix) // helper + { + Symbol* s; + char* id; + string n; + size_t nlen; + + //writef("Dsymbol::toSymbolX('%s', '%s')\n", prefix, this.classinfo.name); + n = mangle(); + assert(n.length != 0); + + nlen = n.length; +static if (false) { + if (nlen > 2 && n[0] == '_' && n[1] == 'D') + { + nlen -= 2; + n += 2; + } +} + id = cast(char*) alloca(2 + nlen + size_t.sizeof * 3 + prefix.length + suffix.length + 1); + sprintf(id, "_D%.*s%lu%.*s%.*s", n, prefix.length, prefix, suffix); + + static if (false) { + if (global.params.isWindows && (type_mangle(t) == mTYman.mTYman_c || type_mangle(t) == mTYman.mTYman_std)) + id++; // Windows C mangling will put the '_' back in + } + s = symbol_name(id, sclass, t); + + //printf("-Dsymbol::toSymbolX() %s\n", id); + return s; + } + + // Eliminate need for dynamic_cast + Package isPackage() { return null; } + Module isModule() { return null; } + EnumMember isEnumMember() { return null; } + TemplateDeclaration isTemplateDeclaration() { return null; } + TemplateInstance isTemplateInstance() { return null; } + TemplateMixin isTemplateMixin() { return null; } + Declaration isDeclaration() { return null; } + ThisDeclaration isThisDeclaration() { return null; } + TupleDeclaration isTupleDeclaration() { return null; } + TypedefDeclaration isTypedefDeclaration() { return null; } + AliasDeclaration isAliasDeclaration() { return null; } + AggregateDeclaration isAggregateDeclaration() { return null; } + FuncDeclaration isFuncDeclaration() { return null; } + FuncAliasDeclaration isFuncAliasDeclaration() { return null; } + FuncLiteralDeclaration isFuncLiteralDeclaration() { return null; } + CtorDeclaration isCtorDeclaration() { return null; } + PostBlitDeclaration isPostBlitDeclaration() { return null; } + DtorDeclaration isDtorDeclaration() { return null; } + StaticCtorDeclaration isStaticCtorDeclaration() { return null; } + StaticDtorDeclaration isStaticDtorDeclaration() { return null; } + InvariantDeclaration isInvariantDeclaration() { return null; } + UnitTestDeclaration isUnitTestDeclaration() { return null; } + NewDeclaration isNewDeclaration() { return null; } + VarDeclaration isVarDeclaration() { return null; } + ClassDeclaration isClassDeclaration() { return null; } + StructDeclaration isStructDeclaration() { return null; } + UnionDeclaration isUnionDeclaration() { return null; } + InterfaceDeclaration isInterfaceDeclaration() { return null; } + ScopeDsymbol isScopeDsymbol() { return null; } + WithScopeSymbol isWithScopeSymbol() { return null; } + ArrayScopeSymbol isArrayScopeSymbol() { return null; } + Import isImport() { return null; } + EnumDeclaration isEnumDeclaration() { return null; } +version (_DH) { + DeleteDeclaration isDeleteDeclaration() { return null; } +} + SymbolDeclaration isSymbolDeclaration() { return null; } + AttribDeclaration isAttribDeclaration() { return null; } + OverloadSet isOverloadSet() { return null; } +version (TARGET_NET) { + PragmaScope isPragmaScope() { return null; } +} +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/DsymbolExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/DsymbolExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,251 @@ +module dmd.DsymbolExp; + +import dmd.Expression; +import dmd.OutBuffer; +import dmd.EnumMember; +import dmd.VarDeclaration; +import dmd.FuncDeclaration; +import dmd.FuncLiteralDeclaration; +import dmd.OverloadSet; +import dmd.Declaration; +import dmd.ClassDeclaration; +import dmd.Import; +import dmd.Package; +import dmd.Type; +import dmd.DotVarExp; +import dmd.ThisExp; +import dmd.VarExp; +import dmd.FuncExp; +import dmd.OverExp; +import dmd.DotTypeExp; +import dmd.ScopeExp; +import dmd.Module; +import dmd.TypeExp; +import dmd.TupleDeclaration; +import dmd.TupleExp; +import dmd.TemplateInstance; +import dmd.Global; +import dmd.TemplateDeclaration; +import dmd.TemplateExp; +import dmd.Loc; +import dmd.Scope; +import dmd.HdrGenState; +import dmd.Dsymbol; +import dmd.TOK; + +class DsymbolExp : Expression +{ + Dsymbol s; + int hasOverloads; + + this(Loc loc, Dsymbol s, int hasOverloads = 0) + { + super(loc, TOK.TOKdsymbol, DsymbolExp.sizeof); + this.s = s; + this.hasOverloads = hasOverloads; + } + + Expression semantic(Scope sc) + { +version (LOGSEMANTIC) { + printf("DsymbolExp.semantic('%s')\n", s.toChars()); +} + + Lagain: + EnumMember em; + Expression e; + VarDeclaration v; + FuncDeclaration f; + FuncLiteralDeclaration fld; + OverloadSet o; + Declaration d; + ClassDeclaration cd; + ClassDeclaration thiscd = null; + Import imp; + Package pkg; + Type t; + + //printf("DsymbolExp. %p '%s' is a symbol\n", this, toChars()); + //printf("s = '%s', s.kind = '%s'\n", s.toChars(), s.kind()); + if (type) + return this; + + if (!s.isFuncDeclaration()) // functions are checked after overloading + checkDeprecated(sc, s); + + s = s.toAlias(); + //printf("s = '%s', s.kind = '%s', s.needThis() = %p\n", s.toChars(), s.kind(), s.needThis()); + if (!s.isFuncDeclaration()) + checkDeprecated(sc, s); + + if (sc.func) + thiscd = sc.func.parent.isClassDeclaration(); + + // BUG: This should happen after overload resolution for functions, not before + if (s.needThis()) + { +version (DMDV2) { + bool cond = !s.isFuncDeclaration(); +} else { + bool cond = true; +} + if (hasThis(sc) && cond) + { + // Supply an implicit 'this', as in + // this.ident + DotVarExp de = new DotVarExp(loc, new ThisExp(loc), s.isDeclaration()); + return de.semantic(sc); + } + } + + em = s.isEnumMember(); + if (em) + { + e = em.value; + e = e.semantic(sc); + return e; + } + v = s.isVarDeclaration(); + if (v) + { + //printf("Identifier '%s' is a variable, type '%s'\n", toChars(), v.type.toChars()); + if (!type) + { + type = v.type; + if (!v.type) + { + error("forward reference of %s %s", v.kind(), v.toChars()); + type = Type.terror; + } + } + + e = new VarExp(loc, v); + e.type = type; + e = e.semantic(sc); + return e.deref(); + } + + fld = s.isFuncLiteralDeclaration(); + if (fld) + { + //printf("'%s' is a function literal\n", fld.toChars()); + e = new FuncExp(loc, fld); + return e.semantic(sc); + } + f = s.isFuncDeclaration(); + if (f) + { + //printf("'%s' is a function\n", f.toChars()); + + if (!f.type.deco) + { + error("forward reference to %s", toChars()); + } + return new VarExp(loc, f, hasOverloads); + } + o = s.isOverloadSet(); + if (o) + { + //printf("'%s' is an overload set\n", o.toChars()); + return new OverExp(o); + } + cd = s.isClassDeclaration(); + if (cd && thiscd && cd.isBaseOf(thiscd, null) && sc.func.needThis()) + { + // We need to add an implicit 'this' if cd is this class or a base class. + DotTypeExp dte = new DotTypeExp(loc, new ThisExp(loc), s); + return dte.semantic(sc); + } + imp = s.isImport(); + if (imp) + { + if (!imp.pkg) + { + error("forward reference of import %s", imp.toChars()); + return this; + } + ScopeExp ie = new ScopeExp(loc, imp.pkg); + return ie.semantic(sc); + } + pkg = s.isPackage(); + if (pkg) + { + ScopeExp ie = new ScopeExp(loc, pkg); + return ie.semantic(sc); + } + Module mod = s.isModule(); + if (mod) + { + ScopeExp ie = new ScopeExp(loc, mod); + return ie.semantic(sc); + } + + t = s.getType(); + if (t) + { + return new TypeExp(loc, t); + } + + TupleDeclaration tup = s.isTupleDeclaration(); + if (tup) + { + e = new TupleExp(loc, tup); + e = e.semantic(sc); + return e; + } + + TemplateInstance ti = s.isTemplateInstance(); + if (ti && !global.errors) + { + if (!ti.semanticRun) + ti.semantic(sc); + + s = ti.inst.toAlias(); + if (!s.isTemplateInstance()) + goto Lagain; + + e = new ScopeExp(loc, ti); + e = e.semantic(sc); + return e; + } + + TemplateDeclaration td = s.isTemplateDeclaration(); + if (td) + { + e = new TemplateExp(loc, td); + e = e.semantic(sc); + return e; + } + + Lerr: + error("%s '%s' is not a variable", s.kind(), s.toChars()); + type = Type.terror; + return this; + } + + string toChars() + { + assert(false); + } + + void dump(int indent) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + int isLvalue() + { + assert(false); + } + + Expression toLvalue(Scope sc, Expression e) + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/DsymbolTable.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/DsymbolTable.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,63 @@ +module dmd.DsymbolTable; + +import dmd.StringTable; +import dmd.Dsymbol; +import dmd.Identifier; +import dmd.StringValue; + +import std.stdio; + +class DsymbolTable +{ + StringTable tab; + + this() + { + tab = new StringTable; + } + + ~this() + { + delete tab; + } + + // Look up Identifier. Return Dsymbol if found, NULL if not. + Dsymbol lookup(Identifier ident) + { +debug { + assert(ident); + assert(tab); +} + StringValue* sv = tab.lookup(ident.string_); + return (sv ? cast(Dsymbol)sv.ptrvalue : null); + } + + // Insert Dsymbol in table. Return NULL if already there. + Dsymbol insert(Dsymbol s) + { + Identifier ident = s.ident; +debug { + assert(ident); + assert(tab); +} + + return insert(ident, s); + } + + // Look for Dsymbol in table. If there, return it. If not, insert s and return that. + Dsymbol update(Dsymbol s) + { + assert(false); + } + + Dsymbol insert(Identifier ident, Dsymbol s) // when ident and s are not the same + { + StringValue* sv = tab.insert(ident.toChars()); + if (sv is null) { + return null; // already in table + } + + sv.ptrvalue = cast(void*)s; + return s; + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/DtorDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/DtorDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,109 @@ +module dmd.DtorDeclaration; + +import dmd.FuncDeclaration; +import dmd.Loc; +import dmd.Global; +import dmd.Identifier; +import dmd.Dsymbol; +import dmd.Scope; +import dmd.LINK; +import dmd.AggregateDeclaration; +import dmd.TypeFunction; +import dmd.Type; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.STC; +import dmd.Id; + +class DtorDeclaration : FuncDeclaration +{ + this(Loc loc, Loc endloc) + { + super(loc, endloc, Id.dtor, STCundefined, null); + } + + this(Loc loc, Loc endloc, Identifier id) + { + assert(false); + super(loc, endloc, null, STC.init, null); + } + + Dsymbol syntaxCopy(Dsymbol) + { + assert(false); + } + + void semantic(Scope sc) + { + //printf("DtorDeclaration::semantic() %s\n", toChars()); + //printf("ident: %s, %s, %p, %p\n", ident.toChars(), Id::dtor.toChars(), ident, Id::dtor); + parent = sc.parent; + Dsymbol parent = toParent(); + AggregateDeclaration ad = parent.isAggregateDeclaration(); + if (!ad) + { + error("destructors are only for class/struct/union definitions, not %s %s", parent.kind(), parent.toChars()); + } + else if (ident == Id.dtor) + ad.dtors.push(cast(void*)this); + + type = new TypeFunction(null, Type.tvoid, false, LINK.LINKd); + + sc = sc.push(); + sc.stc &= ~STCstatic; // not a static destructor + sc.linkage = LINK.LINKd; + + FuncDeclaration.semantic(sc); + + sc.pop(); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + string kind() + { + assert(false); + } + + string toChars() + { + return "~this"; + } + + bool isVirtual() + { + /* This should be FALSE so that dtor's don't get put into the vtbl[], + * but doing so will require recompiling everything. + */ + version (BREAKABI) { + return false; + } else { + return FuncDeclaration.isVirtual(); + } + } + + bool addPreInvariant() + { + return (isThis() && vthis && global.params.useInvariants); + } + + bool addPostInvariant() + { + return false; + } + + bool overloadInsert(Dsymbol s) + { + assert(false); + } + + void emitComment(Scope sc) + { + assert(false); + } + + DtorDeclaration isDtorDeclaration() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/EnumDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/EnumDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,416 @@ +module dmd.EnumDeclaration; + +import dmd.ScopeDsymbol; +import dmd.AddExp; +import dmd.Type; +import dmd.CmpExp; +import dmd.IntegerExp; +import dmd.EqualExp; +import dmd.TOK; +import dmd.Id; +import dmd.TY; +import dmd.DsymbolTable; +import dmd.STC; +import dmd.Expression; +import dmd.Identifier; +import dmd.Dsymbol; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Global; +import dmd.Loc; +import dmd.TypeEnum; +import dmd.EnumMember; +import dmd.DYNCAST; +import dmd.WANT; +import dmd.Id; +import dmd.Lexer; + +import dmd.backend.SC; +import dmd.backend.FL; +import dmd.backend.Util; +import dmd.backend.Symbol; +import dmd.backend.Classsym; +import dmd.backend.SFL; +import dmd.backend.LIST; +import dmd.codegen.Util; + +import std.stdio : writef; + +class EnumDeclaration : ScopeDsymbol +{ /* enum ident : memtype { ... } + */ + Type type; // the TypeEnum + Type memtype; // type of the members + +version (DMDV1) { + ulong maxval; + ulong minval; + ulong defaultval; // default initializer +} else { + Expression maxval; + Expression minval; + Expression defaultval; // default initializer +} + bool isdeprecated; + + this(Loc loc, Identifier id, Type memtype) + { + super(id); + this.loc = loc; + type = new TypeEnum(this); + this.memtype = memtype; + } + + Dsymbol syntaxCopy(Dsymbol s) + { + assert(false); + } + + void semantic(Scope sc) + { + Type t; + Scope sce; + + //writef("EnumDeclaration.semantic(sd = %p, '%s') %s\n", sc.scopesym, sc.scopesym.toChars(), toChars()); + //writef("EnumDeclaration.semantic() %s\n", toChars()); + if (!members) // enum ident; + return; + + if (!memtype && !isAnonymous()) + { + // Set memtype if we can to reduce fwd reference errors + memtype = Type.tint32; // case 1) enum ident { ... } + } + + if (symtab) // if already done + { + if (!scope_) + return; // semantic() already completed + } + else + symtab = new DsymbolTable(); + + Scope scx = null; + if (scope_) + { sc = scope_; + scx = scope_; // save so we don't make redundant copies + scope_ = null; + } + + if (sc.stc & STC.STCdeprecated) + isdeprecated = true; + + parent = sc.parent; + + /* The separate, and distinct, cases are: + * 1. enum { ... } + * 2. enum : memtype { ... } + * 3. enum ident { ... } + * 4. enum ident : memtype { ... } + */ + + if (memtype) + { + memtype = memtype.semantic(loc, sc); + + /* Check to see if memtype is forward referenced + */ + if (memtype.ty == TY.Tenum) + { EnumDeclaration sym = cast(EnumDeclaration)memtype.toDsymbol(sc); + if (!sym.memtype || !sym.members || !sym.symtab || sym.scope_) + { + // memtype is forward referenced, so try again later + scope_ = scx ? scx : new Scope(sc); + scope_.setNoFree(); + scope_.module_.addDeferredSemantic(this); + writef("\tdeferring %s\n", toChars()); + return; + } + } +static if (false) { + // Decided to abandon this restriction for D 2.0 + if (!memtype.isintegral()) + { error("base type must be of integral type, not %s", memtype.toChars()); + memtype = Type.tint32; + } +} + } + + type = type.semantic(loc, sc); + if (isAnonymous()) + sce = sc; + else + { sce = sc.push(this); + sce.parent = this; + } + if (members.dim == 0) + error("enum %s must have at least one member", toChars()); + int first = 1; + Expression elast = null; + for (int i = 0; i < members.dim; i++) + { + EnumMember em = (cast(Dsymbol)members.data[i]).isEnumMember(); + Expression e; + + if (!em) + /* The e.semantic(sce) can insert other symbols, such as + * template instances and function literals. + */ + continue; + + //printf(" Enum member '%s'\n",em.toChars()); + if (em.type) + em.type = em.type.semantic(em.loc, sce); + e = em.value; + if (e) + { + assert(e.dyncast() == DYNCAST.DYNCAST_EXPRESSION); + e = e.semantic(sce); + e = e.optimize(WANT.WANTvalue | WANT.WANTinterpret); + if (memtype) + { + e = e.implicitCastTo(sce, memtype); + e = e.optimize(WANT.WANTvalue | WANT.WANTinterpret); + if (!isAnonymous()) + e = e.castTo(sce, type); + t = memtype; + } + else if (em.type) + { + e = e.implicitCastTo(sce, em.type); + e = e.optimize(WANT.WANTvalue | WANT.WANTinterpret); + assert(isAnonymous()); + t = e.type; + } + else + t = e.type; + } + else if (first) + { + if (memtype) + t = memtype; + else if (em.type) + t = em.type; + else + t = Type.tint32; + e = new IntegerExp(em.loc, 0, Type.tint32); + e = e.implicitCastTo(sce, t); + e = e.optimize(WANT.WANTvalue | WANT.WANTinterpret); + if (!isAnonymous()) + e = e.castTo(sce, type); + } + else + { + // Set value to (elast + 1). + // But first check that (elast != t.max) + assert(elast); + e = new EqualExp(TOK.TOKequal, em.loc, elast, t.getProperty(Loc(0), Id.max)); + e = e.semantic(sce); + e = e.optimize(WANT.WANTvalue | WANT.WANTinterpret); + if (e.toInteger()) + error("overflow of enum value %s", elast.toChars()); + + // Now set e to (elast + 1) + e = new AddExp(em.loc, elast, new IntegerExp(em.loc, 1, Type.tint32)); + e = e.semantic(sce); + e = e.castTo(sce, elast.type); + e = e.optimize(WANT.WANTvalue | WANT.WANTinterpret); + } + elast = e; + em.value = e; + + // Add to symbol table only after evaluating 'value' + if (isAnonymous()) + { + /* Anonymous enum members get added to enclosing scope. + */ + for (Scope scxx = sce; scxx; scxx = scxx.enclosing) + { + if (scxx.scopesym) + { + if (!scxx.scopesym.symtab) + scxx.scopesym.symtab = new DsymbolTable(); + em.addMember(sce, scxx.scopesym, 1); + break; + } + } + } + else + em.addMember(sc, this, 1); + + /* Compute .min, .max and .default values. + * If enum doesn't have a name, we can never identify the enum type, + * so there is no purpose for a .min, .max or .default + */ + if (!isAnonymous()) + { + if (first) + { defaultval = e; + minval = e; + maxval = e; + } + else + { Expression ec; + + /* In order to work successfully with UDTs, + * build expressions to do the comparisons, + * and let the semantic analyzer and constant + * folder give us the result. + */ + + // Compute if(e < minval) + ec = new CmpExp(TOK.TOKlt, em.loc, e, minval); + ec = ec.semantic(sce); + ec = ec.optimize(WANT.WANTvalue | WANT.WANTinterpret); + if (ec.toInteger()) + minval = e; + + ec = new CmpExp(TOK.TOKgt, em.loc, e, maxval); + ec = ec.semantic(sce); + ec = ec.optimize(WANT.WANTvalue | WANT.WANTinterpret); + if (ec.toInteger()) + maxval = e; + } + } + first = 0; + } + //printf("defaultval = %lld\n", defaultval); + + //if (defaultval) printf("defaultval: %s %s\n", defaultval.toChars(), defaultval.type.toChars()); + if (sc != sce) + sce.pop(); + //members.print(); + } + + bool oneMember(Dsymbol* ps) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + Type getType() + { + return type; + } + + string kind() + { + return "enum"; + } + +version (DMDV2) { + Dsymbol search(Loc, Identifier ident, int flags) + { + //printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident->toChars()); + if (scope_) + // Try one last time to resolve this enum + semantic(scope_); + + if (!members || !symtab || scope_) + { + error("is forward referenced when looking for '%s'", ident.toChars()); + //*(char*)0=0; + return null; + } + + return ScopeDsymbol.search(loc, ident, flags); + } +} + bool isDeprecated() // is Dsymbol deprecated? + { + return isdeprecated; + } + + void emitComment(Scope sc) + { + assert(false); + } + + void toDocBuffer(OutBuffer buf) + { + assert(false); + } + + EnumDeclaration isEnumDeclaration() { return this; } + + void toObjFile(int multiobj) // compile to .obj file + { + //printf("EnumDeclaration::toObjFile('%s')\n", toChars()); + version (DMDV2) { + if (isAnonymous()) + return; + } + + if (global.params.symdebug) + toDebug(); + + type.getTypeInfo(null); // generate TypeInfo + + TypeEnum tc = cast(TypeEnum)type; + if (!tc.sym.defaultval || type.isZeroInit(Loc(0))) { + ; + } else { + SC scclass = SCglobal; + if (inTemplateInstance()) + scclass = SCcomdat; + + // Generate static initializer + toInitializer(); + sinit.Sclass = scclass; + sinit.Sfl = FLdata; + version (ELFOBJ) { // Burton + sinit.Sseg = Segment.CDATA; + } + version (MACHOBJ) { + sinit.Sseg = Segment.DATA; + } + version (DMDV1) { + dtnbytes(&sinit.Sdt, tc.size(0), cast(char*)&tc.sym.defaultval); + //sinit->Sdt = tc->sym->init->toDt(); + } + version (DMDV2) { + tc.sym.defaultval.toDt(&sinit.Sdt); + } + outdata(sinit); + } + } + + void toDebug() + { + assert(false); + } + + int cvMember(ubyte* p) + { + assert(false); + } + + Symbol* sinit; + + Symbol* toInitializer() + { + Symbol* s; + Classsym* stag; + + if (!sinit) + { + stag = fake_classsym(Id.ClassInfo); + Identifier ident_save = ident; + if (!ident) + ident = Lexer.uniqueId("__enum"); + s = toSymbolX("__init", SCextern, stag.Stype, "Z"); + ident = ident_save; + s.Sfl = FLextern; + s.Sflags |= SFLnodebug; + slist_add(s); + sinit = s; + } + + return sinit; + } +}; \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/EnumMember.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/EnumMember.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,52 @@ +module dmd.EnumMember; + +import dmd.Dsymbol; +import dmd.Expression; +import dmd.Type; +import dmd.Loc; +import dmd.Identifier; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; + +class EnumMember : Dsymbol +{ + Expression value; + Type type; + + this(Loc loc, Identifier id, Expression value, Type type) + { + super(id); + + this.value = value; + this.type = type; + this.loc = loc; + } + + Dsymbol syntaxCopy(Dsymbol s) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + string kind() + { + assert(false); + } + + void emitComment(Scope sc) + { + assert(false); + } + + void toDocBuffer(OutBuffer buf) + { + assert(false); + } + + EnumMember isEnumMember() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/EnumUtils.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/EnumUtils.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,11 @@ +module dmd.EnumUtils; + +string BringToCurrentScope(alias enumType)() +{ + string s = ""; + foreach (i, e; __traits(allMembers, enumType)) { + s ~= "alias " ~ enumType.stringof ~ "." ~ __traits(allMembers, enumType)[i] ~ " " ~ __traits(allMembers, enumType)[i] ~ ";\n"; + } + + return s; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/EqualExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/EqualExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,237 @@ +module dmd.EqualExp; + +import dmd.Expression; +import dmd.Id; +import dmd.Identifier; +import dmd.InterState; +import dmd.Loc; +import dmd.Scope; +import dmd.IRState; +import dmd.BinExp; +import dmd.TOK; +import dmd.Type; +import dmd.AddrExp; +import dmd.VarExp; +import dmd.IntegerExp; +import dmd.TY; +import dmd.Token; +import dmd.NotExp; +import dmd.WANT; +import dmd.GlobalExpressions; + +import dmd.backend.elem; +import dmd.backend.OPER; +import dmd.backend.Util; +import dmd.backend.TYM; +import dmd.backend.RTLSYM; + +import dmd.codegen.Util; + +import dmd.expression.util.arrayTypeCompatible; +import dmd.expression.Util; +import dmd.expression.Equal; + +class EqualExp : BinExp +{ + this(TOK op, Loc loc, Expression e1, Expression e2) + { + super(loc, op, EqualExp.sizeof, e1, e2); + assert(op == TOK.TOKequal || op == TOK.TOKnotequal); + } + + Expression semantic(Scope sc) + { + Expression e; + Type t1; + Type t2; + + //printf("EqualExp.semantic('%s')\n", toChars()); + if (type) + return this; + + BinExp.semanticp(sc); + + /* Before checking for operator overloading, check to see if we're + * comparing the addresses of two statics. If so, we can just see + * if they are the same symbol. + */ + if (e1.op == TOK.TOKaddress && e2.op == TOK.TOKaddress) + { + AddrExp ae1 = cast(AddrExp)e1; + AddrExp ae2 = cast(AddrExp)e2; + + if (ae1.e1.op == TOK.TOKvar && ae2.e1.op == TOK.TOKvar) + { + VarExp ve1 = cast(VarExp)ae1.e1; + VarExp ve2 = cast(VarExp)ae2.e1; + + if (ve1.var == ve2.var /*|| ve1.var.toSymbol() == ve2.var.toSymbol()*/) + { + // They are the same, result is 'true' for ==, 'false' for != + e = new IntegerExp(loc, (op == TOK.TOKequal), Type.tboolean); + return e; + } + } + } + + if (e1.type.toBasetype().ty == TY.Tclass && e2.op == TOK.TOKnull || e2.type.toBasetype().ty == TY.Tclass && e1.op == TOK.TOKnull) + { + error("use '%s' instead of '%s' when comparing with null", + Token.toChars(op == TOK.TOKequal ? TOK.TOKidentity : TOK.TOKnotidentity), + Token.toChars(op)); + } + + //if (e2.op != TOKnull) + { + e = op_overload(sc); + if (e) + { + if (op == TOK.TOKnotequal) + { + e = new NotExp(e.loc, e); + e = e.semantic(sc); + } + + return e; + } + } + + e = typeCombine(sc); + type = Type.tboolean; + + // Special handling for array comparisons + if (!arrayTypeCompatible(loc, e1.type, e2.type)) + { + if (e1.type != e2.type && e1.type.isfloating() && e2.type.isfloating()) + { + // Cast both to complex + e1 = e1.castTo(sc, Type.tcomplex80); + e2 = e2.castTo(sc, Type.tcomplex80); + } + } + + return e; + } + + Expression optimize(int result) + { + Expression e; + + //printf("EqualExp::optimize(result = %x) %s\n", result, toChars()); + e1 = e1.optimize(WANTvalue | (result & WANTinterpret)); + e2 = e2.optimize(WANTvalue | (result & WANTinterpret)); + e = this; + + Expression e1 = fromConstInitializer(result, this.e1); + Expression e2 = fromConstInitializer(result, this.e2); + + e = Equal(op, type, e1, e2); + if (e is EXP_CANT_INTERPRET) + e = this; + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + int isBit() + { + assert(false); + } + + bool isCommutative() + { + return true; + } + + Identifier opId() + { + return Id.eq; + } + + elem* toElem(IRState* irs) + { + //printf("EqualExp::toElem() %s\n", toChars()); + elem* e; + OPER eop; + Type t1 = e1.type.toBasetype(); + Type t2 = e2.type.toBasetype(); + + switch (op) + { + case TOKequal: eop = OPeqeq; break; + case TOKnotequal: eop = OPne; break; + default: + dump(0); + assert(0); + } + + //printf("EqualExp::toElem()\n"); + if (t1.ty == Tstruct) + { // Do bit compare of struct's + elem* es1; + elem* es2; + elem* ecount; + + es1 = e1.toElem(irs); + es2 = e2.toElem(irs); + static if (true) { + es1 = addressElem(es1, t1); + es2 = addressElem(es2, t2); + } else { + es1 = el_una(OPaddr, TYnptr, es1); + es2 = el_una(OPaddr, TYnptr, es2); + } + e = el_param(es1, es2); + ecount = el_long(TYint, t1.size()); + e = el_bin(OPmemcmp, TYint, e, ecount); + e = el_bin(eop, TYint, e, el_long(TYint, 0)); + el_setLoc(e,loc); + } +/// static if (false) { +/// else if (t1.ty == Tclass && t2.ty == Tclass) +/// { +/// elem *ec1; +/// elem *ec2; +/// +/// ec1 = e1.toElem(irs); +/// ec2 = e2.toElem(irs); +/// e = el_bin(OPcall,TYint,el_var(rtlsym[RTLSYM_OBJ_EQ]),el_param(ec1, ec2)); +/// } +/// } + else if ((t1.ty == Tarray || t1.ty == Tsarray) && + (t2.ty == Tarray || t2.ty == Tsarray)) + { + elem* ea1; + elem* ea2; + elem* ep; + Type telement = t1.nextOf().toBasetype(); + int rtlfunc; + + ea1 = e1.toElem(irs); + ea1 = array_toDarray(t1, ea1); + ea2 = e2.toElem(irs); + ea2 = array_toDarray(t2, ea2); + + version (DMDV2) { + ep = el_params(telement.arrayOf().getInternalTypeInfo(null).toElem(irs), + ea2, ea1, null); + rtlfunc = RTLSYM_ARRAYEQ2; + } else { + ep = el_params(telement.getInternalTypeInfo(null).toElem(irs), ea2, ea1, null); + rtlfunc = RTLSYM_ARRAYEQ; + } + e = el_bin(OPcall, TYint, el_var(rtlsym[rtlfunc]), ep); + if (op == TOKnotequal) + e = el_bin(OPxor, TYint, e, el_long(TYint, 1)); + el_setLoc(e,loc); + } + else + e = toElemBin(irs, eop); + + return e; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/ErrorExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ErrorExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,25 @@ +module dmd.ErrorExp; + +import dmd.OutBuffer; +import dmd.IntegerExp; +import dmd.Loc; +import dmd.HdrGenState; +import dmd.Type; + +/* Use this expression for error recovery. + * It should behave as a 'sink' to prevent further cascaded error messages. + */ + +class ErrorExp : IntegerExp +{ + this() + { + super(Loc(0), 0, Type.terror); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + buf.writestring("__error"); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/Escape.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Escape.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,11 @@ +module dmd.Escape; + +struct Escape +{ + const(char)* strings[256]; + + static const(char)* escapeChar(uint c) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ExpInitializer.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ExpInitializer.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,115 @@ +module dmd.ExpInitializer; + +import dmd.Initializer; +import dmd.Loc; +import dmd.Scope; +import dmd.Type; +import dmd.SymOffExp; +import dmd.Expression; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.WANT; +import dmd.TOK; +import dmd.StringExp; +import dmd.TY; +import dmd.TypeSArray; + +import dmd.backend.dt_t; + +class ExpInitializer : Initializer +{ + Expression exp; + + this(Loc loc, Expression exp) + { + super(loc); + this.exp = exp; + } + + Initializer syntaxCopy() + { + return new ExpInitializer(loc, exp.syntaxCopy()); + } + + Initializer semantic(Scope sc, Type t) + { + //printf("ExpInitializer.semantic(%s), type = %s\n", exp.toChars(), t.toChars()); + exp = exp.semantic(sc); + exp = resolveProperties(sc, exp); + exp = exp.optimize(WANT.WANTvalue | WANT.WANTinterpret); + Type tb = t.toBasetype(); + + /* Look for case of initializing a static array with a too-short + * string literal, such as: + * char[5] foo = "abc"; + * Allow this by doing an explicit cast, which will lengthen the string + * literal. + */ + if (exp.op == TOK.TOKstring && tb.ty == TY.Tsarray && exp.type.ty == TY.Tsarray) + { + StringExp se = cast(StringExp)exp; + + if (!se.committed && se.type.ty == TY.Tsarray && (cast(TypeSArray)se.type).dim.toInteger() < (cast(TypeSArray)t).dim.toInteger()) + { + exp = se.castTo(sc, t); + goto L1; + } + } + + // Look for the case of statically initializing an array + // with a single member. + if (tb.ty == TY.Tsarray && !tb.nextOf().equals(exp.type.toBasetype().nextOf()) && exp.implicitConvTo(tb.nextOf())) + { + t = tb.nextOf(); + } + + exp = exp.implicitCastTo(sc, t); + L1: + exp = exp.optimize(WANT.WANTvalue | WANT.WANTinterpret); + //printf("-ExpInitializer.semantic(): "); exp.print(); + return this; + } + + Type inferType(Scope sc) + { + //printf("ExpInitializer::inferType() %s\n", toChars()); + exp = exp.semantic(sc); + exp = resolveProperties(sc, exp); + + // Give error for overloaded function addresses + if (exp.op == TOKsymoff) + { + SymOffExp se = cast(SymOffExp)exp; + if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique()) + exp.error("cannot infer type from overloaded function symbol %s", exp.toChars()); + } + + Type t = exp.type; + if (!t) + t = Initializer.inferType(sc); + + return t; + } + + Expression toExpression() + { + return exp; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + dt_t* toDt() + { + dt_t* dt = null; + + exp = exp.optimize(WANT.WANTvalue); + exp.toDt(&dt); + + return dt; + } + + ExpInitializer isExpInitializer() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ExpStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ExpStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,125 @@ +module dmd.ExpStatement; + +import dmd.Loc; +import dmd.Statement; +import dmd.AssertExp; +import dmd.Expression; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Scope; +import dmd.InterState; +import dmd.InlineCostState; +import dmd.InlineDoState; +import dmd.InlineScanState; +import dmd.IRState; +import dmd.BE; +import dmd.TOK; +import dmd.DeclarationStatement; + +import dmd.backend.Blockx; +import dmd.backend.Util; + +class ExpStatement : Statement +{ + Expression exp; + + this(Loc loc, Expression exp) + { + super(loc); + this.exp = exp; + } + + Statement syntaxCopy() + { + Expression e = exp ? exp.syntaxCopy() : null; + ExpStatement es = new ExpStatement(loc, e); + return es; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + if (exp) + exp.toCBuffer(buf, hgs); + buf.writeByte(';'); + if (!hgs.FLinit.init) + buf.writenl(); + } + + Statement semantic(Scope sc) + { + if (exp) + { + //printf("ExpStatement::semantic() %s\n", exp->toChars()); + exp = exp.semantic(sc); + exp = resolveProperties(sc, exp); + exp.checkSideEffect(0); + exp = exp.optimize(0); + if (exp.op == TOK.TOKdeclaration && !isDeclarationStatement()) + { + Statement s = new DeclarationStatement(loc, exp); + return s; + } + //exp = exp.optimize(isDeclarationStatement() ? WANT.WANTvalue : 0); + } + return this; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + BE blockExit() + { + BE result = BE.BEfallthru; + + if (exp) + { + if (exp.op == TOK.TOKhalt) + return BE.BEhalt; + if (exp.op == TOK.TOKassert) + { + AssertExp a = cast(AssertExp)exp; + + if (a.e1.isBool(false)) // if it's an assert(0) + return BE.BEhalt; + } + if (exp.canThrow()) + result |= BE.BEthrow; + } + return result; + } + + int inlineCost(InlineCostState* ics) + { + return exp ? exp.inlineCost(ics) : 0; + } + + Expression doInline(InlineDoState ids) + { + version (LOG) { + if (exp) printf("ExpStatement.doInline() '%s'\n", exp.toChars()); + } + return exp ? exp.doInline(ids) : null; + } + + Statement inlineScan(InlineScanState* iss) + { + version (LOG) { + printf("ExpStatement.inlineScan(%s)\n", toChars()); + } + if (exp) + exp = exp.inlineScan(iss); + return this; + } + + void toIR(IRState* irs) + { + Blockx* blx = irs.blx; + + //printf("ExpStatement.toIR(), exp = %s\n", exp ? exp.toChars() : ""); + incUsage(irs, loc); + if (exp) + block_appendexp(blx.curblock, exp.toElem(irs)); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/Expression.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Expression.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,908 @@ +module dmd.Expression; + +import dmd.Loc; +import dmd.TOK; +import dmd.Type; +import dmd.WANT; +import dmd.Scope; +import dmd.ArrayTypes; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.MATCH; +import dmd.IntRange; +import dmd.Dsymbol; +import dmd.FuncDeclaration; +import dmd.InterState; +import dmd.InlineCostState; +import dmd.InlineDoState; +import dmd.InlineScanState; +import dmd.Identifier; +import dmd.IRState; +import dmd.DotIdExp; +import dmd.TypeExp; +import dmd.DYNCAST; +import dmd.TY; +import dmd.CallExp; +import dmd.VarExp; +import dmd.STC; +import dmd.TemplateInstance; +import dmd.CommaExp; +import dmd.NullExp; +import dmd.AddrExp; +import dmd.ErrorExp; +import dmd.TypeStruct; +import dmd.CastExp; +import dmd.Global; +import dmd.Token; +import dmd.TypeClass; +import dmd.PtrExp; +import dmd.TypeSArray; +import dmd.TypeReference; +import dmd.Util; +import dmd.Complex; + +import dmd.backend.elem; +import dmd.backend.dt_t; + +import std.stdio : writef; +import core.stdc.stdlib : malloc; + +import std.conv; + +/* Things like: + * int.size + * foo.size + * (foo).size + * cast(foo).size + */ + +Expression typeDotIdExp(Loc loc, Type type, Identifier ident) +{ + return new DotIdExp(loc, new TypeExp(loc, type), ident); +} + +/***************************************** + * Determine if 'this' is available. + * If it is, return the FuncDeclaration that has it. + */ + +FuncDeclaration hasThis(Scope sc) +{ + FuncDeclaration fd; + FuncDeclaration fdthis; + + //printf("hasThis()\n"); + fdthis = sc.parent.isFuncDeclaration(); + //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis.toChars() : ""); + + // Go upwards until we find the enclosing member function + fd = fdthis; + while (1) + { + if (!fd) + { + goto Lno; + } + if (!fd.isNested()) + break; + + Dsymbol parent = fd.parent; + while (parent) + { + TemplateInstance ti = parent.isTemplateInstance(); + if (ti) + parent = ti.parent; + else + break; + } + + fd = fd.parent.isFuncDeclaration(); + } + + if (!fd.isThis()) + { + //printf("test '%s'\n", fd.toChars()); + goto Lno; + } + + assert(fd.vthis); + return fd; + +Lno: + return null; // don't have 'this' available +} + +/*************************************** + * Pull out any properties. + */ + +Expression resolveProperties(Scope sc, Expression e) +{ + //printf("resolveProperties(%s)\n", e.toChars()); + if (e.type) + { + Type t = e.type.toBasetype(); + + if (t.ty == TY.Tfunction || e.op == TOK.TOKoverloadset) + { + e = new CallExp(e.loc, e); + e = e.semantic(sc); + } + + /* Look for e being a lazy parameter; rewrite as delegate call + */ + else if (e.op == TOK.TOKvar) + { VarExp ve = cast(VarExp)e; + + if (ve.var.storage_class & STC.STClazy) + { + e = new CallExp(e.loc, e); + e = e.semantic(sc); + } + } + + else if (e.op == TOK.TOKdotexp) + { + e.error("expression has no value"); + } + } + else if (e.op == TOK.TOKdottd) + { + e = new CallExp(e.loc, e); + e = e.semantic(sc); + } + + return e; +} + +class Expression +{ + Loc loc; // file location + TOK op; // handy to minimize use of dynamic_cast + Type type; // !=null means that semantic() has been run + int size; // # of bytes in Expression so we can copy() it + + this(Loc loc, TOK op, int size) + { + this.loc = loc; + //writef("Expression.Expression(op = %d %s) this = %p\n", op, to!(string)(op), this); + this.op = op; + this.size = size; + type = null; + } + + int equals(Object o) + { + return this is o; + } + + /********************************* + * Does *not* do a deep copy. + */ + Expression copy() /// bad bad bad + { + Expression e; + if (!size) + { +debug { + writef("No expression copy for: %s\n", toChars()); + writef("op = %d\n", op); + dump(0); +} + assert(0); + } + auto size = this.classinfo.init.length; + auto ptr = malloc(size); + memcpy(ptr, cast(void*)this, size); + + return cast(Expression)ptr; + } + + Expression syntaxCopy() + { + //printf("Expression::syntaxCopy()\n"); + //dump(0); + return copy(); + } + + Expression semantic(Scope sc) + { + version (LOGSEMANTIC) { + printf("Expression.semantic() %s\n", toChars()); + } + if (type) + type = type.semantic(loc, sc); + else + type = Type.tvoid; + return this; + } + + Expression trySemantic(Scope sc) + { + uint errors = global.errors; + global.gag++; + Expression e = semantic(sc); + global.gag--; + if (errors != global.errors) + { + global.errors = errors; + e = null; + } + return e; + } + + DYNCAST dyncast() { return DYNCAST.DYNCAST_EXPRESSION; } // kludge for template.isExpression() + + void print() + { + assert(false); + } + + string toChars() + { + scope OutBuffer buf = new OutBuffer(); + HdrGenState hgs; + + toCBuffer(buf, &hgs); + return buf.toChars(); + } + + void dump(int indent) + { + assert(false); + } + + void error(T...)(string format, T t) + { + .error(loc, format, t); + } + + void warning(T...)(string formar, T t) + { + .warning(loc, format, t); + } + + void rvalue() + { + if (type && type.toBasetype().ty == TY.Tvoid) + { + error("expression %s is void and has no value", toChars()); +static if (false) { + dump(0); + halt(); +} + type = Type.terror; + } + } + + static Expression combine(Expression e1, Expression e2) + { + if (e1) + { + if (e2) + { + e1 = new CommaExp(e1.loc, e1, e2); + e1.type = e2.type; + } + } + else + { + e1 = e2; + } + + return e1; + } + + static Expressions arraySyntaxCopy(Expressions exps) + { + Expressions a = null; + + if (exps) + { + a = new Expressions(); + a.setDim(exps.dim); + for (int i = 0; i < a.dim; i++) + { + Expression e = cast(Expression)exps.data[i]; + + e = e.syntaxCopy(); + a.data[i] = cast(void*)e; + } + } + return a; + } + + ulong toInteger() + { + assert(false); + } + + ulong toUInteger() + { + //printf("Expression %s\n", Token.toChars(op)); + return cast(ulong)toInteger(); + } + + real toReal() + { + assert(false); + } + + real toImaginary() + { + assert(false); + } + + Complex!(real) toComplex() + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + buf.writestring(Token.toChars(op)); + } + + void toMangleBuffer(OutBuffer buf) + { + assert(false); + } + + int isLvalue() + { + assert(false); + } + + Expression toLvalue(Scope sc, Expression e) + { + assert(false); + } + + Expression modifiableLvalue(Scope sc, Expression e) + { + //printf("Expression::modifiableLvalue() %s, type = %s\n", toChars(), type.toChars()); + + // See if this expression is a modifiable lvalue (i.e. not const) +version (DMDV2) { + if (type && (!type.isMutable() || !type.isAssignable())) + error("%s is not mutable", e.toChars()); +} + return toLvalue(sc, e); + } + + /************************************** + * Do an implicit cast. + * Issue error if it can't be done. + */ + Expression implicitCastTo(Scope sc, Type t) + { + //printf("Expression.implicitCastTo(%s of type %s) => %s\n", toChars(), type.toChars(), t.toChars()); + + MATCH match = implicitConvTo(t); + if (match) + { + TY tyfrom = type.toBasetype().ty; + TY tyto = t.toBasetype().ty; + +version (DMDV1) { + if (global.params.warnings && + Type.impcnvWarn[tyfrom][tyto] && + op != TOKint64) + { + Expression e = optimize(WANT.WANTflags | WANT.WANTvalue); + + if (e.op == TOK.TOKint64) + return e.implicitCastTo(sc, t); + if (tyfrom == Tint32 && (op == TOKadd || op == TOKmin || op == TOKand || op == TOKor || op == TOKxor)) + { + /* This is really only a semi-kludge fix, + * we really should look at the operands of op + * and see if they are narrower types. + * For example, b=b|b and b=b|7 and s=b+b should be allowed, + * but b=b|i should be an error. + */ + ; + } + else + { + warning("implicit conversion of expression (%s) of type %s to %s can cause loss of data", toChars(), type.toChars(), t.toChars()); + } + } +} +version (DMDV2) { + if (match == MATCH.MATCHconst && t == type.constOf()) + { + Expression e = copy(); + e.type = t; + return e; + } +} + return castTo(sc, t); + } + + Expression e = optimize(WANT.WANTflags | WANT.WANTvalue); + if (e != this) + return e.implicitCastTo(sc, t); + +static if (false) { + printf("ty = %d\n", type.ty); + print(); + type.print(); + printf("to:\n"); + t.print(); + printf("%p %p type: %s to: %s\n", type.deco, t.deco, type.deco, t.deco); + //printf("%p %p %p\n", type.nextOf().arrayOf(), type, t); + fflush(stdout); +} + if (!t.deco) { + /* Can happen with: + * enum E { One } + * class A + * { static void fork(EDG dg) { dg(E.One); } + * alias void delegate(E) EDG; + * } + * Should eventually make it work. + */ + error("forward reference to type %s", t.toChars()); + } else if (t.reliesOnTident()) { + error("forward reference to type %s", t.reliesOnTident().toChars()); + } + + error("cannot implicitly convert expression (%s) of type %s to %s", toChars(), type.toChars(), t.toChars()); + return castTo(sc, t); + } + + /******************************************* + * Return !=0 if we can implicitly convert this to type t. + * Don't do the actual cast. + */ + MATCH implicitConvTo(Type t) + { +static if (false) { + printf("Expression.implicitConvTo(this=%s, type=%s, t=%s)\n", + toChars(), type.toChars(), t.toChars()); +} + //static int nest; if (++nest == 10) halt(); + if (!type) + { + error("%s is not an expression", toChars()); + type = Type.terror; + } + Expression e = optimize(WANT.WANTvalue | WANT.WANTflags); + if (e.type == t) + return MATCH.MATCHexact; + if (e != this) + { + //printf("\toptimized to %s of type %s\n", e.toChars(), e.type.toChars()); + return e.implicitConvTo(t); + } + MATCH match = type.implicitConvTo(t); + if (match != MATCH.MATCHnomatch) + return match; + + /* See if we can do integral narrowing conversions + */ + if (type.isintegral() && t.isintegral() && + type.isTypeBasic() && t.isTypeBasic()) + { + IntRange ir = getIntRange(); + if (ir.imax <= t.sizemask()) + return MATCH.MATCHconvert; + } + +static if (false) { + Type tb = t.toBasetype(); + if (tb.ty == Tdelegate) + { + TypeDelegate td = cast(TypeDelegate)tb; + TypeFunction tf = cast(TypeFunction)td.nextOf(); + + if (!tf.varargs && !(tf.arguments && tf.arguments.dim)) + { + match = type.implicitConvTo(tf.nextOf()); + if (match) + return match; + if (tf.nextOf().toBasetype().ty == Tvoid) + return MATCH.MATCHconvert; + } + } +} + return MATCH.MATCHnomatch; + } + + IntRange getIntRange() + { + assert(false); + } + + /************************************** + * Do an explicit cast. + */ + Expression castTo(Scope sc, Type t) + { + //printf("Expression.castTo(this=%s, t=%s)\n", toChars(), t.toChars()); +static if (false) { + writef("Expression.castTo(this=%s, type=%s, t=%s)\n", + toChars(), type.toChars(), t.toChars()); +} + if (type is t) + return this; + Expression e = this; + Type tb = t.toBasetype(); + Type typeb = type.toBasetype(); + if (tb != typeb) + { + // Do (type *) cast of (type [dim]) + if (tb.ty == TY.Tpointer && typeb.ty == TY.Tsarray + ) + { + //printf("Converting [dim] to *\n"); + + if (typeb.size(loc) == 0) + e = new NullExp(loc); + else + e = new AddrExp(loc, e); + } + else { +static if (false) { + if (tb.ty == Tdelegate && type.ty != Tdelegate) + { + TypeDelegate td = cast(TypeDelegate)tb; + TypeFunction tf = cast(TypeFunction)td.nextOf(); + return toDelegate(sc, tf.nextOf()); + } +} + if (typeb.ty == TY.Tstruct) + { + TypeStruct ts = cast(TypeStruct)typeb; + if (!(tb.ty == TY.Tstruct && ts.sym == (cast(TypeStruct)tb).sym) && + ts.sym.aliasthis) + { /* Forward the cast to our alias this member, rewrite to: + * cast(to)e1.aliasthis + */ + Expression e1 = new DotIdExp(loc, this, ts.sym.aliasthis.ident); + Expression e2 = new CastExp(loc, e1, tb); + e2 = e2.semantic(sc); + return e2; + } + } + else if (typeb.ty == TY.Tclass) + { + TypeClass ts = cast(TypeClass)typeb; + if (tb.ty != TY.Tclass && ts.sym.aliasthis) + { /* Forward the cast to our alias this member, rewrite to: + * cast(to)e1.aliasthis + */ + Expression e1 = new DotIdExp(loc, this, ts.sym.aliasthis.ident); + Expression e2 = new CastExp(loc, e1, tb); + e2 = e2.semantic(sc); + return e2; + } + } + e = new CastExp(loc, e, tb); + } + } + else + { + e = e.copy(); // because of COW for assignment to e.type + } + + assert(e != this); + e.type = t; + //printf("Returning: %s\n", e.toChars()); + return e; + } + + /************************************ + * Detect cases where pointers to the stack can 'escape' the + * lifetime of the stack frame. + */ + void checkEscape() + { + } + + void checkScalar() + { + if (!type.isscalar()) + error("'%s' is not a scalar, it is a %s", toChars(), type.toChars()); + + rvalue(); + } + + void checkNoBool() + { + if (type.toBasetype().ty == TY.Tbool) + error("operation not allowed on bool '%s'", toChars()); + } + + Expression checkIntegral() + { + if (!type.isintegral()) + { + error("'%s' is not of integral type, it is a %s", toChars(), type.toChars()); + return new ErrorExp(); + } + + rvalue(); + return this; + } + + Expression checkArithmetic() + { + if (!type.isintegral() && !type.isfloating()) + { + error("'%s' is not of arithmetic type, it is a %s", toChars(), type.toChars()); + return new ErrorExp(); + } + + rvalue(); + return this; + } + + void checkDeprecated(Scope sc, Dsymbol s) + { + s.checkDeprecated(loc, sc); + } + + void checkPurity(Scope sc, FuncDeclaration f) + { +static if (true) { + if (sc.func) + { + FuncDeclaration outerfunc = sc.func; + while (outerfunc.toParent2() && outerfunc.toParent2().isFuncDeclaration()) + { + outerfunc = outerfunc.toParent2().isFuncDeclaration(); + } + if (outerfunc.isPure() && !sc.intypeof && (!f.isNested() && !f.isPure())) + error("pure function '%s' cannot call impure function '%s'\n", + sc.func.toChars(), f.toChars()); + } +} else { + if (sc.func && sc.func.isPure() && !sc.intypeof && !f.isPure()) + error("pure function '%s' cannot call impure function '%s'\n", + sc.func.toChars(), .toChars()); +} + } + + /***************************** + * Check that expression can be tested for true or false. + */ + Expression checkToBoolean() + { + // Default is 'yes' - do nothing + +debug { + if (!type) + dump(0); +} + + if (!type.checkBoolean()) + { + error("expression %s of type %s does not have a boolean value", toChars(), type.toChars()); + } + + return this; + } + + Expression checkToPointer() + { + Expression e; + Type tb; + + //printf("Expression::checkToPointer()\n"); + e = this; + + // If C static array, convert to pointer + tb = type.toBasetype(); + if (tb.ty == Tsarray) + { + TypeSArray ts = cast(TypeSArray)tb; + if (ts.size(loc) == 0) + e = new NullExp(loc); + else + e = new AddrExp(loc, this); + e.type = ts.next.pointerTo(); + } + return e; + } + + Expression addressOf(Scope sc) + { + //printf("Expression::addressOf()\n"); + Expression e = toLvalue(sc, null); + e = new AddrExp(loc, e); + e.type = type.pointerTo(); + return e; + } + + /****************************** + * If this is a reference, dereference it. + */ + Expression deref() + { + //printf("Expression::deref()\n"); + if (type.ty == TY.Treference) + { + Expression e = new PtrExp(loc, this); + e.type = (cast(TypeReference)type).next; + return e; + } + return this; + } + + /*********************************** + * Do integral promotions (convertchk). + * Don't convert to + */ + Expression integralPromotions(Scope sc) + { + Expression e = this; + + //printf("integralPromotions %s %s\n", e.toChars(), e.type.toChars()); + switch (type.toBasetype().ty) + { + case TY.Tvoid: + error("void has no value"); + break; + + case TY.Tint8: + case TY.Tuns8: + case TY.Tint16: + case TY.Tuns16: + case TY.Tbit: + case TY.Tbool: + case TY.Tchar: + case TY.Twchar: + e = e.castTo(sc, Type.tint32); + break; + + case TY.Tdchar: + e = e.castTo(sc, Type.tuns32); + break; + default: + break; /// + } + return e; + } + + Expression toDelegate(Scope sc, Type t) + { + assert(false); + } + + void scanForNestedRef(Scope sc) + { + assert(false); + } + + Expression optimize(int result) + { + //printf("Expression.optimize(result = x%x) %s\n", result, toChars()); + return this; + } + + Expression interpret(InterState istate) + { + assert(false); + } + + int isConst() + { + //printf("Expression::isConst(): %s\n", toChars()); + return 0; + } + + /******************************** + * Does this expression statically evaluate to a boolean TRUE or FALSE? + */ + bool isBool(bool result) + { + return false; + } + + int isBit() + { + assert(false); + } + + /******************************** + * Check for expressions that have no use. + * Input: + * flag 0 not going to use the result, so issue error message if no + * side effects + * 1 the result of the expression is used, but still check + * for useless subexpressions + * 2 do not issue error messages, just return !=0 if expression + * has side effects + */ + bool checkSideEffect(int flag) + { + if (flag == 0) + { + if (op == TOKimport) + error("%s has no effect", toChars()); + else + error("%s has no effect in expression (%s)", + + Token.toChars(op), toChars()); + } + + return false; + } + + bool canThrow() + { +version (DMDV2) { + return false; +} else { + return true; +} + } + + int inlineCost(InlineCostState* ics) + { + return 1; + } + + Expression doInline(InlineDoState ids) + { + //printf("Expression.doInline(%s): %s\n", Token.toChars(op), toChars()); + return copy(); + } + + Expression inlineScan(InlineScanState* iss) + { + return this; + } + + /*********************************** + * Determine if operands of binary op can be reversed + * to fit operator overload. + */ + + // For operator overloading + bool isCommutative() + { + return false; // default is no reverse + } + + /*********************************** + * Get Identifier for operator overload. + */ + Identifier opId() + { + assert(false); + } + + /*********************************** + * Get Identifier for reverse operator overload, + * null if not supported for this operator. + */ + Identifier opId_r() + { + return null; + } + + // For array ops + void buildArrayIdent(OutBuffer buf, Expressions arguments) + { + assert(false); + } + + Expression buildArrayLoop(Arguments fparams) + { + assert(false); + } + + // Back end + elem* toElem(IRState* irs) + { + assert(false); + } + + dt_t** toDt(dt_t** pdt) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/File.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/File.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,396 @@ +module dmd.File; + +import dmd.FileName; +import dmd.Array; +import dmd.Util; + +import core.stdc.stdlib; +import core.sys.windows.windows; + +import std.string : toStringz; + +class File +{ + int ref_; // != 0 if this is a reference to someone else's buffer + ubyte* buffer; // data for our file + uint len; // amount of data in buffer[] + void* touchtime; // system time to use for file + + FileName name; // name of our file + + this(string n) + { + name = new FileName(n); + } + + this(FileName n) + { + name = n; + } + + ~this() + { + if (buffer !is null) { + if (ref_ == 0) { + free(buffer); + } else { +version (_WIN32) { + if (ref_ == 2) { + UnmapViewOfFile(buffer); + } +} + } + } + + if (touchtime !is null) { + free(touchtime); + } + } + + void mark() + { + ///mem.mark(buffer); + ///mem.mark(touchtime); + ///mem.mark(name); + } + + string toChars() + { + return name.toChars(); + } + + /* Read file, return !=0 if error + */ + + int read() + { +version (POSIX) { + int result = 0; + + string name = this.name.toChars(); + + //printf("File::read('%s')\n",name); + int fd = open(name, O_RDONLY); + if (fd == -1) { + result = errno; + //printf("\topen error, errno = %d\n", errno); + goto err1; + } + + if (ref_ == 0) { + free(buffer); + } + + ref_ = 0; // we own the buffer now + + //printf("\tfile opened\n"); + stat buf; + if (fstat(fd, &buf)) { + printf("\tfstat error, errno = %d\n", errno); + goto err2; + } + + off_t size = buf.st_size; + buffer = cast(ubyte*)malloc(size + 2); + if (buffer is null) { + printf("\tmalloc error, errno = %d\n", errno); + goto err2; + } + + ssize_t numread = .read(fd, buffer, size); + if (numread != size) { + printf("\tread error, errno = %d\n",errno); + goto err2; + } + + if (touchtime !is null) { + memcpy(touchtime, &buf, buf.sizeof); + } + + if (close(fd) == -1) { + printf("\tclose error, errno = %d\n",errno); + goto err; + } + + len = size; + + // Always store a wchar ^Z past end of buffer so scanner has a sentinel + buffer[size] = 0; // ^Z is obsolete, use 0 + buffer[size + 1] = 0; + + return 0; + + err2: + close(fd); + + err: + free(buffer); + buffer = null; + len = 0; + + err1: + result = 1; + return result; +} else version (_WIN32) { + DWORD size; + DWORD numread; + HANDLE h; + int result = 0; + + string name = this.name.toChars(); + //std.stdio.writeln("Open file ", name); + + h = CreateFileA(toStringz(name), GENERIC_READ, FILE_SHARE_READ, null, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, HANDLE.init); + if (h == INVALID_HANDLE_VALUE) { + goto err1; + } + + if (!ref_) { + free(buffer); + } + ref_ = 0; + + size = GetFileSize(h, null); + buffer = cast(ubyte*) malloc(size + 2); + if (!buffer) + goto err2; + + if (ReadFile(h, buffer, size, &numread, null) != TRUE) + goto err2; + + if (numread != size) + goto err2; + + if (touchtime) { + if (!GetFileTime(h, null, null, &(cast(WIN32_FIND_DATA*)touchtime).ftLastWriteTime)) + goto err2; + } + + if (!CloseHandle(h)) + goto err; + + len = size; + + // Always store a wchar ^Z past end of buffer so scanner has a sentinel + buffer[size] = 0; // ^Z is obsolete, use 0 + buffer[size + 1] = 0; + return 0; + + err2: + CloseHandle(h); + err: + free(buffer); + buffer = null; + len = 0; + + err1: + result = 1; + return result; +} else { + static assert(0); +} + } + + /* Write file, either succeed or fail + * with error message & exit. + */ + + void readv() + { + if (read()) + error("Error reading file '%s'\n",name.toChars()); + } + + /* Read file, return !=0 if error + */ + + int mmread() + { + assert(false); + } + + /* Write file, either succeed or fail + * with error message & exit. + */ + + void mmreadv() + { + assert(false); + } + + /* Write file, return !=0 if error + */ + + /********************************************* + * Write a file. + * Returns: + * 0 success + */ + int write() + { +version (POSIX) { + assert(false); + /+ + int fd; + ssize_t numwritten; + char *name; + + name = this->name->toChars(); + fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, 0644); + if (fd == -1) + goto err; + + numwritten = ::write(fd, buffer, len); + if (len != numwritten) + goto err2; + + if (close(fd) == -1) + goto err; + + if (touchtime) + { struct utimbuf ubuf; + + ubuf.actime = ((struct stat *)touchtime)->st_atime; + ubuf.modtime = ((struct stat *)touchtime)->st_mtime; + if (utime(name, &ubuf)) + goto err; + } + return 0; + + err2: + close(fd); + ::remove(name); + err: + return 1; + +/ +} else version (_WIN32) { + HANDLE h; + DWORD numwritten; + + const(char)* name = toStringz(this.name.toChars()); + h = CreateFileA(name, GENERIC_WRITE, 0, null, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, null); + if (h == INVALID_HANDLE_VALUE) + goto err; + + if (WriteFile(h, buffer, len, &numwritten, null) != TRUE) + goto err2; + + if (len != numwritten) + goto err2; + + if (touchtime) { + SetFileTime(h, null, null, &(cast(WIN32_FIND_DATA*)touchtime).ftLastWriteTime); + } + if (!CloseHandle(h)) + goto err; + return 0; + + err2: + CloseHandle(h); + DeleteFileA(name); + err: + return 1; +} else { + static assert(false); +} + } + + /* Write file, either succeed or fail + * with error message & exit. + */ + + void writev() + { + if (write()) { + error("Error writing file '%s'\n", name.toChars()); + } + } + + /* Return !=0 if file exists. + * 0: file doesn't exist + * 1: normal file + * 2: directory + */ + + /* Append to file, return !=0 if error + */ + + int append() + { + assert(false); + } + + /* Append to file, either succeed or fail + * with error message & exit. + */ + + void appendv() + { + assert(false); + } + + /* Return !=0 if file exists. + * 0: file doesn't exist + * 1: normal file + * 2: directory + */ + + int exists() + { + assert(false); + } + + /* Given wildcard filespec, return an array of + * matching File's. + */ + + static Array match(char*) + { + assert(false); + } + + static Array match(FileName *) + { + assert(false); + } + + // Compare file times. + // Return <0 this < f + // =0 this == f + // >0 this > f + int compareTime(File f) + { + assert(false); + } + + // Read system file statistics + void stat() + { + assert(false); + } + + /* Set buffer + */ + + void setbuffer(void* buffer, uint len) + { + this.buffer = cast(ubyte*)buffer; + this.len = len; + } + + void checkoffset(size_t offset, size_t nbytes) + { + assert(false); + } + + void remove() // delete file + { +version (POSIX) { + .remove(this.name.toChars()); +} else version (_WIN32) { + DeleteFileA(toStringz(this.name.toChars())); +} else { + assert(0); +} + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/FileExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/FileExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,29 @@ +module dmd.FileExp; + +import dmd.Expression; +import dmd.UnaExp; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.HdrGenState; +import dmd.TOK; + +class FileExp : UnaExp +{ + this(Loc loc, Expression e) + { + assert(false); + super(loc, TOK.init, 0, e); + } + + Expression semantic(Scope sc) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/FileInitExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/FileInitExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,27 @@ +module dmd.FileInitExp; + +import dmd.Expression; +import dmd.Loc; +import dmd.Scope; +import dmd.DefaultInitExp; +import dmd.TOK; + +class FileInitExp : DefaultInitExp +{ + this(Loc loc) + { + assert(false); + super(loc, TOK.init, 0); + } + + Expression semantic(Scope sc) + { + assert(false); + } + + Expression resolve(Loc loc, Scope sc) + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/FileName.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/FileName.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,535 @@ +module dmd.FileName; + +import dmd.String; +import dmd.Array; +import dmd.OutBuffer; +import dmd.File; + +import core.stdc.stdlib : malloc, alloca; +import core.stdc.string : memcpy, strlen; +import core.stdc.ctype : isspace; + +import std.contracts : assumeUnique; +import std.string : cmp, icmp; +import std.file : mkdirRecurse; + +import core.sys.windows.windows; + +class FileName : String +{ + this(string str) + { + super(str); + } + + this(string path, string name) + { + super(combine(path, name)); + } + + hash_t hashCode() + { +version (_WIN32) { + // We need a different hashCode because it must be case-insensitive + size_t len = str.length; + hash_t hash = 0; + ubyte* s = cast(ubyte*)str.ptr; + + for (;;) + { + switch (len) + { + case 0: + return hash; + + case 1: + hash *= 37; + hash += *(cast(ubyte*)s) | 0x20; + return hash; + + case 2: + hash *= 37; + hash += *(cast(ushort*)s) | 0x2020; + return hash; + + case 3: + hash *= 37; + hash += (*cast(ushort*)s) << 8 + + ((cast(ubyte*)s)[2]) | 0x202020; + break; + + default: + hash *= 37; + hash += (*cast(int*)s) | 0x20202020; + s += 4; + len -= 4; + break; + } + } +} else { + // darwin HFS is case insensitive, though... + return super.hashCode(); +} + } + + bool opEquals(Object obj) + { + return opCmp(obj) == 0; + } + + static int equals(string name1, string name2) + { + return compare(name1, name2) == 0; + } + + int opCmp(Object obj) + { + return compare(str, (cast(FileName)obj).str); + } + + static int compare(string name1, string name2) + { +version (_WIN32) { + return icmp(name1, name2); +} else { + return cmp(name1, name2); +} + } + + static bool absolute(string name) + { +version (_WIN32) { + return (*name == '\\') || + (*name == '/') || + (*name && name[1] == ':'); +} else version (POSIX) { + return (*name == '/'); +} else { + static assert(false); +} + } + + /******************************** + * Return filename extension (read-only). + * Points past '.' of extension. + * If there isn't one, return NULL. + */ + static string ext(string str) + { + foreach_reverse (i, c; str) + { + switch (c) + { + case '.': + return str[i+1..$]; +version (POSIX) { + case '/': + return null; +} +version (_WIN32) { + case '\\': + case ':': + case '/': + return null; + +} default: + break; + } + } + + return null; + } + + string ext() + { + return ext(str); + } + + /******************************** + * Return filename with extension removed. + */ + + static string removeExt(string str) + { + string e = ext(str); + if (e !is null) + { + size_t len = (e.ptr - str.ptr - 1); + return str[0..len]; + } + + return str; + } + + /******************************** + * Return filename name excluding path (read-only). + */ + + static string name(string str) + { + foreach_reverse(i, c; str) + { + switch (c) + { +version (POSIX) { + case '/': + return str[i+1..$]; +} +version (_WIN32) { + case '/': + case '\\': + return str[i+1..$]; + case ':': + /* The ':' is a drive letter only if it is the second + * character or the last character, + * otherwise it is an ADS (Alternate Data Stream) separator. + * Consider ADS separators as part of the file name. + */ + if (i == 1 || i == str.length - 1) + return str[i+1..$]; +} + default: + break; + } + } + + return str; + } + + string name() + { + return name(str); + } + + /************************************** + * Return path portion of str. + * Path will does not include trailing path separator. + */ + + static string path(string str) + { + auto n = name(str).ptr; + + if (n > str.ptr) + { + auto p = n - 1; +version (POSIX) { + if (*p == '/') + n--; +} else version (_WIN32) { + if (*p == '\\' || *p == '/') + n--; +} else { + static assert(false); +} + } + + size_t pathlen = n - str.ptr; + return str[0..pathlen]; + } + + /************************************** + * Replace filename portion of path. + */ + + static string replaceName(string path, string name) + { + if (absolute(name)) + return name; + + string n = FileName.name(path); + if (n is path) + return name; + + size_t pathlen = n.ptr - path.ptr; + size_t namelen = name.length; + + char* f = cast(char*)malloc(pathlen + 1 + namelen + 1); + memcpy(f, path.ptr, pathlen); +version (POSIX) { + if (path[pathlen - 1] != '/') + { + f[pathlen] = '/'; + pathlen++; + } +} else version (_WIN32) { + if (path[pathlen - 1] != '\\' && + path[pathlen - 1] != '/' && + path[pathlen - 1] != ':') + { + f[pathlen] = '\\'; + pathlen++; + } +} else { + static assert(false); +} + memcpy(f + pathlen, name.ptr, namelen + 1); + + return assumeUnique(f[0..pathlen+namelen]); + } + + static string combine(string path, string name) + { + size_t pathlen; + size_t namelen; + + if (path.length == 0) + return name; + + pathlen = path.length; + namelen = name.length; + + char* f = cast(char*)malloc(pathlen + 1 + namelen + 1); + + memcpy(f, path.ptr, pathlen); + +version (POSIX) { + if (path[pathlen - 1] != '/') + { + f[pathlen] = '/'; + pathlen++; + } +} else version (_WIN32) { + if (path[pathlen - 1] != '\\' && + path[pathlen - 1] != '/' && + path[pathlen - 1] != ':') + { + f[pathlen] = '\\'; + pathlen++; + } +} else { + static assert(0); +} + memcpy(f + pathlen, name.ptr, namelen + 1); + + return assumeUnique(f[0..pathlen+namelen]); + } + + static string[] splitPath(const(char)[] spath) + { + char c = 0; // unnecessary initializer is for VC /W4 + + scope OutBuffer buf = new OutBuffer(); + string[] array; + + if (spath !is null) + { + const(char)* p = spath.ptr; + int len = spath.length; + do + { + char instring = 0; + + while (len > 0 && isspace(*p)) { // skip leading whitespace + p++; + --len; + } + + buf.reserve(len + 1); // guess size of path + for (; len; p++, len--) + { + c = *p; + switch (c) + { + case '"': + instring ^= 1; // toggle inside/outside of string + continue; + + version (MACINTOSH) { + case ',': + } + version (_WIN32) { + case ';': + } + version (POSIX) { + case ':': + } + p++; + break; // note that ; cannot appear as part + // of a path, quotes won't protect it + + case 0x1A: // ^Z means end of file + //case 0: + break; + + case '\r': + continue; // ignore carriage returns + + version (POSIX) { + case '~': + buf.writestring(getenv("HOME")); + continue; + } + + version (disabled) { + case ' ': + case '\t': // tabs in filenames? + if (!instring) // if not in string + break; // treat as end of path + } + default: + buf.writeByte(c); + continue; + } + break; + } + if (buf.offset) // if path is not empty + { + //buf.writeByte(0); // to asciiz + array ~= buf.extractString(); + } + } while (len > 0); + } + + return array; + } + + static FileName defaultExt(string name, string ext) + { + string e = FileName.ext(name); + if (e !is null) { + // if already has an extension + return new FileName(name); + } + + size_t len = name.length; + size_t extlen = ext.length; + char* s = cast(char*)malloc(len + 1 + extlen + 1); + memcpy(s, name.ptr, len); + s[len] = '.'; + memcpy(s + len + 1, ext.ptr, extlen + 1); + + return new FileName(assumeUnique(s[0..len+1+extlen])); + } + + static FileName forceExt(string name, string ext) + { + string e = FileName.ext(name); + if (e !is null) // if already has an extension + { + size_t len = e.ptr - name.ptr; + size_t extlen = ext.length; + + char* s = cast(char*)malloc(len + extlen + 1); + memcpy(s, name.ptr, len); + memcpy(s + len, ext.ptr, extlen + 1); + return new FileName(assumeUnique(s[0..len+extlen])); + } + + return defaultExt(name, ext); // doesn't have one + } + + /****************************** + * Return true if extensions match. + */ + + bool equalsExt(string ext) + { + string e = FileName.ext(); + if (e.length == 0 && ext.length == 0) + return true; + + if (e.length == 0 || ext.length == 0) + return false; + +version (POSIX) { + return cmp(e,ext) == 0; +} else version (_WIN32) { + return icmp(e,ext) == 0; +} else { + static assert(0); +} + } + + /************************************* + * Copy file from this to to. + */ + + void CopyTo(FileName to) + { + scope File file = new File(this); + +version (_WIN32) { + file.touchtime = malloc(WIN32_FIND_DATA.sizeof); // keep same file time +} else version (POSIX) { + file.touchtime = malloc(stat.sizeof); // keep same file time +} else { + static assert(0); +} + file.readv(); + file.name = to; + file.writev(); + } + + /************************************* + * Search Path for file. + * Input: + * cwd if true, search current directory before searching path + */ + + static string searchPath(Array path, string name, bool cwd) + { + if (absolute(name)) { + return exists(name) ? name : null; + } + + if (cwd) { + if (exists(name)) { + return name; + } + } + + if (path !is null) { + foreach (i; 0..path.dim) + { + String p = cast(String)path.data[i]; + string n = combine(p.str, name); + + if (exists(n)) + return n; + } + } + + return null; + } + + static int exists(string name) + { +version (POSIX) { + stat st; + + if (stat(name, &st) < 0) + return 0; + if (S_ISDIR(st.st_mode)) + return 2; + return 1; +} else version (_WIN32) { + HANDLE h = CreateFileA(toStringz(name), GENERIC_READ, FILE_SHARE_READ, null, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, HANDLE.init); /// + if (h == INVALID_HANDLE_VALUE) { + return 0; + } + + CloseHandle(h); + + DWORD dw = GetFileAttributesA(name.ptr); /// CARE! + if (dw == -1L) { + assert(false); + return 0; + } else if (dw & FILE_ATTRIBUTE_DIRECTORY) { + return 2; + } else { + return 1; + } +} else { + static assert(0); +} + } + + static void ensurePathExists(string path) + { + try { + mkdirRecurse(path); + } catch { + } + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ForStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ForStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,251 @@ +module dmd.ForStatement; + +import dmd.Statement; +import dmd.Expression; +import dmd.Loc; +import dmd.Scope; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.InlineScanState; +import dmd.WANT; +import dmd.ScopeDsymbol; +import dmd.IRState; +import dmd.BE; + +import dmd.backend.Blockx; +import dmd.backend.block; +import dmd.backend.Util; +import dmd.backend.BC; + +class ForStatement : Statement +{ + Statement init; + Expression condition; + Expression increment; + Statement body_; + + this(Loc loc, Statement init, Expression condition, Expression increment, Statement body_) + { + super(loc); + + this.init = init; + this.condition = condition; + this.increment = increment; + this.body_ = body_; + } + + Statement syntaxCopy() + { + Statement i = null; + if (init) + i = init.syntaxCopy(); + Expression c = null; + if (condition) + c = condition.syntaxCopy(); + Expression inc = null; + if (increment) + inc = increment.syntaxCopy(); + ForStatement s = new ForStatement(loc, i, c, inc, body_.syntaxCopy()); + return s; + } + + Statement semantic(Scope sc) + { + ScopeDsymbol sym = new ScopeDsymbol(); + sym.parent = sc.scopesym; + sc = sc.push(sym); + if (init) + init = init.semantic(sc); + sc.noctor++; + if (condition) + { + condition = condition.semantic(sc); + condition = resolveProperties(sc, condition); + condition = condition.optimize(WANTvalue); + condition = condition.checkToBoolean(); + } + if (increment) + { + increment = increment.semantic(sc); + increment = resolveProperties(sc, increment); + } + + sc.sbreak = this; + sc.scontinue = this; + if (body_) + body_ = body_.semantic(sc); + sc.noctor--; + + sc.pop(); + return this; + } + + void scopeCode(Scope sc, Statement* sentry, Statement* sexception, Statement* sfinally) + { + //printf("ForStatement::scopeCode()\n"); + //print(); + if (init) + init.scopeCode(sc, sentry, sexception, sfinally); + else + Statement.scopeCode(sc, sentry, sexception, sfinally); + } + + bool hasBreak() + { + //printf("ForStatement.hasBreak()\n"); + return true; + } + + bool hasContinue() + { + return true; + } + + bool usesEH() + { + return (init && init.usesEH()) || body_.usesEH(); + } + + BE blockExit() + { + BE result = BE.BEfallthru; + + if (init) + { + result = init.blockExit(); + if (!(result & BE.BEfallthru)) + return result; + } + if (condition) + { + if (condition.canThrow()) + result |= BE.BEthrow; + if (condition.isBool(true)) + result &= ~BE.BEfallthru; + else if (condition.isBool(false)) + return result; + } + else + result &= ~BE.BEfallthru; // the body must do the exiting + if (body_) + { + int r = body_.blockExit(); + if (r & (BE.BEbreak | BE.BEgoto)) + result |= BE.BEfallthru; + result |= r & ~(BE.BEfallthru | BE.BEbreak | BE.BEcontinue); + } + if (increment && increment.canThrow()) + result |= BE.BEthrow; + return result; + } + + bool comeFrom() + { + //printf("ForStatement.comeFrom()\n"); + if (body_) + { + bool result = body_.comeFrom(); + //printf("result = %d\n", result); + return result; + } + return false; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + buf.writestring("for ("); + if (init) + { + hgs.FLinit.init++; + init.toCBuffer(buf, hgs); + hgs.FLinit.init--; + } + else + buf.writebyte(';'); + if (condition) + { buf.writebyte(' '); + condition.toCBuffer(buf, hgs); + } + buf.writebyte(';'); + if (increment) + { + buf.writebyte(' '); + increment.toCBuffer(buf, hgs); + } + buf.writebyte(')'); + buf.writenl(); + buf.writebyte('{'); + buf.writenl(); + body_.toCBuffer(buf, hgs); + buf.writebyte('}'); + buf.writenl(); + } + + Statement inlineScan(InlineScanState* iss) + { + if (init) + init = init.inlineScan(iss); + if (condition) + condition = condition.inlineScan(iss); + if (increment) + increment = increment.inlineScan(iss); + if (body_) + body_ = body_.inlineScan(iss); + return this; + } + + void toIR(IRState* irs) + { + Blockx* blx = irs.blx; + + IRState mystate = IRState(irs,this); + mystate.breakBlock = block_calloc(blx); + mystate.contBlock = block_calloc(blx); + + if (init) + init.toIR(&mystate); + block* bpre = blx.curblock; + block_next(blx,BCgoto,null); + block* bcond = blx.curblock; + list_append(&bpre.Bsucc, bcond); + list_append(&mystate.contBlock.Bsucc, bcond); + if (condition) + { + incUsage(irs, condition.loc); + block_appendexp(bcond, condition.toElem(&mystate)); + block_next(blx,BCiftrue,null); + list_append(&bcond.Bsucc, blx.curblock); + list_append(&bcond.Bsucc, mystate.breakBlock); + } + else + { + /* No conditional, it's a straight goto + */ + block_next(blx,BCgoto,null); + list_append(&bcond.Bsucc, blx.curblock); + } + + if (body_) + body_.toIR(&mystate); + /* End of the body goes to the continue block + */ + list_append(&blx.curblock.Bsucc, mystate.contBlock); + block_next(blx, BCgoto, mystate.contBlock); + + if (increment) + { + incUsage(irs, increment.loc); + block_appendexp(mystate.contBlock, increment.toElem(&mystate)); + } + + /* The 'break' block follows the for statement. + */ + block_next(blx,BCgoto, mystate.breakBlock); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ForeachRangeStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ForeachRangeStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,224 @@ +module dmd.ForeachRangeStatement; + +import dmd.Statement; +import dmd.TOK; +import dmd.Argument; +import dmd.Expression; +import dmd.Statement; +import dmd.VarDeclaration; +import dmd.Scope; +import dmd.ExpInitializer; +import dmd.Identifier; +import dmd.Lexer; +import dmd.ArrayTypes; +import dmd.DeclarationStatement; +import dmd.CompoundDeclarationStatement; +import dmd.DeclarationExp; +import dmd.PostExp; +import dmd.VarExp; +import dmd.ForStatement; +import dmd.IntegerExp; +import dmd.AddAssignExp; +import dmd.CmpExp; +import dmd.IRState; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.AddExp; +import dmd.WANT; +import dmd.ScopeDsymbol; +import dmd.HdrGenState; +import dmd.InlineScanState; +import dmd.Loc; +import dmd.BE; + +class ForeachRangeStatement : Statement +{ + TOK op; // TOK.TOKforeach or TOK.TOKforeach_reverse + Argument arg; // loop index variable + Expression lwr; + Expression upr; + Statement body_; + + VarDeclaration key = null; + + this(Loc loc, TOK op, Argument arg, Expression lwr, Expression upr, Statement body_) + { + super(loc); + this.op = op; + this.arg = arg; + this.lwr = lwr; + this.upr = upr; + this.body_ = body_; + } + + Statement syntaxCopy() + { + ForeachRangeStatement s = new ForeachRangeStatement(loc, op, + arg.syntaxCopy(), + lwr.syntaxCopy(), + upr.syntaxCopy(), + body_ ? body_.syntaxCopy() : null); + + return s; + } + + Statement semantic(Scope sc) + { + //printf("ForeachRangeStatement.semantic() %p\n", this); + ScopeDsymbol sym; + Statement s = this; + + lwr = lwr.semantic(sc); + lwr = resolveProperties(sc, lwr); + lwr = lwr.optimize(WANTvalue); + if (!lwr.type) + { + error("invalid range lower bound %s", lwr.toChars()); + return this; + } + + upr = upr.semantic(sc); + upr = resolveProperties(sc, upr); + upr = upr.optimize(WANTvalue); + if (!upr.type) + { + error("invalid range upper bound %s", upr.toChars()); + return this; + } + + if (arg.type) + { + arg.type = arg.type.semantic(loc, sc); + lwr = lwr.implicitCastTo(sc, arg.type); + upr = upr.implicitCastTo(sc, arg.type); + } + else + { + /* Must infer types from lwr and upr + */ + scope AddExp ea = new AddExp(loc, lwr, upr); + ea.typeCombine(sc); + arg.type = ea.type.mutableOf(); + lwr = ea.e1; + upr = ea.e2; + } + static if (true) { + /* Convert to a for loop: + * foreach (key; lwr .. upr) => + * for (auto key = lwr, auto tmp = upr; key < tmp; ++key) + * + * foreach_reverse (key; lwr .. upr) => + * for (auto tmp = lwr, auto key = upr; key-- > tmp;) + */ + + ExpInitializer ie = new ExpInitializer(loc, (op == TOKforeach) ? lwr : upr); + key = new VarDeclaration(loc, arg.type, arg.ident, ie); + + Identifier id = Lexer.uniqueId("__limit"); + ie = new ExpInitializer(loc, (op == TOKforeach) ? upr : lwr); + VarDeclaration tmp = new VarDeclaration(loc, arg.type, id, ie); + + Statements cs = new Statements(); + // Keep order of evaluation as lwr, then upr + if (op == TOKforeach) + { + cs.push(cast(void*)new DeclarationStatement(loc, new DeclarationExp(loc, key))); + cs.push(cast(void*)new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); + } + else + { + cs.push(cast(void*)new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); + cs.push(cast(void*)new DeclarationStatement(loc, new DeclarationExp(loc, key))); + } + Statement forinit = new CompoundDeclarationStatement(loc, cs); + + Expression cond; + if (op == TOKforeach_reverse) + { // key-- > tmp + cond = new PostExp(TOKminusminus, loc, new VarExp(loc, key)); + cond = new CmpExp(TOKgt, loc, cond, new VarExp(loc, tmp)); + } + else + // key < tmp + cond = new CmpExp(TOKlt, loc, new VarExp(loc, key), new VarExp(loc, tmp)); + + Expression increment = null; + if (op == TOKforeach) + // key += 1 + increment = new AddAssignExp(loc, new VarExp(loc, key), new IntegerExp(1)); + + ForStatement fs = new ForStatement(loc, forinit, cond, increment, body_); + s = fs.semantic(sc); + return s; + } else { + if (!arg.type.isscalar()) + error("%s is not a scalar type", arg.type.toChars()); + + sym = new ScopeDsymbol(); + sym.parent = sc.scopesym; + sc = sc.push(sym); + + sc.noctor++; + + key = new VarDeclaration(loc, arg.type, arg.ident, null); + DeclarationExp de = new DeclarationExp(loc, key); + de.semantic(sc); + + if (key.storage_class) + error("foreach range: key cannot have storage class"); + + sc.sbreak = this; + sc.scontinue = this; + body_ = body_.semantic(sc); + + sc.noctor--; + sc.pop(); + return s; + } + } + + bool hasBreak() + { + assert(false); + } + + bool hasContinue() + { + assert(false); + } + + bool usesEH() + { + assert(false); + } + + BE blockExit() + { + assert(false); + } + + bool comeFrom() + { + assert(false); + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + Statement inlineScan(InlineScanState* iss) + { + assert(false); + } + + void toIR(IRState* irs) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ForeachStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ForeachStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,826 @@ +module dmd.ForeachStatement; + +import dmd.Statement; +import dmd.TOK; +import dmd.Loc; +import dmd.LINK; +import dmd.ArrayTypes; +import dmd.Expression; +import dmd.VarDeclaration; +import dmd.FuncDeclaration; +import dmd.Array; +import dmd.Scope; +import dmd.InterState; +import dmd.InlineScanState; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.IRState; +import dmd.BE; +import dmd.ScopeDsymbol; +import dmd.TypeAArray; +import dmd.Type; +import dmd.CallExp; +import dmd.WANT; +import dmd.TY; +import dmd.TypeTuple; +import dmd.TupleExp; +import dmd.Global; +import dmd.Initializer; +import dmd.ExpInitializer; +import dmd.IntegerExp; +import dmd.ExpStatement; +import dmd.DeclarationExp; +import dmd.Dsymbol; +import dmd.BreakStatement; +import dmd.DefaultStatement; +import dmd.CaseStatement; +import dmd.SwitchStatement; +import dmd.VarExp; +import dmd.AliasDeclaration; +import dmd.CompoundStatement; +import dmd.ScopeStatement; +import dmd.UnrolledLoopStatement; +import dmd.Identifier; +import dmd.Lexer; +import dmd.DeclarationStatement; +import dmd.CompoundDeclarationStatement; +import dmd.AggregateDeclaration; +import dmd.TypeClass; +import dmd.NotExp; +import dmd.TypeStruct; +import dmd.FuncLiteralDeclaration; +import dmd.IdentifierExp; +import dmd.TypeFunction; +import dmd.GotoStatement; +import dmd.FuncExp; +import dmd.ReturnStatement; +import dmd.IndexExp; +import dmd.ForStatement; +import dmd.SliceExp; +import dmd.DotIdExp; +import dmd.PostExp; +import dmd.AddAssignExp; +import dmd.CmpExp; +import dmd.Id; +import dmd.Argument; +import dmd.STC; + +import dmd.expression.Util; + +import core.stdc.stdio; + +class ForeachStatement : Statement +{ + TOK op; // TOKforeach or TOKforeach_reverse + Arguments arguments; // array of Argument*'s + Expression aggr; + Statement body_; + + VarDeclaration key; + VarDeclaration value; + + FuncDeclaration func; // function we're lexically in + + Array cases; // put breaks, continues, gotos and returns here + Array gotos; // forward referenced goto's go here + + this(Loc loc, TOK op, Arguments arguments, Expression aggr, Statement body_) + { + super(loc); + + this.op = op; + this.arguments = arguments; + this.aggr = aggr; + this.body_ = body_; + + gotos = new Array(); + cases = new Array(); + } + + Statement syntaxCopy() + { + assert(false); + } + + Statement semantic(Scope sc) + { + //printf("ForeachStatement.semantic() %p\n", this); + ScopeDsymbol sym; + Statement s = this; + size_t dim = arguments.dim; + TypeAArray taa = null; + + Type tn = null; + Type tnv = null; + + func = sc.func; + if (func.fes) + func = func.fes.func; + + aggr = aggr.semantic(sc); + aggr = resolveProperties(sc, aggr); + aggr = aggr.optimize(WANT.WANTvalue); + if (!aggr.type) + { + error("invalid foreach aggregate %s", aggr.toChars()); + return this; + } + + inferApplyArgTypes(op, arguments, aggr); + + /* Check for inference errors + */ + if (dim != arguments.dim) + { + //printf("dim = %d, arguments.dim = %d\n", dim, arguments.dim); + error("cannot uniquely infer foreach argument types"); + return this; + } + + Type tab = aggr.type.toBasetype(); + + if (tab.ty == TY.Ttuple) // don't generate new scope for tuple loops + { + if (dim < 1 || dim > 2) + { + error("only one (value) or two (key,value) arguments for tuple foreach"); + return s; + } + + TypeTuple tuple = cast(TypeTuple)tab; + Statements statements = new Statements(); + //printf("aggr: op = %d, %s\n", aggr.op, aggr.toChars()); + size_t n; + TupleExp te = null; + if (aggr.op == TOK.TOKtuple) // expression tuple + { + te = cast(TupleExp)aggr; + n = te.exps.dim; + } + else if (aggr.op == TOK.TOKtype) // type tuple + { + n = Argument.dim(tuple.arguments); + } + else + assert(0); + + for (size_t j = 0; j < n; j++) + { + size_t k = (op == TOK.TOKforeach) ? j : n - 1 - j; + Expression e; + Type t; + if (te) + e = cast(Expression)te.exps.data[k]; + else + t = Argument.getNth(tuple.arguments, k).type; + + Argument arg = cast(Argument)arguments.data[0]; + Statements st = new Statements(); + + if (dim == 2) + { + // Declare key + if (arg.storageClass & (STC.STCout | STC.STCref | STC.STClazy)) + error("no storage class for key %s", arg.ident.toChars()); + TY keyty = arg.type.ty; + if (keyty != TY.Tint32 && keyty != TY.Tuns32) + { + if (global.params.isX86_64) + { + if (keyty != TY.Tint64 && keyty != TY.Tuns64) + error("foreach: key type must be int or uint, long or ulong, not %s", arg.type.toChars()); + } + else + error("foreach: key type must be int or uint, not %s", arg.type.toChars()); + } + Initializer ie = new ExpInitializer(Loc(0), new IntegerExp(k)); + VarDeclaration var = new VarDeclaration(loc, arg.type, arg.ident, ie); + var.storage_class |= STC.STCmanifest; + DeclarationExp de = new DeclarationExp(loc, var); + st.push(cast(void*)new ExpStatement(loc, de)); + arg = cast(Argument)arguments.data[1]; // value + } + // Declare value + if (arg.storageClass & (STC.STCout | STC.STCref | STC.STClazy)) + error("no storage class for value %s", arg.ident.toChars()); + Dsymbol var; + if (te) + { + Type tb = e.type.toBasetype(); + if ((tb.ty == TY.Tfunction || tb.ty == TY.Tsarray) && e.op == TOK.TOKvar) + { + VarExp ve = cast(VarExp)e; + var = new AliasDeclaration(loc, arg.ident, ve.var); + } + else + { + arg.type = e.type; + Initializer ie = new ExpInitializer(Loc(0), e); + VarDeclaration v = new VarDeclaration(loc, arg.type, arg.ident, ie); + if (e.isConst()) + v.storage_class |= STC.STCconst; + + var = v; + } + } + else + { + var = new AliasDeclaration(loc, arg.ident, t); + } + + DeclarationExp de = new DeclarationExp(loc, var); + st.push(cast(void*)new ExpStatement(loc, de)); + + st.push(cast(void*)body_.syntaxCopy()); + s = new CompoundStatement(loc, st); + s = new ScopeStatement(loc, s); + statements.push(cast(void*)s); + } + + s = new UnrolledLoopStatement(loc, statements); + s = s.semantic(sc); + return s; + } + + sym = new ScopeDsymbol(); + sym.parent = sc.scopesym; + sc = sc.push(sym); + + sc.noctor++; + + switch (tab.ty) + { + case TY.Tarray: + case TY.Tsarray: + if (!checkForArgTypes()) + return this; + + if (dim < 1 || dim > 2) + { + error("only one or two arguments for array foreach"); + break; + } + + /* Look for special case of parsing char types out of char type + * array. + */ + tn = tab.nextOf().toBasetype(); + if (tn.ty == TY.Tchar || tn.ty == TY.Twchar || tn.ty == TY.Tdchar) + { + Argument arg; + + int i = (dim == 1) ? 0 : 1; // index of value + arg = cast(Argument)arguments.data[i]; + arg.type = arg.type.semantic(loc, sc); + tnv = arg.type.toBasetype(); + if (tnv.ty != tn.ty && (tnv.ty == TY.Tchar || tnv.ty == TY.Twchar || tnv.ty == TY.Tdchar)) + { + if (arg.storageClass & STC.STCref) + error("foreach: value of UTF conversion cannot be ref"); + if (dim == 2) + { + arg = cast(Argument)arguments.data[0]; + if (arg.storageClass & STC.STCref) + error("foreach: key cannot be ref"); + } + goto Lapply; + } + } + + for (size_t i = 0; i < dim; i++) + { + // Declare args + Argument arg = cast(Argument)arguments.data[i]; + Type argtype = arg.type.semantic(loc, sc); + VarDeclaration var = new VarDeclaration(loc, argtype, arg.ident, null); + var.storage_class |= STC.STCforeach; + var.storage_class |= arg.storageClass & (STC.STCin | STC.STCout | STC.STCref | STC.STC_TYPECTOR); + if (var.storage_class & (STC.STCref | STC.STCout)) + var.storage_class |= STC.STCnodtor; + + if (dim == 2 && i == 0) + { + key = var; + //var.storage_class |= STCfinal; + } + else + { + value = var; + /* Reference to immutable data should be marked as const + */ + if (var.storage_class & STC.STCref && !tn.isMutable()) + { + var.storage_class |= STC.STCconst; + } + } +static if (false) { + DeclarationExp de = new DeclarationExp(loc, var); + de.semantic(sc); +} + } + +static if (true) { + { + /* Convert to a ForStatement + * foreach (key, value; a) body => + * for (T[] tmp = a[], size_t key; key < tmp.length; ++key) + * { T value = tmp[k]; body } + * + * foreach_reverse (key, value; a) body => + * for (T[] tmp = a[], size_t key = tmp.length; key--; ) + * { T value = tmp[k]; body } + */ + Identifier id = Lexer.uniqueId("__aggr"); + ExpInitializer ie = new ExpInitializer(loc, new SliceExp(loc, aggr, null, null)); + VarDeclaration tmp = new VarDeclaration(loc, aggr.type.nextOf().arrayOf(), id, ie); + + Expression tmp_length = new DotIdExp(loc, new VarExp(loc, tmp), Id.length); + + if (!key) + { + Identifier id2 = Lexer.uniqueId("__key"); + key = new VarDeclaration(loc, Type.tsize_t, id2, null); + } + + if (op == TOK.TOKforeach_reverse) + key.init = new ExpInitializer(loc, tmp_length); + else + key.init = new ExpInitializer(loc, new IntegerExp(0)); + + Statements cs = new Statements(); + cs.push(cast(void*)new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); + cs.push(cast(void*)new DeclarationStatement(loc, new DeclarationExp(loc, key))); + Statement forinit = new CompoundDeclarationStatement(loc, cs); + + Expression cond; + if (op == TOK.TOKforeach_reverse) + // key-- + cond = new PostExp(TOK.TOKminusminus, loc, new VarExp(loc, key)); + else + // key < tmp.length + cond = new CmpExp(TOK.TOKlt, loc, new VarExp(loc, key), tmp_length); + + Expression increment = null; + if (op == TOK.TOKforeach) + // key += 1 + increment = new AddAssignExp(loc, new VarExp(loc, key), new IntegerExp(1)); + + // T value = tmp[key]; + value.init = new ExpInitializer(loc, new IndexExp(loc, new VarExp(loc, tmp), new VarExp(loc, key))); + Statement ds = new DeclarationStatement(loc, new DeclarationExp(loc, value)); + + body_ = new CompoundStatement(loc, ds, body_); + + ForStatement fs = new ForStatement(loc, forinit, cond, increment, body_); + s = fs.semantic(sc); + break; + } +} else { + if (tab.nextOf().implicitConvTo(value.type) < MATCH.MATCHconst) + { + if (aggr.op == TOK.TOKstring) + aggr = aggr.implicitCastTo(sc, value.type.arrayOf()); + else + error("foreach: %s is not an array of %s", + tab.toChars(), value.type.toChars()); + } + + if (key) + { + if (key.type.ty != Tint32 && key.type.ty != Tuns32) + { + if (global.params.isX86_64) + { + if (key.type.ty != Tint64 && key.type.ty != Tuns64) + error("foreach: key type must be int or uint, long or ulong, not %s", key.type.toChars()); + } + else + error("foreach: key type must be int or uint, not %s", key.type.toChars()); + } + + if (key.storage_class & (STCout | STCref)) + error("foreach: key cannot be out or ref"); + } + + sc.sbreak = this; + sc.scontinue = this; + body_ = body_.semantic(sc); + break; +} + + case TY.Taarray: + if (!checkForArgTypes()) + return this; + + taa = cast(TypeAArray)tab; + if (dim < 1 || dim > 2) + { + error("only one or two arguments for associative array foreach"); + break; + } + if (op == TOK.TOKforeach_reverse) + { + error("no reverse iteration on associative arrays"); + } + goto Lapply; + + case TY.Tclass: + case TY.Tstruct: +version (DMDV2) { + { /* Look for range iteration, i.e. the properties + * .empty, .next, .retreat, .head and .rear + * foreach (e; aggr) { ... } + * translates to: + * for (auto __r = aggr[]; !__r.empty; __r.next) + * { auto e = __r.head; + * ... + * } + */ + if (dim != 1) // only one argument allowed with ranges + goto Lapply; + + AggregateDeclaration ad = (tab.ty == TY.Tclass) + ? cast(AggregateDeclaration)(cast(TypeClass)tab).sym + : cast(AggregateDeclaration)(cast(TypeStruct)tab).sym; + + Identifier idhead; + Identifier idnext; + if (op == TOK.TOKforeach) + { + idhead = Id.Fhead; + idnext = Id.Fnext; + } + else + { + idhead = Id.Ftoe; + idnext = Id.Fretreat; + } + + Dsymbol shead = search_function(ad, idhead); + if (!shead) + goto Lapply; + + /* Generate a temporary __r and initialize it with the aggregate. + */ + Identifier id = Identifier.generateId("__r"); + Expression rinit = new SliceExp(loc, aggr, null, null); + rinit = rinit.trySemantic(sc); + if (!rinit) // if application of [] failed + rinit = aggr; + + VarDeclaration r = new VarDeclaration(loc, null, id, new ExpInitializer(loc, rinit)); + + // r.semantic(sc); + //printf("r: %s, init: %s\n", r.toChars(), r.init.toChars()); + Statement init = new DeclarationStatement(loc, r); + //printf("init: %s\n", init.toChars()); + + // !__r.empty + Expression e = new VarExp(loc, r); + e = new DotIdExp(loc, e, Id.Fempty); + Expression condition = new NotExp(loc, e); + + // __r.next + e = new VarExp(loc, r); + Expression increment = new DotIdExp(loc, e, idnext); + + /* Declaration statement for e: + * auto e = __r.idhead; + */ + e = new VarExp(loc, r); + Expression einit = new DotIdExp(loc, e, idhead); + // einit = einit.semantic(sc); + Argument arg = cast(Argument)arguments.data[0]; + VarDeclaration ve = new VarDeclaration(loc, arg.type, arg.ident, new ExpInitializer(loc, einit)); + ve.storage_class |= STC.STCforeach; + ve.storage_class |= arg.storageClass & (STC.STCin | STC.STCout | STC.STCref | STC.STC_TYPECTOR); + + DeclarationExp de = new DeclarationExp(loc, ve); + + Statement body2 = new CompoundStatement(loc, new DeclarationStatement(loc, de), this.body_); + s = new ForStatement(loc, init, condition, increment, body2); + + static if (false) { + printf("init: %s\n", init.toChars()); + printf("condition: %s\n", condition.toChars()); + printf("increment: %s\n", increment.toChars()); + printf("body: %s\n", body2.toChars()); + } + s = s.semantic(sc); + break; + } +} + case TY.Tdelegate: + Lapply: + { + FuncDeclaration fdapply; + Arguments args; + Expression ec; + Expression e; + FuncLiteralDeclaration fld; + Argument a; + Type t; + Expression flde; + Identifier id; + Type tret; + + if (!checkForArgTypes()) + { + body_ = body_.semantic(sc); + return this; + } + + tret = func.type.nextOf(); + + // Need a variable to hold value from any return statements in body. + if (!sc.func.vresult && tret && tret != Type.tvoid) + { + VarDeclaration v = new VarDeclaration(loc, tret, Id.result, null); + v.noauto = true; + v.semantic(sc); + if (!sc.insert(v)) + assert(0); + + v.parent = sc.func; + sc.func.vresult = v; + } + + /* Turn body into the function literal: + * int delegate(ref T arg) { body } + */ + args = new Arguments(); + for (size_t i = 0; i < dim; i++) + { + Argument arg = cast(Argument)arguments.data[i]; + + arg.type = arg.type.semantic(loc, sc); + if (arg.storageClass & STC.STCref) + id = arg.ident; + else + { // Make a copy of the ref argument so it isn't + // a reference. + VarDeclaration v; + Initializer ie; + + id = Lexer.uniqueId("__applyArg", i); + + ie = new ExpInitializer(Loc(0), new IdentifierExp(Loc(0), id)); + v = new VarDeclaration(Loc(0), arg.type, arg.ident, ie); + s = new DeclarationStatement(Loc(0), v); + body_ = new CompoundStatement(loc, s, body_); + } + a = new Argument(STC.STCref, arg.type, id, null); + args.push(cast(void*)a); + } + t = new TypeFunction(args, Type.tint32, 0, LINK.LINKd); + fld = new FuncLiteralDeclaration(loc, Loc(0), t, TOK.TOKdelegate, this); + fld.fbody = body_; + flde = new FuncExp(loc, fld); + flde = flde.semantic(sc); + fld.tookAddressOf = 0; + + // Resolve any forward referenced goto's + for (int i = 0; i < gotos.dim; i++) + { + CompoundStatement cs = cast(CompoundStatement)gotos.data[i]; + GotoStatement gs = cast(GotoStatement)cs.statements.data[0]; + + if (!gs.label.statement) + { + // 'Promote' it to this scope, and replace with a return + cases.push(cast(void*)gs); + s = new ReturnStatement(Loc(0), new IntegerExp(cases.dim + 1)); + cs.statements.data[0] = cast(void*)s; + } + } + + if (tab.ty == TY.Taarray) + { + // Check types + Argument arg = cast(Argument)arguments.data[0]; + if (dim == 2) + { + if (arg.storageClass & STC.STCref) + error("foreach: index cannot be ref"); + if (!arg.type.equals(taa.index)) + error("foreach: index must be type %s, not %s", taa.index.toChars(), arg.type.toChars()); + + arg = cast(Argument)arguments.data[1]; + } + if (!arg.type.equals(taa.nextOf())) + error("foreach: value must be type %s, not %s", taa.nextOf().toChars(), arg.type.toChars()); + + /* Call: + * _aaApply(aggr, keysize, flde) + */ + if (dim == 2) + fdapply = FuncDeclaration.genCfunc(Type.tindex, "_aaApply2"); + else + fdapply = FuncDeclaration.genCfunc(Type.tindex, "_aaApply"); + + ec = new VarExp(Loc(0), fdapply); + Expressions exps = new Expressions(); + exps.push(cast(void*)aggr); + size_t keysize = cast(uint)taa.index.size(); + keysize = (keysize + (PTRSIZE-1)) & ~(PTRSIZE-1); + exps.push(cast(void*)new IntegerExp(Loc(0), keysize, Type.tsize_t)); + exps.push(cast(void*)flde); + e = new CallExp(loc, ec, exps); + e.type = Type.tindex; // don't run semantic() on e + } + else if (tab.ty == TY.Tarray || tab.ty == TY.Tsarray) + { + /* Call: + * _aApply(aggr, flde) + */ + static char fntab[9][3] = + [ "cc","cw","cd", + "wc","cc","wd", + "dc","dw","dd" + ]; + char fdname[7+1+2+ dim.sizeof*3 + 1]; + int flag; + + switch (tn.ty) + { + case TY.Tchar: flag = 0; break; + case TY.Twchar: flag = 3; break; + case TY.Tdchar: flag = 6; break; + } + switch (tnv.ty) + { + case TY.Tchar: flag += 0; break; + case TY.Twchar: flag += 1; break; + case TY.Tdchar: flag += 2; break; + } + string r = (op == TOK.TOKforeach_reverse) ? "R" : ""; + int j = sprintf(fdname.ptr, "_aApply%*.s%.*s%ld".ptr, r, 2, fntab[flag].ptr, dim); + assert(j < fdname.sizeof); + fdapply = FuncDeclaration.genCfunc(Type.tindex, fdname[0..j].idup); + + ec = new VarExp(Loc(0), fdapply); + Expressions exps = new Expressions(); + if (tab.ty == TY.Tsarray) + aggr = aggr.castTo(sc, tn.arrayOf()); + exps.push(cast(void*)aggr); + exps.push(cast(void*)flde); + e = new CallExp(loc, ec, exps); + e.type = Type.tindex; // don't run semantic() on e + } + else if (tab.ty == TY.Tdelegate) + { + /* Call: + * aggr(flde) + */ + Expressions exps = new Expressions(); + exps.push(cast(void*)flde); + e = new CallExp(loc, aggr, exps); + e = e.semantic(sc); + if (e.type != Type.tint32) + error("opApply() function for %s must return an int", tab.toChars()); + } + else + { + assert(tab.ty == TY.Tstruct || tab.ty == TY.Tclass); + Identifier idapply = (op == TOK.TOKforeach_reverse) + ? Id.applyReverse : Id.apply; + Dsymbol sapply = search_function(cast(AggregateDeclaration)tab.toDsymbol(sc), idapply); + Expressions exps = new Expressions(); +static if (false) { + TemplateDeclaration td; + if (sapply && (td = sapply.isTemplateDeclaration()) !is null) + { + /* Call: + * aggr.apply!(fld)() + */ + TemplateInstance ti = new TemplateInstance(loc, idapply); + Objects tiargs = new Objects(); + tiargs.push(cast(void*)fld); + ti.tiargs = tiargs; + ec = new DotTemplateInstanceExp(loc, aggr, ti); + } + else + { + /* Call: + * aggr.apply(flde) + */ + ec = new DotIdExp(loc, aggr, idapply); + exps.push(cast(void*)flde); + } +} else { + ec = new DotIdExp(loc, aggr, idapply); + exps.push(cast(void*)flde); +} + e = new CallExp(loc, ec, exps); + e = e.semantic(sc); + if (e.type != Type.tint32) { + error("opApply() function for %s must return an int", tab.toChars()); + } + } + + if (!cases.dim) + { + // Easy case, a clean exit from the loop + s = new ExpStatement(loc, e); + } + else + { // Construct a switch statement around the return value + // of the apply function. + Statements a2 = new Statements(); + + // default: break; takes care of cases 0 and 1 + s = new BreakStatement(Loc(0), null); + s = new DefaultStatement(Loc(0), s); + a2.push(cast(void*)s); + + // cases 2... + for (int i = 0; i < cases.dim; i++) + { + s = cast(Statement)cases.data[i]; + s = new CaseStatement(Loc(0), new IntegerExp(i + 2), s); + a2.push(cast(void*)s); + } + + s = new CompoundStatement(loc, a2); + s = new SwitchStatement(loc, e, s, false); + s = s.semantic(sc); + } + break; + } + + default: + error("foreach: %s is not an aggregate type", aggr.type.toChars()); + s = null; // error recovery + break; + } + + sc.noctor--; + sc.pop(); + return s; + } + + bool checkForArgTypes() + { + bool result = true; + + for (size_t i = 0; i < arguments.dim; i++) + { + Argument arg = cast(Argument)arguments.data[i]; + if (!arg.type) + { + error("cannot infer type for %s", arg.ident.toChars()); + arg.type = Type.terror; + result = false; + } + } + return result; + } + + bool hasBreak() + { + assert(false); + } + + bool hasContinue() + { + assert(false); + } + + bool usesEH() + { + assert(false); + } + + BE blockExit() + { + assert(false); + } + + bool comeFrom() + { + assert(false); + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void toCBuffer(OutBuffer uf, HdrGenState* hgs) + { + assert(false); + } + + Statement inlineScan(InlineScanState* iss) + { + aggr = aggr.inlineScan(iss); + if (body_) + body_ = body_.inlineScan(iss); + return this; + } + + void toIR(IRState* irs) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/FuncAliasDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/FuncAliasDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,33 @@ +module dmd.FuncAliasDeclaration; + +import dmd.FuncDeclaration; + +import dmd.backend.Symbol; +import dmd.backend.Symbol; + +import dmd.Loc; +import dmd.STC; + +class FuncAliasDeclaration : FuncDeclaration +{ + FuncDeclaration funcalias; + + this(FuncDeclaration funcalias) + { + super(funcalias.loc, funcalias.endloc, funcalias.ident, funcalias.storage_class, funcalias.type); + assert(funcalias !is this); + this.funcalias = funcalias; + } + + FuncAliasDeclaration isFuncAliasDeclaration() { return this; } + + string kind() + { + return "function alias"; + } + + Symbol* toSymbol() + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/FuncDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/FuncDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,3248 @@ +module dmd.FuncDeclaration; + +import dmd.Declaration; +import dmd.DotIdExp; +import dmd.TryFinallyStatement; +import dmd.StaticDtorDeclaration; +import dmd.PeelStatement; +import dmd.SynchronizedStatement; +import dmd.TOK; +import dmd.SymOffExp; +import dmd.AssignExp; +import dmd.ExpInitializer; +import dmd.BE; +import dmd.Id; +import dmd.StringExp; +import dmd.DsymbolExp; +import dmd.HaltExp; +import dmd.CommaExp; +import dmd.ReturnStatement; +import dmd.IntegerExp; +import dmd.ExpStatement; +import dmd.CSX; +import dmd.CompoundStatement; +import dmd.LabelStatement; +import dmd.ThisExp; +import dmd.SuperExp; +import dmd.IdentifierExp; +import dmd.AssertExp; +import dmd.CallExp; +import dmd.RET; +import dmd.VarExp; +import dmd.TupleDeclaration; +import dmd.ThisDeclaration; +import dmd.TypeTuple; +import dmd.TemplateInstance; +import dmd.ScopeDsymbol; +import dmd.AliasDeclaration; +import dmd.MOD; +import dmd.PROT; +import dmd.Lexer; +import dmd.LINK; +import dmd.CtorDeclaration; +import dmd.Global; +import dmd.DtorDeclaration; +import dmd.InvariantDeclaration; +import dmd.TY; +import dmd.PtrExp; +import dmd.DeclarationExp; +import dmd.InlineDoState; +import dmd.Argument; +import dmd.StructDeclaration; +import dmd.ClassDeclaration; +import dmd.InterfaceDeclaration; +import dmd.Array; +import dmd.Statement; +import dmd.Identifier; +import dmd.VarDeclaration; +import dmd.LabelDsymbol; +import dmd.DsymbolTable; +import dmd.ArrayTypes; +import dmd.Loc; +import dmd.ILS; +import dmd.ForeachStatement; +import dmd.Type; +import dmd.BUILTIN; +import dmd.TypeFunction; +import dmd.Expression; +import dmd.STC; +import dmd.Dsymbol; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.MATCH; +import dmd.AggregateDeclaration; +import dmd.InterState; +import dmd.InlineScanState; +import dmd.IRState; +import dmd.Util; +import dmd.BaseClass; +import dmd.Module; +import dmd.ILS; +import dmd.InlineCostState; + +import dmd.expression.Util; + +import dmd.declaration.Match; + +import dmd.backend.Symbol; +import dmd.backend.func_t; +import dmd.backend.Util; +import dmd.backend.glue; +import dmd.backend.SC; +import dmd.backend.F; +import dmd.backend.Cstate; +import dmd.backend.TYM; +import dmd.backend.OPER; +import dmd.backend.TYFL; +import dmd.backend.TYPE; +import dmd.backend.SFL; +import dmd.backend.mTY; +import dmd.backend.FL; +import dmd.backend.REG; +import dmd.backend.block; +import dmd.backend.Blockx; +import dmd.backend.Config; +import dmd.backend.BC; +import dmd.backend.elem; +import dmd.backend.targ_types; +import dmd.backend.mTYman; +import dmd.backend.RTLSYM; +import dmd.backend.LIST; + +import core.stdc.stdio; +import core.stdc.string; + +import std.string; + +class FuncDeclaration : Declaration +{ + Array fthrows; // Array of Type's of exceptions (not used) + Statement frequire; + Statement fensure; + Statement fbody; + + Identifier outId; // identifier for out statement + VarDeclaration vresult; // variable corresponding to outId + LabelDsymbol returnLabel; // where the return goes + + DsymbolTable localsymtab; // used to prevent symbols in different + // scopes from having the same name + VarDeclaration vthis; // 'this' parameter (member and nested) + VarDeclaration v_arguments; // '_arguments' parameter +version (IN_GCC) { + VarDeclaration v_argptr; // '_argptr' variable +} + Dsymbols parameters; // Array of VarDeclaration's for parameters + DsymbolTable labtab; // statement label symbol table + Declaration overnext; // next in overload list + Loc endloc; // location of closing curly bracket + int vtblIndex = -1; // for member functions, index into vtbl[] + int naked; // !=0 if naked + int inlineAsm; // !=0 if has inline assembler + ILS inlineStatus = ILS.ILSuninitialized; + int inlineNest; // !=0 if nested inline + int cantInterpret; // !=0 if cannot interpret function + int semanticRun; // 1 semantic() run + // 2 semantic2() run + // 3 semantic3() started + // 4 semantic3() done + // 5 toObjFile() run + // this function's frame ptr + ForeachStatement fes; // if foreach body, this is the foreach + int introducing; // !=0 if 'introducing' function + Type tintro; // if !=null, then this is the type + // of the 'introducing' function + // this one is overriding + int inferRetType; // !=0 if return type is to be inferred + + // Things that should really go into Scope + int hasReturnExp; // 1 if there's a return exp; statement + // 2 if there's a throw statement + // 4 if there's an assert(0) + // 8 if there's inline asm + + // Support for NRVO (named return value optimization) + bool nrvo_can = true; // !=0 means we can do it + VarDeclaration nrvo_var; // variable to replace with shidden + Symbol* shidden; // hidden pointer passed to function + +version (DMDV2) { + BUILTIN builtin; // set if this is a known, builtin + // function we can evaluate at compile + // time + + int tookAddressOf; // set if someone took the address of + // this function + Dsymbols closureVars; // local variables in this function + // which are referenced by nested + // functions +} else { + int nestedFrameRef; // !=0 if nested variables referenced +} + + this(Loc loc, Loc endloc, Identifier id, STC storage_class, Type type) + { + super(id); + + //printf("FuncDeclaration(id = '%s', type = %p)\n", id.toChars(), type); + //printf("storage_class = x%x\n", storage_class); + this.storage_class = storage_class; + this.type = type; + this.loc = loc; + this.endloc = endloc; + + /* The type given for "infer the return type" is a TypeFunction with + * null for the return type. + */ + inferRetType = (type && type.nextOf() is null); + + closureVars = new Dsymbols(); + +version (DMDV2) { + builtin = BUILTIN.BUILTINunknown; +} + } + + Dsymbol syntaxCopy(Dsymbol s) + { + FuncDeclaration f; + + //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars()); + if (s) + f = cast(FuncDeclaration)s; + else + f = new FuncDeclaration(loc, endloc, ident, storage_class, type.syntaxCopy()); + + f.outId = outId; + f.frequire = frequire ? frequire.syntaxCopy() : null; + f.fensure = fensure ? fensure.syntaxCopy() : null; + f.fbody = fbody ? fbody.syntaxCopy() : null; + assert(!fthrows); // deprecated + + return f; + } + + // Do the semantic analysis on the external interface to the function. + void semantic(Scope sc) + { + TypeFunction f; + StructDeclaration sd; + ClassDeclaration cd; + InterfaceDeclaration id; + Dsymbol pd; + +static if (false) { + printf("FuncDeclaration.semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, this, toPrettyChars(), sc.linkage); + if (isFuncLiteralDeclaration()) + printf("\tFuncLiteralDeclaration()\n"); + printf("sc.parent = %s, parent = %s\n", sc.parent.toChars(), parent ? parent.toChars() : ""); + printf("type: %p, %s\n", type, type.toChars()); +} + + if (semanticRun && isFuncLiteralDeclaration()) + { + /* Member functions that have return types that are + * forward references can have semantic() run more than + * once on them. + * See test\interface2.d, test20 + */ + return; + } + assert(semanticRun <= 1); + semanticRun = 1; + + storage_class |= sc.stc & ~STC.STCref; + //printf("function storage_class = x%x\n", storage_class); + + if (!originalType) + originalType = type; + if (!type.deco) + { + /* Apply const and invariant storage class + * to the function type + */ + type = type.semantic(loc, sc); + STC stc = storage_class; + if (type.isInvariant()) + stc |= STC.STCimmutable; + if (type.isConst()) + stc |= STC.STCconst; + if (type.isShared() || storage_class & STC.STCsynchronized) + stc |= STC.STCshared; + switch (stc & STC.STC_TYPECTOR) + { + case STC.STCimmutable: + case STC.STCimmutable | STC.STCconst: + case STC.STCimmutable | STC.STCconst | STC.STCshared: + case STC.STCimmutable | STC.STCshared: + // Don't use toInvariant(), as that will do a merge() + type = type.makeInvariant(); + type.deco = type.merge().deco; + break; + + case STC.STCconst: + type = type.makeConst(); + type.deco = type.merge().deco; + break; + + case STC.STCshared | STC.STCconst: + type = type.makeSharedConst(); + type.deco = type.merge().deco; + break; + + case STC.STCshared: + type = type.makeShared(); + type.deco = type.merge().deco; + break; + + case STC.STCundefined: + break; + + default: + assert(0); + } + } + //type.print(); + if (type.ty != TY.Tfunction) + { + error("%s must be a function", toChars()); + return; + } + f = cast(TypeFunction)type; + size_t nparams = Argument.dim(f.parameters); + + linkage = sc.linkage; + // if (!parent) + { + //parent = sc.scopesym; + parent = sc.parent; + } + protection = sc.protection; + Dsymbol parent = toParent(); + + if (storage_class & STC.STCscope) + error("functions cannot be scope"); + + if (isAbstract() && !isVirtual()) + error("non-virtual functions cannot be abstract"); + + if ((f.isConst() || f.isInvariant()) && !isThis()) + error("without 'this' cannot be const/immutable"); + + if (isAbstract() && isFinal()) + error("cannot be both final and abstract"); +static if (false) { + if (isAbstract() && fbody) + error("abstract functions cannot have bodies"); +} + +static if (false) { + if (isStaticConstructor() || isStaticDestructor()) + { + if (!isStatic() || type.nextOf().ty != Tvoid) + error("static constructors / destructors must be static void"); + if (f.arguments && f.arguments.dim) + error("static constructors / destructors must have empty parameter list"); + // BUG: check for invalid storage classes + } +} + +version (IN_GCC) { + AggregateDeclaration ad; + + ad = parent.isAggregateDeclaration(); + if (ad) + ad.methods.push(cast(void*)this); +} + sd = parent.isStructDeclaration(); + if (sd) + { + if (isCtorDeclaration()) + { + return; + } +static if (false) { + // Verify no constructors, destructors, etc. + if (isCtorDeclaration() + //||isDtorDeclaration() + //|| isInvariantDeclaration() + //|| isUnitTestDeclaration() + ) + { + error("special member functions not allowed for %ss", sd.kind()); + } + + if (!sd.inv) + sd.inv = isInvariantDeclaration(); + + if (!sd.aggNew) + sd.aggNew = isNewDeclaration(); + + if (isDelete()) + { + if (sd.aggDelete) + error("multiple delete's for struct %s", sd.toChars()); + sd.aggDelete = cast(DeleteDeclaration)this; + } +} + } + + id = parent.isInterfaceDeclaration(); + if (id) + { + storage_class |= STC.STCabstract; + + if (isCtorDeclaration() || +///static if (DMDV2) { + isPostBlitDeclaration() || +///} + isDtorDeclaration() || + isInvariantDeclaration() || + isUnitTestDeclaration() || isNewDeclaration() || isDelete()) + error("special function not allowed in interface %s", id.toChars()); + if (fbody) + error("function body is not abstract in interface %s", id.toChars()); + } + + /* Template member functions aren't virtual: + * interface TestInterface { void tpl(T)(); } + * and so won't work in interfaces + */ + if ((pd = toParent()) !is null && + pd.isTemplateInstance() && + (pd = toParent2()) !is null && + (id = pd.isInterfaceDeclaration()) !is null) + { + error("template member function not allowed in interface %s", id.toChars()); + } + + cd = parent.isClassDeclaration(); + if (cd) + { int vi; + CtorDeclaration ctor; + DtorDeclaration dtor; + InvariantDeclaration inv; + + if (isCtorDeclaration()) + { + // ctor = cast(CtorDeclaration)this; + // if (!cd.ctor) + // cd.ctor = ctor; + return; + } + +static if (false) { + dtor = isDtorDeclaration(); + if (dtor) + { + if (cd.dtor) + error("multiple destructors for class %s", cd.toChars()); + cd.dtor = dtor; + } + + inv = isInvariantDeclaration(); + if (inv) + { + cd.inv = inv; + } + + if (isNewDeclaration()) + { + if (!cd.aggNew) + cd.aggNew = cast(NewDeclaration)this; + } + + if (isDelete()) + { + if (cd.aggDelete) + error("multiple delete's for class %s", cd.toChars()); + cd.aggDelete = cast(DeleteDeclaration)this; + } +} + + if (storage_class & STC.STCabstract) + cd.isabstract = true; + + // if static function, do not put in vtbl[] + if (!isVirtual()) + { + //printf("\tnot virtual\n"); + goto Ldone; + } + + // Find index of existing function in vtbl[] to override + vi = findVtblIndex(cd.vtbl, cd.baseClass ? cd.baseClass.vtbl.dim : 0); + switch (vi) + { + case -1: + /* Didn't find one, so + * This is an 'introducing' function which gets a new + * slot in the vtbl[]. + */ + + // Verify this doesn't override previous final function + if (cd.baseClass) + { + Dsymbol s = cd.baseClass.search(loc, ident, 0); + if (s) + { + FuncDeclaration ff = s.isFuncDeclaration(); + ff = ff.overloadExactMatch(type); + if (ff && ff.isFinal() && ff.prot() != PROT.PROTprivate) + error("cannot override final function %s", ff.toPrettyChars()); + } + } + + if (isFinal()) + { + if (isOverride()) + error("does not override any function"); + cd.vtblFinal.push(cast(void*)this); + } + else + { + // Append to end of vtbl[] + //printf("\tintroducing function\n"); + introducing = 1; + vi = cd.vtbl.dim; + cd.vtbl.push(cast(void*)this); + vtblIndex = vi; + } + break; + + case -2: // can't determine because of fwd refs + cd.sizeok = 2; // can't finish due to forward reference + return; + + default: + { + FuncDeclaration fdv = cast(FuncDeclaration)cd.vtbl.data[vi]; + // This function is covariant with fdv + if (fdv.isFinal()) + error("cannot override final function %s", fdv.toPrettyChars()); + +version (DMDV2) { + if (!isOverride()) + warning(loc, "overrides base class function %s, but is not marked with 'override'", fdv.toPrettyChars()); +} + + if (fdv.toParent() == parent) + { + // If both are mixins, then error. + // If either is not, the one that is not overrides + // the other. + if (fdv.parent.isClassDeclaration()) + break; + if (!this.parent.isClassDeclaration() +///static if (!BREAKABI) { + && !isDtorDeclaration() +///} +///version (DMDV2) { + && !isPostBlitDeclaration() +///} + ) + error("multiple overrides of same function"); + } + cd.vtbl.data[vi] = cast(void*)this; + vtblIndex = vi; + + /* This works by whenever this function is called, + * it actually returns tintro, which gets dynamically + * cast to type. But we know that tintro is a base + * of type, so we could optimize it by not doing a + * dynamic cast, but just subtracting the isBaseOf() + * offset if the value is != null. + */ + + if (fdv.tintro) + tintro = fdv.tintro; + else if (!type.equals(fdv.type)) + { + /* Only need to have a tintro if the vptr + * offsets differ + */ + int offset; + if (fdv.type.nextOf().isBaseOf(type.nextOf(), &offset)) + { + tintro = fdv.type; + } + } + break; + } + } + + /* Go through all the interface bases. + * If this function is covariant with any members of those interface + * functions, set the tintro. + */ + for (int i = 0; i < cd.interfaces_dim; i++) + { + BaseClass b = cd.interfaces[i]; + vi = findVtblIndex(b.base.vtbl, b.base.vtbl.dim); + switch (vi) + { + case -1: + break; + + case -2: + cd.sizeok = 2; // can't finish due to forward reference + return; + + default: + { FuncDeclaration fdv = cast(FuncDeclaration)b.base.vtbl.data[vi]; + Type ti = null; + + if (fdv.tintro) + ti = fdv.tintro; + else if (!type.equals(fdv.type)) + { + /* Only need to have a tintro if the vptr + * offsets differ + */ + int offset; + if (fdv.type.nextOf().isBaseOf(type.nextOf(), &offset)) + { + ti = fdv.type; +static if (false) { + if (offset) + ti = fdv.type; + else if (type.nextOf().ty == Tclass) + { + ClassDeclaration cdn = (cast(TypeClass)type.nextOf()).sym; + if (cdn && cdn.sizeok != 1) + ti = fdv.type; + } +} + } + } + if (ti) + { + if (tintro && !tintro.equals(ti)) + { + error("incompatible covariant types %s and %s", tintro.toChars(), ti.toChars()); + } + tintro = ti; + } + goto L2; + } + } + } + + if (introducing && isOverride()) + { + error("does not override any function"); + } + + L2: ; + } + else if (isOverride() && !parent.isTemplateInstance()) + error("override only applies to class member functions"); + + /* Do not allow template instances to add virtual functions + * to a class. + */ + if (isVirtual()) + { + TemplateInstance ti = parent.isTemplateInstance(); + if (ti) + { + // Take care of nested templates + while (1) + { + TemplateInstance ti2 = ti.tempdecl.parent.isTemplateInstance(); + if (!ti2) + break; + ti = ti2; + } + + // If it's a member template + ClassDeclaration cdd = ti.tempdecl.isClassMember(); + if (cdd) + { + error("cannot use template to add virtual function to class '%s'", cdd.toChars()); + } + } + } + + if (isMain()) + { + // Check parameters to see if they are either () or (char[][] args) + switch (nparams) + { + case 0: + break; + + case 1: + { + Argument arg0 = Argument.getNth(f.parameters, 0); + if (arg0.type.ty != TY.Tarray || + arg0.type.nextOf().ty != TY.Tarray || + arg0.type.nextOf().nextOf().ty != TY.Tchar || + arg0.storageClass & (STC.STCout | STC.STCref | STC.STClazy)) + goto Lmainerr; + break; + } + + default: + goto Lmainerr; + } + + if (f.nextOf().ty != TY.Tint32 && f.nextOf().ty != TY.Tvoid) + error("must return int or void, not %s", f.nextOf().toChars()); + if (f.varargs) + { + Lmainerr: + error("parameters must be main() or main(char[][] args)"); + } + } + + if (ident == Id.assign && (sd || cd)) + { // Disallow identity assignment operator. + + // opAssign(...) + if (nparams == 0) + { if (f.varargs == 1) + goto Lassignerr; + } + else + { + Argument arg0 = Argument.getNth(f.parameters, 0); + Type t0 = arg0.type.toBasetype(); + Type tb = sd ? sd.type : cd.type; + if (arg0.type.implicitConvTo(tb) || + (sd && t0.ty == TY.Tpointer && t0.nextOf().implicitConvTo(tb)) + ) + { + if (nparams == 1) + goto Lassignerr; + Argument arg1 = Argument.getNth(f.parameters, 1); + if (arg1.defaultArg) + goto Lassignerr; + } + } + } + + Ldone: + /* Save scope for possible later use (if we need the + * function internals) + */ + scope_ = new Scope(sc); + scope_.setNoFree(); + return; + + Lassignerr: + if (sd) + { + sd.hasIdentityAssign = 1; // don't need to generate it + goto Ldone; + } + error("identity assignment operator overload is illegal"); + } + + void semantic2(Scope sc) + { + } + + // Do the semantic analysis on the internals of the function. + void semantic3(Scope sc) + { + TypeFunction f; + VarDeclaration argptr = null; + VarDeclaration _arguments = null; + + if (!parent) + { + if (global.errors) + return; + //printf("FuncDeclaration.semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc); + assert(0); + } + //printf("FuncDeclaration.semantic3('%s.%s', sc = %p, loc = %s)\n", parent.toChars(), toChars(), sc, loc.toChars()); + //fflush(stdout); + //printf("storage class = x%x %x\n", sc.stc, storage_class); + //{ static int x; if (++x == 2) *(char*)0=0; } + //printf("\tlinkage = %d\n", sc.linkage); + + //printf(" sc.incontract = %d\n", sc.incontract); + if (semanticRun >= 3) + return; + semanticRun = 3; + + if (!type || type.ty != TY.Tfunction) + return; + f = cast(TypeFunction)(type); + + // Check the 'throws' clause + if (fthrows) + { + for (int i = 0; i < fthrows.dim; i++) + { + Type t = cast(Type)fthrows.data[i]; + + t = t.semantic(loc, sc); + if (!t.isClassHandle()) + error("can only throw classes, not %s", t.toChars()); + } + } + + if (fbody || frequire) + { + /* Symbol table into which we place parameters and nested functions, + * solely to diagnose name collisions. + */ + localsymtab = new DsymbolTable(); + + // Establish function scope + ScopeDsymbol ss = new ScopeDsymbol(); + ss.parent = sc.scopesym; + Scope sc2 = sc.push(ss); + sc2.func = this; + sc2.parent = this; + sc2.callSuper = 0; + sc2.sbreak = null; + sc2.scontinue = null; + sc2.sw = null; + sc2.fes = fes; + sc2.linkage = LINK.LINKd; + sc2.stc &= ~(STC.STCauto | STC.STCscope | STC.STCstatic | STC.STCabstract | STC.STCdeprecated | STC.STC_TYPECTOR | STC.STCfinal | STC.STCtls | STC.STCgshared | STC.STCref); + sc2.protection = PROT.PROTpublic; + sc2.explicitProtection = 0; + sc2.structalign = 8; + sc2.incontract = 0; + sc2.tf = null; + sc2.noctor = 0; + + // Declare 'this' + AggregateDeclaration ad = isThis(); + if (ad) + { VarDeclaration v; + + if (isFuncLiteralDeclaration() && isNested()) + { + error("literals cannot be class members"); + return; + } + else + { + assert(!isNested()); // can't be both member and nested + assert(ad.handle); + Type thandle = ad.handle; +version (STRUCTTHISREF) { + thandle = thandle.addMod(type.mod); + thandle = thandle.addStorageClass(storage_class); + if (isPure()) + thandle = thandle.addMod(MOD.MODconst); +} else { + if (storage_class & STC.STCconst || type.isConst()) + { + assert(0); // BUG: shared not handled + if (thandle.ty == TY.Tclass) + thandle = thandle.constOf(); + else + { assert(thandle.ty == TY.Tpointer); + thandle = thandle.nextOf().constOf().pointerTo(); + } + } + else if (storage_class & STC.STCimmutable || type.isInvariant()) + { + if (thandle.ty == TY.Tclass) + thandle = thandle.invariantOf(); + else + { assert(thandle.ty == TY.Tpointer); + thandle = thandle.nextOf().invariantOf().pointerTo(); + } + } + else if (storage_class & STC.STCshared || type.isShared()) + { + assert(0); // not implemented + } +} + v = new ThisDeclaration(loc, thandle); + v.storage_class |= STC.STCparameter; +version (STRUCTTHISREF) { + if (thandle.ty == TY.Tstruct) + v.storage_class |= STC.STCref; +} + v.semantic(sc2); + if (!sc2.insert(v)) + assert(0); + v.parent = this; + vthis = v; + } + } + else if (isNested()) + { + /* The 'this' for a nested function is the link to the + * enclosing function's stack frame. + * Note that nested functions and member functions are disjoint. + */ + VarDeclaration v = new ThisDeclaration(loc, Type.tvoid.pointerTo()); + v.storage_class |= STC.STCparameter; + v.semantic(sc2); + if (!sc2.insert(v)) + assert(0); + v.parent = this; + vthis = v; + } + + // Declare hidden variable _arguments[] and _argptr + if (f.varargs == 1) + { +version (TARGET_NET) { + varArgs(sc2, f, argptr, _arguments); +} else { + Type t; + + if (f.linkage == LINK.LINKd) + { + // Declare _arguments[] +version (BREAKABI) { + v_arguments = new VarDeclaration(Loc(0), Type.typeinfotypelist.type, Id._arguments_typeinfo, null); + v_arguments.storage_class = STCparameter; + v_arguments.semantic(sc2); + sc2.insert(v_arguments); + v_arguments.parent = this; + + //t = Type.typeinfo.type.constOf().arrayOf(); + t = Type.typeinfo.type.arrayOf(); + _arguments = new VarDeclaration(Loc(0), t, Id._arguments, null); + _arguments.semantic(sc2); + sc2.insert(_arguments); + _arguments.parent = this; +} else { + t = Type.typeinfo.type.arrayOf(); + v_arguments = new VarDeclaration(Loc(0), t, Id._arguments, null); + v_arguments.storage_class = STC.STCparameter | STC.STCin; + v_arguments.semantic(sc2); + sc2.insert(v_arguments); + v_arguments.parent = this; + } + } + if (f.linkage == LINK.LINKd || (parameters && parameters.dim)) + { // Declare _argptr +version (IN_GCC) { + t = d_gcc_builtin_va_list_d_type; +} else { + t = Type.tvoid.pointerTo(); +} + argptr = new VarDeclaration(Loc(0), t, Id._argptr, null); + argptr.semantic(sc2); + sc2.insert(argptr); + argptr.parent = this; + } +} + } + + // Propagate storage class from tuple parameters to their element-parameters. + if (f.parameters) + { + for (size_t i = 0; i < f.parameters.dim; i++) + { Argument arg = cast(Argument)f.parameters.data[i]; + + //printf("[%d] arg.type.ty = %d %s\n", i, arg.type.ty, arg.type.toChars()); + if (arg.type.ty == TY.Ttuple) + { TypeTuple t = cast(TypeTuple)arg.type; + size_t dim = Argument.dim(t.arguments); + for (size_t j = 0; j < dim; j++) + { Argument narg = Argument.getNth(t.arguments, j); + narg.storageClass = arg.storageClass; + } + } + } + } + + /* Declare all the function parameters as variables + * and install them in parameters[] + */ + size_t nparams = Argument.dim(f.parameters); + if (nparams) + { /* parameters[] has all the tuples removed, as the back end + * doesn't know about tuples + */ + parameters = new Dsymbols(); + parameters.reserve(nparams); + for (size_t i = 0; i < nparams; i++) + { + Argument arg = Argument.getNth(f.parameters, i); + Identifier id = arg.ident; + if (!id) + { + /* Generate identifier for un-named parameter, + * because we need it later on. + */ + arg.ident = id = Identifier.generateId("_param_", i); + } + Type vtype = arg.type; + if (isPure()) + vtype = vtype.addMod(MOD.MODconst); + VarDeclaration v = new VarDeclaration(loc, vtype, id, null); + //printf("declaring parameter %s of type %s\n", v.toChars(), v.type.toChars()); + v.storage_class |= STC.STCparameter; + if (f.varargs == 2 && i + 1 == nparams) + v.storage_class |= STC.STCvariadic; + v.storage_class |= arg.storageClass & (STC.STCin | STC.STCout | STC.STCref | STC.STClazy | STC.STCfinal | STC.STC_TYPECTOR | STC.STCnodtor); + v.semantic(sc2); + if (!sc2.insert(v)) + error("parameter %s.%s is already defined", toChars(), v.toChars()); + else + parameters.push(cast(void*)v); + localsymtab.insert(v); + v.parent = this; + } + } + + // Declare the tuple symbols and put them in the symbol table, + // but not in parameters[]. + if (f.parameters) + { + for (size_t i = 0; i < f.parameters.dim; i++) + { Argument arg = cast(Argument)f.parameters.data[i]; + + if (!arg.ident) + continue; // never used, so ignore + if (arg.type.ty == TY.Ttuple) + { TypeTuple t = cast(TypeTuple)arg.type; + size_t dim = Argument.dim(t.arguments); + Objects exps = new Objects(); + exps.setDim(dim); + for (size_t j = 0; j < dim; j++) + { Argument narg = Argument.getNth(t.arguments, j); + assert(narg.ident); + VarDeclaration v = sc2.search(Loc(0), narg.ident, null).isVarDeclaration(); + assert(v); + Expression e = new VarExp(v.loc, v); + exps.data[j] = cast(void*)e; + } + assert(arg.ident); + TupleDeclaration v = new TupleDeclaration(loc, arg.ident, exps); + //printf("declaring tuple %s\n", v.toChars()); + v.isexp = 1; + if (!sc2.insert(v)) + error("parameter %s.%s is already defined", toChars(), v.toChars()); + localsymtab.insert(v); + v.parent = this; + } + } + } + + /* Do the semantic analysis on the [in] preconditions and + * [out] postconditions. + */ + sc2.incontract++; + + if (frequire) + { /* frequire is composed of the [in] contracts + */ + // BUG: need to error if accessing out parameters + // BUG: need to treat parameters as const + // BUG: need to disallow returns and throws + // BUG: verify that all in and ref parameters are read + frequire = frequire.semantic(sc2); + labtab = null; // so body can't refer to labels + } + + if (fensure || addPostInvariant()) + { /* fensure is composed of the [out] contracts + */ + ScopeDsymbol sym = new ScopeDsymbol(); + sym.parent = sc2.scopesym; + sc2 = sc2.push(sym); + + assert(type.nextOf()); + if (type.nextOf().ty == TY.Tvoid) + { + if (outId) + error("void functions have no result"); + } + else + { + if (!outId) + outId = Id.result; // provide a default + } + + if (outId) + { // Declare result variable + VarDeclaration v; + Loc loc = this.loc; + + if (fensure) + loc = fensure.loc; + + v = new VarDeclaration(loc, type.nextOf(), outId, null); + v.noauto = true; +version (DMDV2) { + if (f.isref) + { + v.storage_class |= STC.STCref | STC.STCforeach; + } +} + sc2.incontract--; + v.semantic(sc2); + sc2.incontract++; + if (!sc2.insert(v)) + error("out result %s is already defined", v.toChars()); + v.parent = this; + vresult = v; + + // vresult gets initialized with the function return value + // in ReturnStatement.semantic() + } + + // BUG: need to treat parameters as const + // BUG: need to disallow returns and throws + if (fensure) + { fensure = fensure.semantic(sc2); + labtab = null; // so body can't refer to labels + } + + if (!global.params.useOut) + { fensure = null; // discard + vresult = null; + } + + // Postcondition invariant + if (addPostInvariant()) + { + Expression e = null; + if (isCtorDeclaration()) + { + // Call invariant directly only if it exists + InvariantDeclaration inv = ad.inv; + ClassDeclaration cd = ad.isClassDeclaration(); + + while (!inv && cd) + { + cd = cd.baseClass; + if (!cd) + break; + inv = cd.inv; + } + if (inv) + { + e = new DsymbolExp(Loc(0), inv); + e = new CallExp(Loc(0), e); + e = e.semantic(sc2); + } + } + else + { // Call invariant virtually + Expression v = new ThisExp(Loc(0)); + v.type = vthis.type; +version (STRUCTTHISREF) { + if (ad.isStructDeclaration()) + v = v.addressOf(sc); +} + e = new AssertExp(Loc(0), v); + } + if (e) + { + ExpStatement s = new ExpStatement(Loc(0), e); + if (fensure) + fensure = new CompoundStatement(Loc(0), s, fensure); + else + fensure = s; + } + } + + if (fensure) + { returnLabel = new LabelDsymbol(Id.returnLabel); + LabelStatement ls = new LabelStatement(Loc(0), Id.returnLabel, fensure); + ls.isReturnLabel = 1; + returnLabel.statement = ls; + } + sc2 = sc2.pop(); + } + + sc2.incontract--; + + if (fbody) + { ClassDeclaration cd = isClassMember(); + + /* If this is a class constructor + */ + if (isCtorDeclaration() && cd) + { + for (int i = 0; i < cd.fields.dim; i++) + { VarDeclaration v = cast(VarDeclaration)cd.fields.data[i]; + + v.ctorinit = 0; + } + } + + if (inferRetType || f.retStyle() != RET.RETstack) + nrvo_can = 0; + + fbody = fbody.semantic(sc2); + if (!fbody) + fbody = new CompoundStatement(Loc(0), new Statements()); + + if (inferRetType) + { // If no return type inferred yet, then infer a void + if (!type.nextOf()) + { + (cast(TypeFunction)type).next = Type.tvoid; + type = type.semantic(loc, sc); + } + f = cast(TypeFunction)type; + } + + if (isStaticCtorDeclaration()) + { + /* It's a static constructor. Ensure that all + * ctor consts were initialized. + */ + + Dsymbol p = toParent(); + ScopeDsymbol add = p.isScopeDsymbol(); + if (!add) + { + error("static constructor can only be member of struct/class/module, not %s %s", p.kind(), p.toChars()); + } + else + { + for (int i = 0; i < add.members.dim; i++) + { Dsymbol s = cast(Dsymbol)add.members.data[i]; + + s.checkCtorConstInit(); + } + } + } + + if (isCtorDeclaration() && cd) + { + //printf("callSuper = x%x\n", sc2.callSuper); + + // Verify that all the ctorinit fields got initialized + if (!(sc2.callSuper & CSX.CSXthis_ctor)) + { + for (int i = 0; i < cd.fields.dim; i++) + { VarDeclaration v = cast(VarDeclaration)cd.fields.data[i]; + + if (v.ctorinit == 0 && v.isCtorinit()) + error("missing initializer for final field %s", v.toChars()); + } + } + + if (!(sc2.callSuper & CSX.CSXany_ctor) && + cd.baseClass && cd.baseClass.ctor) + { + sc2.callSuper = 0; + + // Insert implicit super() at start of fbody + Expression e1 = new SuperExp(Loc(0)); + Expression e = new CallExp(Loc(0), e1); + + e = e.trySemantic(sc2); + if (!e) + error("no match for implicit super() call in constructor"); + else + { + Statement s = new ExpStatement(Loc(0), e); + fbody = new CompoundStatement(Loc(0), s, fbody); + } + } + } + else if (fes) + { // For foreach(){} body, append a return 0; + Expression e = new IntegerExp(0); + Statement s = new ReturnStatement(Loc(0), e); + fbody = new CompoundStatement(Loc(0), fbody, s); + assert(!returnLabel); + } + else if (!hasReturnExp && type.nextOf().ty != TY.Tvoid) + error("expected to return a value of type %s", type.nextOf().toChars()); + else if (!inlineAsm) + { +version (DMDV2) { + BE blockexit = fbody ? fbody.blockExit() : BE.BEfallthru; + if (f.isnothrow && blockexit & BE.BEthrow) + error("'%s' is nothrow yet may throw", toChars()); + + int offend = blockexit & BE.BEfallthru; +} + if (type.nextOf().ty == TY.Tvoid) + { + if (offend && isMain()) + { // Add a return 0; statement + Statement s = new ReturnStatement(Loc(0), new IntegerExp(0)); + fbody = new CompoundStatement(Loc(0), fbody, s); + } + } + else + { + if (offend) + { + Expression e; +version (DMDV1) { + warning(loc, "no return exp; or assert(0); at end of function"); +} else { + error("no return exp; or assert(0); at end of function"); +} + if (global.params.useAssert && + !global.params.useInline) + { /* Add an assert(0, msg); where the missing return + * should be. + */ + e = new AssertExp( + endloc, + new IntegerExp(0), + new StringExp(loc, "missing return expression") + ); + } + else + e = new HaltExp(endloc); + + e = new CommaExp(Loc(0), e, type.nextOf().defaultInit(Loc(0))); + e = e.semantic(sc2); + Statement s = new ExpStatement(Loc(0), e); + fbody = new CompoundStatement(Loc(0), fbody, s); + } + } + } + } + + { + Statements a = new Statements(); + + // Merge in initialization of 'out' parameters + if (parameters) + { for (size_t i = 0; i < parameters.dim; i++) + { + VarDeclaration v = cast(VarDeclaration)parameters.data[i]; + if (v.storage_class & STC.STCout) + { + assert(v.init); + ExpInitializer ie = v.init.isExpInitializer(); + assert(ie); + a.push(cast(void*)new ExpStatement(Loc(0), ie.exp)); + } + } + } + + if (argptr) + { // Initialize _argptr to point past non-variadic arg +version (IN_GCC) { + // Handled in FuncDeclaration.toObjFile + v_argptr = argptr; + v_argptr.init = new VoidInitializer(loc); +} else { + Expression e1; + Expression e; + Type t = argptr.type; + VarDeclaration p; + uint offset; + + e1 = new VarExp(Loc(0), argptr); + if (parameters && parameters.dim) + p = cast(VarDeclaration)parameters.data[parameters.dim - 1]; + else + p = v_arguments; // last parameter is _arguments[] + offset = cast(uint)p.type.size(); /// + offset = (offset + 3) & ~3; // assume stack aligns on 4 + e = new SymOffExp(Loc(0), p, offset); + e = new AssignExp(Loc(0), e1, e); + e.type = t; + a.push(cast(void*)new ExpStatement(Loc(0), e)); +} + } + + if (_arguments) + { + /* Advance to elements[] member of TypeInfo_Tuple with: + * _arguments = v_arguments.elements; + */ + Expression e = new VarExp(Loc(0), v_arguments); + e = new DotIdExp(Loc(0), e, Id.elements); + Expression e1 = new VarExp(Loc(0), _arguments); + e = new AssignExp(Loc(0), e1, e); + e.op = TOK.TOKconstruct; + e = e.semantic(sc2); + a.push(cast(void*)new ExpStatement(Loc(0), e)); + } + + // Merge contracts together with body into one compound statement + +version (_DH) { + if (frequire && global.params.useIn) + { frequire.incontract = 1; + a.push(frequire); + } +} else { + if (frequire && global.params.useIn) + a.push(cast(void*)frequire); +} + + // Precondition invariant + if (addPreInvariant()) + { + Expression e = null; + if (isDtorDeclaration()) + { + // Call invariant directly only if it exists + InvariantDeclaration inv = ad.inv; + ClassDeclaration cd = ad.isClassDeclaration(); + + while (!inv && cd) + { + cd = cd.baseClass; + if (!cd) + break; + inv = cd.inv; + } + if (inv) + { + e = new DsymbolExp(Loc(0), inv); + e = new CallExp(Loc(0), e); + e = e.semantic(sc2); + } + } + else + { // Call invariant virtually + Expression v = new ThisExp(Loc(0)); + v.type = vthis.type; +version (STRUCTTHISREF) { + if (ad.isStructDeclaration()) + v = v.addressOf(sc); +} + Expression se = new StringExp(Loc(0), "null this"); + se = se.semantic(sc); + se.type = Type.tchar.arrayOf(); + e = new AssertExp(loc, v, se); + } + if (e) + { + ExpStatement s = new ExpStatement(Loc(0), e); + a.push(cast(void*)s); + } + } + + if (fbody) + a.push(cast(void*)fbody); + + if (fensure) + { + a.push(cast(void*)returnLabel.statement); + + if (type.nextOf().ty != TY.Tvoid) + { + // Create: return vresult; + assert(vresult); + Expression e = new VarExp(Loc(0), vresult); + if (tintro) + { e = e.implicitCastTo(sc, tintro.nextOf()); + e = e.semantic(sc); + } + ReturnStatement s = new ReturnStatement(Loc(0), e); + a.push(cast(void*)s); + } + } + + fbody = new CompoundStatement(Loc(0), a); +version (DMDV2) { + /* Append destructor calls for parameters as finally blocks. + */ + if (parameters) + { for (size_t i = 0; i < parameters.dim; i++) + { + VarDeclaration v = cast(VarDeclaration)parameters.data[i]; + + if (v.storage_class & (STC.STCref | STC.STCout)) + continue; + + /* Don't do this for static arrays, since static + * arrays are called by reference. Remove this + * when we change them to call by value. + */ + if (v.type.toBasetype().ty == TY.Tsarray) + continue; + + Expression e = v.callAutoDtor(sc); + if (e) + { Statement s = new ExpStatement(Loc(0), e); + s = s.semantic(sc); + if (fbody.blockExit() == BE.BEfallthru) + fbody = new CompoundStatement(Loc(0), fbody, s); + else + fbody = new TryFinallyStatement(Loc(0), fbody, s); + } + } + } +} + +static if (true) { + if (isSynchronized()) + { /* Wrap the entire function body in a synchronized statement + */ + ClassDeclaration cd = parent.isClassDeclaration(); + if (cd) + { +///version (TARGET_WINDOS) { + if (/*config.flags2 & CFG2.CFG2seh &&*/ // always on for WINDOS + !isStatic() && !fbody.usesEH()) + { + /* The back end uses the "jmonitor" hack for syncing; + * no need to do the sync at this level. + */ + } + else +///} + { + Expression vsync; + if (isStatic()) + { + // The monitor is in the ClassInfo + vsync = new DotIdExp(loc, new DsymbolExp(loc, cd), Id.classinfo_); + } + else + { // 'this' is the monitor + vsync = new VarExp(loc, vthis); + } + fbody = new PeelStatement(fbody); // don't redo semantic() + fbody = new SynchronizedStatement(loc, vsync, fbody); + fbody = fbody.semantic(sc2); + } + } + else + { + error("synchronized function %s must be a member of a class", toChars()); + } + } +} + } + + sc2.callSuper = 0; + sc2.pop(); + } + semanticRun = 4; + } + + // called from semantic3 + void varArgs(Scope sc, TypeFunction, ref VarDeclaration, ref VarDeclaration) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + void bodyToCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + /**************************************************** + * Determine if 'this' overrides fd. + * Return true if it does. + */ + bool overrides(FuncDeclaration fd) + { + bool result = false; + + if (fd.ident == ident) + { + int cov = type.covariant(fd.type); + if (cov) + { + ClassDeclaration cd1 = toParent().isClassDeclaration(); + ClassDeclaration cd2 = fd.toParent().isClassDeclaration(); + + if (cd1 && cd2 && cd2.isBaseOf(cd1, null)) + result = true; + } + } + return result; + } + + /************************************************* + * Find index of function in vtbl[0..dim] that + * this function overrides. + * Returns: + * -1 didn't find one + * -2 can't determine because of forward references + */ + int findVtblIndex(Array vtbl, int dim) + { + for (int vi = 0; vi < dim; vi++) + { + FuncDeclaration fdv = (cast(Dsymbol)vtbl.data[vi]).isFuncDeclaration(); + if (fdv && fdv.ident is ident) + { + int cov = type.covariant(fdv.type); + //printf("\tbaseclass cov = %d\n", cov); + switch (cov) + { + case 0: // types are distinct + break; + + case 1: + return vi; + + case 2: + //type.print(); + //fdv.type.print(); + //printf("%s %s\n", type.deco, fdv.type.deco); + error("of type %s overrides but is not covariant with %s of type %s", + type.toChars(), fdv.toPrettyChars(), fdv.type.toChars()); + break; + + case 3: + return -2; // forward references + } + } + } + return -1; + } + + /**************************************************** + * Overload this FuncDeclaration with the new one f. + * Return !=0 if successful; i.e. no conflict. + */ + bool overloadInsert(Dsymbol s) + { + FuncDeclaration f; + AliasDeclaration a; + + //writef("FuncDeclaration.overloadInsert(%s)\n", s.toChars()); + a = s.isAliasDeclaration(); + if (a) + { + if (overnext) + return overnext.overloadInsert(a); + + if (!a.aliassym && a.type.ty != TY.Tident && a.type.ty != TY.Tinstance) + { + //writef("\ta = '%s'\n", a.type.toChars()); + return false; + } + overnext = a; + //printf("\ttrue: no conflict\n"); + return true; + } + f = s.isFuncDeclaration(); + if (!f) + return false; + +static if (false) { + /* Disable this check because: + * const void foo(); + * semantic() isn't run yet on foo(), so the const hasn't been + * applied yet. + */ + if (type) + { + printf("type = %s\n", type.toChars()); + printf("f.type = %s\n", f.type.toChars()); + } + if (type && f.type && // can be null for overloaded constructors + f.type.covariant(type) && + f.type.mod == type.mod && + !isFuncAliasDeclaration()) + { + //printf("\tfalse: conflict %s\n", kind()); + return false; + } +} + + if (overnext) + return overnext.overloadInsert(f); + overnext = f; + //printf("\ttrue: no conflict\n"); + return true; + } + + FuncDeclaration overloadExactMatch(Type t) + { + Param1 p; + p.t = t; + p.f = null; + overloadApply(this, &p.fp1); + return p.f; + } + + FuncDeclaration overloadResolve(Loc loc, Expression ethis, Expressions arguments, int flags = 0) + { + TypeFunction tf; + Match m; + +static if (false) { + printf("FuncDeclaration.overloadResolve('%s')\n", toChars()); + if (arguments) + { + int i; + + for (i = 0; i < arguments.dim; i++) + { + Expression arg; + + arg = cast(Expression)arguments.data[i]; + assert(arg.type); + printf("\t%s: ", arg.toChars()); + arg.type.print(); + } + } +} + + m.last = MATCH.MATCHnomatch; + overloadResolveX(&m, this, ethis, arguments); + + if (m.count == 1) // exactly one match + { + return m.lastf; + } + else + { + scope OutBuffer buf = new OutBuffer(); + + buf.writeByte('('); + if (arguments) + { + HdrGenState hgs; + + argExpTypesToCBuffer(buf, arguments, &hgs); + buf.writeByte(')'); + if (ethis) + ethis.type.modToBuffer(buf); + } + else + buf.writeByte(')'); + + if (m.last == MATCH.MATCHnomatch) + { + if (flags & 1) // if do not print error messages + return null; // no match + + tf = cast(TypeFunction)type; + + scope OutBuffer buf2 = new OutBuffer(); + tf.modToBuffer(buf2); + + //printf("tf = %s, args = %s\n", tf.deco, ((Expression *)arguments.data[0]).type.deco); + error(loc, "%s%s is not callable using argument types %s", + Argument.argsTypesToChars(tf.parameters, tf.varargs), + buf2.toChars(), + buf.toChars()); + return m.anyf; // as long as it's not a FuncAliasDeclaration + } + else + { +static if (true) { + TypeFunction t1 = cast(TypeFunction)m.lastf.type; + TypeFunction t2 = cast(TypeFunction)m.nextf.type; + + error(loc, "called with argument types:\n\t(%s)\nmatches both:\n\t%s%s\nand:\n\t%s%s", + buf.toChars(), + m.lastf.toPrettyChars(), Argument.argsTypesToChars(t1.parameters, t1.varargs), + m.nextf.toPrettyChars(), Argument.argsTypesToChars(t2.parameters, t2.varargs)); +} else { + error(loc, "overloads %s and %s both match argument list for %s", + m.lastf.type.toChars(), + m.nextf.type.toChars(), + m.lastf.toChars()); +} + return m.lastf; + } + } + } + + /************************************* + * Determine partial specialization order of 'this' vs g. + * This is very similar to TemplateDeclaration.leastAsSpecialized(). + * Returns: + * match 'this' is at least as specialized as g + * 0 g is more specialized than 'this' + */ + MATCH leastAsSpecialized(FuncDeclaration g) + { + version (LOG_LEASTAS) { + printf("%s.leastAsSpecialized(%s)\n", toChars(), g.toChars()); + } + + /* This works by calling g() with f()'s parameters, and + * if that is possible, then f() is at least as specialized + * as g() is. + */ + + TypeFunction tf = cast(TypeFunction)type; + TypeFunction tg = cast(TypeFunction)g.type; + size_t nfparams = Argument.dim(tf.parameters); + size_t ngparams = Argument.dim(tg.parameters); + MATCH match = MATCHexact; + + /* If both functions have a 'this' pointer, and the mods are not + * the same and g's is not const, then this is less specialized. + */ + if (needThis() && g.needThis()) + { + if (tf.mod != tg.mod) + { + if (tg.mod == MODconst) + match = MATCHconst; + else + return MATCHnomatch; + } + } + + /* Create a dummy array of arguments out of the parameters to f() + */ + scope Expressions args = new Expressions(); + args.setDim(nfparams); + for (int u = 0; u < nfparams; u++) + { + Argument p = Argument.getNth(tf.parameters, u); + Expression e; + if (p.storageClass & (STCref | STCout)) + { + e = new IdentifierExp(Loc(0), p.ident); + e.type = p.type; + } + else + e = p.type.defaultInit(Loc(0)); + + args.data[u] = cast(void*)e; + } + + MATCH m = cast(MATCH) tg.callMatch(null, args); + if (m) + { + /* A variadic parameter list is less specialized than a + * non-variadic one. + */ + if (tf.varargs && !tg.varargs) + goto L1; // less specialized + + version (LOG_LEASTAS) { + printf(" matches %d, so is least as specialized\n", m); + } + return m; + } + L1: + version (LOG_LEASTAS) { + printf(" doesn't match, so is not as specialized\n"); + } + return MATCHnomatch; + } + + /******************************** + * Labels are in a separate scope, one per function. + */ + LabelDsymbol searchLabel(Identifier ident) + { + Dsymbol s; + + if (!labtab) + labtab = new DsymbolTable(); // guess we need one + + s = labtab.lookup(ident); + if (!s) + { + s = new LabelDsymbol(ident); + labtab.insert(s); + } + + return cast(LabelDsymbol)s; + } + + /**************************************** + * If non-static member function that has a 'this' pointer, + * return the aggregate it is a member of. + * Otherwise, return null. + */ + AggregateDeclaration isThis() + { + AggregateDeclaration ad = null; + + //printf("+FuncDeclaration.isThis() '%s'\n", toChars()); + if ((storage_class & STC.STCstatic) == 0) + { + ad = isMember2(); + } + //printf("-FuncDeclaration.isThis() %p\n", ad); + return ad; + } + + AggregateDeclaration isMember2() + { + AggregateDeclaration ad = null; + + //printf("+FuncDeclaration.isMember2() '%s'\n", toChars()); + for (Dsymbol s = this; s; s = s.parent) + { + //printf("\ts = '%s', parent = '%s', kind = %s\n", s.toChars(), s.parent.toChars(), s.parent.kind()); + ad = s.isMember(); + if (ad) + { //printf("test4\n"); + break; + } + if (!s.parent || (!s.parent.isTemplateInstance())) + { //printf("test5\n"); + break; + } + } + //printf("-FuncDeclaration.isMember2() %p\n", ad); + return ad; + } + + /***************************************** + * Determine lexical level difference from 'this' to nested function 'fd'. + * Error if this cannot call fd. + * Returns: + * 0 same level + * -1 increase nesting by 1 (fd is nested within 'this') + * >0 decrease nesting by number + */ + int getLevel(Loc loc, FuncDeclaration fd) // lexical nesting level difference + { + int level; + Dsymbol s; + Dsymbol fdparent; + + //printf("FuncDeclaration.getLevel(fd = '%s')\n", fd.toChars()); + fdparent = fd.toParent2(); + if (fdparent == this) + return -1; + s = this; + level = 0; + while (fd != s && fdparent != s.toParent2()) + { + //printf("\ts = '%s'\n", s.toChars()); + FuncDeclaration thisfd = s.isFuncDeclaration(); + if (thisfd) + { + if (!thisfd.isNested() && !thisfd.vthis) + goto Lerr; + } + else + { + AggregateDeclaration thiscd = s.isAggregateDeclaration(); + if (thiscd) + { + if (!thiscd.isNested()) + goto Lerr; + } + else + goto Lerr; + } + + s = s.toParent2(); + assert(s); + level++; + } + return level; + + Lerr: + error(loc, "cannot access frame of function %s", fd.toChars()); + return 1; + } + + void appendExp(Expression e) + { + assert(false); + } + + void appendState(Statement s) + { + assert(false); + } + + string mangle() + out (result) + { + assert(result.length > 0); + } + body + { + if (isMain()) { + return "_Dmain"; + } + + if (isWinMain() || isDllMain() || ident == Id.tls_get_addr) + return ident.toChars(); + + assert(this); + + return Declaration.mangle(); + } + + string toPrettyChars() + { + if (isMain()) + return "D main"; + else + return Dsymbol.toPrettyChars(); + } + + int isMain() + { + return ident is Id.main && linkage != LINK.LINKc && !isMember() && !isNested(); + } + + int isWinMain() + { + //printf("FuncDeclaration::isWinMain() %s\n", toChars()); +static if (false) { + int x = ident == Id.WinMain && + linkage != LINK.LINKc && !isMember(); + printf("%s\n", x ? "yes" : "no"); + return x; +} else { + return ident == Id.WinMain && linkage != LINK.LINKc && !isMember(); +} + } + + int isDllMain() + { + return ident == Id.DllMain && linkage != LINK.LINKc && !isMember(); + } + + /********************************** + * Determine if function is a builtin one that we can + * evaluate at compile time. + */ + BUILTIN isBuiltin() + { + static string FeZe = "FNaNbeZe"; // pure nothrow real function(real) + + //printf("FuncDeclaration::isBuiltin() %s\n", toChars()); + if (builtin == BUILTIN.BUILTINunknown) + { + builtin = BUILTIN.BUILTINnot; + if (parent && parent.isModule()) + { + // If it's in the std.math package + if (parent.ident == Id.math && parent.parent && parent.parent.ident == Id.std && !parent.parent.parent) + { + //printf("deco = %s\n", type.deco); + if (type.deco == FeZe) + { + if (ident == Id.sin) + builtin = BUILTIN.BUILTINsin; + else if (ident == Id.cos) + builtin = BUILTIN.BUILTINcos; + else if (ident == Id.tan) + builtin = BUILTIN.BUILTINtan; + else if (ident == Id._sqrt) + builtin = BUILTIN.BUILTINsqrt; + else if (ident == Id.fabs) + builtin = BUILTIN.BUILTINfabs; + //printf("builtin = %d\n", builtin); + } + // if float or double versions + else if (type.deco == "FNaNbdZd" || type.deco == "FNaNbfZf") + { + if (ident == Id._sqrt) + builtin = BUILTIN.BUILTINsqrt; + } + } + } + } + + return builtin; + } + + bool isExport() + { + return protection == PROT.PROTexport; + } + + bool isImportedSymbol() + { + //printf("isImportedSymbol()\n"); + //printf("protection = %d\n", protection); + return (protection == PROT.PROTexport) && !fbody; + } + + bool isAbstract() + { + return (storage_class & STC.STCabstract) != 0; + } + + bool isCodeseg() + { + assert(false); + } + + bool isOverloadable() + { + assert(false); + } + + bool isPure() + { + //printf("FuncDeclaration::isPure() '%s'\n", toChars()); + assert(type.ty == TY.Tfunction); + return (cast(TypeFunction)this.type).ispure; + } + + bool isNested() + { + //if (!toParent()) + //printf("FuncDeclaration.isNested('%s') parent=%p\n", toChars(), parent); + //printf("\ttoParent2() = '%s'\n", toParent2().toChars()); + return ((storage_class & STC.STCstatic) == 0) && + (toParent2().isFuncDeclaration() !is null); + } + + bool needThis() + { + //printf("FuncDeclaration.needThis() '%s'\n", toChars()); + bool needThis = isThis() !is null; + + //printf("\t%d\n", i); + if (!needThis) { + if (auto fa = isFuncAliasDeclaration()) { + needThis = fa.funcalias.needThis(); + } + } + + return needThis; + } + + bool isVirtual() + { +static if (false) { + printf("FuncDeclaration.isVirtual(%s)\n", toChars()); + printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), protection == PROT.PROTprivate, isCtorDeclaration(), linkage != LINK.LINKd); + printf("result is %d\n", + isMember() && !(isStatic() || protection == PROT.PROTprivate || protection == PROT.PROTpackage) && toParent().isClassDeclaration()); +} + return isMember() && !(isStatic() || protection == PROT.PROTprivate || protection == PROT.PROTpackage) && toParent().isClassDeclaration(); + } + + int isFinal() + { + ClassDeclaration cd; +static if (false) { + printf("FuncDeclaration.isFinal(%s)\n", toChars()); + printf("%p %d %d %d %d\n", isMember(), isStatic(), protection == PROT.PROTprivate, isCtorDeclaration(), linkage != LINK.LINKd); + printf("result is %d\n", + isMember() && !(isStatic() || protection == PROT.PROTprivate || protection == PROT.PROTpackage) && (cd = toParent().isClassDeclaration()) !is null && cd.storage_class & STC.STCfinal); +} + return isMember() && (Declaration.isFinal() || ((cd = toParent().isClassDeclaration()) !is null && cd.storage_class & STC.STCfinal)); + } + + bool addPreInvariant() + { + AggregateDeclaration ad = isThis(); + return (ad && + //ad.isClassDeclaration() && + global.params.useInvariants && + (protection == PROT.PROTpublic || protection == PROT.PROTexport) && + !naked && + ident !is Id.cpctor); + } + + bool addPostInvariant() + { + AggregateDeclaration ad = isThis(); + return (ad && ad.inv && + //ad.isClassDeclaration() && + global.params.useInvariants && + (protection == PROT.PROTpublic || protection == PROT.PROTexport) && + !naked && + ident !is Id.cpctor); + } + + Expression interpret(InterState* istate, Expressions arguments, Expression thisexp = null) + { + assert(false); + } + + void inlineScan() + { + InlineScanState iss; + + version (LOG) { + printf("FuncDeclaration.inlineScan('%s')\n", toChars()); + } + ///memset(&iss, 0, sizeof(iss)); + iss.fd = this; + if (fbody) + { + inlineNest++; + fbody = fbody.inlineScan(&iss); + inlineNest--; + } + } + + int canInline(int hasthis, int hdrscan = 0) + { + int cost; + +// #define CANINLINE_LOG 0 + + version (CANINLINE_LOG) { + printf("FuncDeclaration.canInline(hasthis = %d, '%s')\n", hasthis, toChars()); + } + + if (needThis() && !hasthis) + return 0; + + if (inlineNest || (semanticRun < 3 && !hdrscan)) + { + version (CANINLINE_LOG) { + printf("\t1: no, inlineNest = %d, semanticRun = %d\n", inlineNest, semanticRun); + } + return 0; + } + + switch (inlineStatus) + { + case ILS.ILSyes: + version (CANINLINE_LOG) { + printf("\t1: yes %s\n", toChars()); + } + return 1; + + case ILS.ILSno: + version (CANINLINE_LOG) { + printf("\t1: no %s\n", toChars()); + } + return 0; + + case ILS.ILSuninitialized: + break; + + default: + assert(0); + } + + if (type) + { + assert(type.ty == Tfunction); + TypeFunction tf = cast(TypeFunction)type; + if (tf.varargs == 1) // no variadic parameter lists + goto Lno; + + /* Don't inline a function that returns non-void, but has + * no return expression. + */ + if (tf.next && tf.next.ty != Tvoid && + !(hasReturnExp & 1) && + !hdrscan) + goto Lno; + } + else + { + CtorDeclaration ctor = isCtorDeclaration(); + if (ctor && ctor.varargs == 1) + goto Lno; + } + + if ( + !fbody || + !hdrscan && + ( +/// static if (false) { +/// isCtorDeclaration() || // cannot because need to convert: +/// // return; +/// // to: +/// // return this; +/// } + isSynchronized() || + isImportedSymbol() || +/// version (DMDV2) { + closureVars.dim || // no nested references to this frame +/// } else { +/// nestedFrameRef || // no nested references to this frame +/// } + (isVirtual() && !isFinal()) + )) + { + goto Lno; + } + + /* If any parameters are Tsarray's (which are passed by reference) + * or out parameters (also passed by reference), don't do inlining. + */ + if (parameters) + { + for (int i = 0; i < parameters.dim; i++) + { + VarDeclaration v = cast(VarDeclaration)parameters.data[i]; + if (v.isOut() || v.isRef() || v.type.toBasetype().ty == Tsarray) + goto Lno; + } + } + + InlineCostState ics; + ///memset(&ics, 0, sizeof(ics)); + ics.hasthis = hasthis; + ics.fd = this; + ics.hdrscan = hdrscan; + cost = fbody.inlineCost(&ics); + version (CANINLINE_LOG) { + printf("cost = %d\n", cost); + } + if (cost >= COST_MAX) + goto Lno; + + if (!hdrscan) // Don't scan recursively for header content scan + inlineScan(); + + Lyes: + if (!hdrscan) // Don't modify inlineStatus for header content scan + inlineStatus = ILS.ILSyes; + version (CANINLINE_LOG) { + printf("\t2: yes %s\n", toChars()); + } + return 1; + + Lno: + if (!hdrscan) // Don't modify inlineStatus for header content scan + inlineStatus = ILS.ILSno; + version (CANINLINE_LOG) { + printf("\t2: no %s\n", toChars()); + } + return 0; + } + + Expression doInline(InlineScanState* iss, Expression ethis, Array arguments) + { + InlineDoState ids = new InlineDoState(); + DeclarationExp de; + Expression e = null; + + version (LOG) { + printf("FuncDeclaration.doInline('%s')\n", toChars()); + } + + ///memset(&ids, 0, sizeof(ids)); + ids.parent = iss.fd; + + // Set up vthis + if (ethis) + { + VarDeclaration vthis; + ExpInitializer ei; + VarExp ve; + + version (STRUCTTHISREF) { + if (ethis.type.ty == Tpointer) + { + Type t = ethis.type.nextOf(); + ethis = new PtrExp(ethis.loc, ethis); + ethis.type = t; + } + ei = new ExpInitializer(ethis.loc, ethis); + + vthis = new VarDeclaration(ethis.loc, ethis.type, Id.This, ei); + if (ethis.type.ty != Tclass) + vthis.storage_class = STCref; + else + vthis.storage_class = STCin; + } else { + if (ethis.type.ty != Tclass && ethis.type.ty != Tpointer) + { + ethis = ethis.addressOf(null); + } + + ei = new ExpInitializer(ethis.loc, ethis); + + vthis = new VarDeclaration(ethis.loc, ethis.type, Id.This, ei); + vthis.storage_class = STCin; + } + vthis.linkage = LINKd; + vthis.parent = iss.fd; + + ve = new VarExp(vthis.loc, vthis); + ve.type = vthis.type; + + ei.exp = new AssignExp(vthis.loc, ve, ethis); + ei.exp.type = ve.type; + version (STRUCTTHISREF) { + if (ethis.type.ty != Tclass) + { + /* This is a reference initialization, not a simple assignment. + */ + ei.exp.op = TOKconstruct; + } + } + + ids.vthis = vthis; + } + + // Set up parameters + if (ethis) + { + e = new DeclarationExp(Loc(0), ids.vthis); + e.type = Type.tvoid; + } + + if (arguments && arguments.dim) + { + assert(parameters.dim == arguments.dim); + + for (int i = 0; i < arguments.dim; i++) + { + VarDeclaration vfrom = cast(VarDeclaration)parameters.data[i]; + VarDeclaration vto; + Expression arg = cast(Expression)arguments.data[i]; + ExpInitializer ei; + VarExp ve; + + ei = new ExpInitializer(arg.loc, arg); + + vto = new VarDeclaration(vfrom.loc, vfrom.type, vfrom.ident, ei); + vto.storage_class |= vfrom.storage_class & (STCin | STCout | STClazy | STCref); + vto.linkage = vfrom.linkage; + vto.parent = iss.fd; + //printf("vto = '%s', vto.storage_class = x%x\n", vto.toChars(), vto.storage_class); + //printf("vto.parent = '%s'\n", iss.fd.toChars()); + + ve = new VarExp(vto.loc, vto); + //ve.type = vto.type; + ve.type = arg.type; + + ei.exp = new AssignExp(vto.loc, ve, arg); + ei.exp.type = ve.type; + //ve.type.print(); + //arg.type.print(); + //ei.exp.print(); + + ids.from.push(cast(void*)vfrom); + ids.to.push(cast(void*)vto); + + de = new DeclarationExp(Loc(0), vto); + de.type = Type.tvoid; + + e = Expression.combine(e, de); + } + } + + inlineNest++; + Expression eb = fbody.doInline(ids); + inlineNest--; + //eb.type.print(); + //eb.print(); + //eb.dump(0); + return Expression.combine(e, eb); + } + + string kind() + { + return "function"; + } + + void toDocBuffer(OutBuffer buf) + { + assert(false); + } + + FuncDeclaration isUnique() + { + assert(false); + } + + /******************************* + * Look at all the variables in this function that are referenced + * by nested functions, and determine if a closure needs to be + * created for them. + */ + bool needsClosure() + { + /* Need a closure for all the closureVars[] if any of the + * closureVars[] are accessed by a + * function that escapes the scope of this function. + * We take the conservative approach and decide that any function that: + * 1) is a virtual function + * 2) has its address taken + * 3) has a parent that escapes + * + * Note that since a non-virtual function can be called by + * a virtual one, if that non-virtual function accesses a closure + * var, the closure still has to be taken. Hence, we check for isThis() + * instead of isVirtual(). (thanks to David Friedman) + */ + + //printf("FuncDeclaration.needsClosure() %s\n", toChars()); + for (int i = 0; i < closureVars.dim; i++) + { + VarDeclaration v = cast(VarDeclaration)closureVars.data[i]; + assert(v.isVarDeclaration()); + //printf("\tv = %s\n", v.toChars()); + + for (int j = 0; j < v.nestedrefs.dim; j++) + { FuncDeclaration f = cast(FuncDeclaration)v.nestedrefs.data[j]; + assert(f != this); + + //printf("\t\tf = %s, %d, %p, %d\n", f.toChars(), f.isVirtual(), f.isThis(), f.tookAddressOf); + if (f.isThis() || f.tookAddressOf) + goto Lyes; // assume f escapes this function's scope + + // Look to see if any parents of f that are below this escape + for (Dsymbol s = f.parent; s && s !is this; s = s.parent) + { + f = s.isFuncDeclaration(); + if (f && (f.isThis() || f.tookAddressOf)) { + goto Lyes; + } + } + } + } + return false; + + Lyes: + //printf("\tneeds closure\n"); + return true; + } + + static FuncDeclaration genCfunc(Type treturn, string name) + { + return genCfunc(treturn, Lexer.idPool(name)); + } + + /********************************** + * Generate a FuncDeclaration for a runtime library function. + */ + static FuncDeclaration genCfunc(Type treturn, Identifier id) + { + FuncDeclaration fd; + TypeFunction tf; + Dsymbol s; + static DsymbolTable st = null; + + //printf("genCfunc(name = '%s')\n", id.toChars()); + //printf("treturn\n\t"); treturn.print(); + + // See if already in table + if (!st) + st = new DsymbolTable(); + + s = st.lookup(id); + if (s) + { + fd = s.isFuncDeclaration(); + assert(fd); + assert(fd.type.nextOf().equals(treturn)); + } + else + { + tf = new TypeFunction(null, treturn, 0, LINK.LINKc); + fd = new FuncDeclaration(Loc(0), Loc(0), id, STCstatic, tf); + fd.protection = PROT.PROTpublic; + fd.linkage = LINK.LINKc; + + st.insert(fd); + } + return fd; + } + + Symbol* toSymbol() + { + if (!csym) + { + Symbol* s; + TYPE* t; + string id; + +static if (false) { + id = ident.toChars(); +} else { + id = mangle(); +} + //writef("FuncDeclaration.toSymbol(%s %s)\n", kind(), toChars()); + //writef("\tid = '%s'\n", id); + //writef("\ttype = %s\n", type.toChars()); + s = symbol_calloc(toStringz(id)); + slist_add(s); + + { + s.prettyIdent = toStringz(toPrettyChars()); + s.Sclass = SC.SCglobal; + symbol_func(s); + func_t* f = s.Sfunc; + if (isVirtual()) + f.Fflags |= F.Fvirtual; + else if (isMember2()) + f.Fflags |= F.Fstatic; + f.Fstartline.Slinnum = loc.linnum; + f.Fstartline.Sfilename = cast(char*)toStringz(loc.filename); + if (endloc.linnum) + { + f.Fendline.Slinnum = endloc.linnum; + f.Fendline.Sfilename = cast(char*)toStringz(endloc.filename); + } + else + { + f.Fendline.Slinnum = loc.linnum; + f.Fendline.Sfilename = cast(char*)toStringz(loc.filename); + } + t = type.toCtype(); + } + + mangle_t msave = t.Tmangle; + if (isMain()) + { + t.Tty = TYM.TYnfunc; + t.Tmangle = mTYman.mTYman_c; + } + else + { + switch (linkage) + { + case LINK.LINKwindows: + t.Tmangle = mTYman.mTYman_std; + break; + + case LINK.LINKpascal: + t.Tty = TYM.TYnpfunc; + t.Tmangle = mTYman.mTYman_pas; + break; + + case LINK.LINKc: + t.Tmangle = mTYman.mTYman_c; + break; + + case LINK.LINKd: + t.Tmangle = mTYman.mTYman_d; + break; + + case LINK.LINKcpp: + { t.Tmangle = mTYman.mTYman_cpp; + version (TARGET_WINDOS) { + if (isThis()) + t.Tty = TYM.TYmfunc; + } + s.Sflags |= SFL.SFLpublic; + Dsymbol parent = toParent(); + ClassDeclaration cd = parent.isClassDeclaration(); + if (cd) + { + .type* tt = cd.type.toCtype(); + s.Sscope = tt.Tnext.Ttag; + } + break; + } + default: + writef("linkage = %d\n", linkage); + assert(0); + } + } + if (msave) + assert(msave == t.Tmangle); + //printf("Tty = %x, mangle = x%x\n", t.Tty, t.Tmangle); + t.Tcount++; + s.Stype = t; + //s.Sfielddef = this; + + csym = s; + } + return csym; + } + + Symbol* toThunkSymbol(int offset) // thunk version + { + Symbol *sthunk; + + toSymbol(); + + static if (false) { + char *id; + char *n; + type *t; + + n = sym.Sident; + id = cast(char*) alloca(8 + 5 + strlen(n) + 1); + sprintf(id, "_thunk%d__%s", offset, n); + s = symbol_calloc(id); + slist_add(s); + s.Stype = csym.Stype; + s.Stype.Tcount++; + } + sthunk = symbol_generate(SCstatic, csym.Stype); + sthunk.Sflags |= SFLimplem; + cod3_thunk(sthunk, csym, 0, TYnptr, -offset, -1, 0); + return sthunk; + } + + void toObjFile(int multiobj) // compile to .obj file + { + Symbol* s; + func_t* f; + Symbol* senter; + Symbol* sexit; + + FuncDeclaration func = this; + ClassDeclaration cd = func.parent.isClassDeclaration(); + int reverse; + int i; + int has_arguments; + + //printf("FuncDeclaration.toObjFile(%p, %s.%s)\n", func, parent.toChars(), func.toChars()); +static if (false) { + //printf("line = %d\n",func.getWhere() / LINEINC); + EEcontext ee = env.getEEcontext(); + if (ee.EEcompile == 2) + { + if (ee.EElinnum < (func.getWhere() / LINEINC) || + ee.EElinnum > (func.endwhere / LINEINC) + ) + return; // don't compile this function + ee.EEfunc = func.toSymbol(); + } +} + + if (multiobj && !isStaticDtorDeclaration() && !isStaticCtorDeclaration()) + { + obj_append(this); + return; + } + + if (semanticRun >= 5) // if toObjFile() already run + return; + + semanticRun = 5; + + if (!func.fbody) + { + return; + } + + if (func.isUnitTestDeclaration() && !global.params.useUnitTests) + return; + + if (global.params.verbose) + writef("function %s\n",func.toChars()); + + s = func.toSymbol(); + f = s.Sfunc; + +version (TARGET_OSX) { + s.Sclass = SC.SCcomdat; +} else { + s.Sclass = SC.SCglobal; +} + + for (Dsymbol p = parent; p; p = p.parent) + { + if (p.isTemplateInstance()) + { + s.Sclass = SC.SCcomdat; + break; + } + } + + if (isNested()) + { + // if (!(config.flags3 & CFG3pic)) + // s.Sclass = SCstatic; + f.Fflags3 |= F3.Fnested; + } + else + { + const(char)* libname = (global.params.symdebug) ? global.params.debuglibname : global.params.defaultlibname; + + // Pull in RTL startup code + if (func.isMain()) + { objextdef("_main"); +version (XXX) { ///TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS + obj_ehsections(); // initialize exception handling sections +} else { + objextdef("__acrtused_con"); +} + obj_includelib(libname); + s.Sclass = SC.SCglobal; + } + else if (strcmp(s.Sident.ptr, "main".ptr) == 0 && linkage == LINK.LINKc) + s.Sclass = SC.SCglobal; + + else if (func.isWinMain()) + { + objextdef("__acrtused"); + obj_includelib(libname); + s.Sclass = SC.SCglobal; + } + + // Pull in RTL startup code + else if (func.isDllMain()) + { + objextdef("__acrtused_dll"); + obj_includelib(libname); + s.Sclass = SC.SCglobal; + } + } + + cstate.CSpsymtab = &f.Flocsym; + + // Find module m for this function + Module m = null; + for (Dsymbol p = parent; p; p = p.parent) + { + m = p.isModule(); + if (m) + break; + } + + IRState irs = IRState(m, func); + Array deferToObj = new Array(); // write these to OBJ file later + irs.deferToObj = deferToObj; + + TypeFunction tf; + RET retmethod; + Symbol* shidden = null; + Symbol* sthis = null; + tym_t tyf; + + tyf = tybasic(s.Stype.Tty); + //printf("linkage = %d, tyf = x%x\n", linkage, tyf); + reverse = tyrevfunc(s.Stype.Tty); + + assert(func.type.ty == TY.Tfunction); + tf = cast(TypeFunction)(func.type); + has_arguments = (tf.linkage == LINK.LINKd) && (tf.varargs == 1); + retmethod = tf.retStyle(); + if (retmethod == RET.RETstack) + { + // If function returns a struct, put a pointer to that + // as the first argument + .type* thidden = tf.next.pointerTo().toCtype(); + char hiddenparam[5+4+1]; + static int hiddenparami; // how many we've generated so far + + sprintf(hiddenparam.ptr, "__HID%d".ptr, ++hiddenparami); + shidden = symbol_name(hiddenparam.ptr, SC.SCparameter, thidden); + shidden.Sflags |= SFL.SFLtrue | SFL.SFLfree; + +version (DMDV1) { + bool nestedref = func.nrvo_can && func.nrvo_var && func.nrvo_var.nestedref; +} else { + bool nestedref = func.nrvo_can && func.nrvo_var && (func.nrvo_var.nestedrefs.dim != 0); +} + if (nestedref) { + type_setcv(&shidden.Stype, shidden.Stype.Tty | mTY.mTYvolatile); + } + + irs.shidden = shidden; + this.shidden = shidden; + } + + if (vthis) + { + assert(!vthis.csym); + sthis = vthis.toSymbol(); + irs.sthis = sthis; + if (!(f.Fflags3 & F3.Fnested)) + f.Fflags3 |= F3.Fmember; + } + + Symbol** params; + uint pi; + + // Estimate number of parameters, pi + pi = (v_arguments !is null); + if (parameters) + pi += parameters.dim; + + // Allow extra 2 for sthis and shidden + params = cast(Symbol**)alloca((pi + 2) * (Symbol*).sizeof); + + // Get the actual number of parameters, pi, and fill in the params[] + pi = 0; + if (v_arguments) + { + params[pi] = v_arguments.toSymbol(); + pi += 1; + } + if (parameters) + { + for (i = 0; i < parameters.dim; i++) + { + VarDeclaration v = cast(VarDeclaration)parameters.data[i]; +debug { + if (v.csym) + writef("parameter '%s'\n", v.toChars()); +} + assert(!v.csym); + params[pi + i] = v.toSymbol(); + } + pi += i; + } + + if (reverse) + { + // Reverse params[] entries + for (i = 0; i < pi/2; i++) + { + Symbol* sptmp = params[i]; + params[i] = params[pi - 1 - i]; + params[pi - 1 - i] = sptmp; + } + } + + if (shidden) + { +static if (false) { + // shidden becomes last parameter + params[pi] = shidden; +} else { + // shidden becomes first parameter + memmove(params + 1, params, pi * (*params).sizeof); + params[0] = shidden; +} + pi++; + } + + + if (sthis) + { +static if (false) { + // sthis becomes last parameter + params[pi] = sthis; +} else { + // sthis becomes first parameter + memmove(params + 1, params, pi * (*params).sizeof); + params[0] = sthis; +} + pi++; + } + + if ((global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isSolaris) && + linkage != LINK.LINKd && shidden && sthis) + { + /* swap shidden and sthis + */ + Symbol* sp = params[0]; + params[0] = params[1]; + params[1] = sp; + } + + for (i = 0; i < pi; i++) + { + Symbol *sp = params[i]; + sp.Sclass = SC.SCparameter; + sp.Sflags &= ~SFL.SFLspill; + sp.Sfl = FL.FLpara; + symbol_add(sp); + } + + // First parameter goes in register + if (pi) + { + Symbol* sp = params[0]; + if ((tyf == TYM.TYjfunc || tyf == TYM.TYmfunc) && type_jparam(sp.Stype)) + { + sp.Sclass = SC.SCfastpar; + sp.Spreg = (tyf == TYM.TYjfunc) ? REG.AX : REG.CX; + sp.Sfl = FL.FLauto; + //printf("'%s' is SCfastpar\n",sp.Sident); + } + } + + if (func.fbody) + { + block* b; + Blockx bx; + Statement sbody; + + localgot = null; + + sbody = func.fbody; + ///memset(&bx, 0, (bx).sizeof); + bx.startblock = block_calloc(); + bx.curblock = bx.startblock; + bx.funcsym = s; + bx.scope_index = -1; + bx.classdec = cd; + bx.member = func; + bx.module_ = getModule(); + irs.blx = &bx; + + buildClosure(&irs); + +static if (false) { + if (func.isSynchronized()) + { + if (cd) + { + elem *esync; + if (func.isStatic()) + { // monitor is in ClassInfo + esync = el_ptr(cd.toSymbol()); + } + else + { // 'this' is the monitor + esync = el_var(sthis); + } + + if (func.isStatic() || sbody.usesEH() || + !(config.flags2 & CFG2.CFG2seh)) + { // BUG: what if frequire or fensure uses EH? + + sbody = new SynchronizedStatement(func.loc, esync, sbody); + } + else + { + version (TARGET_WINDOS) { + if (config.flags2 & CFG2.CFG2seh) + { + /* The "jmonitor" uses an optimized exception handling frame + * which is a little shorter than the more general EH frame. + * It isn't strictly necessary. + */ + s.Sfunc.Fflags3 |= Fjmonitor; + } + } + el_free(esync); + } + } + else + { + error("synchronized function %s must be a member of a class", func.toChars()); + } + } +} else version (TARGET_WINDOS) { + if (func.isSynchronized() && cd && config.flags2 & CFG2.CFG2seh && + !func.isStatic() && !sbody.usesEH()) + { + /* The "jmonitor" hack uses an optimized exception handling frame + * which is a little shorter than the more general EH frame. + */ + s.Sfunc.Fflags3 |= F3.Fjmonitor; + } +} + + sbody.toIR(&irs); + bx.curblock.BC = BC.BCret; + + f.Fstartblock = bx.startblock; + // einit = el_combine(einit,bx.init); + + if (isCtorDeclaration()) + { + assert(sthis); + for (b = f.Fstartblock; b; b = b.Bnext) + { + if (b.BC == BC.BCret) + { + b.BC = BC.BCretexp; + b.Belem = el_combine(b.Belem, el_var(sthis)); + } + } + } + } + + // If static constructor + if (isStaticConstructor()) + { + elem* e = el_una(OPER.OPucall, TYM.TYvoid, el_var(s)); + ector = el_combine(ector, e); + } + + // If static destructor + if (isStaticDestructor()) + { + elem* e; + +version (STATICCTOR) { + e = el_bin(OPER.OPcall, TYM.TYvoid, el_var(rtlsym[RTLSYM.RTLSYM_FATEXIT]), el_ptr(s)); + ector = el_combine(ector, e); + dtorcount++; +} else { + StaticDtorDeclaration f2 = isStaticDtorDeclaration(); + assert(f2); + if (f2.vgate) + { + /* Increment destructor's vgate at construction time + */ + ectorgates.push(cast(void*)f2); + } + + e = el_una(OPER.OPucall, TYM.TYvoid, el_var(s)); + edtor = el_combine(e, edtor); +} + } + + // If unit test + if (isUnitTestDeclaration()) + { + elem* e = el_una(OPER.OPucall, TYM.TYvoid, el_var(s)); + etest = el_combine(etest, e); + } + + if (global.errors) + return; + + writefunc(s); + + if (isExport()) { + obj_export(s, Poffset); + } + + for (i = 0; i < irs.deferToObj.dim; i++) + { + Dsymbol ss = cast(Dsymbol)irs.deferToObj.data[i]; + ss.toObjFile(0); + } + +version (XXX) { ///TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS + // A hack to get a pointer to this function put in the .dtors segment + if (ident && ident.toChars() == "_STD") { + obj_staticdtor(s); + } +} +version (DMDV2) { + if (irs.startaddress) + { + writef("Setting start address\n"); + obj_startaddress(irs.startaddress); + } +} + } + + int cvMember(ubyte* p) + { + assert(false); + } + + /************************************* + * Closures are implemented by taking the local variables that + * need to survive the scope of the function, and copying them + * into a gc allocated chuck of memory. That chunk, called the + * closure here, is inserted into the linked list of stack + * frames instead of the usual stack frame. + * + * buildClosure() inserts code just after the function prolog + * is complete. It allocates memory for the closure, allocates + * a local variable (sclosure) to point to it, inserts into it + * the link to the enclosing frame, and copies into it the parameters + * that are referred to in nested functions. + * In VarExp.toElem and SymOffExp.toElem, when referring to a + * variable that is in a closure, takes the offset from sclosure rather + * than from the frame pointer. + * + * getEthis() and NewExp.toElem need to use sclosure, if set, rather + * than the current frame pointer. + */ + void buildClosure(IRState* irs) + { + if (needsClosure()) + { + // Generate closure on the heap + // BUG: doesn't capture variadic arguments passed to this function + + version (DMDV2) { + /* BUG: doesn't handle destructors for the local variables. + * The way to do it is to make the closure variables the fields + * of a class object: + * class Closure + * { vtbl[] + * monitor + * ptr to destructor + * sthis + * ... closure variables ... + * ~this() { call destructor } + * } + */ + } + //printf("FuncDeclaration.buildClosure()\n"); + Symbol* sclosure; + sclosure = symbol_name("__closptr".ptr, SC.SCauto, Type.tvoidptr.toCtype()); + sclosure.Sflags |= SFL.SFLtrue | SFL.SFLfree; + symbol_add(sclosure); + irs.sclosure = sclosure; + + uint offset = PTRSIZE; // leave room for previous sthis + for (int i = 0; i < closureVars.dim; i++) + { + VarDeclaration v = cast(VarDeclaration)closureVars.data[i]; + assert(v.isVarDeclaration()); + + version (DMDV2) { + if (v.needsAutoDtor()) + v.error("has scoped destruction, cannot build closure"); + } + /* Align and allocate space for v in the closure + * just like AggregateDeclaration.addField() does. + */ + uint memsize; + uint memalignsize; + uint xalign; +/// version (DMDV2) { + if (v.storage_class & STC.STClazy) + { + /* Lazy variables are really delegates, + * so give same answers that TypeDelegate would + */ + memsize = PTRSIZE * 2; + memalignsize = memsize; + xalign = global.structalign; + } + else +/// } + { + memsize = cast(uint)v.type.size(); + memalignsize = v.type.alignsize(); + xalign = v.type.memalign(global.structalign); + } + AggregateDeclaration.alignmember(xalign, memalignsize, &offset); + v.offset = offset; + offset += memsize; + + /* Can't do nrvo if the variable is put in a closure, since + * what the shidden points to may no longer exist. + */ + if (nrvo_can && nrvo_var == v) + { + nrvo_can = 0; + } + } + // offset is now the size of the closure + + // Allocate memory for the closure + elem* e; + e = el_long(TYM.TYint, offset); + e = el_bin(OPER.OPcall, TYM.TYnptr, el_var(rtlsym[RTLSYM.RTLSYM_ALLOCMEMORY]), e); + + // Assign block of memory to sclosure + // sclosure = allocmemory(sz); + e = el_bin(OPER.OPeq, TYM.TYvoid, el_var(sclosure), e); + + // Set the first element to sthis + // *(sclosure + 0) = sthis; + elem* ethis; + if (irs.sthis) + ethis = el_var(irs.sthis); + else + ethis = el_long(TYM.TYnptr, 0); + elem *ex = el_una(OPER.OPind, TYM.TYnptr, el_var(sclosure)); + ex = el_bin(OPER.OPeq, TYM.TYnptr, ex, ethis); + e = el_combine(e, ex); + + // Copy function parameters into closure + for (int i = 0; i < closureVars.dim; i++) + { VarDeclaration v = cast(VarDeclaration)closureVars.data[i]; + + if (!v.isParameter()) + continue; + TYM tym = v.type.totym(); + if (v.type.toBasetype().ty == TY.Tsarray || v.isOut() || v.isRef()) + tym = TYM.TYnptr; // reference parameters are just pointers +/// version (DMDV2) { + else if (v.storage_class & STC.STClazy) + tym = TYM.TYdelegate; +/// } + ex = el_bin(OPER.OPadd, TYM.TYnptr, el_var(sclosure), el_long(TYM.TYint, v.offset)); + ex = el_una(OPER.OPind, tym, ex); + if (ex.Ety == TYM.TYstruct) + { + ex.Enumbytes = cast(uint)v.type.size(); + ex = el_bin(OPER.OPstreq, tym, ex, el_var(v.toSymbol())); + ex.Enumbytes = cast(uint)v.type.size(); + } + else + { + ex = el_bin(OPER.OPeq, tym, ex, el_var(v.toSymbol())); + } + + e = el_combine(e, ex); + } + + block_appendexp(irs.blx.curblock, e); + } + } + + FuncDeclaration isFuncDeclaration() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/FuncExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/FuncExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,126 @@ +module dmd.FuncExp; + +import dmd.Expression; +import dmd.backend.elem; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.InlineCostState; +import dmd.IRState; +import dmd.HdrGenState; +import dmd.FuncLiteralDeclaration; +import dmd.TOK; +import dmd.TypeFunction; +import dmd.TypeDelegate; +import dmd.TY; +import dmd.Type; +import dmd.Global; + +import dmd.backend.Util; +import dmd.codegen.Util; +import dmd.backend.TYM; +import dmd.backend.Symbol; + +class FuncExp : Expression +{ + FuncLiteralDeclaration fd; + + this(Loc loc, FuncLiteralDeclaration fd) + { + super(loc, TOK.TOKfunction, FuncExp.sizeof); + this.fd = fd; + } + + Expression syntaxCopy() + { + assert(false); + } + + Expression semantic(Scope sc) + { +version (LOGSEMANTIC) { + printf("FuncExp.semantic(%s)\n", toChars()); +} + if (!type) + { + fd.semantic(sc); + + //fd.parent = sc.parent; + if (global.errors) + { + } + else + { + fd.semantic2(sc); + if (!global.errors || + // need to infer return type + (fd.type && fd.type.ty == TY.Tfunction && !fd.type.nextOf())) + { + fd.semantic3(sc); + + if (!global.errors && global.params.useInline) + fd.inlineScan(); + } + } + + // need to infer return type + if (global.errors && fd.type && fd.type.ty == TY.Tfunction && !fd.type.nextOf()) + (cast(TypeFunction)fd.type).next = Type.terror; + + // Type is a "delegate to" or "pointer to" the function literal + if (fd.isNested()) + { + type = new TypeDelegate(fd.type); + type = type.semantic(loc, sc); + } + else + { + type = fd.type.pointerTo(); + } + + fd.tookAddressOf++; + } + + return this; + } + + void scanForNestedRef(Scope sc) + { + assert(false); + } + + string toChars() + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + elem* toElem(IRState* irs) + { + elem* e; + Symbol* s; + + //printf("FuncExp::toElem() %s\n", toChars()); + s = fd.toSymbol(); + e = el_ptr(s); + if (fd.isNested()) + { + elem* ethis = getEthis(loc, irs, fd); + e = el_pair(TYM.TYullong, ethis, e); + } + + irs.deferToObj.push(cast(void*)fd); + el_setLoc(e,loc); + return e; + } + + int inlineCost(InlineCostState* ics) + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/FuncLiteralDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/FuncLiteralDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,65 @@ +module dmd.FuncLiteralDeclaration; + +import dmd.FuncDeclaration; +import dmd.TOK; +import dmd.Loc; +import dmd.Type; +import dmd.ForeachStatement; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Dsymbol; +import dmd.STC; +import dmd.Lexer; + +class FuncLiteralDeclaration : FuncDeclaration +{ + TOK tok; // TOKfunction or TOKdelegate + + this(Loc loc, Loc endloc, Type type, TOK tok, ForeachStatement fes) + { + super(loc, endloc, null, STC.STCundefined, type); + + string id; + + if (fes) + id = "__foreachbody"; + else if (tok == TOK.TOKdelegate) + id = "__dgliteral"; + else + id = "__funcliteral"; + + this.ident = Lexer.uniqueId(id); + this.tok = tok; + this.fes = fes; + + //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this->ident->toChars(), type->toChars()); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + Dsymbol syntaxCopy(Dsymbol) + { + assert(false); + } + + bool isNested() + { + //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars()); + return (tok == TOK.TOKdelegate); + } + + bool isVirtual() + { + return false; + } + + FuncLiteralDeclaration isFuncLiteralDeclaration() { return this; } + + string kind() + { + return (tok == TOKdelegate) ? "delegate" : "function"; + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/Global.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Global.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,52 @@ +module dmd.Global; + +import dmd.Array; +import dmd.Param; + +class Global +{ + string mars_ext = "d"; + string sym_ext = "d"; + +version (TARGET_WINDOS) { + string obj_ext = "obj"; +} else version (XXX) { // TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS + string obj_ext = "o"; +} else version (TARGET_NET) { +} else { + static assert (false); +} + +version (TARGET_WINDOS) { + string lib_ext = "lib"; +} else version (XXX) { // TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS + string lib_ext = "a"; +} else version (TARGET_NET) { +} else { + static assert (false); +} + string doc_ext = "html";; // for Ddoc generated files + string ddoc_ext = "ddoc";; // for Ddoc macro include files + string hdr_ext = "di"; // for D 'header' import files + string copyright= "Copyright (c) 1999-2009 by Digital Mars"; + string written = "written by Walter Bright"; +///version (TARGET_NET) { +/// "\nMSIL back-end (alpha release) by Cristian L. Vlasceanu and associates."; +///} + + string[] path; // Array of char*'s which form the import lookup path + string[] filePath; // Array of char*'s which form the file import lookup path + int structalign = 8; + string version_ = "v2.032"; + + Param params; + uint errors; // number of errors reported so far + uint gag; // !=0 means gag reporting of errors + + this() + { + params.versionids = new Array(); + } +} + +Global global; \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/GlobalExpressions.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/GlobalExpressions.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,31 @@ +module dmd.GlobalExpressions; + +import dmd.Expression; +import dmd.TOK; +import dmd.Loc; + +Expression EXP_CANT_INTERPRET; +Expression EXP_CONTINUE_INTERPRET; +Expression EXP_BREAK_INTERPRET; +Expression EXP_GOTO_INTERPRET; +Expression EXP_VOID_INTERPRET; + +void* castToVoid(int i) +{ + return cast(void*)i; +} + +static this() +{ + //EXP_CANT_INTERPRET = new Expression(Loc(0), TOK.init, 0); + //EXP_CONTINUE_INTERPRET = new Expression(Loc(0), TOK.init, 0); + //EXP_BREAK_INTERPRET = new Expression(Loc(0), TOK.init, 0); + //EXP_GOTO_INTERPRET = new Expression(Loc(0), TOK.init, 0); + //EXP_VOID_INTERPRET = new Expression(Loc(0), TOK.init, 0); + + EXP_CANT_INTERPRET = cast(Expression)castToVoid(1); + EXP_CONTINUE_INTERPRET = cast(Expression)castToVoid(2); + EXP_BREAK_INTERPRET = cast(Expression)castToVoid(3); + EXP_GOTO_INTERPRET = cast(Expression)castToVoid(4); + EXP_VOID_INTERPRET = cast(Expression)castToVoid(5); +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/GotoCaseStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/GotoCaseStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,54 @@ +module dmd.GotoCaseStatement; + +import dmd.Statement; +import dmd.Expression; +import dmd.CaseStatement; +import dmd.IRState; +import dmd.Scope; +import dmd.Loc; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.BE; + +class GotoCaseStatement : Statement +{ + Expression exp; // NULL, or which case to goto + CaseStatement cs; // case statement it resolves to + + this(Loc loc, Expression exp) + { + assert(false); + super(loc); + } + + Statement syntaxCopy() + { + assert(false); + } + + Statement semantic(Scope sc) + { + assert(false); + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + BE blockExit() + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + void toIR(IRState* irs) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/GotoDefaultStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/GotoDefaultStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,53 @@ +module dmd.GotoDefaultStatement; + +import dmd.Statement; +import dmd.SwitchStatement; +import dmd.Loc; +import dmd.Scope; +import dmd.Expression; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.IRState; +import dmd.BE; + +class GotoDefaultStatement : Statement +{ + SwitchStatement sw; + + this(Loc loc) + { + assert(false); + super(loc); + } + + Statement syntaxCopy() + { + assert(false); + } + + Statement semantic(Scope sc) + { + assert(false); + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + BE blockExit() + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + void toIR(IRState *irs) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/GotoStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/GotoStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,133 @@ +module dmd.GotoStatement; + +import dmd.Loc; +import dmd.Scope; +import dmd.Statement; +import dmd.Identifier; +import dmd.CompoundStatement; +import dmd.LabelDsymbol; +import dmd.TryFinallyStatement; +import dmd.FuncDeclaration; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Expression; +import dmd.InterState; +import dmd.IRState; +import dmd.ArrayTypes; +import dmd.BE; + +import dmd.codegen.Util; +import dmd.backend.Util; +import dmd.backend.block; +import dmd.backend.Blockx; +import dmd.backend.BC; + +class GotoStatement : Statement +{ + Identifier ident; + LabelDsymbol label = null; + TryFinallyStatement tf = null; + + this(Loc loc, Identifier ident) + { + super(loc); + this.ident = ident; + } + + Statement syntaxCopy() + { + GotoStatement s = new GotoStatement(loc, ident); + return s; + } + + Statement semantic(Scope sc) + { + FuncDeclaration fd = sc.parent.isFuncDeclaration(); + + //printf("GotoStatement.semantic()\n"); + tf = sc.tf; + label = fd.searchLabel(ident); + if (!label.statement && sc.fes) + { + /* Either the goto label is forward referenced or it + * is in the function that the enclosing foreach is in. + * Can't know yet, so wrap the goto in a compound statement + * so we can patch it later, and add it to a 'look at this later' + * list. + */ + Statements a = new Statements(); + Statement s; + + a.push(cast(void*)this); + s = new CompoundStatement(loc, a); + sc.fes.gotos.push(cast(void*)s); // 'look at this later' list + return s; + } + + if (label.statement && label.statement.tf != sc.tf) + error("cannot goto in or out of finally block"); + return this; + } + + BE blockExit() + { + //printf("GotoStatement.blockExit(%p)\n", this); + return BE.BEgoto; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void toIR(IRState* irs) + { + block* b; + block* bdest; + Blockx* blx = irs.blx; + + if (!label.statement) + { + error("label %s is undefined", label.toChars()); + return; + } + if (tf !is label.statement.tf) + error("cannot goto forward out of or into finally block"); + + bdest = labelToBlock(loc, blx, label); + if (!bdest) + return; + b = blx.curblock; + incUsage(irs, loc); + + // Adjust exception handler scope index if in different try blocks + if (b.Btry != bdest.Btry) + { + // Check that bdest is in an enclosing try block + for (block* bt = b.Btry; bt != bdest.Btry; bt = bt.Btry) + { + if (!bt) + { + //printf("b.Btry = %p, bdest.Btry = %p\n", b.Btry, bdest.Btry); + error("cannot goto into try block"); + break; + } + } + + //setScopeIndex(blx, b, bdest.Btry ? bdest.Btry.Bscope_index : -1); + } + + list_append(&b.Bsucc,bdest); + block_next(blx,BCgoto,null); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + buf.writestring("goto "); + buf.writestring(ident.toChars()); + buf.writebyte(';'); + buf.writenl(); + } + + GotoStatement isGotoStatement() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/HaltExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/HaltExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,55 @@ +module dmd.HaltExp; + +import dmd.Expression; +import dmd.backend.elem; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.IRState; +import dmd.Type; +import dmd.HdrGenState; +import dmd.Loc; +import dmd.TOK; + +import dmd.backend.Util; +import dmd.backend.OPER; +import dmd.backend.TYM; + +class HaltExp : Expression +{ + this(Loc loc) + { + super(loc, TOK.TOKhalt, HaltExp.sizeof); + } + + Expression semantic(Scope sc) + { +version (LOGSEMANTIC) { + printf("HaltExp.semantic()\n"); +} + type = Type.tvoid; + return this; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + buf.writestring("halt"); + } + + bool checkSideEffect(int flag) + { + return true; + } + + elem* toElem(IRState* irs) + { + elem *e; + + e = el_calloc(); + e.Ety = TYvoid; + e.Eoper = OPhalt; + el_setLoc(e,loc); + return e; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/HdrGenState.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/HdrGenState.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,24 @@ +module dmd.HdrGenState; + +struct HdrGenState +{ + int hdrgen; // 1 if generating header file + int ddoc; // 1 if generating Ddoc file + int console; // 1 if writing to console + int tpltMember; + int inCallExp; + int inPtrExp; + int inSlcExp; + int inDotExp; + int inBinExp; + int inArrExp; + int emitInst; + + struct FLinit_ + { + int init; + int decl; + } + + FLinit_ FLinit; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ILS.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ILS.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,8 @@ +module dmd.ILS; + +enum ILS +{ + ILSuninitialized, // not computed yet + ILSno, // cannot inline + ILSyes, // can inline +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/IRState.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/IRState.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,171 @@ +module dmd.IRState; + +import dmd.Statement; +import dmd.Module; +import dmd.Dsymbol; +import dmd.Identifier; +import dmd.Array; +import dmd.FuncDeclaration; +import dmd.Global; +import dmd.Loc; + +import dmd.backend.Symbol; +import dmd.backend.Blockx; +import dmd.backend.block; +import dmd.backend.elem; +import dmd.backend.Util; +import dmd.backend.TYM; +import dmd.backend.OPER; + +struct IRState +{ + IRState* prev; + Statement statement; + Module m; // module + Dsymbol symbol; + Identifier ident; + Symbol* shidden; // hidden parameter to function + Symbol* sthis; // 'this' parameter to function (member and nested) + Symbol* sclosure; // pointer to closure instance + Blockx* blx; + Array deferToObj; // array of Dsymbol's to run toObjFile(int multiobj) on later + elem* ehidden; // transmit hidden pointer to CallExp::toElem() + Symbol* startaddress; + + block* breakBlock; + block* contBlock; + block* switchBlock; + block* defaultBlock; + + this(IRState* irs, Statement s) + { + prev = irs; + statement = s; + if (irs) + { + m = irs.m; + shidden = irs.shidden; + sclosure = irs.sclosure; + sthis = irs.sthis; + blx = irs.blx; + deferToObj = irs.deferToObj; + } + } + + this(IRState* irs, Dsymbol s) + { + assert(false); + } + + this(Module m, Dsymbol s) + { + this.m = m; + symbol = s; + } + + block* getBreakBlock(Identifier ident) + { + for (IRState* bc = &this; bc; bc = bc.prev) + { + if (ident) + { + if (bc.prev && bc.prev.ident == ident) + return bc.breakBlock; + } + else if (bc.breakBlock) + return bc.breakBlock; + } + return null; + } + + block* getContBlock(Identifier ident) + { + IRState* bc; + + for (bc = &this; bc; bc = bc.prev) + { + if (ident) + { + if (bc.prev && bc.prev.ident == ident) + return bc.contBlock; + } + else if (bc.contBlock) + return bc.contBlock; + } + return null; + } + + block* getSwitchBlock() + { + for (IRState* bc = &this; bc; bc = bc.prev) + { + if (bc.switchBlock) + return bc.switchBlock; + } + return null; + } + + block* getDefaultBlock() + { + for (IRState* bc = &this; bc; bc = bc.prev) + { + if (bc.defaultBlock) + return bc.defaultBlock; + } + return null; + } + + FuncDeclaration getFunc() + { + IRState* bc; + for (bc = &this; bc.prev; bc = bc.prev) + { + } + return cast(FuncDeclaration)(bc.symbol); + } +} + +/********************************************* + * Produce elem which increments the usage count for a particular line. + * Used to implement -cov switch (coverage analysis). + */ + +elem *incUsageElem(IRState *irs, Loc loc) +{ + uint linnum = loc.linnum; + + if (!irs.blx.module_.cov || !linnum || loc.filename != irs.blx.module_.srcfile.toChars()) + return null; + + //printf("cov = %p, covb = %p, linnum = %u\n", irs->blx->module->cov, irs->blx->module->covb, p, linnum); + + linnum--; // from 1-based to 0-based + + /* Set bit in covb[] indicating this is a valid code line number + */ + uint* p = irs.blx.module_.covb; + if (p) // covb can be NULL if it has already been written out to its .obj file + { + p += linnum / ((*p).sizeof * 8); + *p |= 1 << (linnum & ((*p).sizeof * 8 - 1)); + } + + elem* e; + e = el_ptr(irs.blx.module_.cov); + e = el_bin(OPER.OPadd, TYM.TYnptr, e, el_long(TYM.TYuint, linnum * 4)); + e = el_una(OPER.OPind, TYM.TYuint, e); + e = el_bin(OPER.OPaddass, TYM.TYuint, e, el_long(TYM.TYuint, 1)); + + return e; +} + +/************************************** + * Add in code to increment usage count for linnum. + */ +void incUsage(IRState* irs, Loc loc) +{ + if (global.params.cov && loc.linnum) + { + block_appendexp(irs.blx.curblock, incUsageElem(irs, loc)); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/Id.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Id.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,456 @@ +module dmd.Id; + +import dmd.Identifier; +import dmd.Lexer; + +struct Id +{ + static Identifier IUnknown; + static Identifier Object_; + static Identifier object; + static Identifier max; + static Identifier min; + static Identifier This; + static Identifier ctor; + static Identifier dtor; + static Identifier cpctor; + static Identifier _postblit; + static Identifier classInvariant; + static Identifier unitTest; + static Identifier init_; + static Identifier size; + static Identifier __sizeof; + static Identifier alignof_; + static Identifier mangleof_; + static Identifier stringof_; + static Identifier tupleof_; + static Identifier length; + static Identifier remove; + static Identifier ptr; + static Identifier funcptr; + static Identifier dollar; + static Identifier offset; + static Identifier offsetof; + static Identifier ModuleInfo; + static Identifier ClassInfo; + static Identifier classinfo_; + static Identifier typeinfo_; + static Identifier outer; + static Identifier Exception; + static Identifier Throwable; + static Identifier withSym; + static Identifier result; + static Identifier returnLabel; + static Identifier delegate_; + static Identifier line; + static Identifier empty; + static Identifier p; + static Identifier coverage; + static Identifier __vptr; + static Identifier __monitor; + static Identifier system; + static Identifier TypeInfo; + static Identifier TypeInfo_Class; + static Identifier TypeInfo_Interface; + static Identifier TypeInfo_Struct; + static Identifier TypeInfo_Enum; + static Identifier TypeInfo_Typedef; + static Identifier TypeInfo_Pointer; + static Identifier TypeInfo_Array; + static Identifier TypeInfo_StaticArray; + static Identifier TypeInfo_AssociativeArray; + static Identifier TypeInfo_Function; + static Identifier TypeInfo_Delegate; + static Identifier TypeInfo_Tuple; + static Identifier TypeInfo_Const; + static Identifier TypeInfo_Invariant; + static Identifier TypeInfo_Shared; + static Identifier elements; + static Identifier _arguments_typeinfo; + static Identifier _arguments; + static Identifier _argptr; + static Identifier _match; + static Identifier destroy; + static Identifier postblit; + static Identifier LINE; + static Identifier FILE; + static Identifier DATE; + static Identifier TIME; + static Identifier TIMESTAMP; + static Identifier VENDOR; + static Identifier VERSIONX; + static Identifier EOFX; + static Identifier nan; + static Identifier infinity; + static Identifier dig; + static Identifier epsilon; + static Identifier mant_dig; + static Identifier max_10_exp; + static Identifier max_exp; + static Identifier min_10_exp; + static Identifier min_exp; + static Identifier re; + static Identifier im; + static Identifier C; + static Identifier D; + static Identifier Windows; + static Identifier Pascal; + static Identifier System; + static Identifier exit; + static Identifier success; + static Identifier failure; + static Identifier keys; + static Identifier values; + static Identifier rehash; + static Identifier sort; + static Identifier reverse; + static Identifier dup; + static Identifier idup; + static Identifier property; + static Identifier ___out; + static Identifier ___in; + static Identifier __int; + static Identifier __dollar; + static Identifier __LOCAL_SIZE; + static Identifier uadd; + static Identifier neg; + static Identifier com; + static Identifier add; + static Identifier add_r; + static Identifier sub; + static Identifier sub_r; + static Identifier mul; + static Identifier mul_r; + static Identifier div; + static Identifier div_r; + static Identifier mod; + static Identifier mod_r; + static Identifier eq; + static Identifier cmp; + static Identifier iand; + static Identifier iand_r; + static Identifier ior; + static Identifier ior_r; + static Identifier ixor; + static Identifier ixor_r; + static Identifier shl; + static Identifier shl_r; + static Identifier shr; + static Identifier shr_r; + static Identifier ushr; + static Identifier ushr_r; + static Identifier cat; + static Identifier cat_r; + static Identifier assign; + static Identifier addass; + static Identifier subass; + static Identifier mulass; + static Identifier divass; + static Identifier modass; + static Identifier andass; + static Identifier orass; + static Identifier xorass; + static Identifier shlass; + static Identifier shrass; + static Identifier ushrass; + static Identifier catass; + static Identifier postinc; + static Identifier postdec; + static Identifier index; + static Identifier indexass; + static Identifier slice; + static Identifier sliceass; + static Identifier call; + static Identifier cast_; + static Identifier match; + static Identifier next; + static Identifier opIn; + static Identifier opIn_r; + static Identifier opStar; + static Identifier opDot; + static Identifier opImplicitCast; + static Identifier classNew; + static Identifier classDelete; + static Identifier apply; + static Identifier applyReverse; + static Identifier Fempty; + static Identifier Fhead; + static Identifier Ftoe; + static Identifier Fnext; + static Identifier Fretreat; + static Identifier adDup; + static Identifier adReverse; + static Identifier aaLen; + static Identifier aaKeys; + static Identifier aaValues; + static Identifier aaRehash; + static Identifier monitorenter; + static Identifier monitorexit; + static Identifier criticalenter; + static Identifier criticalexit; + static Identifier GNU_asm; + static Identifier lib; + static Identifier msg; + static Identifier startaddress; + static Identifier tohash; + static Identifier tostring; + static Identifier getmembers; + static Identifier alloca; + static Identifier main; + static Identifier WinMain; + static Identifier DllMain; + static Identifier tls_get_addr; + static Identifier std; + static Identifier math; + static Identifier sin; + static Identifier cos; + static Identifier tan; + static Identifier _sqrt; + static Identifier fabs; + static Identifier isAbstractClass; + static Identifier isArithmetic; + static Identifier isAssociativeArray; + static Identifier isFinalClass; + static Identifier isFloating; + static Identifier isIntegral; + static Identifier isScalar; + static Identifier isStaticArray; + static Identifier isUnsigned; + static Identifier isVirtualFunction; + static Identifier isAbstractFunction; + static Identifier isFinalFunction; + static Identifier hasMember; + static Identifier getMember; + static Identifier getVirtualFunctions; + static Identifier classInstanceSize; + static Identifier allMembers; + static Identifier derivedMembers; + static Identifier isSame; + static Identifier compiles; + + static void initialize() + { + IUnknown = Lexer.idPool("IUnknown"); + Object_ = Lexer.idPool("Object"); + object = Lexer.idPool("object"); + max = Lexer.idPool("max"); + min = Lexer.idPool("min"); + This = Lexer.idPool("this"); + ctor = Lexer.idPool("__ctor"); + dtor = Lexer.idPool("__dtor"); + cpctor = Lexer.idPool("__cpctor"); + _postblit = Lexer.idPool("__postblit"); + classInvariant = Lexer.idPool("__invariant"); + unitTest = Lexer.idPool("__unitTest"); + init_ = Lexer.idPool("init"); + size = Lexer.idPool("size"); + __sizeof = Lexer.idPool("sizeof"); + alignof_ = Lexer.idPool("alignof"); + mangleof_ = Lexer.idPool("mangleof"); + stringof_ = Lexer.idPool("stringof"); + tupleof_ = Lexer.idPool("tupleof"); + length = Lexer.idPool("length"); + remove = Lexer.idPool("remove"); + ptr = Lexer.idPool("ptr"); + funcptr = Lexer.idPool("funcptr"); + dollar = Lexer.idPool("__dollar"); + offset = Lexer.idPool("offset"); + offsetof = Lexer.idPool("offsetof"); + ModuleInfo = Lexer.idPool("ModuleInfo"); + ClassInfo = Lexer.idPool("ClassInfo"); + classinfo_ = Lexer.idPool("classinfo"); + typeinfo_ = Lexer.idPool("typeinfo"); + outer = Lexer.idPool("outer"); + Exception = Lexer.idPool("Exception"); + Throwable = Lexer.idPool("Throwable"); + withSym = Lexer.idPool("__withSym"); + result = Lexer.idPool("__result"); + returnLabel = Lexer.idPool("__returnLabel"); + delegate_ = Lexer.idPool("delegate"); + line = Lexer.idPool("line"); + empty = Lexer.idPool(""); + p = Lexer.idPool("p"); + coverage = Lexer.idPool("__coverage"); + __vptr = Lexer.idPool("__vptr"); + __monitor = Lexer.idPool("__monitor"); + system = Lexer.idPool("system"); + TypeInfo = Lexer.idPool("TypeInfo"); + TypeInfo_Class = Lexer.idPool("TypeInfo_Class"); + TypeInfo_Interface = Lexer.idPool("TypeInfo_Interface"); + TypeInfo_Struct = Lexer.idPool("TypeInfo_Struct"); + TypeInfo_Enum = Lexer.idPool("TypeInfo_Enum"); + TypeInfo_Typedef = Lexer.idPool("TypeInfo_Typedef"); + TypeInfo_Pointer = Lexer.idPool("TypeInfo_Pointer"); + TypeInfo_Array = Lexer.idPool("TypeInfo_Array"); + TypeInfo_StaticArray = Lexer.idPool("TypeInfo_StaticArray"); + TypeInfo_AssociativeArray = Lexer.idPool("TypeInfo_AssociativeArray"); + TypeInfo_Function = Lexer.idPool("TypeInfo_Function"); + TypeInfo_Delegate = Lexer.idPool("TypeInfo_Delegate"); + TypeInfo_Tuple = Lexer.idPool("TypeInfo_Tuple"); + TypeInfo_Const = Lexer.idPool("TypeInfo_Const"); + TypeInfo_Invariant = Lexer.idPool("TypeInfo_Invariant"); + TypeInfo_Shared = Lexer.idPool("TypeInfo_Shared"); + elements = Lexer.idPool("elements"); + _arguments_typeinfo = Lexer.idPool("_arguments_typeinfo"); + _arguments = Lexer.idPool("_arguments"); + _argptr = Lexer.idPool("_argptr"); + _match = Lexer.idPool("_match"); + destroy = Lexer.idPool("destroy"); + postblit = Lexer.idPool("postblit"); + LINE = Lexer.idPool("__LINE__"); + FILE = Lexer.idPool("__FILE__"); + DATE = Lexer.idPool("__DATE__"); + TIME = Lexer.idPool("__TIME__"); + TIMESTAMP = Lexer.idPool("__TIMESTAMP__"); + VENDOR = Lexer.idPool("__VENDOR__"); + VERSIONX = Lexer.idPool("__VERSION__"); + EOFX = Lexer.idPool("__EOF__"); + nan = Lexer.idPool("nan"); + infinity = Lexer.idPool("infinity"); + dig = Lexer.idPool("dig"); + epsilon = Lexer.idPool("epsilon"); + mant_dig = Lexer.idPool("mant_dig"); + max_10_exp = Lexer.idPool("max_10_exp"); + max_exp = Lexer.idPool("max_exp"); + min_10_exp = Lexer.idPool("min_10_exp"); + min_exp = Lexer.idPool("min_exp"); + re = Lexer.idPool("re"); + im = Lexer.idPool("im"); + C = Lexer.idPool("C"); + D = Lexer.idPool("D"); + Windows = Lexer.idPool("Windows"); + Pascal = Lexer.idPool("Pascal"); + System = Lexer.idPool("System"); + exit = Lexer.idPool("exit"); + success = Lexer.idPool("success"); + failure = Lexer.idPool("failure"); + keys = Lexer.idPool("keys"); + values = Lexer.idPool("values"); + rehash = Lexer.idPool("rehash"); + sort = Lexer.idPool("sort"); + reverse = Lexer.idPool("reverse"); + dup = Lexer.idPool("dup"); + idup = Lexer.idPool("idup"); + property = Lexer.idPool("property"); + ___out = Lexer.idPool("out"); + ___in = Lexer.idPool("in"); + __int = Lexer.idPool("int"); + __dollar = Lexer.idPool("$"); + __LOCAL_SIZE = Lexer.idPool("__LOCAL_SIZE"); + uadd = Lexer.idPool("opPos"); + neg = Lexer.idPool("opNeg"); + com = Lexer.idPool("opCom"); + add = Lexer.idPool("opAdd"); + add_r = Lexer.idPool("opAdd_r"); + sub = Lexer.idPool("opSub"); + sub_r = Lexer.idPool("opSub_r"); + mul = Lexer.idPool("opMul"); + mul_r = Lexer.idPool("opMul_r"); + div = Lexer.idPool("opDiv"); + div_r = Lexer.idPool("opDiv_r"); + mod = Lexer.idPool("opMod"); + mod_r = Lexer.idPool("opMod_r"); + eq = Lexer.idPool("opEquals"); + cmp = Lexer.idPool("opCmp"); + iand = Lexer.idPool("opAnd"); + iand_r = Lexer.idPool("opAnd_r"); + ior = Lexer.idPool("opOr"); + ior_r = Lexer.idPool("opOr_r"); + ixor = Lexer.idPool("opXor"); + ixor_r = Lexer.idPool("opXor_r"); + shl = Lexer.idPool("opShl"); + shl_r = Lexer.idPool("opShl_r"); + shr = Lexer.idPool("opShr"); + shr_r = Lexer.idPool("opShr_r"); + ushr = Lexer.idPool("opUShr"); + ushr_r = Lexer.idPool("opUShr_r"); + cat = Lexer.idPool("opCat"); + cat_r = Lexer.idPool("opCat_r"); + assign = Lexer.idPool("opAssign"); + addass = Lexer.idPool("opAddAssign"); + subass = Lexer.idPool("opSubAssign"); + mulass = Lexer.idPool("opMulAssign"); + divass = Lexer.idPool("opDivAssign"); + modass = Lexer.idPool("opModAssign"); + andass = Lexer.idPool("opAndAssign"); + orass = Lexer.idPool("opOrAssign"); + xorass = Lexer.idPool("opXorAssign"); + shlass = Lexer.idPool("opShlAssign"); + shrass = Lexer.idPool("opShrAssign"); + ushrass = Lexer.idPool("opUShrAssign"); + catass = Lexer.idPool("opCatAssign"); + postinc = Lexer.idPool("opPostInc"); + postdec = Lexer.idPool("opPostDec"); + index = Lexer.idPool("opIndex"); + indexass = Lexer.idPool("opIndexAssign"); + slice = Lexer.idPool("opSlice"); + sliceass = Lexer.idPool("opSliceAssign"); + call = Lexer.idPool("opCall"); + cast_ = Lexer.idPool("opCast"); + match = Lexer.idPool("opMatch"); + next = Lexer.idPool("opNext"); + opIn = Lexer.idPool("opIn"); + opIn_r = Lexer.idPool("opIn_r"); + opStar = Lexer.idPool("opStar"); + opDot = Lexer.idPool("opDot"); + opImplicitCast = Lexer.idPool("opImplicitCast"); + classNew = Lexer.idPool("new"); + classDelete = Lexer.idPool("delete"); + apply = Lexer.idPool("opApply"); + applyReverse = Lexer.idPool("opApplyReverse"); + Fempty = Lexer.idPool("empty"); + Fhead = Lexer.idPool("front"); + Ftoe = Lexer.idPool("back"); + Fnext = Lexer.idPool("popFront"); + Fretreat = Lexer.idPool("popBack"); + adDup = Lexer.idPool("_adDupT"); + adReverse = Lexer.idPool("_adReverse"); + aaLen = Lexer.idPool("_aaLen"); + aaKeys = Lexer.idPool("_aaKeys"); + aaValues = Lexer.idPool("_aaValues"); + aaRehash = Lexer.idPool("_aaRehash"); + monitorenter = Lexer.idPool("_d_monitorenter"); + monitorexit = Lexer.idPool("_d_monitorexit"); + criticalenter = Lexer.idPool("_d_criticalenter"); + criticalexit = Lexer.idPool("_d_criticalexit"); + GNU_asm = Lexer.idPool("GNU_asm"); + lib = Lexer.idPool("lib"); + msg = Lexer.idPool("msg"); + startaddress = Lexer.idPool("startaddress"); + tohash = Lexer.idPool("toHash"); + tostring = Lexer.idPool("toString"); + getmembers = Lexer.idPool("getMembers"); + alloca = Lexer.idPool("alloca"); + main = Lexer.idPool("main"); + WinMain = Lexer.idPool("WinMain"); + DllMain = Lexer.idPool("DllMain"); + tls_get_addr = Lexer.idPool("___tls_get_addr"); + std = Lexer.idPool("std"); + math = Lexer.idPool("math"); + sin = Lexer.idPool("sin"); + cos = Lexer.idPool("cos"); + tan = Lexer.idPool("tan"); + _sqrt = Lexer.idPool("sqrt"); + fabs = Lexer.idPool("fabs"); + isAbstractClass = Lexer.idPool("isAbstractClass"); + isArithmetic = Lexer.idPool("isArithmetic"); + isAssociativeArray = Lexer.idPool("isAssociativeArray"); + isFinalClass = Lexer.idPool("isFinalClass"); + isFloating = Lexer.idPool("isFloating"); + isIntegral = Lexer.idPool("isIntegral"); + isScalar = Lexer.idPool("isScalar"); + isStaticArray = Lexer.idPool("isStaticArray"); + isUnsigned = Lexer.idPool("isUnsigned"); + isVirtualFunction = Lexer.idPool("isVirtualFunction"); + isAbstractFunction = Lexer.idPool("isAbstractFunction"); + isFinalFunction = Lexer.idPool("isFinalFunction"); + hasMember = Lexer.idPool("hasMember"); + getMember = Lexer.idPool("getMember"); + getVirtualFunctions = Lexer.idPool("getVirtualFunctions"); + classInstanceSize = Lexer.idPool("classInstanceSize"); + allMembers = Lexer.idPool("allMembers"); + derivedMembers = Lexer.idPool("derivedMembers"); + isSame = Lexer.idPool("isSame"); + compiles = Lexer.idPool("compiles"); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/Identifier.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Identifier.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,79 @@ +module dmd.Identifier; + +import dmd.TOK; +import dmd.DYNCAST; +import dmd.Lexer; +import dmd.OutBuffer; + +import std.stdio : writef; + +class Identifier +{ + TOK value; + string string_; + + this(string string_, TOK value) + { + this.string_ = string_; + this.value = value; + } + + int equals(Object o) + { + return this is o || string_ == (cast(Identifier)o).toChars(); /// hack + } + + hash_t hashCode() + { + assert(false); + } + + int compare(Object o) + { + assert(false); + } + + void print() + { + assert(false); + } + + string toChars() + { + return string_; + } + +version (_DH) { + char* toHChars() + { + assert(false); + } +} + string toHChars2() + { + assert(false); + } + + DYNCAST dyncast() + { + return DYNCAST.DYNCAST_IDENTIFIER; + } + + // BUG: these are redundant with Lexer::uniqueId() + static Identifier generateId(string prefix) + { + static size_t i; + return generateId(prefix, ++i); + } + + static Identifier generateId(string prefix, size_t i) + { + scope OutBuffer buf = new OutBuffer(); + + buf.writestring(prefix); + buf.printf("%d", i); ///ident, + // if so then insert alias + if (!mod.importedFrom) + mod.importedFrom = sc ? sc.module_.importedFrom : Module.rootModule; + } + + if (!pkg) + pkg = mod; + + //writef("-Import::load('%s'), pkg = %p\n", toChars(), pkg); + } + + void semantic(Scope sc) + { + //writef("Import.semantic('%s')\n", toChars()); + + load(sc); + + if (mod) + { +static if (false) { + if (mod.loc.linnum != 0) + { /* If the line number is not 0, then this is not + * a 'root' module, i.e. it was not specified on the command line. + */ + mod.importedFrom = sc.module_.importedFrom; + assert(mod.importedFrom); + } +} + + // Modules need a list of each imported module + //printf("%s imports %s\n", sc.module.toChars(), mod.toChars()); + sc.module_.aimports.push(cast(void*)mod); + + if (!isstatic && !aliasId && !names.dim) + { + /* Default to private importing + */ + PROT prot = sc.protection; + if (!sc.explicitProtection) + prot = PROT.PROTprivate; + + sc.scopesym.importScope(mod, prot); + } + + mod.semantic(); + + if (mod.needmoduleinfo) + sc.module_.needmoduleinfo = 1; + + sc = sc.push(mod); + for (size_t i = 0; i < aliasdecls.dim; i++) + { + Dsymbol s = cast(Dsymbol)aliasdecls.data[i]; + + //writef("\tImport alias semantic('%s')\n", s.toChars()); + if (!mod.search(loc, cast(Identifier)names.data[i], 0)) + error("%s not found", (cast(Identifier)names.data[i]).toChars()); + + s.semantic(sc); + } + sc = sc.pop(); + } + + if (global.params.moduleDeps !is null) + { + /* The grammar of the file is: + * ImportDeclaration + * .= BasicImportDeclaration [ " : " ImportBindList ] [ " . " + * ModuleAliasIdentifier ] "\n" + * + * BasicImportDeclaration + * .= ModuleFullyQualifiedName " (" FilePath ") : " Protection + * " [ " static" ] : " ModuleFullyQualifiedName " (" FilePath ")" + * + * FilePath + * - any string with '(', ')' and '\' escaped with the '\' character + */ + + OutBuffer ob = global.params.moduleDeps; + + ob.writestring(sc.module_.toPrettyChars()); + ob.writestring(" ("); + escapePath(ob, sc.module_.srcfile.toChars()); + ob.writestring(") : "); + + ProtDeclaration.protectionToCBuffer(ob, sc.protection); + if (isstatic) + StorageClassDeclaration.stcToCBuffer(ob, STC.STCstatic); + ob.writestring(": "); + + if (packages) + { + for (size_t i = 0; i < packages.dim; i++) + { + Identifier pid = cast(Identifier)packages.data[i]; + ob.printf("%s.", pid.toChars()); + } + } + + ob.writestring(id.toChars()); + ob.writestring(" ("); + if (mod) + escapePath(ob, mod.srcfile.toChars()); + else + ob.writestring("???"); + ob.writebyte(')'); + + for (size_t i = 0; i < names.dim; i++) + { + if (i == 0) + ob.writebyte(':'); + else + ob.writebyte(','); + + Identifier name = cast(Identifier)names.data[i]; + Identifier alias_ = cast(Identifier)aliases.data[i]; + + if (!alias_) + { + ob.printf("%s", name.toChars()); + alias_ = name; + } + else + ob.printf("%s=%s", alias_.toChars(), name.toChars()); + } + + if (aliasId) + ob.printf(" . %s", aliasId.toChars()); + + ob.writenl(); + } + + //printf("-Import.semantic('%s'), pkg = %p\n", toChars(), pkg); + } + + void semantic2(Scope sc) + { + //printf("Import::semantic2('%s')\n", toChars()); + mod.semantic2(); + if (mod.needmoduleinfo) + sc.module_.needmoduleinfo = 1; + } + + Dsymbol toAlias() + { + if (aliasId) + return mod; + return this; + } + + /***************************** + * Add import to sd's symbol table. + */ + bool addMember(Scope sc, ScopeDsymbol sd, int memnum) + { + bool result = false; + + if (names.dim == 0) + return Dsymbol.addMember(sc, sd, memnum); + + if (aliasId) + result = Dsymbol.addMember(sc, sd, memnum); + + /* Instead of adding the import to sd's symbol table, + * add each of the alias=name pairs + */ + for (size_t i = 0; i < names.dim; i++) + { + Identifier name = cast(Identifier)names.data[i]; + Identifier alias_ = cast(Identifier)aliases.data[i]; + + if (!alias_) + alias_ = name; + + TypeIdentifier tname = new TypeIdentifier(loc, name); + AliasDeclaration ad = new AliasDeclaration(loc, alias_, tname); + result |= ad.addMember(sc, sd, memnum); + + aliasdecls.push(cast(void*)ad); + } + + return result; + } + + Dsymbol search(Loc loc, Identifier ident, int flags) + { + //printf("%s.Import.search(ident = '%s', flags = x%x)\n", toChars(), ident.toChars(), flags); + + if (!pkg) + { + load(null); + mod.semantic(); + } + + // Forward it to the package/module + return pkg.search(loc, ident, flags); + } + + bool overloadInsert(Dsymbol s) + { + // Allow multiple imports of the same name + return s.isImport() !is null; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + Import isImport() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/InExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/InExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,46 @@ +module dmd.InExp; + +import dmd.Expression; +import dmd.Identifier; +import dmd.Loc; +import dmd.Scope; +import dmd.IRState; +import dmd.BinExp; +import dmd.TOK; + +import dmd.backend.elem; + +class InExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + assert(false); + super(loc, TOK.init, 0, e1, e2); + } + + Expression semantic(Scope sc) + { + assert(false); + } + + int isBit() + { + assert(false); + } + + Identifier opId() + { + assert(false); + } + + Identifier opId_r() + { + assert(false); + } + + elem* toElem(IRState* irs) + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/IndexExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/IndexExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,427 @@ +module dmd.IndexExp; + +import dmd.Expression; +import dmd.backend.elem; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.VarDeclaration; +import dmd.InlineDoState; +import dmd.Type; +import dmd.ScopeDsymbol; +import dmd.TY; +import dmd.ArrayScopeSymbol; +import dmd.TypeNext; +import dmd.TypeSArray; +import dmd.TypeAArray; +import dmd.UnaExp; +import dmd.IRState; +import dmd.BinExp; +import dmd.HdrGenState; +import dmd.TOK; +import dmd.WANT; +import dmd.TupleExp; +import dmd.TypeTuple; +import dmd.Argument; +import dmd.TypeExp; +import dmd.VarExp; +import dmd.STC; +import dmd.GlobalExpressions; +import dmd.ExpInitializer; +import dmd.Global; + +import dmd.expression.util.arrayTypeCompatible; +import dmd.expression.Util; +import dmd.expression.Index; + +import dmd.backend.Symbol; +import dmd.backend.Util; +import dmd.codegen.Util; +import dmd.backend.OPER; +import dmd.backend.mTY; +import dmd.backend.TYM; + +import core.stdc.string; + +class IndexExp : BinExp +{ + VarDeclaration lengthVar; + int modifiable = 0; // assume it is an rvalue + + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKindex, IndexExp.sizeof, e1, e2); + //printf("IndexExp.IndexExp('%s')\n", toChars()); + } + + Expression semantic(Scope sc) + { + Expression e; + BinExp b; + UnaExp u; + Type t1; + ScopeDsymbol sym; + + version (LOGSEMANTIC) { + printf("IndexExp.semantic('%s')\n", toChars()); + } + if (type) + return this; + if (!e1.type) + e1 = e1.semantic(sc); + assert(e1.type); // semantic() should already be run on it + e = this; + + // Note that unlike C we do not implement the int[ptr] + + t1 = e1.type.toBasetype(); + + if (t1.ty == Tsarray || t1.ty == Tarray || t1.ty == Ttuple) + { + // Create scope for 'length' variable + sym = new ArrayScopeSymbol(sc, this); + sym.loc = loc; + sym.parent = sc.scopesym; + sc = sc.push(sym); + } + + e2 = e2.semantic(sc); + if (!e2.type) + { + error("%s has no value", e2.toChars()); + e2.type = Type.terror; + } + e2 = resolveProperties(sc, e2); + + if (t1.ty == Tsarray || t1.ty == Tarray || t1.ty == Ttuple) + sc = sc.pop(); + + switch (t1.ty) + { + case Tpointer: + case Tarray: + e2 = e2.implicitCastTo(sc, Type.tsize_t); + e.type = (cast(TypeNext)t1).next; + break; + + case Tsarray: + { + e2 = e2.implicitCastTo(sc, Type.tsize_t); + + TypeSArray tsa = cast(TypeSArray)t1; + + static if (false) { + // Don't do now, because it might be short-circuit evaluated + // Do compile time array bounds checking if possible + e2 = e2.optimize(WANTvalue); + if (e2.op == TOKint64) + { + ulong index = e2.toInteger(); + ulong length = tsa.dim.toInteger(); + if (index < 0 || index >= length) + error("array index [%lld] is outside array bounds [0 .. %lld]", index, length); + } + } + e.type = t1.nextOf(); + break; + } + + case Taarray: + { + TypeAArray taa = cast(TypeAArray)t1; + if (!arrayTypeCompatible(e2.loc, e2.type, taa.index)) + { + e2 = e2.implicitCastTo(sc, taa.index); // type checking + } + type = taa.next; + break; + } + + case Ttuple: + { + e2 = e2.implicitCastTo(sc, Type.tsize_t); + e2 = e2.optimize(WANTvalue | WANTinterpret); + ulong index = e2.toUInteger(); + size_t length; + TupleExp te; + TypeTuple tup; + + if (e1.op == TOKtuple) + { + te = cast(TupleExp)e1; + length = te.exps.dim; + } + else if (e1.op == TOKtype) + { + tup = cast(TypeTuple)t1; + length = Argument.dim(tup.arguments); + } + else + assert(0); + + if (index < length) + { + if (e1.op == TOKtuple) + e = cast(Expression)te.exps.data[cast(size_t)index]; + else + e = new TypeExp(e1.loc, Argument.getNth(tup.arguments, cast(size_t)index).type); + } + else + { + error("array index [%ju] is outside array bounds [0 .. %zu]", index, length); + e = e1; + } + break; + } + + default: + error("%s must be an array or pointer type, not %s", e1.toChars(), e1.type.toChars()); + type = Type.tint32; + break; + } + + return e; + } + + int isLvalue() + { + assert(false); + } + + Expression toLvalue(Scope sc, Expression e) + { + // if (type && type.toBasetype().ty == Tvoid) + // error("voids have no value"); + return this; + } + + Expression modifiableLvalue(Scope sc, Expression e) + { + //printf("IndexExp::modifiableLvalue(%s)\n", toChars()); + modifiable = 1; + if (e1.op == TOKstring) + error("string literals are immutable"); + if (type && !type.isMutable()) + error("%s isn't mutable", e.toChars()); + if (e1.type.toBasetype().ty == Taarray) + e1 = e1.modifiableLvalue(sc, e1); + return toLvalue(sc, e); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + Expression optimize(int result) + { + Expression e; + + //printf("IndexExp::optimize(result = %d) %s\n", result, toChars()); + Expression e1 = this.e1.optimize(WANTvalue | (result & WANTinterpret)); + e1 = fromConstInitializer(result, e1); + if (this.e1.op == TOKvar) + { + VarExp ve = cast(VarExp)this.e1; + if (ve.var.storage_class & STCmanifest) + { + /* We generally don't want to have more than one copy of an + * array literal, but if it's an enum we have to because the + * enum isn't stored elsewhere. See Bugzilla 2559 + */ + this.e1 = e1; + } + } + + e2 = e2.optimize(WANTvalue | (result & WANTinterpret)); + e = Index(type, e1, e2); + if (e is EXP_CANT_INTERPRET) + e = this; + + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + Expression doInline(InlineDoState ids) + { + IndexExp are = cast(IndexExp)copy(); + + are.e1 = e1.doInline(ids); + + if (lengthVar) + { //printf("lengthVar\n"); + VarDeclaration vd = lengthVar; + ExpInitializer ie; + ExpInitializer ieto; + VarDeclaration vto; + + vto = new VarDeclaration(vd.loc, vd.type, vd.ident, vd.init); + ///*vto = *vd; + memcpy(cast(void*)vto, cast(void*)vd, VarDeclaration.classinfo.init.length); + vto.parent = ids.parent; + vto.csym = null; + vto.isym = null; + + ids.from.push(cast(void*)vd); + ids.to.push(cast(void*)vto); + + if (vd.init) + { + ie = vd.init.isExpInitializer(); + assert(ie); + ieto = new ExpInitializer(ie.loc, ie.exp.doInline(ids)); + vto.init = ieto; + } + + are.lengthVar = vto; + } + are.e2 = e2.doInline(ids); + return are; + } + + void scanForNestedRef(Scope sc) + { + assert(false); + } + + elem* toElem(IRState* irs) + { + elem* e; + elem* n1 = e1.toElem(irs); + elem* n2; + elem* eb = null; + Type t1; + + //printf("IndexExp.toElem() %s\n", toChars()); + t1 = e1.type.toBasetype(); + if (t1.ty == Taarray) + { + // set to: + // *aaGet(aa, keyti, valuesize, index); + + TypeAArray taa = cast(TypeAArray)t1; + elem* keyti; + elem* ep; + int vsize = cast(int)taa.next.size(); + elem* valuesize; + Symbol* s; + + // n2 becomes the index, also known as the key + n2 = e2.toElem(irs); + if (tybasic(n2.Ety) == TYstruct || tybasic(n2.Ety) == TYarray) + { + n2 = el_una(OPstrpar, TYstruct, n2); + n2.Enumbytes = n2.E1.Enumbytes; + //printf("numbytes = %d\n", n2.Enumbytes); + assert(n2.Enumbytes); + } + valuesize = el_long(TYuint, vsize); // BUG: should be TYsize_t + //printf("valuesize: "); elem_print(valuesize); + if (modifiable) + { + n1 = el_una(OPaddr, TYnptr, n1); + s = taa.aaGetSymbol("Get", 1); + } + else + { + s = taa.aaGetSymbol("GetRvalue", 1); + } + //printf("taa.index = %s\n", taa.index.toChars()); + keyti = taa.index.getInternalTypeInfo(null).toElem(irs); + //keyti = taa.index.getTypeInfo(null).toElem(irs); + //printf("keyti:\n"); + //elem_print(keyti); + ep = el_params(n2, valuesize, keyti, n1, null); + e = el_bin(OPcall, TYnptr, el_var(s), ep); + if (global.params.useArrayBounds) + { + elem* n; + elem* ea; + + n = el_same(&e); + + // Construct: ((e || ModuleAssert(line)),n) + Symbol* sassert; + + sassert = irs.blx.module_.toModuleArray(); + ea = el_bin(OPcall,TYvoid,el_var(sassert), + el_long(TYint, loc.linnum)); + e = el_bin(OPoror,TYvoid,e,ea); + e = el_bin(OPcomma, TYnptr, e, n); + } + e = el_una(OPind, type.totym(), e); + if (tybasic(e.Ety) == TYstruct) + e.Enumbytes = cast(uint)type.size(); + } + else + { + elem* einit; + + einit = resolveLengthVar(lengthVar, &n1, t1); + n2 = e2.toElem(irs); + + if (global.params.useArrayBounds) + { + elem* elength; + elem* n2x; + elem* ea; + + if (t1.ty == Tsarray) + { + TypeSArray tsa = cast(TypeSArray)t1; + ulong length = tsa.dim.toInteger(); + + elength = el_long(TYuint, length); + goto L1; + } + else if (t1.ty == Tarray) + { + elength = n1; + n1 = el_same(&elength); + elength = el_una(OP64_32, TYuint, elength); + L1: + n2x = n2; + n2 = el_same(&n2x); + n2x = el_bin(OPlt, TYint, n2x, elength); + + // Construct: (n2x || ModuleAssert(line)) + Symbol* sassert; + + sassert = irs.blx.module_.toModuleArray(); + ea = el_bin(OPcall,TYvoid,el_var(sassert), + el_long(TYint, loc.linnum)); + eb = el_bin(OPoror,TYvoid,n2x,ea); + } + } + + n1 = array_toPtr(t1, n1); + + { + elem* escale; + + escale = el_long(TYint, t1.nextOf().size()); + n2 = el_bin(OPmul, TYint, n2, escale); + e = el_bin(OPadd, TYnptr, n1, n2); + e = el_una(OPind, type.totym(), e); + if (tybasic(e.Ety) == TYstruct || tybasic(e.Ety) == TYarray) + { + e.Ety = TYstruct; + e.Enumbytes = cast(uint)type.size(); + } + } + + eb = el_combine(einit, eb); + e = el_combine(eb, e); + } + + el_setLoc(e,loc); + + return e; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/Initializer.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Initializer.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,67 @@ +module dmd.Initializer; + +import dmd.Loc; +import dmd.Scope; +import dmd.Type; +import dmd.ArrayTypes; +import dmd.Expression; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.VoidInitializer; +import dmd.StructInitializer; +import dmd.ArrayInitializer; +import dmd.ExpInitializer; + +import dmd.backend.dt_t; + +class Initializer +{ + Loc loc; + + this(Loc loc) + { + this.loc = loc; + } + + Initializer syntaxCopy() + { + assert(false); + } + + Initializer semantic(Scope sc, Type t) + { + assert(false); + } + + Type inferType(Scope sc) + { + assert(false); + } + + abstract Expression toExpression(); + + abstract void toCBuffer(OutBuffer buf, HdrGenState* hgs); + + string toChars() + { + assert(false); + } + + static Initializers arraySyntaxCopy(Initializers *ai) + { + assert(false); + } + + dt_t* toDt() + { + assert(false); + } + + VoidInitializer isVoidInitializer() { return null; } + + StructInitializer isStructInitializer() { return null; } + + ArrayInitializer isArrayInitializer() { return null; } + + ExpInitializer isExpInitializer() { return null; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/InlineCostState.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/InlineCostState.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,31 @@ +module dmd.InlineCostState; + +import dmd.FuncDeclaration; +import dmd.Array; +import dmd.Expression; + +struct InlineCostState +{ + int nested; + int hasthis; + int hdrscan; // !=0 if inline scan for 'header' content + FuncDeclaration fd; +} + +const int COST_MAX = 250; + +int arrayInlineCost(InlineCostState* ics, Array arguments) +{ + int cost = 0; + + if (arguments) + { + for (int i = 0; i < arguments.dim; i++) + { + Expression e = cast(Expression)arguments.data[i]; + if (e) + cost += e.inlineCost(ics); + } + } + return cost; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/InlineDoState.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/InlineDoState.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,48 @@ +module dmd.InlineDoState; + +import dmd.Array; +import dmd.Dsymbol; +import dmd.VarDeclaration; +import dmd.Expression; +import dmd.ArrayTypes; + +class InlineDoState +{ + VarDeclaration vthis; + Array from; // old Dsymbols + Array to; // parallel array of new Dsymbols + Dsymbol parent; // new parent + + this() + { + from = new Array(); + to = new Array(); + } +} + +/****************************** + * Perform doInline() on an array of Expressions. + */ + +Expressions arrayExpressiondoInline(Expressions a, InlineDoState ids) +{ + Expressions newa = null; + + if (a) + { + newa = new Expressions(); + newa.setDim(a.dim); + + for (int i = 0; i < a.dim; i++) + { + Expression e = cast(Expression)a.data[i]; + + if (e) + { + e = e.doInline(ids); + newa.data[i] = cast(void*)e; + } + } + } + return newa; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/InlineScanState.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/InlineScanState.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,97 @@ +module dmd.InlineScanState; + +import dmd.FuncDeclaration; +import dmd.ExpInitializer; +import dmd.Dsymbol; +import dmd.InlineScanState; +import dmd.TupleDeclaration; +import dmd.VarDeclaration; +import dmd.Type; +import dmd.TypeStruct; +import dmd.StructDeclaration; +import dmd.Array; +import dmd.Expression; +import dmd.DsymbolExp; +import dmd.TOK; +import dmd.TY; + +struct InlineScanState +{ + FuncDeclaration fd; // function being scanned +} + +void scanVar(Dsymbol s, InlineScanState* iss) +{ + VarDeclaration vd = s.isVarDeclaration(); + if (vd) + { + TupleDeclaration td = vd.toAlias().isTupleDeclaration(); + if (td) + { + for (size_t i = 0; i < td.objects.dim; i++) + { + DsymbolExp se = cast(DsymbolExp)td.objects.data[i]; + assert(se.op == TOKdsymbol); + scanVar(se.s, iss); + } + } + else + { + // Scan initializer (vd.init) + if (vd.init) + { + ExpInitializer ie = vd.init.isExpInitializer(); + + if (ie) + { + version (DMDV2) { + if (vd.type) + { + Type tb = vd.type.toBasetype(); + if (tb.ty == Tstruct) + { + StructDeclaration sd = (cast(TypeStruct)tb).sym; + if (sd.cpctor) + { + /* The problem here is that if the initializer is a + * function call that returns a struct S with a cpctor: + * S s = foo(); + * the postblit is done by the return statement in foo() + * in s2ir.c, the intermediate code generator. + * But, if foo() is inlined and now the code looks like: + * S s = x; + * the postblit is not there, because such assignments + * are rewritten as s.cpctor(&x) by the front end. + * So, the inlining won't get the postblit called. + * Work around by not inlining these cases. + * A proper fix would be to move all the postblit + * additions to the front end. + */ + return; + } + } + } + } + ie.exp = ie.exp.inlineScan(iss); + } + } + } + } +} + +void arrayInlineScan(InlineScanState* iss, Array arguments) +{ + if (arguments) + { + for (int i = 0; i < arguments.dim; i++) + { + Expression e = cast(Expression)arguments.data[i]; + + if (e) + { + e = e.inlineScan(iss); + arguments.data[i] = cast(void*)e; + } + } + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/IntRange.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/IntRange.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,7 @@ +module dmd.IntRange; + +struct IntRange +{ + ulong imin; + ulong imax; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/IntegerExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/IntegerExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,549 @@ +module dmd.IntegerExp; + +import dmd.Expression; +import dmd.backend.elem; +import dmd.TY; +import dmd.TypeEnum; +import dmd.TypeTypedef; +import dmd.Global; +import dmd.InterState; +import dmd.MATCH; +import dmd.Type; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.IntRange; +import dmd.IRState; +import dmd.HdrGenState; +import dmd.TOK; +import dmd.Complex; + +import dmd.backend.dt_t; +import dmd.backend.Util; + +import core.stdc.ctype : isprint; + +class IntegerExp : Expression +{ + ulong value; + + this(Loc loc, ulong value, Type type) + { + super(loc, TOK.TOKint64, IntegerExp.sizeof); + + //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type.toChars() : ""); + if (type && !type.isscalar()) + { + //printf("%s, loc = %d\n", toChars(), loc.linnum); + error("integral constant must be scalar type, not %s", type.toChars()); + type = Type.terror; + } + this.type = type; + this.value = value; + } + + this(ulong value) + { + super(Loc(0), TOK.TOKint64, IntegerExp.sizeof); + this.type = Type.tint32; + this.value = value; + } + + int equals(Object o) + { + IntegerExp ne; + + if (this == o || + ((cast(Expression)o).op == TOKint64 && + ((ne = cast(IntegerExp)o), type.toHeadMutable().equals(ne.type.toHeadMutable())) && + value == ne.value) + ) + return 1; + + return 0; + } + + Expression semantic(Scope sc) + { + if (!type) + { + // Determine what the type of this number is + ulong number = value; + + if (number & 0x8000000000000000) + type = Type.tuns64; + else if (number & 0xFFFFFFFF80000000) + type = Type.tint64; + else + type = Type.tint32; + } + else + { if (!type.deco) + type = type.semantic(loc, sc); + } + return this; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + string toChars() + { +static if (true) { + return Expression.toChars(); +} else { + static char buffer[value.sizeof * 3 + 1]; + int len = sprintf(buffer.ptr, "%jd", value); + return buffer[0..len].idup; +} + } + + void dump(int indent) + { + assert(false); + } + + IntRange getIntRange() + { + assert(false); + } + + ulong toInteger() + { + Type t; + + t = type; + while (t) + { + switch (t.ty) + { + case TY.Tbit: + case TY.Tbool: value = (value != 0); break; + case TY.Tint8: value = cast(byte) value; break; + case TY.Tchar: + case TY.Tuns8: value = cast(ubyte) value; break; + case TY.Tint16: value = cast(short) value; break; + case TY.Twchar: + case TY.Tuns16: value = cast(ushort)value; break; + case TY.Tint32: value = cast(int) value; break; + case TY.Tdchar: + case TY.Tuns32: value = cast(uint) value; break; + case TY.Tint64: value = cast(long) value; break; + case TY.Tuns64: value = cast(ulong) value; break; + case TY.Tpointer: + if (PTRSIZE == 4) + value = cast(uint) value; + else if (PTRSIZE == 8) + value = cast(ulong) value; + else + assert(0); + break; + + case TY.Tenum: + { + TypeEnum te = cast(TypeEnum)t; + t = te.sym.memtype; + continue; + } + + case TY.Ttypedef: + { + TypeTypedef tt = cast(TypeTypedef)t; + t = tt.sym.basetype; + continue; + } + + default: + /* This can happen if errors, such as + * the type is painted on like in fromConstInitializer(). + */ + if (!global.errors) + { + ///type.print(); + assert(0); + } + break; + } + break; + } + return value; + } + + real toReal() + { + Type t; + + toInteger(); + t = type.toBasetype(); + if (t.ty == Tuns64) + return cast(real)cast(ulong)value; + else + return cast(real)cast(long)value; + } + + real toImaginary() + { + assert(false); + } + + Complex!(real) toComplex() + { + assert(false); + } + + int isConst() + { + return 1; + } + + bool isBool(bool result) + { + return result ? value != 0 : value == 0; + } + + MATCH implicitConvTo(Type t) + { +static if (false) { + printf("IntegerExp.implicitConvTo(this=%s, type=%s, t=%s)\n", + toChars(), type.toChars(), t.toChars()); +} + + MATCH m = type.implicitConvTo(t); + if (m >= MATCH.MATCHconst) + return m; + + TY ty = type.toBasetype().ty; + TY toty = t.toBasetype().ty; + + if (m == MATCH.MATCHnomatch && t.ty == TY.Tenum) + goto Lno; + + switch (ty) + { + case TY.Tbit: + case TY.Tbool: + value &= 1; + ty = TY.Tint32; + break; + + case TY.Tint8: + value = cast(byte)value; + ty = TY.Tint32; + break; + + case TY.Tchar: + case TY.Tuns8: + value &= 0xFF; + ty = TY.Tint32; + break; + + case TY.Tint16: + value = cast(short)value; + ty = TY.Tint32; + break; + + case TY.Tuns16: + case TY.Twchar: + value &= 0xFFFF; + ty = TY.Tint32; + break; + + case TY.Tint32: + value = cast(int)value; + break; + + case TY.Tuns32: + case TY.Tdchar: + value &= 0xFFFFFFFF; + ty = TY.Tuns32; + break; + + default: + break; + } + + // Only allow conversion if no change in value + switch (toty) + { + case TY.Tbit: + case TY.Tbool: + if ((value & 1) != value) + goto Lno; + goto Lyes; + + case TY.Tint8: + if (cast(byte)value != value) + goto Lno; + goto Lyes; + + case TY.Tchar: + case TY.Tuns8: + //printf("value = %llu %llu\n", (dinteger_t)(unsigned char)value, value); + if (cast(ubyte)value != value) + goto Lno; + goto Lyes; + + case TY.Tint16: + if (cast(short)value != value) + goto Lno; + goto Lyes; + + case TY.Tuns16: + if (cast(ushort)value != value) + goto Lno; + goto Lyes; + + case TY.Tint32: + if (ty == TY.Tuns32) { + ; + } + else if (cast(int)value != value) { + goto Lno; + } + goto Lyes; + + case TY.Tuns32: + if (ty == TY.Tint32) { + } else if (cast(uint)value != value) { + goto Lno; + } + goto Lyes; + + case TY.Tdchar: + if (value > 0x10FFFF) { + goto Lno; + } + goto Lyes; + + case TY.Twchar: + if (cast(ushort)value != value) { + goto Lno; + } + goto Lyes; + + case TY.Tfloat32: + { + /*volatile*/ float f; /// + if (type.isunsigned()) { + f = cast(float)value; + if (f != value) { + goto Lno; + } + } else { + f = cast(float)cast(long)value; + if (f != cast(long)value) { + goto Lno; + } + } + goto Lyes; + } + + case TY.Tfloat64: + { + /*volatile*/ double f; /// + if (type.isunsigned()) { + f = cast(double)value; + if (f != value) + goto Lno; + } else { + f = cast(double)cast(long)value; + if (f != cast(long)value) + goto Lno; + } + goto Lyes; + } + + case TY.Tfloat80: + { + /*volatile*/ real f; /// + if (type.isunsigned()) { + f = cast(real)value; + if (f != value) + goto Lno; + } else { + f = cast(real)cast(long)value; + if (f != cast(long)value) + goto Lno; + } + goto Lyes; + } + + case TY.Tpointer: + //printf("type = %s\n", type.toBasetype().toChars()); + //printf("t = %s\n", t.toBasetype().toChars()); + if (ty == TY.Tpointer && type.toBasetype().nextOf().ty == t.toBasetype().nextOf().ty) + { + /* Allow things like: + * const char* P = cast(char *)3; + * char* q = P; + */ + goto Lyes; + } + break; + + default: + break; /// + } + + return Expression.implicitConvTo(t); + + Lyes: + //printf("MATCHconvert\n"); + return MATCH.MATCHconvert; + + Lno: + //printf("MATCHnomatch\n"); + return MATCH.MATCHnomatch; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + long v = toInteger(); + + if (type) + { + Type t = type; + + L1: + switch (t.ty) + { + case TY.Tenum: + { + TypeEnum te = cast(TypeEnum)t; + buf.printf("cast(%s)", te.sym.toChars()); + t = te.sym.memtype; + goto L1; + } + + case TY.Ttypedef: + { + TypeTypedef tt = cast(TypeTypedef)t; + buf.printf("cast(%s)", tt.sym.toChars()); + t = tt.sym.basetype; + goto L1; + } + + case TY.Twchar: // BUG: need to cast(wchar) + case TY.Tdchar: // BUG: need to cast(dchar) + if (cast(ulong)v > 0xFF) + { + buf.printf("'\\U%08x'", v); + break; + } + case TY.Tchar: + if (v == '\'') + buf.writestring("'\\''"); + else if (isprint(cast(int)v) && v != '\\') + buf.printf("'%c'", cast(int)v); + else + buf.printf("'\\x%02x'", cast(int)v); + break; + + case TY.Tint8: + buf.writestring("cast(byte)"); + goto L2; + + case TY.Tint16: + buf.writestring("cast(short)"); + goto L2; + + case TY.Tint32: + L2: + buf.printf("%d", cast(int)v); + break; + + case TY.Tuns8: + buf.writestring("cast(ubyte)"); + goto L3; + + case TY.Tuns16: + buf.writestring("cast(ushort)"); + goto L3; + + case TY.Tuns32: + L3: + buf.printf("%du", cast(uint)v); + break; + + case TY.Tint64: + buf.printf("%jdL", v); + break; + + case TY.Tuns64: + L4: + buf.printf("%juLU", v); + break; + + case TY.Tbit: + case TY.Tbool: + buf.writestring(v ? "true" : "false"); + break; + + case TY.Tpointer: + buf.writestring("cast("); + buf.writestring(t.toChars()); + buf.writeByte(')'); + if (PTRSIZE == 4) + goto L3; + else if (PTRSIZE == 8) + goto L4; + else + assert(0); + + default: + /* This can happen if errors, such as + * the type is painted on like in fromConstInitializer(). + */ + if (!global.errors) + { + debug { + writef("%s\n", t.toChars()); + } + assert(0); + } + break; + } + } + else if (v & 0x8000000000000000L) + buf.printf("0x%jx", v); + else + buf.printf("%jd", v); + } + + void toMangleBuffer(OutBuffer buf) + { + assert(false); + } + + Expression toLvalue(Scope sc, Expression e) + { + if (!e) + e = this; + else if (!loc.filename) + loc = e.loc; + e.error("constant %s is not an lvalue", e.toChars()); + return this; + } + + elem* toElem(IRState* irs) + { + elem* e = el_long(type.totym(), value); + el_setLoc(e,loc); + return e; + } + + dt_t** toDt(dt_t** pdt) + { + //printf("IntegerExp.toDt() %d\n", op); + uint sz = cast(uint)type.size(); + if (value == 0) + pdt = dtnzeros(pdt, sz); + else + pdt = dtnbytes(pdt, sz, cast(char*)&value); + + return pdt; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/InterState.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/InterState.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,16 @@ +module dmd.InterState; + +import dmd.FuncDeclaration; +import dmd.ArrayTypes; +import dmd.Expression; +import dmd.Statement; + +struct InterState +{ + InterState* caller; // calling function's InterState + FuncDeclaration fd; // function being interpreted + Dsymbols vars; // variables used in this function + Statement start; // if !=NULL, start execution at this statement + Statement gotoTarget; // target of EXP_GOTO_INTERPRET result + Expression localThis; // value of 'this', or NULL if none +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/InterfaceDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/InterfaceDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,511 @@ +module dmd.InterfaceDeclaration; + +import dmd.ClassDeclaration; +import dmd.Loc; +import dmd.DsymbolTable; +import dmd.STC; +import dmd.Type; +import dmd.TY; +import dmd.LINK; +import dmd.Argument; +import dmd.Util; +import dmd.TypeTuple; +import dmd.PROT; +import dmd.TypeClass; +import dmd.Identifier; +import dmd.ArrayTypes; +import dmd.Dsymbol; +import dmd.Scope; +import dmd.Global; +import dmd.BaseClass; +import dmd.Id; + +import dmd.backend.Symbol; +import dmd.backend.TYM; +import dmd.backend.dt_t; +import dmd.backend.Util; +import dmd.codegen.Util; +import dmd.backend.SC; +import dmd.backend.FL; +import dmd.backend.LIST; +import dmd.backend.SFL; + +class InterfaceDeclaration : ClassDeclaration +{ +version (DMDV2) { + bool cpp; // true if this is a C++ interface +} + this(Loc loc, Identifier id, BaseClasses baseclasses) + { + super(loc, id, baseclasses); + + if (id is Id.IUnknown) // IUnknown is the root of all COM interfaces + { + com = true; + cpp = true; // IUnknown is also a C++ interface + } + } + + Dsymbol syntaxCopy(Dsymbol s) + { + assert(false); + } + + void semantic(Scope sc) + { + int i; + + //printf("InterfaceDeclaration.semantic(%s), type = %p\n", toChars(), type); + if (inuse) + return; + + if (!sc) + sc = scope_; + if (!parent && sc.parent && !sc.parent.isModule()) + parent = sc.parent; + + type = type.semantic(loc, sc); + handle = type; + + if (!members) // if forward reference + { + //printf("\tinterface '%s' is forward referenced\n", toChars()); + return; + } + if (symtab) // if already done + { + if (!scope_) + return; + } + else + symtab = new DsymbolTable(); + + Scope scx = null; + if (scope_) + { + sc = scope_; + scx = scope_; // save so we don't make redundant copies + scope_ = null; + } + + if (sc.stc & STC.STCdeprecated) + { + isdeprecated = true; + } + + // Expand any tuples in baseclasses[] + for (i = 0; i < baseclasses.dim; ) + { + BaseClass b = cast(BaseClass)baseclasses.data[0]; + b.type = b.type.semantic(loc, sc); + Type tb = b.type.toBasetype(); + + if (tb.ty == TY.Ttuple) + { TypeTuple tup = cast(TypeTuple)tb; + PROT protection = b.protection; + baseclasses.remove(i); + size_t dim = Argument.dim(tup.arguments); + for (size_t j = 0; j < dim; j++) + { Argument arg = Argument.getNth(tup.arguments, j); + b = new BaseClass(arg.type, protection); + baseclasses.insert(i + j, cast(void*)b); + } + } + else + i++; + } + + if (!baseclasses.dim && sc.linkage == LINK.LINKcpp) + cpp = 1; + + // Check for errors, handle forward references + for (i = 0; i < baseclasses.dim; ) + { + TypeClass tc; + BaseClass b; + Type tb; + + b = cast(BaseClass)baseclasses.data[i]; + b.type = b.type.semantic(loc, sc); + tb = b.type.toBasetype(); + if (tb.ty == TY.Tclass) + tc = cast(TypeClass)tb; + else + tc = null; + if (!tc || !tc.sym.isInterfaceDeclaration()) + { + error("base type must be interface, not %s", b.type.toChars()); + baseclasses.remove(i); + continue; + } + else + { + // Check for duplicate interfaces + for (size_t j = 0; j < i; j++) + { + BaseClass b2 = cast(BaseClass)baseclasses.data[j]; + if (b2.base is tc.sym) + error("inherits from duplicate interface %s", b2.base.toChars()); + } + + b.base = tc.sym; + if (b.base == this || isBaseOf2(b.base)) + { + error("circular inheritance of interface"); + baseclasses.remove(i); + continue; + } + if (!b.base.symtab) + { + // Try to resolve forward reference + if (sc.mustsemantic && b.base.scope_) + b.base.semantic(null); + } + if (!b.base.symtab || b.base.scope_ || b.base.inuse) + { + //error("forward reference of base class %s", baseClass.toChars()); + // Forward reference of base, try again later + //printf("\ttry later, forward reference of base %s\n", b.base.toChars()); + scope_ = scx ? scx : new Scope(sc); + scope_.setNoFree(); + scope_.module_.addDeferredSemantic(this); + return; + } + } +static if (false) { + // Inherit const/invariant from base class + storage_class |= b.base.storage_class & STC.STC_TYPECTOR; +} + i++; + } + + interfaces_dim = baseclasses.dim; + interfaces = cast(BaseClass*)baseclasses.data; + + interfaceSemantic(sc); + + if (vtblOffset()) + vtbl.push(cast(void*)this); // leave room at vtbl[0] for classinfo + + // Cat together the vtbl[]'s from base interfaces + for (i = 0; i < interfaces_dim; i++) + { + BaseClass b = interfaces[i]; + + // Skip if b has already appeared + for (int k = 0; k < i; k++) + { + if (b == interfaces[i]) + goto Lcontinue; + } + + // Copy vtbl[] from base class + if (b.base.vtblOffset()) + { int d = b.base.vtbl.dim; + if (d > 1) + { + vtbl.reserve(d - 1); + for (int j = 1; j < d; j++) + vtbl.push(b.base.vtbl.data[j]); + } + } + else + { + vtbl.append(b.base.vtbl); + } + + Lcontinue: + ; + } + + protection = sc.protection; + storage_class |= sc.stc & STC.STC_TYPECTOR; + + for (i = 0; i < members.dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + s.addMember(sc, this, 1); + } + + sc = sc.push(this); + sc.stc &= ~(STC.STCfinal | STC.STCauto | STC.STCscope | STC.STCstatic | + STC.STCabstract | STC.STCdeprecated | STC.STC_TYPECTOR | STC.STCtls | STC.STCgshared); + sc.stc |= storage_class & STC.STC_TYPECTOR; + sc.parent = this; + if (isCOMinterface()) + sc.linkage = LINK.LINKwindows; + else if (isCPPinterface()) + sc.linkage = LINK.LINKcpp; + sc.structalign = 8; + structalign = sc.structalign; + sc.offset = PTRSIZE * 2; + inuse++; + for (i = 0; i < members.dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + s.semantic(sc); + } + inuse--; + //members.print(); + sc.pop(); + //printf("-InterfaceDeclaration.semantic(%s), type = %p\n", toChars(), type); + } + + bool isBaseOf(ClassDeclaration cd, int* poffset) + { + uint j; + + //printf("%s.InterfaceDeclaration.isBaseOf(cd = '%s')\n", toChars(), cd.toChars()); + assert(!baseClass); + for (j = 0; j < cd.interfaces_dim; j++) + { + BaseClass b = cd.interfaces[j]; + + //printf("\tbase %s\n", b.base.toChars()); + if (this == b.base) + { + //printf("\tfound at offset %d\n", b.offset); + if (poffset) + { + *poffset = b.offset; + if (j && cd.isInterfaceDeclaration()) + *poffset = OFFSET_RUNTIME; + } + return true; + } + if (isBaseOf(b, poffset)) + { + if (j && poffset && cd.isInterfaceDeclaration()) + *poffset = OFFSET_RUNTIME; + return true; + } + } + + if (cd.baseClass && isBaseOf(cd.baseClass, poffset)) + return true; + + if (poffset) + *poffset = 0; + return false; + } + + bool isBaseOf(BaseClass bc, int* poffset) + { + assert(false); + } + + string kind() + { + assert(false); + } + + /**************************************** + * Determine if slot 0 of the vtbl[] is reserved for something else. + * For class objects, yes, this is where the ClassInfo ptr goes. + * For COM interfaces, no. + * For non-COM interfaces, yes, this is where the Interface ptr goes. + */ + int vtblOffset() + { + if (isCOMinterface() || isCPPinterface()) + return 0; + return 1; + } + +version (DMDV2) { + bool isCPPinterface() + { + return cpp; + } +} + bool isCOMinterface() + { + return com; + } + + void toObjFile(int multiobj) // compile to .obj file + { + uint i; + uint offset; + Symbol* sinit; + SC scclass; + + //printf("InterfaceDeclaration.toObjFile('%s')\n", toChars()); + + if (!members) + return; + + if (global.params.symdebug) + toDebug(); + + scclass = SCglobal; + if (inTemplateInstance()) + scclass = SCcomdat; + + // Put out the members + for (i = 0; i < members.dim; i++) + { + Dsymbol member; + + member = cast(Dsymbol)members.data[i]; + if (!member.isFuncDeclaration()) + member.toObjFile(0); + } + + // Generate C symbols + toSymbol(); + + ////////////////////////////////////////////// + + // Put out the TypeInfo + type.getTypeInfo(null); + type.vtinfo.toObjFile(multiobj); + + ////////////////////////////////////////////// + + // Put out the ClassInfo + csym.Sclass = scclass; + csym.Sfl = FLdata; + + /* The layout is: + { + void **vptr; + monitor_t monitor; + byte[] initializer; // static initialization data + char[] name; // class name + void *[] vtbl; + Interface[] interfaces; + Object *base; // base class + void *destructor; + void *invariant; // class invariant + uint flags; + void *deallocator; + OffsetTypeInfo[] offTi; + void *defaultConstructor; + #if DMDV2 + const(MemberInfo[]) function(string) xgetMembers; // module getMembers() function + #endif + TypeInfo typeinfo; + } + */ + dt_t *dt = null; + + if (classinfo) + dtxoff(&dt, classinfo.toVtblSymbol(), 0, TYnptr); // vtbl for ClassInfo + else + dtdword(&dt, 0); // BUG: should be an assert() + dtdword(&dt, 0); // monitor + + // initializer[] + dtdword(&dt, 0); // size + dtdword(&dt, 0); // initializer + + // name[] + string name = toPrettyChars(); + size_t namelen = name.length; + dtdword(&dt, namelen); + dtabytes(&dt, TYnptr, 0, namelen + 1, toStringz(name)); + + // vtbl[] + dtdword(&dt, 0); + dtdword(&dt, 0); + + // vtblInterfaces.data[] + dtdword(&dt, vtblInterfaces.dim); + if (vtblInterfaces.dim) + { + if (classinfo) + assert(classinfo.structsize == CLASSINFO_SIZE); + offset = CLASSINFO_SIZE; + dtxoff(&dt, csym, offset, TYnptr); // (*) + } + else + dtdword(&dt, 0); + + // base + assert(!baseClass); + dtdword(&dt, 0); + + // dtor + dtdword(&dt, 0); + + // invariant + dtdword(&dt, 0); + + // flags + dtdword(&dt, 4 | isCOMinterface() | 32); + + // deallocator + dtdword(&dt, 0); + + // offTi[] + dtdword(&dt, 0); + dtdword(&dt, 0); // null for now, fix later + + // defaultConstructor + dtdword(&dt, 0); + + version (DMDV2) { + // xgetMembers + dtdword(&dt, 0); + } + + dtxoff(&dt, type.vtinfo.toSymbol(), 0, TYnptr); // typeinfo + + ////////////////////////////////////////////// + + // Put out vtblInterfaces.data[]. Must immediately follow csym, because + // of the fixup (*) + + offset += vtblInterfaces.dim * (4 * PTRSIZE); + for (i = 0; i < vtblInterfaces.dim; i++) + { + BaseClass b = cast(BaseClass)vtblInterfaces.data[i]; + ClassDeclaration id = b.base; + + // ClassInfo + dtxoff(&dt, id.toSymbol(), 0, TYnptr); + + // vtbl[] + dtdword(&dt, 0); + dtdword(&dt, 0); + + // this offset + dtdword(&dt, b.offset); + } + + csym.Sdt = dt; + version (ELFOBJ) { + csym.Sseg = CDATA; + } + version (MACHOBJ) { + csym.Sseg = DATA; + } + outdata(csym); + if (isExport()) + obj_export(csym,0); + } + + /************************************* + * Create the "InterfaceInfo" symbol + */ + Symbol* toSymbol() + { + if (!csym) + { + Symbol *s; + + if (!scc) + scc = fake_classsym(Id.ClassInfo); + + s = toSymbolX("__Interface", SCextern, scc.Stype, "Z"); + s.Sfl = FLextern; + s.Sflags |= SFLnodebug; + csym = s; + slist_add(s); + } + return csym; + } + + InterfaceDeclaration isInterfaceDeclaration() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/InvariantDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/InvariantDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,90 @@ +module dmd.InvariantDeclaration; + +import dmd.FuncDeclaration; +import dmd.Loc; +import dmd.Dsymbol; +import dmd.Id; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.LINK; +import dmd.STC; +import dmd.TypeFunction; +import dmd.Type; +import dmd.AggregateDeclaration; + +class InvariantDeclaration : FuncDeclaration +{ + this(Loc loc, Loc endloc) + { + super(loc, endloc, Id.classInvariant, STCundefined, null); + } + + Dsymbol syntaxCopy(Dsymbol s) + { + assert(!s); + InvariantDeclaration id = new InvariantDeclaration(loc, endloc); + FuncDeclaration.syntaxCopy(id); + return id; + } + + void semantic(Scope sc) + { + AggregateDeclaration ad; + Type tret; + + parent = sc.parent; + Dsymbol parent = toParent(); + ad = parent.isAggregateDeclaration(); + if (!ad) + { + error("invariants are only for struct/union/class definitions"); + return; + } + else if (ad.inv && ad.inv != this) + { + error("more than one invariant for %s", ad.toChars()); + } + ad.inv = this; + type = new TypeFunction(null, Type.tvoid, false, LINKd); + + sc = sc.push(); + sc.stc &= ~STCstatic; // not a static invariant + sc.incontract++; + sc.linkage = LINK.LINKd; + + FuncDeclaration.semantic(sc); + + sc.pop(); + } + + bool isVirtual() + { + return false; + } + + bool addPreInvariant() + { + return false; + } + + bool addPostInvariant() + { + return false; + } + + void emitComment(Scope sc) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + if (hgs.hdrgen) + return; + buf.writestring("invariant"); + bodyToCBuffer(buf, hgs); + } + + InvariantDeclaration isInvariantDeclaration() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/IsExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/IsExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,323 @@ +module dmd.IsExp; + +import dmd.Expression; +import dmd.Identifier; +import dmd.ArrayTypes; +import dmd.Type; +import dmd.TOK; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.HdrGenState; +import dmd.TY; +import dmd.TypeEnum; +import dmd.STC; +import dmd.TypeClass; +import dmd.TemplateParameter; +import dmd.BaseClass; +import dmd.ClassDeclaration; +import dmd.TypeStruct; +import dmd.TypeTypedef; +import dmd.IntegerExp; +import dmd.AliasDeclaration; +import dmd.Dsymbol; +import dmd.TypeTuple; +import dmd.TypeDelegate; +import dmd.Declaration; +import dmd.TypeFunction; +import dmd.MATCH; +import dmd.TypePointer; +import dmd.Argument; + +class IsExp : Expression +{ + /* is(targ id tok tspec) + * is(targ id == tok2) + */ + Type targ; + Identifier id; // can be null + TOK tok; // ':' or '==' + Type tspec; // can be null + TOK tok2; // 'struct', 'union', 'typedef', etc. + TemplateParameters parameters; + + this(Loc loc, Type targ, Identifier id, TOK tok, Type tspec, TOK tok2, TemplateParameters parameters) + { + super(loc, TOK.TOKis, IsExp.sizeof); + + this.targ = targ; + this.id = id; + this.tok = tok; + this.tspec = tspec; + this.tok2 = tok2; + this.parameters = parameters; + } + + Expression syntaxCopy() + { + assert(false); + } + + Expression semantic(Scope sc) + { + Type tded; + + /* is(targ id tok tspec) + * is(targ id == tok2) + */ + + //printf("IsExp.semantic(%s)\n", toChars()); + if (id && !(sc.flags & SCOPE.SCOPEstaticif)) + error("can only declare type aliases within static if conditionals"); + + Type t = targ.trySemantic(loc, sc); + if (!t) + goto Lno; // errors, so condition is false + targ = t; + if (tok2 != TOK.TOKreserved) + { + switch (tok2) + { + case TOKtypedef: + if (targ.ty != Ttypedef) + goto Lno; + tded = (cast(TypeTypedef)targ).sym.basetype; + break; + + case TOKstruct: + if (targ.ty != Tstruct) + goto Lno; + if ((cast(TypeStruct)targ).sym.isUnionDeclaration()) + goto Lno; + tded = targ; + break; + + case TOKunion: + if (targ.ty != Tstruct) + goto Lno; + if (!(cast(TypeStruct)targ).sym.isUnionDeclaration()) + goto Lno; + tded = targ; + break; + + case TOKclass: + if (targ.ty != Tclass) + goto Lno; + if ((cast(TypeClass)targ).sym.isInterfaceDeclaration()) + goto Lno; + tded = targ; + break; + + case TOKinterface: + if (targ.ty != Tclass) + goto Lno; + if (!(cast(TypeClass)targ).sym.isInterfaceDeclaration()) + goto Lno; + tded = targ; + break; + version (DMDV2) { + case TOKconst: + if (!targ.isConst()) + goto Lno; + tded = targ; + break; + + case TOKinvariant: + case TOKimmutable: + if (!targ.isInvariant()) + goto Lno; + tded = targ; + break; + + case TOKshared: + if (!targ.isShared()) + goto Lno; + tded = targ; + break; + } + + case TOKsuper: + // If class or interface, get the base class and interfaces + if (targ.ty != Tclass) + goto Lno; + else + { ClassDeclaration cd = (cast(TypeClass)targ).sym; + Arguments args = new Arguments; + args.reserve(cd.baseclasses.dim); + for (size_t i = 0; i < cd.baseclasses.dim; i++) + { + BaseClass b = cast(BaseClass)cd.baseclasses.data[i]; + args.push(cast(void*)new Argument(STCin, b.type, null, null)); + } + tded = new TypeTuple(args); + } + break; + + case TOKenum: + if (targ.ty != Tenum) + goto Lno; + tded = (cast(TypeEnum)targ).sym.memtype; + break; + + case TOKdelegate: + if (targ.ty != Tdelegate) + goto Lno; + tded = (cast(TypeDelegate)targ).next; // the underlying function type + break; + + case TOKfunction: + { + if (targ.ty != Tfunction) + goto Lno; + tded = targ; + + /* Generate tuple from function parameter types. + */ + assert(tded.ty == Tfunction); + Arguments params = (cast(TypeFunction)tded).parameters; + size_t dim = Argument.dim(params); + Arguments args = new Arguments; + args.reserve(dim); + for (size_t i = 0; i < dim; i++) + { + Argument arg = Argument.getNth(params, i); + assert(arg && arg.type); + args.push(cast(void*)new Argument(arg.storageClass, arg.type, null, null)); + } + tded = new TypeTuple(args); + break; + } + + case TOKreturn: + /* Get the 'return type' for the function, + * delegate, or pointer to function. + */ + if (targ.ty == Tfunction) + tded = (cast(TypeFunction)targ).next; + else if (targ.ty == Tdelegate) + { tded = (cast(TypeDelegate)targ).next; + tded = (cast(TypeFunction)tded).next; + } + else if (targ.ty == Tpointer && + (cast(TypePointer)targ).next.ty == Tfunction) + { tded = (cast(TypePointer)targ).next; + tded = (cast(TypeFunction)tded).next; + } + else + goto Lno; + break; + + default: + assert(0); + } + goto Lyes; + } + else if (id && tspec) + { + /* Evaluate to true if targ matches tspec. + * If true, declare id as an alias for the specialized type. + */ + + MATCH m; + assert(parameters && parameters.dim); + + scope Objects dedtypes = new Objects(); + dedtypes.setDim(parameters.dim); + dedtypes.zero(); + + m = targ.deduceType(null, tspec, parameters, dedtypes); + if (m == MATCHnomatch || + (m != MATCHexact && tok == TOKequal)) + { + goto Lno; + } + else + { + tded = cast(Type)dedtypes.data[0]; + if (!tded) + tded = targ; + + scope Objects tiargs = new Objects(); + tiargs.setDim(1); + tiargs.data[0] = cast(void*)targ; + + /* Declare trailing parameters + */ + for (int i = 1; i < parameters.dim; i++) + { + TemplateParameter tp = cast(TemplateParameter)parameters.data[i]; + Declaration s = null; + + m = tp.matchArg(sc, tiargs, i, parameters, dedtypes, &s); + if (m == MATCHnomatch) + goto Lno; + s.semantic(sc); + if (!sc.insert(s)) + error("declaration %s is already defined", s.toChars()); + static if (false) { + Object o = cast(Object)dedtypes.data[i]; + Dsymbol s = TemplateDeclaration.declareParameter(loc, sc, tp, o); + } + if (sc.sd) + s.addMember(sc, sc.sd, 1); + } + + goto Lyes; + } + } + else if (id) + { + /* Declare id as an alias for type targ. Evaluate to true + */ + tded = targ; + goto Lyes; + } + else if (tspec) + { + /* Evaluate to true if targ matches tspec + * is(targ == tspec) + * is(targ : tspec) + */ + tspec = tspec.semantic(loc, sc); + //printf("targ = %s\n", targ.toChars()); + //printf("tspec = %s\n", tspec.toChars()); + if (tok == TOKcolon) + { + if (targ.implicitConvTo(tspec)) + goto Lyes; + else + goto Lno; + } + else /* == */ + { + if (targ.equals(tspec)) + goto Lyes; + else + goto Lno; + } + } + + Lyes: + if (id) + { + Dsymbol s = new AliasDeclaration(loc, id, tded); + s.semantic(sc); + if (!sc.insert(s)) + error("declaration %s is already defined", s.toChars()); + if (sc.sd) + s.addMember(sc, sc.sd, 1); + } + //printf("Lyes\n"); + return new IntegerExp(loc, 1, Type.tbool); + + Lno: + //printf("Lno\n"); + return new IntegerExp(loc, 0, Type.tbool); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/Keyword.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Keyword.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,9 @@ +module dmd.Keyword; + +import dmd.TOK; + +struct Keyword +{ + string name; + TOK value; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/LINK.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/LINK.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,14 @@ +module dmd.LINK; + +enum LINK +{ + LINKdefault, + LINKd, + LINKc, + LINKcpp, + LINKwindows, + LINKpascal, +} + +import dmd.EnumUtils; +mixin(BringToCurrentScope!(LINK)); \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/LabelDsymbol.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/LabelDsymbol.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,24 @@ +module dmd.LabelDsymbol; + +import dmd.Dsymbol; +import dmd.LabelStatement; +import dmd.Identifier; + +class LabelDsymbol : Dsymbol +{ + LabelStatement statement; + +version (IN_GCC) { + uint asmLabelNum; // GCC-specific +} + + this(Identifier ident) + { + super(ident); + } + + LabelDsymbol isLabel() + { + return this; + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/LabelStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/LabelStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,153 @@ +module dmd.LabelStatement; + +import dmd.Statement; +import dmd.Identifier; +import dmd.TryFinallyStatement; +import dmd.Scope; +import dmd.Loc; +import dmd.ExpStatement; +import dmd.ArrayTypes; +import dmd.Expression; +import dmd.InterState; +import dmd.InlineScanState; +import dmd.LabelDsymbol; +import dmd.FuncDeclaration; +import dmd.CSX; +import dmd.IRState; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.BE; + +import dmd.backend.block; +import dmd.backend.Blockx; +import dmd.backend.Util; +import dmd.backend.BC; + +class LabelStatement : Statement +{ + Identifier ident; + Statement statement; + TryFinallyStatement tf = null; + block* lblock = null; // back end + int isReturnLabel = 0; + + this(Loc loc, Identifier ident, Statement statement) + { + super(loc); + this.ident = ident; + this.statement = statement; + } + + Statement syntaxCopy() + { + LabelStatement s = new LabelStatement(loc, ident, statement.syntaxCopy()); + return s; + } + + Statement semantic(Scope sc) + { + LabelDsymbol ls; + FuncDeclaration fd = sc.parent.isFuncDeclaration(); + + //printf("LabelStatement.semantic()\n"); + ls = fd.searchLabel(ident); + if (ls.statement) + error("Label '%s' already defined", ls.toChars()); + else + ls.statement = this; + tf = sc.tf; + sc = sc.push(); + sc.scopesym = sc.enclosing.scopesym; + sc.callSuper |= CSXlabel; + sc.slabel = this; + if (statement) + statement = statement.semantic(sc); + sc.pop(); + return this; + } + + Statements flatten(Scope sc) + { + Statements a = null; + + if (statement) + { + a = statement.flatten(sc); + if (a) + { + if (!a.dim) + a.push(cast(void*)new ExpStatement(loc, null)); + + Statement s = cast(Statement)a.data[0]; + + s = new LabelStatement(loc, ident, s); + a.data[0] = cast(void*)s; + } + } + + return a; + } + + bool usesEH() + { + return statement ? statement.usesEH() : false; + } + + BE blockExit() + { + //printf("LabelStatement.blockExit(%p)\n", this); + return statement ? statement.blockExit() : BE.BEfallthru; + } + + bool comeFrom() + { + //printf("LabelStatement.comeFrom()\n"); + return true; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + buf.writestring(ident.toChars()); + buf.writebyte(':'); + buf.writenl(); + if (statement) + statement.toCBuffer(buf, hgs); + } + + Statement inlineScan(InlineScanState* iss) + { + if (statement) + statement = statement.inlineScan(iss); + return this; + } + + void toIR(IRState* irs) + { + //printf("LabelStatement.toIR() %p, statement = %p\n", this, statement); + Blockx* blx = irs.blx; + block* bc = blx.curblock; + IRState mystate = IRState(irs,this); + mystate.ident = ident; + + if (lblock) + { + // We had made a guess about which tryblock the label is in. + // Error if we guessed wrong. + // BUG: should fix this + if (lblock.Btry != blx.tryblock) + error("cannot goto forward into different try block level"); + } + else + lblock = block_calloc(blx); + + block_next(blx,BCgoto,lblock); + list_append(&bc.Bsucc,blx.curblock); + if (statement) + statement.toIR(&mystate); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/Lexer.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Lexer.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,2425 @@ +module dmd.Lexer; + +import dmd.StringTable; +import dmd.OutBuffer; +import dmd.Token; +import dmd.Loc; +import dmd.Module; +import dmd.Identifier; +import dmd.TOK; +import dmd.Keyword; +import dmd.StringValue; +import dmd.Global; +import dmd.Util; +import dmd.Id; +import dmd.Dchar; +import dmd.Utf; + +import std.stdio : writeln; + +import core.stdc.ctype; +import core.stdc.stdlib; +import core.stdc.string; +import core.stdc.stdio; +import core.stdc.time; +import core.stdc.errno; + +enum LS = 0x2028; // UTF line separator +enum PS = 0x2029; // UTF paragraph separator + +extern (C) extern +{ + __gshared char* __locale_decpoint; +} + +int isUniAlpha(uint u) +{ + assert(false); +} + +class Lexer +{ + static StringTable stringtable; + static OutBuffer stringbuffer; + static Token* freelist; + + Loc loc; // for error messages + + ubyte* base; // pointer to start of buffer + ubyte* end; // past end of buffer + ubyte* p; // current character + Token token; + Module mod; + int doDocComment; // collect doc comment information + int anyToken; // !=0 means seen at least one token + int commentToken; // !=0 means comments are TOKcomment's + + static this() + { + stringtable = new StringTable(); + stringbuffer = new OutBuffer(); + } + + static ~this() + { + delete stringtable; + } + + this(Module mod, ubyte* base, uint begoffset, uint endoffset, int doDocComment, int commentToken) + { + loc = Loc(mod, 1); + + memset(&token,0,token.sizeof); + this.base = base; + this.end = base + endoffset; + p = base + begoffset; + this.mod = mod; + this.doDocComment = doDocComment; + this.anyToken = 0; + this.commentToken = commentToken; + //initKeywords(); + + /* If first line starts with '#!', ignore the line + */ + + if (p[0] == '#' && p[1] =='!') + { + p += 2; + while (1) + { + ubyte c = *p; + switch (c) + { + case '\n': + p++; + break; + + case '\r': + p++; + if (*p == '\n') + p++; + break; + + case 0: + case 0x1A: + break; + + default: + if (c & 0x80) + { + uint u = decodeUTF(); + if (u == PS || u == LS) + break; + } + p++; + continue; + } + break; + } + loc.linnum = 2; + } + } + +version (DMDV2) { + static Keyword[] keywords = + [ + // { "", TOK }, + + { "this", TOK.TOKthis }, + { "super", TOK.TOKsuper }, + { "assert", TOK.TOKassert }, + { "null", TOK.TOKnull }, + { "true", TOK.TOKtrue }, + { "false", TOK.TOKfalse }, + { "cast", TOK.TOKcast }, + { "new", TOK.TOKnew }, + { "delete", TOK.TOKdelete }, + { "throw", TOK.TOKthrow }, + { "module", TOK.TOKmodule }, + { "pragma", TOK.TOKpragma }, + { "typeof", TOK.TOKtypeof }, + { "typeid", TOK.TOKtypeid }, + + { "template", TOK.TOKtemplate }, + + { "void", TOK.TOKvoid }, + { "byte", TOK.TOKint8 }, + { "ubyte", TOK.TOKuns8 }, + { "short", TOK.TOKint16 }, + { "ushort", TOK.TOKuns16 }, + { "int", TOK.TOKint32 }, + { "uint", TOK.TOKuns32 }, + { "long", TOK.TOKint64 }, + { "ulong", TOK.TOKuns64 }, + { "cent", TOK.TOKcent, }, + { "ucent", TOK.TOKucent, }, + { "float", TOK.TOKfloat32 }, + { "double", TOK.TOKfloat64 }, + { "real", TOK.TOKfloat80 }, + + { "bool", TOK.TOKbool }, + { "char", TOK.TOKchar }, + { "wchar", TOK.TOKwchar }, + { "dchar", TOK.TOKdchar }, + + { "ifloat", TOK.TOKimaginary32 }, + { "idouble", TOK.TOKimaginary64 }, + { "ireal", TOK.TOKimaginary80 }, + + { "cfloat", TOK.TOKcomplex32 }, + { "cdouble", TOK.TOKcomplex64 }, + { "creal", TOK.TOKcomplex80 }, + + { "delegate", TOK.TOKdelegate }, + { "function", TOK.TOKfunction }, + + { "is", TOK.TOKis }, + { "if", TOK.TOKif }, + { "else", TOK.TOKelse }, + { "while", TOK.TOKwhile }, + { "for", TOK.TOKfor }, + { "do", TOK.TOKdo }, + { "switch", TOK.TOKswitch }, + { "case", TOK.TOKcase }, + { "default", TOK.TOKdefault }, + { "break", TOK.TOKbreak }, + { "continue", TOK.TOKcontinue }, + { "synchronized", TOK.TOKsynchronized }, + { "return", TOK.TOKreturn }, + { "goto", TOK.TOKgoto }, + { "try", TOK.TOKtry }, + { "catch", TOK.TOKcatch }, + { "finally", TOK.TOKfinally }, + { "with", TOK.TOKwith }, + { "asm", TOK.TOKasm }, + { "foreach", TOK.TOKforeach }, + { "foreach_reverse", TOK.TOKforeach_reverse }, + { "scope", TOK.TOKscope }, + + { "struct", TOK.TOKstruct }, + { "class", TOK.TOKclass }, + { "interface", TOK.TOKinterface }, + { "union", TOK.TOKunion }, + { "enum", TOK.TOKenum }, + { "import", TOK.TOKimport }, + { "mixin", TOK.TOKmixin }, + { "static", TOK.TOKstatic }, + { "final", TOK.TOKfinal }, + { "const", TOK.TOKconst }, + { "typedef", TOK.TOKtypedef }, + { "alias", TOK.TOKalias }, + { "override", TOK.TOKoverride }, + { "abstract", TOK.TOKabstract }, + { "volatile", TOK.TOKvolatile }, + { "debug", TOK.TOKdebug }, + { "deprecated", TOK.TOKdeprecated }, + { "in", TOK.TOKin }, + { "out", TOK.TOKout }, + { "inout", TOK.TOKinout }, + { "lazy", TOK.TOKlazy }, + { "auto", TOK.TOKauto }, + + { "align", TOK.TOKalign }, + { "extern", TOK.TOKextern }, + { "private", TOK.TOKprivate }, + { "package", TOK.TOKpackage }, + { "protected", TOK.TOKprotected }, + { "public", TOK.TOKpublic }, + { "export", TOK.TOKexport }, + + { "body", TOK.TOKbody }, + { "invariant", TOK.TOKinvariant }, + { "unittest", TOK.TOKunittest }, + { "version", TOK.TOKversion }, + //{ "manifest", TOK.TOKmanifest }, + + // Added after 1.0 + { "ref", TOK.TOKref }, + { "macro", TOK.TOKmacro }, + { "pure", TOK.TOKpure }, + { "nothrow", TOK.TOKnothrow }, + { "__thread", TOK.TOKtls }, + { "__gshared", TOK.TOKgshared }, + { "__traits", TOK.TOKtraits }, + { "__overloadset", TOK.TOKoverloadset }, + { "__FILE__", TOK.TOKfile }, + { "__LINE__", TOK.TOKline }, + { "shared", TOK.TOKshared }, + { "immutable", TOK.TOKimmutable }, + ]; +} else { + static Keyword[] keywords = + [ + // { "", TOK }, + + { "this", TOK.TOKthis }, + { "super", TOK.TOKsuper }, + { "assert", TOK.TOKassert }, + { "null", TOK.TOKnull }, + { "true", TOK.TOKtrue }, + { "false", TOK.TOKfalse }, + { "cast", TOK.TOKcast }, + { "new", TOK.TOKnew }, + { "delete", TOK.TOKdelete }, + { "throw", TOK.TOKthrow }, + { "module", TOK.TOKmodule }, + { "pragma", TOK.TOKpragma }, + { "typeof", TOK.TOKtypeof }, + { "typeid", TOK.TOKtypeid }, + + { "template", TOK.TOKtemplate }, + + { "void", TOK.TOKvoid }, + { "byte", TOK.TOKint8 }, + { "ubyte", TOK.TOKuns8 }, + { "short", TOK.TOKint16 }, + { "ushort", TOK.TOKuns16 }, + { "int", TOK.TOKint32 }, + { "uint", TOK.TOKuns32 }, + { "long", TOK.TOKint64 }, + { "ulong", TOK.TOKuns64 }, + { "cent", TOK.TOKcent, }, + { "ucent", TOK.TOKucent, }, + { "float", TOK.TOKfloat32 }, + { "double", TOK.TOKfloat64 }, + { "real", TOK.TOKfloat80 }, + + { "bool", TOK.TOKbool }, + { "char", TOK.TOKchar }, + { "wchar", TOK.TOKwchar }, + { "dchar", TOK.TOKdchar }, + + { "ifloat", TOK.TOKimaginary32 }, + { "idouble", TOK.TOKimaginary64 }, + { "ireal", TOK.TOKimaginary80 }, + + { "cfloat", TOK.TOKcomplex32 }, + { "cdouble", TOK.TOKcomplex64 }, + { "creal", TOK.TOKcomplex80 }, + + { "delegate", TOK.TOKdelegate }, + { "function", TOK.TOKfunction }, + + { "is", TOK.TOKis }, + { "if", TOK.TOKif }, + { "else", TOK.TOKelse }, + { "while", TOK.TOKwhile }, + { "for", TOK.TOKfor }, + { "do", TOK.TOKdo }, + { "switch", TOK.TOKswitch }, + { "case", TOK.TOKcase }, + { "default", TOK.TOKdefault }, + { "break", TOK.TOKbreak }, + { "continue", TOK.TOKcontinue }, + { "synchronized", TOK.TOKsynchronized }, + { "return", TOK.TOKreturn }, + { "goto", TOK.TOKgoto }, + { "try", TOK.TOKtry }, + { "catch", TOK.TOKcatch }, + { "finally", TOK.TOKfinally }, + { "with", TOK.TOKwith }, + { "asm", TOK.TOKasm }, + { "foreach", TOK.TOKforeach }, + { "foreach_reverse", TOK.TOKforeach_reverse }, + { "scope", TOK.TOKscope }, + + { "struct", TOK.TOKstruct }, + { "class", TOK.TOKclass }, + { "interface", TOK.TOKinterface }, + { "union", TOK.TOKunion }, + { "enum", TOK.TOKenum }, + { "import", TOK.TOKimport }, + { "mixin", TOK.TOKmixin }, + { "static", TOK.TOKstatic }, + { "final", TOK.TOKfinal }, + { "const", TOK.TOKconst }, + { "typedef", TOK.TOKtypedef }, + { "alias", TOK.TOKalias }, + { "override", TOK.TOKoverride }, + { "abstract", TOK.TOKabstract }, + { "volatile", TOK.TOKvolatile }, + { "debug", TOK.TOKdebug }, + { "deprecated", TOK.TOKdeprecated }, + { "in", TOK.TOKin }, + { "out", TOK.TOKout }, + { "inout", TOK.TOKinout }, + { "lazy", TOK.TOKlazy }, + { "auto", TOK.TOKauto }, + + { "align", TOK.TOKalign }, + { "extern", TOK.TOKextern }, + { "private", TOK.TOKprivate }, + { "package", TOK.TOKpackage }, + { "protected", TOK.TOKprotected }, + { "public", TOK.TOKpublic }, + { "export", TOK.TOKexport }, + + { "body", TOK.TOKbody }, + { "invariant", TOK.TOKinvariant }, + { "unittest", TOK.TOKunittest }, + { "version", TOK.TOKversion }, + //{ "manifest", TOK.TOKmanifest }, + + // Added after 1.0 + { "ref", TOK.TOKref }, + { "macro", TOK.TOKmacro }, + ]; +} + + static ubyte cmtable[256]; + enum CMoctal = 0x1; + enum CMhex = 0x2; + enum CMidchar = 0x4; + + ubyte isoctal (ubyte c) { return cmtable[c] & CMoctal; } + ubyte ishex (ubyte c) { return cmtable[c] & CMhex; } + ubyte isidchar(ubyte c) { return cmtable[c] & CMidchar; } + + static void cmtable_init() + { + for (uint c = 0; c < cmtable.length; c++) + { + if ('0' <= c && c <= '7') + cmtable[c] |= CMoctal; + if (isdigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')) + cmtable[c] |= CMhex; + if (isalnum(c) || c == '_') + cmtable[c] |= CMidchar; + } + } + + static void initKeywords() + { + uint nkeywords = keywords.length; + + if (global.params.Dversion == 1) + nkeywords -= 2; + + cmtable_init(); + + for (uint u = 0; u < nkeywords; u++) + { + //printf("keyword[%d] = '%s'\n",u, keywords[u].name); + string s = keywords[u].name; + TOK v = keywords[u].value; + StringValue* sv = stringtable.insert(s); + sv.ptrvalue = cast(void*) new Identifier(sv.lstring.string_, v); + + //printf("tochars[%d] = '%s'\n",v, s); + Token.tochars[v] = s; + } + + Token.tochars[TOK.TOKeof] = "EOF"; + Token.tochars[TOK.TOKlcurly] = "{"; + Token.tochars[TOK.TOKrcurly] = "}"; + Token.tochars[TOK.TOKlparen] = "("; + Token.tochars[TOK.TOKrparen] = ")"; + Token.tochars[TOK.TOKlbracket] = "["; + Token.tochars[TOK.TOKrbracket] = "]"; + Token.tochars[TOK.TOKsemicolon] = ";"; + Token.tochars[TOK.TOKcolon] = ":"; + Token.tochars[TOK.TOKcomma] = ","; + Token.tochars[TOK.TOKdot] = "."; + Token.tochars[TOK.TOKxor] = "^"; + Token.tochars[TOK.TOKxorass] = "^="; + Token.tochars[TOK.TOKassign] = "="; + Token.tochars[TOK.TOKconstruct] = "="; +version (DMDV2) { + Token.tochars[TOK.TOKblit] = "="; +} + Token.tochars[TOK.TOKlt] = "<"; + Token.tochars[TOK.TOKgt] = ">"; + Token.tochars[TOK.TOKle] = "<="; + Token.tochars[TOK.TOKge] = ">="; + Token.tochars[TOK.TOKequal] = "=="; + Token.tochars[TOK.TOKnotequal] = "!="; + Token.tochars[TOK.TOKnotidentity] = "!is"; + Token.tochars[TOK.TOKtobool] = "!!"; + + Token.tochars[TOK.TOKunord] = "!<>="; + Token.tochars[TOK.TOKue] = "!<>"; + Token.tochars[TOK.TOKlg] = "<>"; + Token.tochars[TOK.TOKleg] = "<>="; + Token.tochars[TOK.TOKule] = "!>"; + Token.tochars[TOK.TOKul] = "!>="; + Token.tochars[TOK.TOKuge] = "!<"; + Token.tochars[TOK.TOKug] = "!<="; + + Token.tochars[TOK.TOKnot] = "!"; + Token.tochars[TOK.TOKtobool] = "!!"; + Token.tochars[TOK.TOKshl] = "<<"; + Token.tochars[TOK.TOKshr] = ">>"; + Token.tochars[TOK.TOKushr] = ">>>"; + Token.tochars[TOK.TOKadd] = "+"; + Token.tochars[TOK.TOKmin] = "-"; + Token.tochars[TOK.TOKmul] = "*"; + Token.tochars[TOK.TOKdiv] = "/"; + Token.tochars[TOK.TOKmod] = "%"; + Token.tochars[TOK.TOKslice] = ".."; + Token.tochars[TOK.TOKdotdotdot] = "..."; + Token.tochars[TOK.TOKand] = "&"; + Token.tochars[TOK.TOKandand] = "&&"; + Token.tochars[TOK.TOKor] = "|"; + Token.tochars[TOK.TOKoror] = "||"; + Token.tochars[TOK.TOKarray] = "[]"; + Token.tochars[TOK.TOKindex] = "[i]"; + Token.tochars[TOK.TOKaddress] = "&"; + Token.tochars[TOK.TOKstar] = "*"; + Token.tochars[TOK.TOKtilde] = "~"; + Token.tochars[TOK.TOKdollar] = "$"; + Token.tochars[TOK.TOKcast] = "cast"; + Token.tochars[TOK.TOKplusplus] = "++"; + Token.tochars[TOK.TOKminusminus] = "--"; + Token.tochars[TOK.TOKtype] = "type"; + Token.tochars[TOK.TOKquestion] = "?"; + Token.tochars[TOK.TOKneg] = "-"; + Token.tochars[TOK.TOKuadd] = "+"; + Token.tochars[TOK.TOKvar] = "var"; + Token.tochars[TOK.TOKaddass] = "+="; + Token.tochars[TOK.TOKminass] = "-="; + Token.tochars[TOK.TOKmulass] = "*="; + Token.tochars[TOK.TOKdivass] = "/="; + Token.tochars[TOK.TOKmodass] = "%="; + Token.tochars[TOK.TOKshlass] = "<<="; + Token.tochars[TOK.TOKshrass] = ">>="; + Token.tochars[TOK.TOKushrass] = ">>>="; + Token.tochars[TOK.TOKandass] = "&="; + Token.tochars[TOK.TOKorass] = "|="; + Token.tochars[TOK.TOKcatass] = "~="; + Token.tochars[TOK.TOKcat] = "~"; + Token.tochars[TOK.TOKcall] = "call"; + Token.tochars[TOK.TOKidentity] = "is"; + Token.tochars[TOK.TOKnotidentity] = "!is"; + + Token.tochars[TOK.TOKorass] = "|="; + Token.tochars[TOK.TOKidentifier] = "identifier"; + Token.tochars[TOK.TOKat] = "@"; + + // For debugging + Token.tochars[TOK.TOKdotexp] = "dotexp"; + Token.tochars[TOK.TOKdotti] = "dotti"; + Token.tochars[TOK.TOKdotvar] = "dotvar"; + Token.tochars[TOK.TOKdottype] = "dottype"; + Token.tochars[TOK.TOKsymoff] = "symoff"; + Token.tochars[TOK.TOKarraylength] = "arraylength"; + Token.tochars[TOK.TOKarrayliteral] = "arrayliteral"; + Token.tochars[TOK.TOKassocarrayliteral] = "assocarrayliteral"; + Token.tochars[TOK.TOKstructliteral] = "structliteral"; + Token.tochars[TOK.TOKstring] = "string"; + Token.tochars[TOK.TOKdsymbol] = "symbol"; + Token.tochars[TOK.TOKtuple] = "tuple"; + Token.tochars[TOK.TOKdeclaration] = "declaration"; + Token.tochars[TOK.TOKdottd] = "dottd"; + Token.tochars[TOK.TOKon_scope_exit] = "scope(exit)"; + Token.tochars[TOK.TOKon_scope_success] = "scope(success)"; + Token.tochars[TOK.TOKon_scope_failure] = "scope(failure)"; + } + + static Identifier idPool(string s) + { + StringValue* sv = stringtable.update(s); + Identifier id = cast(Identifier) sv.ptrvalue; + if (id is null) + { + id = new Identifier(sv.lstring.string_, TOK.TOKidentifier); + sv.ptrvalue = cast(void*)id; + } + + return id; + } + + static Identifier uniqueId(string s) + { + static int num; + return uniqueId(s, ++num); + } + + /********************************************* + * Create a unique identifier using the prefix s. + */ + static Identifier uniqueId(string s, int num) + { + char buffer[32]; + size_t slen = s.length; + + assert(slen + num.sizeof * 3 + 1 <= buffer.sizeof); + int len = sprintf(buffer.ptr, "%.*s%d", s, num); + + return idPool(buffer[0..len].idup); + } + + TOK nextToken() + { + Token *t; + + if (token.next) + { + t = token.next; + memcpy(&token, t, Token.sizeof); + t.next = freelist; + freelist = t; + } + else + { + scan(&token); + } + + //token.print(); + return token.value; + } + + /*********************** + * Look ahead at next token's value. + */ + TOK peekNext() + { + return peek(&token).value; + } + + TOK peekNext2() + { + assert(false); + } + + void scan(Token* t) + { + uint lastLine = loc.linnum; + uint linnum; + + t.blockComment = null; + t.lineComment = null; + while (1) + { + t.ptr = p; + //printf("p = %p, *p = '%c'\n",p,*p); + switch (*p) + { + case 0: + case 0x1A: + t.value = TOK.TOKeof; // end of file + return; + + case ' ': + case '\t': + case '\v': + case '\f': + p++; + continue; // skip white space + + case '\r': + p++; + if (*p != '\n') // if CR stands by itself + loc.linnum++; + continue; // skip white space + + case '\n': + p++; + loc.linnum++; + continue; // skip white space + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + t.value = number(t); + return; + +version (CSTRINGS) { + case '\'': + t.value = charConstant(t, 0); + return; + + case '"': + t.value = stringConstant(t,0); + return; + + case 'l': + case 'L': + if (p[1] == '\'') + { + p++; + t.value = charConstant(t, 1); + return; + } + else if (p[1] == '"') + { + p++; + t.value = stringConstant(t, 1); + return; + } +} else { + case '\'': + t.value = charConstant(t,0); + return; + + case 'r': + if (p[1] != '"') + goto case_ident; + p++; + case '`': + t.value = wysiwygStringConstant(t, *p); + return; + + case 'x': + if (p[1] != '"') + goto case_ident; + p++; + t.value = hexStringConstant(t); + return; + +version (DMDV2) { + case 'q': + if (p[1] == '"') + { + p++; + t.value = delimitedStringConstant(t); + return; + } + else if (p[1] == '{') + { + p++; + t.value = tokenStringConstant(t); + return; + } + else + goto case_ident; +} + + case '"': + t.value = escapeStringConstant(t,0); + return; +version (TEXTUAL_ASSEMBLY_OUT) { +} else { + case '\\': // escaped string literal + { uint c; + ubyte* pstart = p; + + stringbuffer.reset(); + do + { + p++; + switch (*p) + { + case 'u': + case 'U': + case '&': + c = escapeSequence(); + stringbuffer.writeUTF8(c); + break; + + default: + c = escapeSequence(); + stringbuffer.writeByte(c); + break; + } + } while (*p == '\\'); + t.len = stringbuffer.offset; + stringbuffer.writeByte(0); + char* cc = cast(char*)malloc(stringbuffer.offset); + memcpy(cc, stringbuffer.data, stringbuffer.offset); + t.ustring = cc; + t.postfix = 0; + t.value = TOK.TOKstring; + if (!global.params.useDeprecated) + error("Escape String literal %.*s is deprecated, use double quoted string literal \"%.*s\" instead", p - pstart, pstart, p - pstart, pstart); + return; + } +} + case 'l': + case 'L': +} + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': case 'g': case 'h': case 'i': case 'j': + case 'k': case 'm': case 'n': case 'o': +version (DMDV2) { + case 'p': /*case 'q': case 'r':*/ case 's': case 't': +} else { + case 'p': case 'q': /*case 'r':*/ case 's': case 't': +} + case 'u': case 'v': case 'w': /*case 'x':*/ case 'y': + case 'z': + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': case 'G': case 'H': case 'I': case 'J': + case 'K': case 'M': case 'N': case 'O': + case 'P': case 'Q': case 'R': case 'S': case 'T': + case 'U': case 'V': case 'W': case 'X': case 'Y': + case 'Z': + case '_': + case_ident: + { ubyte c; + StringValue *sv; + Identifier id; + + do + { + c = *++p; + } while (isidchar(c) || (c & 0x80 && isUniAlpha(decodeUTF()))); + sv = stringtable.update((cast(immutable(char)*)t.ptr)[0.. p - t.ptr]); /// + id = cast(Identifier) sv.ptrvalue; + if (id is null) + { id = new Identifier(sv.lstring.string_, TOK.TOKidentifier); + sv.ptrvalue = cast(void*)id; + } + t.ident = id; + t.value = cast(TOK) id.value; + anyToken = 1; + if (*t.ptr == '_') // if special identifier token + { + static char date[11+1]; + static char time[8+1]; + static char timestamp[24+1]; + + if (!date[0]) // lazy evaluation + { time_t tm; + char *p; + + .time(&tm); + p = ctime(&tm); + assert(p); + sprintf(date.ptr, "%.6s %.4s", p + 4, p + 20); + sprintf(time.ptr, "%.8s", p + 11); + sprintf(timestamp.ptr, "%.24s", p); + } + +///version (DMDV1) { +/// if (mod && id == Id.FILE) +/// { +/// t.ustring = cast(ubyte*)(loc.filename ? loc.filename : mod.ident.toChars()); +/// goto Lstr; +/// } +/// else if (mod && id == Id.LINE) +/// { +/// t.value = TOK.TOKint64v; +/// t.uns64value = loc.linnum; +/// } +/// else +///} + if (id == Id.DATE) + { + t.ustring = date.ptr; + goto Lstr; + } + else if (id == Id.TIME) + { + t.ustring = time.ptr; + goto Lstr; + } + else if (id == Id.VENDOR) + { + t.ustring = "Digital Mars D".ptr; + goto Lstr; + } + else if (id == Id.TIMESTAMP) + { + t.ustring = timestamp.ptr; + Lstr: + t.value = TOK.TOKstring; + Llen: + t.postfix = 0; + t.len = strlen(cast(char*)t.ustring); + } + else if (id == Id.VERSIONX) + { + uint major = 0; + uint minor = 0; + + foreach (char cc; global.version_[1..$]) + { + if (isdigit(cc)) + minor = minor * 10 + cc - '0'; + else if (cc == '.') + { + major = minor; + minor = 0; + } + else + break; + } + t.value = TOK.TOKint64v; + t.uns64value = major * 1000 + minor; + } +///version (DMDV2) { + else if (id == Id.EOFX) + { + t.value = TOK.TOKeof; + // Advance scanner to end of file + while (!(*p == 0 || *p == 0x1A)) + p++; + } +///} + } + //printf("t.value = %d\n",t.value); + return; + } + + case '/': + p++; + switch (*p) + { + case '=': + p++; + t.value = TOK.TOKdivass; + return; + + case '*': + p++; + linnum = loc.linnum; + while (1) + { + while (1) + { + ubyte c = *p; + switch (c) + { + case '/': + break; + + case '\n': + loc.linnum++; + p++; + continue; + + case '\r': + p++; + if (*p != '\n') + loc.linnum++; + continue; + + case 0: + case 0x1A: + error("unterminated /* */ comment"); + p = end; + t.value = TOK.TOKeof; + return; + + default: + if (c & 0x80) + { uint u = decodeUTF(); + if (u == PS || u == LS) + loc.linnum++; + } + p++; + continue; + } + break; + } + p++; + if (p[-2] == '*' && p - 3 != t.ptr) + break; + } + if (commentToken) + { + t.value = TOK.TOKcomment; + return; + } + else if (doDocComment && t.ptr[2] == '*' && p - 4 != t.ptr) + { // if /** but not /**/ + getDocComment(t, lastLine == linnum); + } + continue; + + case '/': // do // style comments + linnum = loc.linnum; + while (1) + { ubyte c = *++p; + switch (c) + { + case '\n': + break; + + case '\r': + if (p[1] == '\n') + p++; + break; + + case 0: + case 0x1A: + if (commentToken) + { + p = end; + t.value = TOK.TOKcomment; + return; + } + if (doDocComment && t.ptr[2] == '/') + getDocComment(t, lastLine == linnum); + p = end; + t.value = TOK.TOKeof; + return; + + default: + if (c & 0x80) + { uint u = decodeUTF(); + if (u == PS || u == LS) + break; + } + continue; + } + break; + } + + if (commentToken) + { + p++; + loc.linnum++; + t.value = TOK.TOKcomment; + return; + } + if (doDocComment && t.ptr[2] == '/') + getDocComment(t, lastLine == linnum); + + p++; + loc.linnum++; + continue; + + case '+': + { + int nest; + + linnum = loc.linnum; + p++; + nest = 1; + while (1) + { ubyte c = *p; + switch (c) + { + case '/': + p++; + if (*p == '+') + { + p++; + nest++; + } + continue; + + case '+': + p++; + if (*p == '/') + { + p++; + if (--nest == 0) + break; + } + continue; + + case '\r': + p++; + if (*p != '\n') + loc.linnum++; + continue; + + case '\n': + loc.linnum++; + p++; + continue; + + case 0: + case 0x1A: + error("unterminated /+ +/ comment"); + p = end; + t.value = TOK.TOKeof; + return; + + default: + if (c & 0x80) + { uint u = decodeUTF(); + if (u == PS || u == LS) + loc.linnum++; + } + p++; + continue; + } + break; + } + if (commentToken) + { + t.value = TOK.TOKcomment; + return; + } + if (doDocComment && t.ptr[2] == '+' && p - 4 != t.ptr) + { // if /++ but not /++/ + getDocComment(t, lastLine == linnum); + } + continue; + } + + default: + break; /// + } + t.value = TOK.TOKdiv; + return; + + case '.': + p++; + if (isdigit(*p)) + { /* Note that we don't allow ._1 and ._ as being + * valid floating point numbers. + */ + p--; + t.value = inreal(t); + } + else if (p[0] == '.') + { + if (p[1] == '.') + { p += 2; + t.value = TOK.TOKdotdotdot; + } + else + { p++; + t.value = TOK.TOKslice; + } + } + else + t.value = TOK.TOKdot; + return; + + case '&': + p++; + if (*p == '=') + { p++; + t.value = TOK.TOKandass; + } + else if (*p == '&') + { p++; + t.value = TOK.TOKandand; + } + else + t.value = TOK.TOKand; + return; + + case '|': + p++; + if (*p == '=') + { p++; + t.value = TOK.TOKorass; + } + else if (*p == '|') + { p++; + t.value = TOK.TOKoror; + } + else + t.value = TOK.TOKor; + return; + + case '-': + p++; + if (*p == '=') + { p++; + t.value = TOK.TOKminass; + } +/// #if 0 +/// else if (*p == '>') +/// { p++; +/// t.value = TOK.TOKarrow; +/// } +/// #endif + else if (*p == '-') + { p++; + t.value = TOK.TOKminusminus; + } + else + t.value = TOK.TOKmin; + return; + + case '+': + p++; + if (*p == '=') + { p++; + t.value = TOK.TOKaddass; + } + else if (*p == '+') + { p++; + t.value = TOK.TOKplusplus; + } + else + t.value = TOK.TOKadd; + return; + + case '<': + p++; + if (*p == '=') + { p++; + t.value = TOK.TOKle; // <= + } + else if (*p == '<') + { p++; + if (*p == '=') + { p++; + t.value = TOK.TOKshlass; // <<= + } + else + t.value = TOK.TOKshl; // << + } + else if (*p == '>') + { p++; + if (*p == '=') + { p++; + t.value = TOK.TOKleg; // <>= + } + else + t.value = TOK.TOKlg; // <> + } + else + t.value = TOK.TOKlt; // < + return; + + case '>': + p++; + if (*p == '=') + { p++; + t.value = TOK.TOKge; // >= + } + else if (*p == '>') + { p++; + if (*p == '=') + { p++; + t.value = TOK.TOKshrass; // >>= + } + else if (*p == '>') + { p++; + if (*p == '=') + { p++; + t.value = TOK.TOKushrass; // >>>= + } + else + t.value = TOK.TOKushr; // >>> + } + else + t.value = TOK.TOKshr; // >> + } + else + t.value = TOK.TOKgt; // > + return; + + case '!': + p++; + if (*p == '=') + { p++; + if (*p == '=' && global.params.Dversion == 1) + { p++; + t.value = TOK.TOKnotidentity; // !== + } + else + t.value = TOK.TOKnotequal; // != + } + else if (*p == '<') + { p++; + if (*p == '>') + { p++; + if (*p == '=') + { p++; + t.value = TOK.TOKunord; // !<>= + } + else + t.value = TOK.TOKue; // !<> + } + else if (*p == '=') + { p++; + t.value = TOK.TOKug; // !<= + } + else + t.value = TOK.TOKuge; // !< + } + else if (*p == '>') + { p++; + if (*p == '=') + { p++; + t.value = TOK.TOKul; // !>= + } + else + t.value = TOK.TOKule; // !> + } + else + t.value = TOK.TOKnot; // ! + return; + + case '=': + p++; + if (*p == '=') + { p++; + if (*p == '=' && global.params.Dversion == 1) + { p++; + t.value = TOK.TOKidentity; // === + } + else + t.value = TOK.TOKequal; // == + } + else + t.value = TOK.TOKassign; // = + return; + + case '~': + p++; + if (*p == '=') + { p++; + t.value = TOK.TOKcatass; // ~= + } + else + t.value = TOK.TOKtilde; // ~ + return; +/* + #define SINGLE(c,tok) case c: p++; t.value = tok; return; + + SINGLE('(', TOKlparen) + SINGLE(')', TOKrparen) + SINGLE('[', TOKlbracket) + SINGLE(']', TOKrbracket) + SINGLE('{', TOKlcurly) + SINGLE('}', TOKrcurly) + SINGLE('?', TOKquestion) + SINGLE(',', TOKcomma) + SINGLE(';', TOKsemicolon) + SINGLE(':', TOKcolon) + SINGLE('$', TOKdollar) + SINGLE('@', TOKat) + + #undef SINGLE + + #define DOUBLE(c1,tok1,c2,tok2) \ + case c1: \ + p++; \ + if (*p == c2) \ + { p++; \ + t.value = tok2; \ + } \ + else \ + t.value = tok1; \ + return; + + DOUBLE('*', TOKmul, '=', TOKmulass) + DOUBLE('%', TOKmod, '=', TOKmodass) + DOUBLE('^', TOKxor, '=', TOKxorass) + + #undef DOUBLE +*/ + + case '(': p++; t.value = TOK.TOKlparen; return; + case ')': p++; t.value = TOK.TOKrparen; return; + case '[': p++; t.value = TOK.TOKlbracket; return; + case ']': p++; t.value = TOK.TOKrbracket; return; + case '{': p++; t.value = TOK.TOKlcurly; return; + case '}': p++; t.value = TOK.TOKrcurly; return; + case '?': p++; t.value = TOK.TOKquestion; return; + case ',': p++; t.value = TOK.TOKcomma; return; + case ';': p++; t.value = TOK.TOKsemicolon; return; + case ':': p++; t.value = TOK.TOKcolon; return; + case '$': p++; t.value = TOK.TOKdollar; return; + case '@': p++; t.value = TOK.TOKat; return; + + case '*': + p++; + if (*p == '=') { + p++; + t.value = TOK.TOKmulass; + } else { + t.value = TOK.TOKmul; + } + return; + + case '%': + p++; + if (*p == '=') { + p++; + t.value = TOK.TOKmodass; + } else { + t.value = TOK.TOKmod; + } + return; + + case '^': + p++; + if (*p == '=') { + p++; + t.value = TOK.TOKxorass; + } else { + t.value = TOK.TOKxor; + } + return; + + case '#': + p++; + pragma_(); + continue; + + default: + { ubyte c = *p; + + if (c & 0x80) + { uint u = decodeUTF(); + + // Check for start of unicode identifier + if (isUniAlpha(u)) + goto case_ident; + + if (u == PS || u == LS) + { + loc.linnum++; + p++; + continue; + } + } + if (isprint(c)) + error("unsupported char '%c'", c); + else + error("unsupported char 0x%02x", c); + p++; + continue; + } + } + } + } + + Token* peek(Token* ct) + { + Token* t; + + if (ct.next) + t = ct.next; + else + { + t = new Token(); + scan(t); + t.next = null; + ct.next = t; + } + return t; + } + + Token* peekPastParen(Token* tk) + { + //printf("peekPastParen()\n"); + int parens = 1; + int curlynest = 0; + while (1) + { + tk = peek(tk); + //tk.print(); + switch (tk.value) + { + case TOK.TOKlparen: + parens++; + continue; + + case TOK.TOKrparen: + --parens; + if (parens) + continue; + tk = peek(tk); + break; + + case TOK.TOKlcurly: + curlynest++; + continue; + + case TOK.TOKrcurly: + if (--curlynest >= 0) + continue; + break; + + case TOK.TOKsemicolon: + if (curlynest) + continue; + break; + + case TOK.TOKeof: + break; + + default: + continue; + } + return tk; + } + } + + /******************************************* + * Parse escape sequence. + */ + uint escapeSequence() + { + uint c = *p; + + version (TEXTUAL_ASSEMBLY_OUT) { + return c; + } + int n; + int ndigits; + + switch (c) + { + case '\'': + case '"': + case '?': + case '\\': + Lconsume: + p++; + break; + + case 'a': c = 7; goto Lconsume; + case 'b': c = 8; goto Lconsume; + case 'f': c = 12; goto Lconsume; + case 'n': c = 10; goto Lconsume; + case 'r': c = 13; goto Lconsume; + case 't': c = 9; goto Lconsume; + case 'v': c = 11; goto Lconsume; + + case 'u': + ndigits = 4; + goto Lhex; + case 'U': + ndigits = 8; + goto Lhex; + case 'x': + ndigits = 2; + Lhex: + p++; + c = *p; + if (ishex(cast(ubyte)c)) + { + uint v; + + n = 0; + v = 0; + while (1) + { + if (isdigit(c)) + c -= '0'; + else if (islower(c)) + c -= 'a' - 10; + else + c -= 'A' - 10; + v = v * 16 + c; + c = *++p; + if (++n == ndigits) + break; + if (!ishex(cast(ubyte)c)) + { error("escape hex sequence has %d hex digits instead of %d", n, ndigits); + break; + } + } + if (ndigits != 2 && !utf_isValidDchar(v)) + { error("invalid UTF character \\U%08x", v); + v = '?'; // recover with valid UTF character + } + c = v; + } + else + error("undefined escape hex sequence \\%c\n",c); + break; + + case '&': // named character entity + for (ubyte* idstart = ++p; true; p++) + { + switch (*p) + { + case ';': + c = HtmlNamedEntity(idstart, p - idstart); + if (c == ~0) + { + error("unnamed character entity &%s;", idstart[0..(p - idstart)]); + c = ' '; + } + p++; + break; + + default: + if (isalpha(*p) || + (p != idstart + 1 && isdigit(*p))) + continue; + error("unterminated named entity"); + break; + } + break; + } + break; + + case 0: + case 0x1A: // end of file + c = '\\'; + break; + + default: + if (isoctal(cast(ubyte)c)) + { + uint v; + + n = 0; + v = 0; + do + { + v = v * 8 + (c - '0'); + c = *++p; + } while (++n < 3 && isoctal(cast(ubyte)c)); + c = v; + if (c > 0xFF) + error("0%03o is larger than a byte", c); + } + else + error("undefined escape sequence \\%c\n",c); + break; + } + return c; + } + + TOK wysiwygStringConstant(Token* t, int tc) + { + assert(false); + } + + TOK hexStringConstant(Token* t) + { + assert(false); + } + +version (DMDV2) { + TOK delimitedStringConstant(Token* t) + { + assert(false); + } + + TOK tokenStringConstant(Token* t) + { + assert(false); + } +} + TOK escapeStringConstant(Token* t, int wide) + { + uint c; + Loc start = loc; + + p++; + stringbuffer.reset(); + while (true) + { + c = *p++; + switch (c) + { + version (TEXTUAL_ASSEMBLY_OUT) { + } else { + case '\\': + switch (*p) + { + case 'u': + case 'U': + case '&': + c = escapeSequence(); + stringbuffer.writeUTF8(c); + continue; + + default: + c = escapeSequence(); + break; + } + break; + } + case '\n': + loc.linnum++; + break; + + case '\r': + if (*p == '\n') + continue; // ignore + c = '\n'; // treat EndOfLine as \n character + loc.linnum++; + break; + + case '"': + t.len = stringbuffer.offset; + stringbuffer.writeByte(0); + char* tmp = cast(char*)malloc(stringbuffer.offset); + memcpy(tmp, stringbuffer.data, stringbuffer.offset); + t.ustring = tmp; + stringPostfix(t); + return TOK.TOKstring; + + case 0: + case 0x1A: + p--; + error("unterminated string constant starting at %s", start.toChars()); + t.ustring = "".ptr; + t.len = 0; + t.postfix = 0; + return TOK.TOKstring; + + default: + if (c & 0x80) + { + p--; + c = decodeUTF(); + if (c == LS || c == PS) + { c = '\n'; + loc.linnum++; + } + p++; + stringbuffer.writeUTF8(c); + continue; + } + break; + } + stringbuffer.writeByte(c); + } + + assert(false); + } + + TOK charConstant(Token* t, int wide) + { + uint c; + TOK tk = TOKcharv; + + //printf("Lexer.charConstant\n"); + p++; + c = *p++; + switch (c) + { + version (TEXTUAL_ASSEMBLY_OUT) { + } else { + case '\\': + switch (*p) + { + case 'u': + t.uns64value = escapeSequence(); + tk = TOKwcharv; + break; + + case 'U': + case '&': + t.uns64value = escapeSequence(); + tk = TOKdcharv; + break; + + default: + t.uns64value = escapeSequence(); + break; + } + break; + } + case '\n': + L1: + loc.linnum++; + case '\r': + case 0: + case 0x1A: + case '\'': + error("unterminated character constant"); + return tk; + + default: + if (c & 0x80) + { + p--; + c = decodeUTF(); + p++; + if (c == LS || c == PS) + goto L1; + if (c < 0xD800 || (c >= 0xE000 && c < 0xFFFE)) + tk = TOKwcharv; + else + tk = TOKdcharv; + } + t.uns64value = c; + break; + } + + if (*p != '\'') + { + error("unterminated character constant"); + return tk; + } + p++; + return tk; + } + + /*************************************** + * Get postfix of string literal. + */ + void stringPostfix(Token* t) + { + switch (*p) + { + case 'c': + case 'w': + case 'd': + t.postfix = *p; + p++; + break; + + default: + t.postfix = 0; + break; + } + } + + uint wchar_(uint u) + { + assert(false); + } + + /************************************** + * Read in a number. + * If it's an integer, store it in tok.TKutok.Vlong. + * integers can be decimal, octal or hex + * Handle the suffixes U, UL, LU, L, etc. + * If it's double, store it in tok.TKutok.Vdouble. + * Returns: + * TKnum + * TKdouble,... + */ + + TOK number(Token* t) + { + // We use a state machine to collect numbers + enum STATE { STATE_initial, STATE_0, STATE_decimal, STATE_octal, STATE_octale, + STATE_hex, STATE_binary, STATE_hex0, STATE_binary0, + STATE_hexh, STATE_error }; + STATE state; + + enum FLAGS + { + FLAGS_undefined = 0, + FLAGS_decimal = 1, // decimal + FLAGS_unsigned = 2, // u or U suffix + FLAGS_long = 4, // l or L suffix + }; + + FLAGS flags = FLAGS.FLAGS_decimal; + + int i; + int base; + uint c; + ubyte *start; + TOK result; + + //printf("Lexer.number()\n"); + state = STATE.STATE_initial; + base = 0; + stringbuffer.reset(); + start = p; + while (1) + { + c = *p; + switch (state) + { + case STATE.STATE_initial: // opening state + if (c == '0') + state = STATE.STATE_0; + else + state = STATE.STATE_decimal; + break; + + case STATE.STATE_0: + flags = (flags & ~FLAGS.FLAGS_decimal); + switch (c) + { +version (ZEROH) { + case 'H': // 0h + case 'h': + goto hexh; +} + case 'X': + case 'x': + state = STATE.STATE_hex0; + break; + + case '.': + if (p[1] == '.') // .. is a separate token + goto done; + case 'i': + case 'f': + case 'F': + goto real_; +version (ZEROH) { + case 'E': + case 'e': + goto case_hex; +} + case 'B': + case 'b': + state = STATE.STATE_binary0; + break; + + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + state = STATE.STATE_octal; + break; + +version (ZEROH) { + case '8': case '9': case 'A': + case 'C': case 'D': case 'F': + case 'a': case 'c': case 'd': case 'f': + case_hex: + state = STATE.STATE_hexh; + break; +} + case '_': + state = STATE.STATE_octal; + p++; + continue; + + case 'L': + if (p[1] == 'i') + goto real_; + goto done; + + default: + goto done; + } + break; + + case STATE.STATE_decimal: // reading decimal number + if (!isdigit(c)) + { +version (ZEROH) { + if (ishex(c) + || c == 'H' || c == 'h' + ) + goto hexh; +} + if (c == '_') // ignore embedded _ + { p++; + continue; + } + if (c == '.' && p[1] != '.') + goto real_; + else if (c == 'i' || c == 'f' || c == 'F' || + c == 'e' || c == 'E') + { + real_: // It's a real number. Back up and rescan as a real + p = start; + return inreal(t); + } + else if (c == 'L' && p[1] == 'i') + goto real_; + goto done; + } + break; + + case STATE.STATE_hex0: // reading hex number + case STATE.STATE_hex: + if (! ishex(cast(ubyte)c)) + { + if (c == '_') // ignore embedded _ + { p++; + continue; + } + if (c == '.' && p[1] != '.') + goto real_; + if (c == 'P' || c == 'p' || c == 'i') + goto real_; + if (state == STATE.STATE_hex0) + error("Hex digit expected, not '%c'", c); + goto done; + } + state = STATE.STATE_hex; + break; + +version (ZEROH) { + hexh: + state = STATE.STATE_hexh; + case STATE.STATE_hexh: // parse numbers like 0FFh + if (!ishex(c)) + { + if (c == 'H' || c == 'h') + { + p++; + base = 16; + goto done; + } + else + { + // Check for something like 1E3 or 0E24 + if (memchr(cast(char*)stringbuffer.data, 'E', stringbuffer.offset) || + memchr(cast(char*)stringbuffer.data, 'e', stringbuffer.offset)) + goto real_; + error("Hex digit expected, not '%c'", c); + goto done; + } + } + break; +} + + case STATE.STATE_octal: // reading octal number + case STATE.STATE_octale: // reading octal number with non-octal digits + if (!isoctal(cast(ubyte)c)) + { +version (ZEROH) { + if (ishex(c) + || c == 'H' || c == 'h' + ) + goto hexh; +} + if (c == '_') // ignore embedded _ + { p++; + continue; + } + if (c == '.' && p[1] != '.') + goto real_; + if (c == 'i') + goto real_; + if (isdigit(c)) + { + state = STATE.STATE_octale; + } + else + goto done; + } + break; + + case STATE.STATE_binary0: // starting binary number + case STATE.STATE_binary: // reading binary number + if (c != '0' && c != '1') + { +version (ZEROH) { + if (ishex(c) + || c == 'H' || c == 'h' + ) + goto hexh; +} + if (c == '_') // ignore embedded _ + { p++; + continue; + } + if (state == STATE.STATE_binary0) + { error("binary digit expected"); + state = STATE.STATE_error; + break; + } + else + goto done; + } + state = STATE.STATE_binary; + break; + + case STATE.STATE_error: // for error recovery + if (!isdigit(c)) // scan until non-digit + goto done; + break; + + default: + assert(0); + } + stringbuffer.writeByte(c); + p++; + } + done: + stringbuffer.writeByte(0); // terminate string + if (state == STATE.STATE_octale) + error("Octal digit expected"); + + ulong n; // unsigned >=64 bit integer type + + if (stringbuffer.offset == 2 && (state == STATE.STATE_decimal || state == STATE.STATE_0)) + n = stringbuffer.data[0] - '0'; + else + { + // Convert string to integer +version (__DMC__) { + errno = 0; + n = strtoull(cast(char*)stringbuffer.data,null,base); + if (errno == ERANGE) + error("integer overflow"); +} else { + // Not everybody implements strtoull() + char* p = cast(char*)stringbuffer.data; + int r = 10, d; + + if (*p == '0') + { + if (p[1] == 'x' || p[1] == 'X') + p += 2, r = 16; + else if (p[1] == 'b' || p[1] == 'B') + p += 2, r = 2; + else if (isdigit(p[1])) + p += 1, r = 8; + } + + n = 0; + while (1) + { + if (*p >= '0' && *p <= '9') + d = *p - '0'; + else if (*p >= 'a' && *p <= 'z') + d = *p - 'a' + 10; + else if (*p >= 'A' && *p <= 'Z') + d = *p - 'A' + 10; + else + break; + if (d >= r) + break; + ulong n2 = n * r; + //printf("n2 / r = %llx, n = %llx\n", n2/r, n); + if (n2 / r != n || n2 + d < n) + { + error ("integer overflow"); + break; + } + + n = n2 + d; + p++; + } +} + if (n.sizeof > 8 && + n > 0xFFFFFFFFFFFFFFFF) // if n needs more than 64 bits + error("integer overflow"); + } + + // Parse trailing 'u', 'U', 'l' or 'L' in any combination + while (1) + { FLAGS f; + + switch (*p) + { case 'U': + case 'u': + f = FLAGS.FLAGS_unsigned; + goto L1; + + case 'l': + if (1 || !global.params.useDeprecated) + error("'l' suffix is deprecated, use 'L' instead"); + case 'L': + f = FLAGS.FLAGS_long; + L1: + p++; + if (flags & f) + error("unrecognized token"); + flags = (flags | f); + continue; + default: + break; + } + break; + } + + switch (flags) + { + case FLAGS.FLAGS_undefined: + /* Octal or Hexadecimal constant. + * First that fits: int, uint, long, ulong + */ + if (n & 0x8000000000000000) + result = TOK.TOKuns64v; + else if (n & 0xFFFFFFFF00000000) + result = TOK.TOKint64v; + else if (n & 0x80000000) + result = TOK.TOKuns32v; + else + result = TOK.TOKint32v; + break; + + case FLAGS.FLAGS_decimal: + /* First that fits: int, long, long long + */ + if (n & 0x8000000000000000) + { error("signed integer overflow"); + result = TOK.TOKuns64v; + } + else if (n & 0xFFFFFFFF80000000) + result = TOK.TOKint64v; + else + result = TOK.TOKint32v; + break; + + case FLAGS.FLAGS_unsigned: + case FLAGS.FLAGS_decimal | FLAGS.FLAGS_unsigned: + /* First that fits: uint, ulong + */ + if (n & 0xFFFFFFFF00000000) + result = TOK.TOKuns64v; + else + result = TOK.TOKuns32v; + break; + + case FLAGS.FLAGS_decimal | FLAGS.FLAGS_long: + if (n & 0x8000000000000000) + { error("signed integer overflow"); + result = TOK.TOKuns64v; + } + else + result = TOK.TOKint64v; + break; + + case FLAGS.FLAGS_long: + if (n & 0x8000000000000000) + result = TOK.TOKuns64v; + else + result = TOK.TOKint64v; + break; + + case FLAGS.FLAGS_unsigned | FLAGS.FLAGS_long: + case FLAGS.FLAGS_decimal | FLAGS.FLAGS_unsigned | FLAGS.FLAGS_long: + result = TOK.TOKuns64v; + break; + + default: +debug { + printf("%x\n",flags); +} + assert(0); + } + t.uns64value = n; + return result; + } + + /************************************** + * Read in characters, converting them to real. + * Bugs: + * Exponent overflow not detected. + * Too much requested precision is not detected. + */ + TOK inreal(Token* t) + in + { + assert(*p == '.' || isdigit(*p)); + } + out (result) + { + switch (result) + { + case TOKfloat32v: + case TOKfloat64v: + case TOKfloat80v: + case TOKimaginary32v: + case TOKimaginary64v: + case TOKimaginary80v: + break; + + default: + assert(0); + } + } + body + { + int dblstate; + uint c; + char hex; // is this a hexadecimal-floating-constant? + TOK result; + + //printf("Lexer.inreal()\n"); + stringbuffer.reset(); + dblstate = 0; + hex = 0; + Lnext: + while (true) + { + // Get next char from input + c = *p++; + //printf("dblstate = %d, c = '%c'\n", dblstate, c); + while (true) + { + switch (dblstate) + { + case 0: // opening state + if (c == '0') + dblstate = 9; + else if (c == '.') + dblstate = 3; + else + dblstate = 1; + break; + + case 9: + dblstate = 1; + if (c == 'X' || c == 'x') + { + hex++; + break; + } + case 1: // digits to left of . + case 3: // digits to right of . + case 7: // continuing exponent digits + if (!isdigit(c) && !(hex && isxdigit(c))) + { + if (c == '_') + goto Lnext; // ignore embedded '_' + dblstate++; + continue; + } + break; + + case 2: // no more digits to left of . + if (c == '.') + { + dblstate++; + break; + } + case 4: // no more digits to right of . + if ((c == 'E' || c == 'e') || + hex && (c == 'P' || c == 'p')) + { + dblstate = 5; + hex = 0; // exponent is always decimal + break; + } + if (hex) + error("binary-exponent-part required"); + goto done; + + case 5: // looking immediately to right of E + dblstate++; + if (c == '-' || c == '+') + break; + case 6: // 1st exponent digit expected + if (!isdigit(c)) + error("exponent expected"); + dblstate++; + break; + + case 8: // past end of exponent digits + goto done; + } + break; + } + stringbuffer.writeByte(c); + } + done: + p--; + + stringbuffer.writeByte(0); + + version (_WIN32) { /// && __DMC__ + char* save = __locale_decpoint; + __locale_decpoint = cast(char*)".".ptr; + } + t.float80value = strtold(cast(char*)stringbuffer.data, null); + + errno = 0; + switch (*p) + { + case 'F': + case 'f': + strtof(cast(char*)stringbuffer.data, null); + result = TOKfloat32v; + p++; + break; + + default: + strtod(cast(char*)stringbuffer.data, null); + result = TOKfloat64v; + break; + + case 'l': + if (!global.params.useDeprecated) + error("'l' suffix is deprecated, use 'L' instead"); + case 'L': + result = TOKfloat80v; + p++; + break; + } + if (*p == 'i' || *p == 'I') + { + if (!global.params.useDeprecated && *p == 'I') + error("'I' suffix is deprecated, use 'i' instead"); + p++; + switch (result) + { + case TOKfloat32v: + result = TOKimaginary32v; + break; + case TOKfloat64v: + result = TOKimaginary64v; + break; + case TOKfloat80v: + result = TOKimaginary80v; + break; + } + } + + version (_WIN32) { ///&& __DMC__ + __locale_decpoint = save; + } + if (errno == ERANGE) + error("number is not representable"); + + return result; + } + + void error(T...)(string format, T t) + { + error(this.loc, format, t); + } + + void error(T...)(Loc loc, string format, T t) + { + if (mod && !global.gag) + { + string p = loc.toChars(); + if (p.length != 0) + writef("%s: ", p); + + writefln(format, t); + + if (global.errors >= 20) // moderate blizzard of cascading messages + fatal(); + } + + global.errors++; + } + + void pragma_() + { + assert(false); + } + + uint decodeUTF() + { + assert(false); + } + + void getDocComment(Token* t, uint lineComment) + { + assert(false); + } + + static bool isValidIdentifier(string p) + { + if (p.length == 0) { + return false; + } + + if (p[0] >= '0' && p[0] <= '9') { // beware of isdigit() on signed chars + return false; + } + + size_t idx = 0; + while (idx < p.length) + { + dchar dc; + + if (utf_decodeChar(p, &idx, &dc) !is null) { + return false; + } + + if (!((dc >= 0x80 && isUniAlpha(dc)) || isalnum(dc) || dc == '_')) { + return false; + } + } + + return true; + } + + /// TODO: reimplement based on strings + static ubyte* combineComments(ubyte* c1, ubyte* c2) + { + //printf("Lexer.combineComments('%s', '%s')\n", c1, c2); + + ubyte* c = c2; + + if (c1) + { + c = c1; + if (c2) + { + size_t len1 = strlen(cast(char*)c1); + size_t len2 = strlen(cast(char*)c2); + + c = cast(ubyte*)malloc(len1 + 1 + len2 + 1); + memcpy(c, c1, len1); + if (len1 && c1[len1 - 1] != '\n') + { + c[len1] = '\n'; + len1++; + } + memcpy(c + len1, c2, len2); + c[len1 + len2] = 0; + } + } + + return c; + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/Library.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Library.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,980 @@ +module dmd.Library; + +import dmd.File; +import dmd.Array; +import dmd.StringTable; +import dmd.OutBuffer; +import dmd.ObjModule; +import dmd.String; +import dmd.Global; +import dmd.File; +import dmd.FileName; +import dmd.Util; +import dmd.StringValue; +import dmd.String; + +import core.stdc.string; +import core.stdc.stdlib; + +import std.string; + +align(1) +struct LibHeader +{ + ubyte recTyp; // 0xF0 + ushort pagesize; + int lSymSeek; + ushort ndicpages; + ubyte flags; +} + +align(1) +struct Libheader +{ + ubyte recTyp; + ushort recLen; + int trailerPosn; + ushort ndicpages; + ubyte flags; + char[6] filler; +} + +struct ObjSymbol +{ + string name; + ObjModule* om; +} + +/************************** + * Record types: + */ + +enum HASHMOD = 0x25; +enum BUCKETPAGE = 512; +enum BUCKETSIZE = (BUCKETPAGE - HASHMOD - 1); + +/+ +#define RHEADR 0x6E +#define REGINT 0x70 +#define REDATA 0x72 +#define RIDATA 0x74 +#define OVLDEF 0x76 +#define ENDREC 0x78 +#define BLKDEF 0x7A +#define BLKEND 0x7C +#define DEBSYM 0x7E ++/ +enum THEADR = 0x80; +enum LHEADR = 0x82; +/+#define PEDATA 0x84 +#define PIDATA 0x86 ++/ +enum COMENT = 0x88; +enum MODEND = 0x8A; +enum M386END = 0x8B; /* 32 bit module end record */ +/+ +#define EXTDEF 0x8C +#define TYPDEF 0x8E ++/ +enum PUBDEF = 0x90; +enum PUB386 = 0x91; +/+ +#define LOCSYM 0x92 +#define LINNUM 0x94 ++/ +enum LNAMES = 0x96; +/+ +#define SEGDEF 0x98 +#define GRPDEF 0x9A +#define FIXUPP 0x9C +/*#define (none) 0x9E */ +#define LEDATA 0xA0 +#define LIDATA 0xA2 +#define LIBHED 0xA4 +#define LIBNAM 0xA6 +#define LIBLOC 0xA8 +#define LIBDIC 0xAA +#define COMDEF 0xB0 +#define LEXTDEF 0xB4 +#define LPUBDEF 0xB6 +#define LCOMDEF 0xB8 +#define CEXTDEF 0xBC ++/ +enum COMDAT = 0xC2; +/+#define LINSYM 0xC4 ++/ +enum ALIAS = 0xC6; +enum LLNAMES = 0xCA; + + +enum LIBIDMAX = (512 - 0x25 - 3 - 4); // max size that will fit in dictionary + +extern (C) extern char* strdup(const(char)* ptr); + +static uint parseName(ubyte** pp, char* name) +{ + ubyte* p = *pp; + uint len = *p++; + + if (len == 0xFF && *p == 0) // if long name + { + len = p[1] & 0xFF; + len |= cast(uint)p[2] << 8; + p += 3; + assert(len <= LIBIDMAX); + } + + memcpy(name, p, len); + name[len] = 0; + *pp = p + len; + + return len; +} + +static ushort parseIdx(ubyte** pp) +{ + ubyte* p = *pp; + ubyte c = *p++; + + ushort idx = cast(ushort)((0x80 & c) ? ((0x7F & c) << 8) + *p++ : c); + *pp = p; + return idx; +} + +extern (C) int D_NameCompare(const(void*) a, const(void*) b) +{ + ObjSymbol** p1 = cast(ObjSymbol**)a; + ObjSymbol** p2 = cast(ObjSymbol**)b; + + return cmp((*p1).name, (*p2).name); +} + +/******************************************* + * Write a single entry into dictionary. + * Returns: + * 0 failure + */ + +extern (C) extern uint _rotl(uint value, int shift); +extern (C) extern uint _rotr(uint value, int shift); + +static int EnterDict(ubyte* bucketsP, ushort ndicpages, ubyte* entry, uint entrylen) +{ + ushort uStartIndex; + ushort uStep; + ushort uStartPage; + ushort uPageStep; + ushort uIndex; + ushort uPage; + ushort n; + uint u; + uint nbytes; + ubyte* aP; + ubyte* zP; + + aP = entry; + zP = aP + entrylen; // point at last char in identifier + + uStartPage = 0; + uPageStep = 0; + uStartIndex = 0; + uStep = 0; + + u = entrylen; + while ( u-- ) + { + uStartPage = cast(ushort)_rotl( uStartPage, 2 ) ^ ( *aP | 0x20 ); + uStep = cast(ushort)_rotr( uStep, 2 ) ^ ( *aP++ | 0x20 ); + uStartIndex = cast(ushort)_rotr( uStartIndex, 2 ) ^ ( *zP | 0x20 ); + uPageStep = cast(ushort)_rotl( uPageStep, 2 ) ^ ( *zP-- | 0x20 ); + } + + uStartPage %= ndicpages; + uPageStep %= ndicpages; + if ( uPageStep == 0 ) + uPageStep++; + uStartIndex %= HASHMOD; + uStep %= HASHMOD; + if ( uStep == 0 ) + uStep++; + + uPage = uStartPage; + uIndex = uStartIndex; + + // number of bytes in entry + nbytes = 1 + entrylen + 2; + if (entrylen > 255) + nbytes += 2; + + while (1) + { + aP = &bucketsP[uPage * BUCKETPAGE]; + uStartIndex = uIndex; + while (1) + { + if ( 0 == aP[ uIndex ] ) + { + // n = next available position in this page + n = aP[ HASHMOD ] << 1; + assert(n > HASHMOD); + + // if off end of this page + if (n + nbytes > BUCKETPAGE ) + { aP[ HASHMOD ] = 0xFF; + break; // next page + } + else + { + aP[ uIndex ] = cast(ubyte)(n >> 1); + memcpy( (aP + n), entry, nbytes ); + aP[ HASHMOD ] += (nbytes + 1) >> 1; + if (aP[HASHMOD] == 0) + aP[HASHMOD] = 0xFF; + return 1; + } + } + uIndex += uStep; + uIndex %= 0x25; + /*if (uIndex > 0x25) + uIndex -= 0x25;*/ + if( uIndex == uStartIndex ) + break; + } + uPage += uPageStep; + if (uPage >= ndicpages) + uPage -= ndicpages; + if( uPage == uStartPage ) + break; + } + + return 0; +} + +class Library +{ + File libfile; + Array objmodules; // ObjModule[] + Array objsymbols; // ObjSymbol[] + + StringTable tab; + + this() + { + libfile = null; + + objmodules = new Array(); + objsymbols = new Array(); + tab = new StringTable(); + } + + /*********************************** + * Set the library file name based on the output directory + * and the filename. + * Add default library file name extension. + */ + void setFilename(string dir, string filename) + { + string arg = filename; + if (arg.length == 0) + { + // Generate lib file name from first obj name + string n = (cast(String)global.params.objfiles.data[0]).str; + + n = FileName.name(n); + FileName fn = FileName.forceExt(n, global.lib_ext); + arg = fn.toChars(); + } + if (!FileName.absolute(arg)) + arg = FileName.combine(dir, arg); + + FileName libfilename = FileName.defaultExt(arg, global.lib_ext); + libfile = new File(libfilename); + } + + /*************************************** + * Add object module or library to the library. + * Examine the buffer to see which it is. + * If the buffer is null, use module_name as the file name + * and load the file. + */ + void addObject(string module_name, void *buf, size_t buflen) + { + version (LOG) { + printf("Library.addObject(%s)\n", module_name ? module_name : ""); + } + if (!buf) + { + assert(module_name); + scope FileName f = new FileName(module_name); + scope File file = new File(f); + file.readv(); + buf = file.buffer; + buflen = file.len; + file.ref_ = 1; + } + + uint g_page_size; + ubyte* pstart = cast(ubyte*)buf; + int islibrary = 0; + + /* See if it's an OMF library. + * Don't go by file extension. + */ + + /* Determine if it is an OMF library, an OMF object module, + * or something else. + */ + if (buflen < LibHeader.sizeof) + { + Lcorrupt: + error("corrupt object module"); + } + LibHeader* lh = cast(LibHeader*)buf; + if (lh.recTyp == 0xF0) + { /* OMF library + * The modules are all at buf[g_page_size .. lh.lSymSeek] + */ + islibrary = 1; + g_page_size = lh.pagesize + 3; + buf = cast(void*)(pstart + g_page_size); + if (lh.lSymSeek > buflen || + g_page_size > buflen) + goto Lcorrupt; + buflen = lh.lSymSeek - g_page_size; + } + else if (lh.recTyp == '!' && memcmp(lh, "!\n".ptr, 8) == 0) + { + error("COFF libraries not supported"); + return; + } + else + { + // Not a library, assume OMF object module + g_page_size = 16; + } + + /* Split up the buffer buf[0..buflen] into multiple object modules, + * each aligned on a g_page_size boundary. + */ + + ObjModule* om = null; + int first_module = 1; + + ubyte* p = cast(ubyte*)buf; + ubyte* pend = p + buflen; + ubyte* pnext; + for (; p < pend; p = pnext) // for each OMF record + { + if (p + 3 >= pend) + goto Lcorrupt; + ubyte recTyp = *p; + ushort recLen = *cast(ushort*)(p + 1); + pnext = p + 3 + recLen; + if (pnext > pend) + goto Lcorrupt; + recLen--; /* forget the checksum */ + + switch (recTyp) + { + case LHEADR : + case THEADR : + if (!om) + { + char name[LIBIDMAX + 1]; + om = new ObjModule(); + om.flags = 0; + om.base = p; + p += 3; + parseName(&p, name.ptr); + if (first_module && module_name && !islibrary) + { + // Remove path and extension + string fname = FileName.name(module_name); + string ext = FileName.ext(fname); + if (ext.length != 0) { + fname = fname[0..$-ext.length-1]; + } + + om.name = fname; + } + else + { + /* Use THEADR name as module name, + * removing path and extension. + */ + string fname = FileName.name(fromStringz(name.ptr)); + string ext = FileName.ext(fname); + if (ext.length != 0) { + fname = fname[0..$-ext.length-1]; + } + + om.name = fname; + om.flags |= MFtheadr; + } + if (strcmp(name.ptr, "C".ptr) == 0) // old C compilers did this + { + om.flags |= MFgentheadr; // generate our own THEADR + om.base = pnext; // skip past THEADR + } + objmodules.push(cast(void*)om); + first_module = 0; + } + break; + + case MODEND : + case M386END: + if (om) + { + om.page = cast(ushort)((om.base - pstart) / g_page_size); + om.length = pnext - om.base; + om = null; + } + // Round up to next page + uint t = pnext - pstart; + t = (t + g_page_size - 1) & ~cast(uint)(g_page_size - 1); + pnext = pstart + t; + break; + + default: + // ignore + ; + } + } + + if (om) + goto Lcorrupt; // missing MODEND record + } + + void addLibrary(void *buf, size_t buflen) + { + assert(false); + } + + void write() + { + if (global.params.verbose) + writef("library %s\n", libfile.name.toChars()); + + scope OutBuffer libbuf = new OutBuffer(); + WriteLibToBuffer(libbuf); + + // Transfer image to file + libfile.setbuffer(libbuf.data, libbuf.offset); + libbuf.extractData(); + + string p = FileName.path(libfile.name.toChars()); + FileName.ensurePathExists(p); + + libfile.writev(); + } + + private: + void addSymbol(ObjModule* om, string name, int pickAny = 0) + { + version (LOG) { + printf("Library.addSymbol(%s, %s, %d)\n", om.name, name, pickAny); + } + StringValue* s = tab.insert(name); + if (!s) + { + // already in table + if (!pickAny) + { + s = tab.lookup(name); + assert(s); + ObjSymbol* os = cast(ObjSymbol*)s.ptrvalue; + error("multiple definition of %s: %s and %s: %s", + om.name, name, os.om.name, os.name); + } + } + else + { + ObjSymbol* os = new ObjSymbol(); + os.name = name; + os.om = om; + s.ptrvalue = cast(void*)os; + + objsymbols.push(os); + } + } + + void scanObjModule(ObjModule* om) + { + int easyomf; + uint u; + ubyte result = 0; + char name[LIBIDMAX + 1]; + + scope Array names = new Array(); + names.push(null); // don't use index 0 + + assert(om); + easyomf = 0; // assume not EASY-OMF + ubyte* pend = om.base + om.length; + + ubyte* pnext; + for (ubyte* p = om.base; 1; p = pnext) + { + assert(p < pend); + ubyte recTyp = *p++; + ushort recLen = *cast(ushort*)p; + p += 2; + pnext = p + recLen; + recLen--; // forget the checksum + + switch (recTyp) + { + case LNAMES: + case LLNAMES: + while (p + 1 < pnext) + { + uint len = parseName(&p, name.ptr); + names.push(cast(void*)new String(name[0..len].idup)); + } + break; + + case PUBDEF: + if (easyomf) + recTyp = PUB386; // convert to MS format + case PUB386: + if (!(parseIdx(&p) | parseIdx(&p))) + p += 2; // skip seg, grp, frame + while (p + 1 < pnext) + { + uint len = parseName(&p, name.ptr); + p += (recTyp == PUBDEF) ? 2 : 4; // skip offset + parseIdx(&p); // skip type index + addSymbol(om, name[0..len].idup); + } + break; + + case COMDAT: + if (easyomf) + recTyp = COMDAT+1; // convert to MS format + case COMDAT+1: + int pickAny = 0; + + if (*p++ & 5) // if continuation or local comdat + break; + + ubyte attr = *p++; + if (attr & 0xF0) // attr: if multiple instances allowed + pickAny = 1; + p++; // align + + p += 2; // enum data offset + if (recTyp == COMDAT+1) + p += 2; // enum data offset + + parseIdx(&p); // type index + + if ((attr & 0x0F) == 0) // if explicit allocation + { parseIdx(&p); // base group + parseIdx(&p); // base segment + } + + uint idx = parseIdx(&p); // public name index + if( idx == 0 || idx >= names.dim) + { + //debug(printf("[s] name idx=%d, uCntNames=%d\n", idx, uCntNames)); + error("corrupt COMDAT"); + return; + } + + //printf("[s] name='%s'\n",name); + addSymbol(om, (cast(String)names.data[idx]).str, pickAny); + break; + + case ALIAS: + while (p + 1 < pnext) + { + uint len = parseName(&p, name.ptr); + addSymbol(om, name[0..len].idup); + parseName(&p, name.ptr); + } + break; + + case MODEND: + case M386END: + result = 1; + goto Ret; + + case COMENT: + // Recognize Phar Lap EASY-OMF format + { + static ubyte[7] omfstr = [0x80,0xAA,'8','0','3','8','6']; + + if (recLen == omfstr.sizeof) + { + for (uint i = 0; i < omfstr.sizeof; i++) + if (*p++ != omfstr[i]) + goto L1; + easyomf = 1; + break; + L1: ; + } + } + // Recognize .IMPDEF Import Definition Records + { + static ubyte[3] omfstr = [0, 0xA0, 1]; + + if (recLen >= 7) + { + p++; + for (uint i = 1; i < omfstr.sizeof; i++) + if (*p++ != omfstr[i]) + goto L2; + p++; // skip OrdFlag field + uint len = parseName(&p, name.ptr); + addSymbol(om, name[0..len].idup); + break; + L2: ; + } + } + break; + + default: + // ignore + ; + } + } + + Ret: + ; + ///for (u = 1; u < names.dim; u++) + /// free(names.data[u]); + } + + /*********************************** + * Calculates number of pages needed for dictionary + * Returns: + * number of pages + */ + ushort numDictPages(uint padding) + { + ushort ndicpages; + ushort bucksForHash; + ushort bucksForSize; + uint symSize = 0; + + for (int i = 0; i < objsymbols.dim; i++) + { + ObjSymbol* s = cast(ObjSymbol*)objsymbols.data[i]; + symSize += ( s.name.length + 4 ) & ~1; + } + + for (int i = 0; i < objmodules.dim; i++) + { + ObjModule* om = cast(ObjModule*)objmodules.data[i]; + + size_t len = om.name.length; + if (len > 0xFF) + len += 2; // Digital Mars long name extension + symSize += ( len + 4 + 1 ) & ~1; + } + + bucksForHash = cast(ushort)((objsymbols.dim + objmodules.dim + HASHMOD - 3) / (HASHMOD - 2)); + bucksForSize = cast(ushort)((symSize + BUCKETSIZE - padding - padding - 1) / (BUCKETSIZE - padding)); + + ndicpages = (bucksForHash > bucksForSize ) ? bucksForHash : bucksForSize; + //printf("ndicpages = %u\n",ndicpages); + + // Find prime number greater than ndicpages + static uint[] primes = + [ 1,2,3,5,7,11,13,17,19,23,29,31,37,41,43, + 47,53,59,61,67,71,73,79,83,89,97,101,103, + 107,109,113,127,131,137,139,149,151,157, + 163,167,173,179,181,191,193,197,199,211, + 223,227,229,233,239,241,251,257,263,269, + 271,277,281,283,293,307,311,313,317,331, + 337,347,349,353,359,367,373,379,383,389, + 397,401,409,419,421,431,433,439,443,449, + 457,461,463,467,479,487,491,499,503,509, + //521,523,541,547, + 0 + ]; + + for (int i = 0; 1; i++) + { + if ( primes[i] == 0 ) + { + // Quick and easy way is out. + // Now try and find first prime number > ndicpages + uint prime; + + for (prime = (ndicpages + 1) | 1; 1; prime += 2) + { // Determine if prime is prime + for (uint u = 3; u < prime / 2; u += 2) + { + if ((prime / u) * u == prime) + goto L1; + } + break; + + L1: ; + } + ndicpages = cast(ushort)prime; + break; + } + + if (primes[i] > ndicpages) + { + ndicpages = cast(ushort)primes[i]; + break; + } + } + + return ndicpages; + } + + /******************************************* + * Write the module and symbol names to the dictionary. + * Returns: + * 0 failure + */ + int FillDict(ubyte* bucketsP, ushort ndicpages) + { + ubyte entry[4 + LIBIDMAX + 2 + 1]; + + //printf("FillDict()\n"); + + // Add each of the module names + for (int i = 0; i < objmodules.dim; i++) + { + ObjModule* om = cast(ObjModule*)objmodules.data[i]; + + ushort n = cast(ushort)om.name.length; + if (n > 255) + { + entry[0] = 0xFF; + entry[1] = 0; + *cast(ushort*)(entry.ptr + 2) = cast(ushort)(n + 1); + memcpy(entry.ptr + 4, om.name.ptr, n); + n += 3; + } + else + { + entry[ 0 ] = cast(ubyte)(1 + n); + memcpy(entry.ptr + 1, om.name.ptr, n ); + } + entry[ n + 1 ] = '!'; + *(cast(ushort*)( n + 2 + entry.ptr )) = om.page; + if ( n & 1 ) + entry[ n + 2 + 2 ] = 0; + if ( !EnterDict( bucketsP, ndicpages, entry.ptr, n + 1 ) ) + return 0; + } + + // Sort the symbols + qsort( objsymbols.data, objsymbols.dim, 4, /*(cmpfunc_t)*/&D_NameCompare ); + + // Add each of the symbols + for (int i = 0; i < objsymbols.dim; i++) + { + ObjSymbol* os = cast(ObjSymbol*)objsymbols.data[i]; + + ushort n = cast(ushort)os.name.length; + if (n > 255) + { + entry[0] = 0xFF; + entry[1] = 0; + *cast(ushort*)(entry.ptr + 2) = n; + memcpy(entry.ptr + 4, os.name.ptr, n); + n += 3; + } + else + { + entry[ 0 ] = cast(ubyte)n; + memcpy( entry.ptr + 1, os.name.ptr, n ); + } + *(cast(ushort*)( n + 1 + entry.ptr )) = os.om.page; + if ( (n & 1) == 0 ) + entry[ n + 3] = 0; + if ( !EnterDict( bucketsP, ndicpages, entry.ptr, n ) ) + { + return 0; + } + } + + return 1; + } + + /********************************************** + * Create and write library to libbuf. + * The library consists of: + * library header + * object modules... + * dictionary header + * dictionary pages... + */ + void WriteLibToBuffer(OutBuffer libbuf) + { + /* Scan each of the object modules for symbols + * to go into the dictionary + */ + for (int i = 0; i < objmodules.dim; i++) + { + ObjModule* om = cast(ObjModule*)objmodules.data[i]; + scanObjModule(om); + } + + uint g_page_size = 16; + + /* Calculate page size so that the number of pages + * fits in 16 bits. This is because object modules + * are indexed by page number, stored as an unsigned short. + */ + while (1) + { + Lagain: + version (LOG) { + printf("g_page_size = %d\n", g_page_size); + } + uint offset = g_page_size; + + for (int i = 0; i < objmodules.dim; i++) + { + ObjModule* om = cast(ObjModule*)objmodules.data[i]; + + uint page = offset / g_page_size; + if (page > 0xFFFF) + { + // Page size is too small, double it and try again + g_page_size *= 2; + goto Lagain; + } + + // Write out the object module m + if (om.flags & MFgentheadr) // if generate THEADR record + { + size_t size = om.name.length; + assert(size <= LIBIDMAX); + + offset += size + 5; + //offset += om.length - (size + 5); + offset += om.length; + } + else + offset += om.length; + + // Round the size of the file up to the next page size + // by filling with 0s + uint n = (g_page_size - 1) & offset; + if (n) + offset += g_page_size - n; + } + break; + } + + + /* Leave one page of 0s at start as a dummy library header. + * Fill it in later with the real data. + */ + libbuf.fill0(g_page_size); + + /* Write each object module into the library + */ + for (int i = 0; i < objmodules.dim; i++) + { + ObjModule* om = cast(ObjModule*)objmodules.data[i]; + + uint page = libbuf.offset / g_page_size; + assert(page <= 0xFFFF); + om.page = cast(ushort)page; + + // Write out the object module om + if (om.flags & MFgentheadr) // if generate THEADR record + { + uint size = om.name.length; + ubyte header[4 + LIBIDMAX + 1]; + + header [0] = THEADR; + header [1] = cast(ubyte)(2 + size); + header [2] = 0; + header [3] = cast(ubyte)size; + assert(size <= 0xFF - 2); + + memcpy(4 + header.ptr, om.name.ptr, size); + + // Compute and store record checksum + uint n = size + 4; + ubyte checksum = 0; + ubyte* p = header.ptr; + while (n--) + { + checksum -= *p; + p++; + } + *p = checksum; + + libbuf.write(header.ptr, size + 5); + //libbuf.write(om.base, om.length - (size + 5)); + libbuf.write(om.base, om.length); + } + else + libbuf.write(om.base, om.length); + + // Round the size of the file up to the next page size + // by filling with 0s + uint n = (g_page_size - 1) & libbuf.offset; + if (n) + libbuf.fill0(g_page_size - n); + } + + // File offset of start of dictionary + uint offset = libbuf.offset; + + // Write dictionary header, then round it to a BUCKETPAGE boundary + ushort size = (BUCKETPAGE - (cast(short)offset + 3)) & (BUCKETPAGE - 1); + libbuf.writeByte(0xF1); + libbuf.writeword(size); + libbuf.fill0(size); + + // Create dictionary + ubyte* bucketsP = null; + ushort ndicpages; + ushort padding = 32; + for (;;) + { + ndicpages = numDictPages(padding); + + version (LOG) { + printf("ndicpages = %d\n", ndicpages); + } + // Allocate dictionary + if (bucketsP) + bucketsP = cast(ubyte*)realloc(bucketsP, ndicpages * BUCKETPAGE); + else + bucketsP = cast(ubyte*)malloc(ndicpages * BUCKETPAGE); + assert(bucketsP); + memset(bucketsP, 0, ndicpages * BUCKETPAGE); + for (uint u = 0; u < ndicpages; u++) + { + // 'next available' slot + bucketsP[u * BUCKETPAGE + HASHMOD] = (HASHMOD + 1) >> 1; + } + + if (FillDict(bucketsP, ndicpages)) + break; + padding += 16; // try again with more margins + } + + // Write dictionary + libbuf.write(bucketsP, ndicpages * BUCKETPAGE); + if (bucketsP) + free(bucketsP); + + // Create library header + Libheader libHeader; + memset(&libHeader, 0, Libheader.sizeof); + libHeader.recTyp = 0xF0; + libHeader.recLen = 0x0D; + libHeader.trailerPosn = offset + (3 + size); + libHeader.recLen = cast(ushort)(g_page_size - 3); + libHeader.ndicpages = ndicpages; + libHeader.flags = 1; // always case sensitive + + // Write library header at start of buffer + memcpy(libbuf.data, &libHeader, libHeader.sizeof); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/Library__.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Library__.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,976 @@ +module dmd.Library; + +import dmd.File; +import dmd.Array; +import dmd.StringTable; +import dmd.OutBuffer; +import dmd.ObjModule; +import dmd.String; +import dmd.Global; +import dmd.File; +import dmd.FileName; +import dmd.Util; +import dmd.StringValue; +import dmd.String; + +import core.stdc.string; +import core.stdc.stdlib; + +align(1) +struct LibHeader +{ + ubyte recTyp; // 0xF0 + ushort pagesize; + int lSymSeek; + ushort ndicpages; + ubyte flags; +} + +align(1) +struct Libheader +{ + ubyte recTyp; + ushort recLen; + int trailerPosn; + ushort ndicpages; + ubyte flags; + char[6] filler; +} + +struct ObjSymbol +{ + const(char)* name; + ObjModule* om; +} + +/************************** + * Record types: + */ + +enum HASHMOD = 0x25; +enum BUCKETPAGE = 512; +enum BUCKETSIZE = (BUCKETPAGE - HASHMOD - 1); + +/+ +#define RHEADR 0x6E +#define REGINT 0x70 +#define REDATA 0x72 +#define RIDATA 0x74 +#define OVLDEF 0x76 +#define ENDREC 0x78 +#define BLKDEF 0x7A +#define BLKEND 0x7C +#define DEBSYM 0x7E ++/ +enum THEADR = 0x80; +enum LHEADR = 0x82; +/+#define PEDATA 0x84 +#define PIDATA 0x86 ++/ +enum COMENT = 0x88; +enum MODEND = 0x8A; +enum M386END = 0x8B; /* 32 bit module end record */ +/+ +#define EXTDEF 0x8C +#define TYPDEF 0x8E ++/ +enum PUBDEF = 0x90; +enum PUB386 = 0x91; +/+ +#define LOCSYM 0x92 +#define LINNUM 0x94 ++/ +enum LNAMES = 0x96; +/+ +#define SEGDEF 0x98 +#define GRPDEF 0x9A +#define FIXUPP 0x9C +/*#define (none) 0x9E */ +#define LEDATA 0xA0 +#define LIDATA 0xA2 +#define LIBHED 0xA4 +#define LIBNAM 0xA6 +#define LIBLOC 0xA8 +#define LIBDIC 0xAA +#define COMDEF 0xB0 +#define LEXTDEF 0xB4 +#define LPUBDEF 0xB6 +#define LCOMDEF 0xB8 +#define CEXTDEF 0xBC ++/ +enum COMDAT = 0xC2; +/+#define LINSYM 0xC4 ++/ +enum ALIAS = 0xC6; +enum LLNAMES = 0xCA; + + +enum LIBIDMAX = (512 - 0x25 - 3 - 4); // max size that will fit in dictionary + +extern (C) extern char* strdup(const(char)* ptr); + +static void parseName(ubyte** pp, char* name) +{ + ubyte* p = *pp; + uint len = *p++; + + if (len == 0xFF && *p == 0) // if long name + { + len = p[1] & 0xFF; + len |= cast(uint)p[2] << 8; + p += 3; + assert(len <= LIBIDMAX); + } + + memcpy(name, p, len); + name[len] = 0; + *pp = p + len; +} + +static ushort parseIdx(ubyte** pp) +{ + ubyte* p = *pp; + ubyte c = *p++; + + ushort idx = cast(ushort)((0x80 & c) ? ((0x7F & c) << 8) + *p++ : c); + *pp = p; + return idx; +} + +extern (C) int D_NameCompare(const(void*) a, const(void*) b) +{ + ObjSymbol** p1 = cast(ObjSymbol**)a; + ObjSymbol** p2 = cast(ObjSymbol**)b; + + return strcmp((*p1).name, (*p2).name); +} + +/******************************************* + * Write a single entry into dictionary. + * Returns: + * 0 failure + */ + +extern (C) extern uint _rotl(uint value, int shift); +extern (C) extern uint _rotr(uint value, int shift); + +static int EnterDict(ubyte* bucketsP, ushort ndicpages, ubyte* entry, uint entrylen) +{ + ushort uStartIndex; + ushort uStep; + ushort uStartPage; + ushort uPageStep; + ushort uIndex; + ushort uPage; + ushort n; + uint u; + uint nbytes; + ubyte* aP; + ubyte* zP; + + aP = entry; + zP = aP + entrylen; // point at last char in identifier + + uStartPage = 0; + uPageStep = 0; + uStartIndex = 0; + uStep = 0; + + u = entrylen; + while ( u-- ) + { + uStartPage = cast(ushort)_rotl( uStartPage, 2 ) ^ ( *aP | 0x20 ); + uStep = cast(ushort)_rotr( uStep, 2 ) ^ ( *aP++ | 0x20 ); + uStartIndex = cast(ushort)_rotr( uStartIndex, 2 ) ^ ( *zP | 0x20 ); + uPageStep = cast(ushort)_rotl( uPageStep, 2 ) ^ ( *zP-- | 0x20 ); + } + + uStartPage %= ndicpages; + uPageStep %= ndicpages; + if ( uPageStep == 0 ) + uPageStep++; + uStartIndex %= HASHMOD; + uStep %= HASHMOD; + if ( uStep == 0 ) + uStep++; + + uPage = uStartPage; + uIndex = uStartIndex; + + // number of bytes in entry + nbytes = 1 + entrylen + 2; + if (entrylen > 255) + nbytes += 2; + + while (1) + { + aP = &bucketsP[uPage * BUCKETPAGE]; + uStartIndex = uIndex; + while (1) + { + if ( 0 == aP[ uIndex ] ) + { + // n = next available position in this page + n = aP[ HASHMOD ] << 1; + assert(n > HASHMOD); + + // if off end of this page + if (n + nbytes > BUCKETPAGE ) + { aP[ HASHMOD ] = 0xFF; + break; // next page + } + else + { + aP[ uIndex ] = cast(ubyte)(n >> 1); + memcpy( (aP + n), entry, nbytes ); + aP[ HASHMOD ] += (nbytes + 1) >> 1; + if (aP[HASHMOD] == 0) + aP[HASHMOD] = 0xFF; + return 1; + } + } + uIndex += uStep; + uIndex %= 0x25; + /*if (uIndex > 0x25) + uIndex -= 0x25;*/ + if( uIndex == uStartIndex ) + break; + } + uPage += uPageStep; + if (uPage >= ndicpages) + uPage -= ndicpages; + if( uPage == uStartPage ) + break; + } + + return 0; +} + +class Library +{ + File libfile; + Array objmodules; // ObjModule[] + Array objsymbols; // ObjSymbol[] + + StringTable tab; + + this() + { + libfile = null; + + objmodules = new Array(); + objsymbols = new Array(); + tab = new StringTable(); + } + + /*********************************** + * Set the library file name based on the output directory + * and the filename. + * Add default library file name extension. + */ + void setFilename(string dir, string filename) + { + string arg = filename; + if (arg.length == 0) + { + // Generate lib file name from first obj name + string n = (cast(String)global.params.objfiles.data[0]).str; + + n = FileName.name(n); + FileName fn = FileName.forceExt(n, global.lib_ext); + arg = fn.toChars(); + } + if (!FileName.absolute(arg)) + arg = FileName.combine(dir, arg); + + FileName libfilename = FileName.defaultExt(arg, global.lib_ext); + libfile = new File(libfilename); + } + + /*************************************** + * Add object module or library to the library. + * Examine the buffer to see which it is. + * If the buffer is null, use module_name as the file name + * and load the file. + */ + void addObject(string module_name, void *buf, size_t buflen) + { + version (LOG) { + printf("Library.addObject(%s)\n", module_name ? module_name : ""); + } + if (!buf) + { + assert(module_name); + scope FileName f = new FileName(module_name); + scope File file = new File(f); + file.readv(); + buf = file.buffer; + buflen = file.len; + file.ref_ = 1; + } + + uint g_page_size; + ubyte* pstart = cast(ubyte*)buf; + int islibrary = 0; + + /* See if it's an OMF library. + * Don't go by file extension. + */ + + /* Determine if it is an OMF library, an OMF object module, + * or something else. + */ + if (buflen < LibHeader.sizeof) + { + Lcorrupt: + error("corrupt object module"); + } + LibHeader* lh = cast(LibHeader*)buf; + if (lh.recTyp == 0xF0) + { /* OMF library + * The modules are all at buf[g_page_size .. lh.lSymSeek] + */ + islibrary = 1; + g_page_size = lh.pagesize + 3; + buf = cast(void*)(pstart + g_page_size); + if (lh.lSymSeek > buflen || + g_page_size > buflen) + goto Lcorrupt; + buflen = lh.lSymSeek - g_page_size; + } + else if (lh.recTyp == '!' && memcmp(lh, "!\n".ptr, 8) == 0) + { + error("COFF libraries not supported"); + return; + } + else + { + // Not a library, assume OMF object module + g_page_size = 16; + } + + /* Split up the buffer buf[0..buflen] into multiple object modules, + * each aligned on a g_page_size boundary. + */ + + ObjModule* om = null; + int first_module = 1; + + ubyte* p = cast(ubyte*)buf; + ubyte* pend = p + buflen; + ubyte* pnext; + for (; p < pend; p = pnext) // for each OMF record + { + if (p + 3 >= pend) + goto Lcorrupt; + ubyte recTyp = *p; + ushort recLen = *cast(ushort*)(p + 1); + pnext = p + 3 + recLen; + if (pnext > pend) + goto Lcorrupt; + recLen--; /* forget the checksum */ + + switch (recTyp) + { + case LHEADR : + case THEADR : + if (!om) + { + char name[LIBIDMAX + 1]; + om = new ObjModule(); + om.flags = 0; + om.base = p; + p += 3; + parseName(&p, name.ptr); + if (first_module && module_name && !islibrary) + { + // Remove path and extension + string fname = FileName.name(module_name); + string ext = FileName.ext(fname); + if (ext.length != 0) { + fname = fname[0..$-ext.length-1]; + } + + om.name = toStringz(fname); + } + else + { + /* Use THEADR name as module name, + * removing path and extension. + */ + string fname = FileName.name(fromStringz(name.ptr)); + string ext = FileName.ext(fname); + if (ext.length != 0) { + fname = fname[0..$-ext.length-1]; + } + + om.name = toStringz(fname); + om.flags |= MFtheadr; + } + if (strcmp(name.ptr, "C".ptr) == 0) // old C compilers did this + { + om.flags |= MFgentheadr; // generate our own THEADR + om.base = pnext; // skip past THEADR + } + objmodules.push(cast(void*)om); + first_module = 0; + } + break; + + case MODEND : + case M386END: + if (om) + { + om.page = cast(ushort)((om.base - pstart) / g_page_size); + om.length = pnext - om.base; + om = null; + } + // Round up to next page + uint t = pnext - pstart; + t = (t + g_page_size - 1) & ~cast(uint)(g_page_size - 1); + pnext = pstart + t; + break; + + default: + // ignore + ; + } + } + + if (om) + goto Lcorrupt; // missing MODEND record + } + + void addLibrary(void *buf, size_t buflen) + { + assert(false); + } + + void write() + { + if (global.params.verbose) + writef("library %s\n", libfile.name.toChars()); + + scope OutBuffer libbuf = new OutBuffer(); + WriteLibToBuffer(libbuf); + + // Transfer image to file + libfile.setbuffer(libbuf.data, libbuf.offset); + libbuf.extractData(); + + string p = FileName.path(libfile.name.toChars()); + FileName.ensurePathExists(p); + + libfile.writev(); + } + + private: + void addSymbol(ObjModule* om, const(char)* name, int pickAny = 0) + { + version (LOG) { + printf("Library.addSymbol(%s, %s, %d)\n", om.name, name, pickAny); + } + StringValue *s = tab.insert(fromStringz(name)); + if (!s) + { // already in table + if (!pickAny) + { + s = tab.lookup(fromStringz(name)); + assert(s); + ObjSymbol* os = cast(ObjSymbol*)s.ptrvalue; + error("multiple definition of %s: %s and %s: %s", + om.name, name, os.om.name, os.name); + } + } + else + { + ObjSymbol* os = new ObjSymbol(); + os.name = strdup(name); + os.om = om; + s.ptrvalue = cast(void*)os; + + objsymbols.push(cast(void*)os); + } + } + + void scanObjModule(ObjModule* om) + { + int easyomf; + uint u; + ubyte result = 0; + char name[LIBIDMAX + 1]; + + scope Array names = new Array(); + names.push(null); // don't use index 0 + + assert(om); + easyomf = 0; // assume not EASY-OMF + ubyte* pend = om.base + om.length; + + ubyte* pnext; + for (ubyte* p = om.base; 1; p = pnext) + { + assert(p < pend); + ubyte recTyp = *p++; + ushort recLen = *cast(ushort*)p; + p += 2; + pnext = p + recLen; + recLen--; // forget the checksum + + switch (recTyp) + { + case LNAMES: + case LLNAMES: + while (p + 1 < pnext) + { + parseName(&p, name.ptr); + names.push(strdup(name.ptr)); + } + break; + + case PUBDEF: + if (easyomf) + recTyp = PUB386; // convert to MS format + case PUB386: + if (!(parseIdx(&p) | parseIdx(&p))) + p += 2; // skip seg, grp, frame + while (p + 1 < pnext) + { + parseName(&p, name.ptr); + p += (recTyp == PUBDEF) ? 2 : 4; // skip offset + parseIdx(&p); // skip type index + addSymbol(om, name.ptr); + } + break; + + case COMDAT: + if (easyomf) + recTyp = COMDAT+1; // convert to MS format + case COMDAT+1: + int pickAny = 0; + + if (*p++ & 5) // if continuation or local comdat + break; + + ubyte attr = *p++; + if (attr & 0xF0) // attr: if multiple instances allowed + pickAny = 1; + p++; // align + + p += 2; // enum data offset + if (recTyp == COMDAT+1) + p += 2; // enum data offset + + parseIdx(&p); // type index + + if ((attr & 0x0F) == 0) // if explicit allocation + { parseIdx(&p); // base group + parseIdx(&p); // base segment + } + + uint idx = parseIdx(&p); // public name index + if( idx == 0 || idx >= names.dim) + { + //debug(printf("[s] name idx=%d, uCntNames=%d\n", idx, uCntNames)); + error("corrupt COMDAT"); + return; + } + + //printf("[s] name='%s'\n",name); + addSymbol(om, cast(const(char)*)names.data[idx], pickAny); + break; + + case ALIAS: + while (p + 1 < pnext) + { + parseName(&p, name.ptr); + addSymbol(om, name.ptr); + parseName(&p, name.ptr); + } + break; + + case MODEND: + case M386END: + result = 1; + goto Ret; + + case COMENT: + // Recognize Phar Lap EASY-OMF format + { + static ubyte[7] omfstr = [0x80,0xAA,'8','0','3','8','6']; + + if (recLen == omfstr.sizeof) + { + for (uint i = 0; i < omfstr.sizeof; i++) + if (*p++ != omfstr[i]) + goto L1; + easyomf = 1; + break; + L1: ; + } + } + // Recognize .IMPDEF Import Definition Records + { + static ubyte[3] omfstr = [0, 0xA0, 1]; + + if (recLen >= 7) + { + p++; + for (uint i = 1; i < omfstr.sizeof; i++) + if (*p++ != omfstr[i]) + goto L2; + p++; // skip OrdFlag field + parseName(&p, name.ptr); + addSymbol(om, name.ptr); + break; + L2: ; + } + } + break; + + default: + // ignore + ; + } + } + + Ret: + ; + ///for (u = 1; u < names.dim; u++) + /// free(names.data[u]); + } + + /*********************************** + * Calculates number of pages needed for dictionary + * Returns: + * number of pages + */ + ushort numDictPages(uint padding) + { + ushort ndicpages; + ushort bucksForHash; + ushort bucksForSize; + uint symSize = 0; + + for (int i = 0; i < objsymbols.dim; i++) + { + ObjSymbol* s = cast(ObjSymbol*)objsymbols.data[i]; + symSize += ( strlen(s.name) + 4 ) & ~1; + } + + for (int i = 0; i < objmodules.dim; i++) + { + ObjModule* om = cast(ObjModule*)objmodules.data[i]; + + size_t len = strlen(om.name); + if (len > 0xFF) + len += 2; // Digital Mars long name extension + symSize += ( len + 4 + 1 ) & ~1; + } + + bucksForHash = cast(ushort)((objsymbols.dim + objmodules.dim + HASHMOD - 3) / (HASHMOD - 2)); + bucksForSize = cast(ushort)((symSize + BUCKETSIZE - padding - padding - 1) / (BUCKETSIZE - padding)); + + ndicpages = (bucksForHash > bucksForSize ) ? bucksForHash : bucksForSize; + //printf("ndicpages = %u\n",ndicpages); + + // Find prime number greater than ndicpages + static uint[] primes = + [ 1,2,3,5,7,11,13,17,19,23,29,31,37,41,43, + 47,53,59,61,67,71,73,79,83,89,97,101,103, + 107,109,113,127,131,137,139,149,151,157, + 163,167,173,179,181,191,193,197,199,211, + 223,227,229,233,239,241,251,257,263,269, + 271,277,281,283,293,307,311,313,317,331, + 337,347,349,353,359,367,373,379,383,389, + 397,401,409,419,421,431,433,439,443,449, + 457,461,463,467,479,487,491,499,503,509, + //521,523,541,547, + 0 + ]; + + for (int i = 0; 1; i++) + { + if ( primes[i] == 0 ) + { + // Quick and easy way is out. + // Now try and find first prime number > ndicpages + uint prime; + + for (prime = (ndicpages + 1) | 1; 1; prime += 2) + { // Determine if prime is prime + for (uint u = 3; u < prime / 2; u += 2) + { + if ((prime / u) * u == prime) + goto L1; + } + break; + + L1: ; + } + ndicpages = cast(ushort)prime; + break; + } + + if (primes[i] > ndicpages) + { + ndicpages = cast(ushort)primes[i]; + break; + } + } + + return ndicpages; + } + + /******************************************* + * Write the module and symbol names to the dictionary. + * Returns: + * 0 failure + */ + int FillDict(ubyte* bucketsP, ushort ndicpages) + { + ubyte entry[4 + LIBIDMAX + 2 + 1]; + + //printf("FillDict()\n"); + + // Add each of the module names + for (int i = 0; i < objmodules.dim; i++) + { + ObjModule* om = cast(ObjModule*)objmodules.data[i]; + + ushort n = cast(ushort)strlen(om.name); + if (n > 255) + { + entry[0] = 0xFF; + entry[1] = 0; + *cast(ushort*)(entry.ptr + 2) = cast(ushort)(n + 1); + memcpy(entry.ptr + 4, om.name, n); + n += 3; + } + else + { + entry[ 0 ] = cast(ubyte)(1 + n); + memcpy(entry.ptr + 1, om.name, n ); + } + + entry[ n + 1 ] = '!'; + *(cast(ushort*)( n + 2 + entry.ptr )) = om.page; + if ( n & 1 ) + entry[ n + 2 + 2 ] = 0; + if ( !EnterDict( bucketsP, ndicpages, entry.ptr, n + 1 ) ) + return 0; + } + + // Sort the symbols + qsort( objsymbols.data, objsymbols.dim, 4, /*(cmpfunc_t)*/&D_NameCompare ); + + // Add each of the symbols + for (int i = 0; i < objsymbols.dim; i++) + { + ObjSymbol* os = cast(ObjSymbol*)objsymbols.data[i]; + + ushort n = cast(ushort)strlen(os.name); + if (n > 255) + { + entry[0] = 0xFF; + entry[1] = 0; + *cast(ushort*)(entry.ptr + 2) = n; + memcpy(entry.ptr + 4, os.name, n); + n += 3; + } + else + { + entry[ 0 ] = cast(ubyte)n; + memcpy( entry.ptr + 1, os.name, n ); + } + *(cast(ushort*)( n + 1 + entry.ptr )) = os.om.page; + if ( (n & 1) == 0 ) + entry[ n + 3] = 0; + if ( !EnterDict( bucketsP, ndicpages, entry.ptr, n ) ) + { + return 0; + } + } + + return 1; + } + + /********************************************** + * Create and write library to libbuf. + * The library consists of: + * library header + * object modules... + * dictionary header + * dictionary pages... + */ + void WriteLibToBuffer(OutBuffer libbuf) + { + /* Scan each of the object modules for symbols + * to go into the dictionary + */ + for (int i = 0; i < objmodules.dim; i++) + { + ObjModule* om = cast(ObjModule*)objmodules.data[i]; + scanObjModule(om); + } + + uint g_page_size = 16; + + /* Calculate page size so that the number of pages + * fits in 16 bits. This is because object modules + * are indexed by page number, stored as an unsigned short. + */ + while (1) + { + Lagain: + version (LOG) { + printf("g_page_size = %d\n", g_page_size); + } + uint offset = g_page_size; + + for (int i = 0; i < objmodules.dim; i++) + { + ObjModule* om = cast(ObjModule*)objmodules.data[i]; + + uint page = offset / g_page_size; + if (page > 0xFFFF) + { + // Page size is too small, double it and try again + g_page_size *= 2; + goto Lagain; + } + + // Write out the object module m + if (om.flags & MFgentheadr) // if generate THEADR record + { + size_t size = strlen(om.name); + assert(size <= LIBIDMAX); + + offset += size + 5; + //offset += om.length - (size + 5); + offset += om.length; + } + else + offset += om.length; + + // Round the size of the file up to the next page size + // by filling with 0s + uint n = (g_page_size - 1) & offset; + if (n) + offset += g_page_size - n; + } + break; + } + + + /* Leave one page of 0s at start as a dummy library header. + * Fill it in later with the real data. + */ + libbuf.fill0(g_page_size); + + /* Write each object module into the library + */ + for (int i = 0; i < objmodules.dim; i++) + { + ObjModule* om = cast(ObjModule*)objmodules.data[i]; + + uint page = libbuf.offset / g_page_size; + assert(page <= 0xFFFF); + om.page = cast(ushort)page; + + // Write out the object module om + if (om.flags & MFgentheadr) // if generate THEADR record + { + uint size = strlen(om.name); + ubyte header[4 + LIBIDMAX + 1]; + + header [0] = THEADR; + header [1] = cast(ubyte)(2 + size); + header [2] = 0; + header [3] = cast(ubyte)size; + assert(size <= 0xFF - 2); + + memcpy(4 + header.ptr, om.name, size); + + // Compute and store record checksum + uint n = size + 4; + ubyte checksum = 0; + ubyte* p = header.ptr; + while (n--) + { + checksum -= *p; + p++; + } + *p = checksum; + + libbuf.write(header.ptr, size + 5); + //libbuf.write(om.base, om.length - (size + 5)); + libbuf.write(om.base, om.length); + } + else + libbuf.write(om.base, om.length); + + // Round the size of the file up to the next page size + // by filling with 0s + uint n = (g_page_size - 1) & libbuf.offset; + if (n) + libbuf.fill0(g_page_size - n); + } + + // File offset of start of dictionary + uint offset = libbuf.offset; + + // Write dictionary header, then round it to a BUCKETPAGE boundary + ushort size = (BUCKETPAGE - (cast(short)offset + 3)) & (BUCKETPAGE - 1); + libbuf.writeByte(0xF1); + libbuf.writeword(size); + libbuf.fill0(size); + + // Create dictionary + ubyte* bucketsP = null; + ushort ndicpages; + ushort padding = 32; + for (;;) + { + ndicpages = numDictPages(padding); + + version (LOG) { + printf("ndicpages = %d\n", ndicpages); + } + // Allocate dictionary + if (bucketsP) + bucketsP = cast(ubyte*)realloc(bucketsP, ndicpages * BUCKETPAGE); + else + bucketsP = cast(ubyte*)malloc(ndicpages * BUCKETPAGE); + assert(bucketsP); + memset(bucketsP, 0, ndicpages * BUCKETPAGE); + for (uint u = 0; u < ndicpages; u++) + { + // 'next available' slot + bucketsP[u * BUCKETPAGE + HASHMOD] = (HASHMOD + 1) >> 1; + } + + if (FillDict(bucketsP, ndicpages)) + break; + padding += 16; // try again with more margins + } + + // Write dictionary + libbuf.write(bucketsP, ndicpages * BUCKETPAGE); + if (bucketsP) + free(bucketsP); + + // Create library header + Libheader libHeader; + memset(&libHeader, 0, Libheader.sizeof); + libHeader.recTyp = 0xF0; + libHeader.recLen = 0x0D; + libHeader.trailerPosn = offset + (3 + size); + libHeader.recLen = cast(ushort)(g_page_size - 3); + libHeader.ndicpages = ndicpages; + libHeader.flags = 1; // always case sensitive + + // Write library header at start of buffer + memcpy(libbuf.data, &libHeader, libHeader.sizeof); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/LineInitExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/LineInitExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,26 @@ +module dmd.LineInitExp; + +import dmd.Expression; +import dmd.Loc; +import dmd.Scope; +import dmd.DefaultInitExp; +import dmd.TOK; + +class LineInitExp : DefaultInitExp +{ + this(Loc loc) + { + assert(false); + super(loc, TOK.init, 0); + } + + Expression semantic(Scope sc) + { + assert(false); + } + + Expression resolve(Loc loc, Scope sc) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/LinkDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/LinkDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,75 @@ +module dmd.LinkDeclaration; + +import dmd.AttribDeclaration; +import dmd.LINK; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Scope; +import dmd.Dsymbol; +import dmd.Array; + +class LinkDeclaration : AttribDeclaration +{ + LINK linkage; + + this(LINK p, Array decl) + { + super(decl); + //printf("LinkDeclaration(linkage = %d, decl = %p)\n", p, decl); + linkage = p; + } + + Dsymbol syntaxCopy(Dsymbol s) + { + assert(false); + } + + void setScope(Scope sc) + { + //printf("LinkDeclaration::setScope(linkage = %d, decl = %p)\n", linkage, decl); + if (decl) + { + setScopeNewSc(sc, sc.stc, linkage, sc.protection, sc.explicitProtection, sc.structalign); + } + } + + void semantic(Scope sc) + { + //printf("LinkDeclaration::semantic(linkage = %d, decl = %p)\n", linkage, decl); + if (decl) + { + semanticNewSc(sc, sc.stc, linkage, sc.protection, sc.explicitProtection, sc.structalign); + } + } + + void semantic3(Scope sc) + { + //printf("LinkDeclaration::semantic3(linkage = %d, decl = %p)\n", linkage, decl); + if (decl) + { + LINK linkage_save = sc.linkage; + + sc.linkage = linkage; + for (uint i = 0; i < decl.dim; i++) + { + Dsymbol s = cast(Dsymbol)decl.data[i]; + s.semantic3(sc); + } + sc.linkage = linkage_save; + } + else + { + sc.linkage = linkage; + } + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + string toChars() + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/Loc.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Loc.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,43 @@ +module dmd.Loc; + +import dmd.Module; +import dmd.OutBuffer; + +struct Loc +{ + string filename; + uint linnum; + + this(int x) + { + linnum = x; + filename = null; + } + + this(Module mod, uint linnum) + { + this.linnum = linnum; + this.filename = mod ? mod.srcfile.toChars() : null; + } + + string toChars() + { + scope OutBuffer buf = new OutBuffer(); + + if (filename !is null) { + buf.printf("%s", filename); + } + + if (linnum) { + buf.printf("(%d)", linnum); + buf.writeByte(0); + } + + return buf.extractString(); + } + + bool equals(ref const(Loc) loc) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/Lstring.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Lstring.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,73 @@ +module dmd.Lstring; + +import dmd.Dchar; + +struct Lstring +{ + immutable(dchar_t)[] string_; + + static Lstring zero; // 0 length string + + // No constructors because we want to be able to statically + // initialize Lstring's, and Lstrings are of variable size. + +version (M_UNICODE) { + ///#define LSTRING(p,length) { length, L##p } +} else { + ///#define LSTRING(p,length) { length, p } +} + +///#if __GNUC__ +/// #define LSTRING_EMPTY() { 0 } +///#else +/// #define LSTRING_EMPTY() LSTRING("", 0) +///#endif + + static Lstring* ctor(const(dchar_t)* p) { return ctor(p, Dchar.len(p)); } + + static Lstring* ctor(const(dchar_t)* p, uint length) + { + assert(false); + } + + static uint size(uint length) { return Lstring.sizeof + (length + 1) * dchar_t.sizeof; } + + static Lstring* alloc(uint length) + { + assert(false); + } + + Lstring* clone() + { + assert(false); + } + + uint len() { return string_.length; } + + const(dchar_t)[] toDchars() { return string_; } + + hash_t hash() { return Dchar.calcHash(string_.ptr, string_.length); } + hash_t ihash() { return Dchar.icalcHash(string_.ptr, string_.length); } + + static int cmp(const(Lstring)* s1, const(Lstring)* s2) + { + int c = s2.string_.length - s1.string_.length; + return c ? c : Dchar.memcmp(s1.string_.ptr, s2.string_.ptr, s1.string_.length); + } + + static int icmp(const(Lstring)* s1, const(Lstring)* s2) + { + int c = s2.string_.length - s1.string_.length; + return c ? c : Dchar.memicmp(s1.string_.ptr, s2.string_.ptr, s1.string_.length); + } + + Lstring* append(const(Lstring)* s) + { + assert(false); + } + + Lstring* substring(int start, int end) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/MATCH.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/MATCH.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,24 @@ +module dmd.MATCH; + +version (DMDV2) { + enum MATCH + { + MATCHnomatch, // no match + MATCHconvert, // match with conversions + + MATCHconst, // match with conversion to const + + MATCHexact // exact match + } +} else { + enum MATCH + { + MATCHnomatch, // no match + MATCHconvert, // match with conversions + + MATCHexact // exact match + } +} + +import dmd.EnumUtils; +mixin(BringToCurrentScope!(MATCH)); \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/MOD.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/MOD.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,12 @@ +module dmd.MOD; + +enum MOD +{ + MODundefined = 0, + MODconst = 1, // type is const + MODshared = 2, // type is shared + MODinvariant = 4, // type is invariant +} + +import dmd.EnumUtils; +mixin(BringToCurrentScope!(MOD)); \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/Macro.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Macro.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,5 @@ +module dmd.Macro; + +struct Macro /// ??? +{ +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/MinAssignExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/MinAssignExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,93 @@ +module dmd.MinAssignExp; + +import dmd.BinExp; +import dmd.Loc; +import dmd.Expression; +import dmd.Scope; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.ArrayTypes; +import dmd.Identifier; +import dmd.IRState; +import dmd.TY; +import dmd.TOK; +import dmd.Id; + +import dmd.backend.elem; +import dmd.backend.Util; +import dmd.backend.OPER; + +class MinAssignExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKminass, MinAssignExp.sizeof, e1, e2); + } + + Expression semantic(Scope sc) + { + Expression e; + + if (type) + return this; + + BinExp.semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + if (e1.op == TOKslice) + { // T[] -= ... + typeCombine(sc); + type = e1.type; + return arrayOp(sc); + } + + e1 = e1.modifiableLvalue(sc, e1); + e1.checkScalar(); + e1.checkNoBool(); + if (e1.type.ty == Tpointer && e2.type.isintegral()) + e = scaleFactor(sc); + else + { + e1 = e1.checkArithmetic(); + e2 = e2.checkArithmetic(); + type = e1.type; + typeCombine(sc); + if (type.isreal() || type.isimaginary()) + { + assert(e2.type.isfloating()); + e2 = e2.castTo(sc, e1.type); + } + e = this; + } + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void buildArrayIdent(OutBuffer buf, Expressions arguments) + { + assert(false); + } + + Expression buildArrayLoop(Arguments fparams) + { + assert(false); + } + + Identifier opId() /* For operator overloading */ + { + return Id.subass; + } + + elem* toElem(IRState* irs) + { + return toElemBin(irs,OPminass); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/MinExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/MinExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,179 @@ +module dmd.MinExp; + +import dmd.Expression; +import dmd.TY; +import dmd.ErrorExp; +import dmd.Identifier; +import dmd.IntegerExp; +import dmd.DivExp; +import dmd.Type; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.IRState; +import dmd.ArrayTypes; +import dmd.BinExp; +import dmd.TOK; +import dmd.Id; +import dmd.expression.Min; + +import dmd.backend.elem; +import dmd.backend.Util; +import dmd.backend.OPER; + +class MinExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKmin, MinExp.sizeof, e1, e2); + } + + Expression semantic(Scope sc) + { + Expression e; + Type t1; + Type t2; + +version (LOGSEMANTIC) { + printf("MinExp.semantic('%s')\n", toChars()); +} + if (type) + return this; + + super.semanticp(sc); + + e = op_overload(sc); + if (e) + return e; + + e = this; + t1 = e1.type.toBasetype(); + t2 = e2.type.toBasetype(); + if (t1.ty == TY.Tpointer) + { + if (t2.ty == TY.Tpointer) + { // Need to divide the result by the stride + // Replace (ptr - ptr) with (ptr - ptr) / stride + long stride; + Expression ee; + + typeCombine(sc); // make sure pointer types are compatible + type = Type.tptrdiff_t; + stride = t2.nextOf().size(); + if (stride == 0) + { + ee = new IntegerExp(loc, 0, Type.tptrdiff_t); + } + else + { + ee = new DivExp(loc, this, new IntegerExp(Loc(0), stride, Type.tptrdiff_t)); + ee.type = Type.tptrdiff_t; + } + return ee; + } + else if (t2.isintegral()) + e = scaleFactor(sc); + else + { + error("incompatible types for minus"); + return new ErrorExp(); + } + } + else if (t2.ty == TY.Tpointer) + { + type = e2.type; + error("can't subtract pointer from %s", e1.type.toChars()); + return new ErrorExp(); + } + else + { + typeCombine(sc); + t1 = e1.type.toBasetype(); + t2 = e2.type.toBasetype(); + if ((t1.isreal() && t2.isimaginary()) || + (t1.isimaginary() && t2.isreal())) + { + switch (type.ty) + { + case TY.Tfloat32: + case TY.Timaginary32: + type = Type.tcomplex32; + break; + + case TY.Tfloat64: + case TY.Timaginary64: + type = Type.tcomplex64; + break; + + case TY.Tfloat80: + case TY.Timaginary80: + type = Type.tcomplex80; + break; + + default: + assert(0); + } + } + } + return e; + } + + Expression optimize(int result) + { + Expression e; + + e1 = e1.optimize(result); + e2 = e2.optimize(result); + if (e1.isConst() && e2.isConst()) + { + if (e2.op == TOK.TOKsymoff) + return this; + e = Min(type, e1, e2); + } + else + e = this; + + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void buildArrayIdent(OutBuffer buf, Expressions arguments) + { + assert(false); + } + + Expression buildArrayLoop(Arguments fparams) + { + assert(false); + } + + Identifier opId() + { + return Id.sub; + } + + Identifier opId_r() + { + return Id.sub_r; + } + + elem* toElem(IRState* irs) + { + Type tb1 = e1.type.toBasetype(); + Type tb2 = e2.type.toBasetype(); + + if ((tb1.ty == TY.Tarray || tb1.ty == TY.Tsarray) && (tb2.ty == TY.Tarray || tb2.ty == TY.Tsarray)) + { + error("Array operation %s not implemented", toChars()); + return el_long(type.totym(), 0); // error recovery + } + + return toElemBin(irs, OPER.OPmin); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/ModAssignExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ModAssignExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,53 @@ +module dmd.ModAssignExp; + +import dmd.BinExp; +import dmd.Loc; +import dmd.Expression; +import dmd.Scope; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.ArrayTypes; +import dmd.Identifier; +import dmd.IRState; +import dmd.TOK; + +import dmd.backend.elem; + +class ModAssignExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + assert(false); + super(loc, TOK.init, 0, e1, e2); + } + + Expression semantic(Scope sc) + { + assert(false); + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void buildArrayIdent(OutBuffer buf, Expressions arguments) + { + assert(false); + } + + Expression buildArrayLoop(Arguments fparams) + { + assert(false); + } + + Identifier opId() /* For operator overloading */ + { + assert(false); + } + + elem* toElem(IRState* irs) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ModExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ModExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,150 @@ +module dmd.ModExp; + +import dmd.Expression; +import dmd.Identifier; +import dmd.backend.elem; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.IRState; +import dmd.ArrayTypes; +import dmd.BinExp; +import dmd.TOK; +import dmd.Id; +import dmd.ErrorExp; + +import dmd.expression.Util; +import dmd.expression.Mod; +import dmd.backend.RTLSYM; +import dmd.backend.OPER; +import dmd.backend.Util; + +class ModExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKmod, ModExp.sizeof, e1, e2); + } + + Expression semantic(Scope sc) + { + Expression e; + + if (type) + return this; + + BinExp.semanticp(sc); + e = op_overload(sc); + if (e) + return e; + + typeCombine(sc); + if (e1.op != TOKslice && e2.op != TOKslice) + { + e1.checkArithmetic(); + e2.checkArithmetic(); + } + if (type.isfloating()) + { + type = e1.type; + if (e2.type.iscomplex()) + { + error("cannot perform modulo complex arithmetic"); + return new ErrorExp(); + } + } + return this; + } + + Expression optimize(int result) + { + Expression e; + + e1 = e1.optimize(result); + e2 = e2.optimize(result); + if (e1.isConst() == 1 && e2.isConst() == 1) + { + e = Mod(type, e1, e2); + } + else + e = this; + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void buildArrayIdent(OutBuffer buf, Expressions arguments) + { + assert(false); + } + + Expression buildArrayLoop(Arguments fparams) + { + assert(false); + } + + Identifier opId() + { + return Id.mod; + } + + Identifier opId_r() + { + return Id.mod_r; + } + + elem* toElem(IRState* irs) + { + elem* e; + elem* e1; + elem* e2; + tym_t tym; + + tym = type.totym(); + + e1 = this.e1.toElem(irs); + e2 = this.e2.toElem(irs); + + static if (false) { // Now inlined + if (this.e1.type.isfloating()) + { + elem* ep; + + switch (this.e1.type.ty) + { + case Tfloat32: + case Timaginary32: + e1 = el_una(OPf_d, TYdouble, e1); + e2 = el_una(OPf_d, TYdouble, e2); + case Tfloat64: + case Timaginary64: + e1 = el_una(OPd_ld, TYldouble, e1); + e2 = el_una(OPd_ld, TYldouble, e2); + break; + case Tfloat80: + case Timaginary80: + break; + default: + assert(0); + break; + } + ep = el_param(e2,e1); + e = el_bin(OPcall,tym,el_var(rtlsym[RTLSYM_MODULO]),ep); + } + else + { + e = el_bin(OPmod,tym,e1,e2); + el_setLoc(e,loc); + } + } else { + e = el_bin(OPmod,tym,e1,e2); + el_setLoc(e,loc); + } + return e; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/Module.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Module.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,1564 @@ +module dmd.Module; + +import dmd.Package; +import dmd.DsymbolTable; +import dmd.backend.TYM; +import dmd.Array; +import dmd.StaticDtorDeclaration; +import dmd.Scope; +import dmd.Id; +import dmd.Import; +import dmd.ClassDeclaration; +import dmd.ModuleDeclaration; +import dmd.File; +import dmd.Identifier; +import dmd.Dsymbol; +import dmd.ModuleInfoDeclaration; +import dmd.FuncDeclaration; +import dmd.Loc; +import dmd.Macro; +import dmd.Escape; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.ArrayTypes; +import dmd.FileName; +import dmd.Global; +import dmd.Parser; +import dmd.Lexer; +import dmd.Util; +import dmd.String; +import dmd.ScopeDsymbol; +import dmd.Type; +import dmd.backend.TYPE; +import dmd.backend.Cstate; +import dmd.backend.OPER; +import dmd.backend.REG; +import dmd.backend.Symbol; +import dmd.backend.elem; +import dmd.backend.mTYman; +import dmd.backend.Util; +import dmd.backend.SC; +import dmd.backend.FL; +import dmd.backend.SFL; +import dmd.backend.TF; +import dmd.backend.RTLSYM; +import dmd.backend.BC; +import dmd.backend.block; +import dmd.backend.targ_types; +import dmd.backend.dt_t; +import dmd.backend.TYM; +import dmd.backend.Util; +import dmd.backend.Classsym; +import dmd.backend.glue; +import dmd.backend.LIST; +import dmd.codegen.Util; + +import core.stdc.string; +import core.stdc.stdlib; + +uint readwordLE(ushort* p) +{ +version (__I86__) { + return *p; +} else { + return ((cast(ubyte*)p)[1] << 8) | (cast(ubyte*)p)[0]; +} +} + +uint readwordBE(ushort* p) +{ + return ((cast(ubyte*)p)[0] << 8) | (cast(ubyte*)p)[1]; +} + +uint readlongLE(uint* p) +{ +version (__I86__) { + return *p; +} else { + return (cast(ubyte*)p)[0] | + ((cast(ubyte*)p)[1] << 8) | + ((cast(ubyte*)p)[2] << 16) | + ((cast(ubyte*)p)[3] << 24); +} +} + +uint readlongBE(uint* p) +{ + return (cast(ubyte*)p)[3] | + ((cast(ubyte*)p)[2] << 8) | + ((cast(ubyte*)p)[1] << 16) | + ((cast(ubyte*)p)[0] << 24); +} + +/* Segments */ +enum Segment { + CODE = 1, /* code segment */ + DATA = 2, /* initialized data */ + CDATA = 3, /* constant data */ + UDATA = 4, /* uninitialized data */ + UNKNOWN = -1, /* unknown segment */ +} + +struct seg_data +{ + int SDseg; // omf file segment index + targ_size_t SDoffset; // starting offset for data + + bool isfarseg; + int seg; // segment number + int lnameidx; // lname idx of segment name + int classidx; // lname idx of class name + uint attr; // segment attribute + targ_size_t origsize; // original size + int seek; // seek position in output file +} + +extern (C) extern __gshared seg_data** SegData; + +ref targ_size_t Offset(Segment seg) { + return SegData[seg].SDoffset; +} + +ref targ_size_t Doffset() { + return SegData[Segment.DATA].SDoffset; +} + +ref targ_size_t CDoffset() { + return SegData[Segment.CDATA].SDoffset; +} + +ref targ_size_t UDoffset() { + return SegData[Segment.UDATA].SDoffset; +} + +enum CF { + CFes = 1, // generate an ES: segment override for this instr + CFjmp16 = 2, // need 16 bit jump offset (long branch) + CFtarg = 4, // this code is the target of a jump + CFseg = 8, // get segment of immediate value + CFoff = 0x10, // get offset of immediate value + CFss = 0x20, // generate an SS: segment override (not with + // CFes at the same time, though!) + CFpsw = 0x40, // we need the flags result after this instruction + CFopsize = 0x80, // prefix with operand size + CFaddrsize = 0x100, // prefix with address size + CFds = 0x200, // need DS override (not with es, ss, or cs ) + CFcs = 0x400, // need CS override + CFfs = 0x800, // need FS override + CFgs = (CFcs | CFfs), // need GS override + CFwait = 0x1000, // If I32 it indicates when to output a WAIT + CFselfrel = 0x2000, // if self-relative + CFunambig = 0x4000, // indicates cannot be accessed by other addressing + // modes + CFtarg2 = 0x8000, // like CFtarg, but we can't optimize this away + CFvolatile = 0x10000, // volatile reference, do not schedule + CFclassinit = 0x20000, // class init code + + CFSEG = (CFes | CFss | CFds | CFcs | CFfs | CFgs), + CFPREFIX = (CFSEG | CFopsize | CFaddrsize), +} + +class Module : Package +{ + static Module rootModule; + static DsymbolTable modules; // symbol table of all modules + static Array amodules; // array of all modules + static Array deferred; // deferred Dsymbol's needing semantic() run on them + static uint dprogress; // progress resolving the deferred list + + static void init() + { + modules = new DsymbolTable(); + amodules = new Array(); + deferred = new Array(); + } + + static ClassDeclaration moduleinfo; + + + string arg; // original argument name + ModuleDeclaration md; // if !null, the contents of the ModuleDeclaration declaration + File srcfile; // input source file + File objfile; // output .obj file + File hdrfile; // 'header' file + File symfile; // output symbol file + File docfile; // output documentation file + uint errors; // if any errors in file + uint numlines; // number of lines in source file + int isHtml; // if it is an HTML file + int isDocFile; // if it is a documentation input file, not D source + int needmoduleinfo; /// TODO: change to bool +version (IN_GCC) { + int strictlyneedmoduleinfo; +} + + int selfimports; // 0: don't know, 1: does not, 2: does + int selfImports() // returns !=0 if module imports itself + { + assert(false); + } + + int insearch; + Identifier searchCacheIdent; + Dsymbol searchCacheSymbol; // cached value of search + int searchCacheFlags; // cached flags + + int semanticstarted; // has semantic() been started? + int semanticRun; // has semantic() been done? + int root; // != 0 if this is a 'root' module, + // i.e. a module that will be taken all the + // way to an object file + Module importedFrom; // module from command line we're imported from, + // i.e. a module that will be taken all the + // way to an object file + + Array decldefs; // top level declarations for this Module + + Array aimports; // all imported modules + + ModuleInfoDeclaration vmoduleinfo; + + uint debuglevel; // debug level + Array debugids; // debug identifiers + Array debugidsNot; // forward referenced debug identifiers + + uint versionlevel; // version level + Array versionids; // version identifiers + Array versionidsNot; // forward referenced version identifiers + + Macro macrotable; // document comment macros + Escape escapetable; // document comment escapes + bool safe; // TRUE if module is marked as 'safe' + + this(string filename, Identifier ident, int doDocComment, int doHdrGen) + { + super(ident); + FileName objfilename; + + aimports = new Array(); + + //writef("Module.Module(filename = '%s', ident = '%s')\n", filename, ident.toChars()); + this.arg = filename; + + FileName srcfilename = FileName.defaultExt(filename, global.mars_ext); + if (!srcfilename.equalsExt(global.mars_ext) && + !srcfilename.equalsExt(global.hdr_ext) && + !srcfilename.equalsExt("dd")) + { + if (srcfilename.equalsExt("html") || + srcfilename.equalsExt("htm") || + srcfilename.equalsExt("xhtml")) + { + if (!global.params.useDeprecated) + error("html source files is deprecated %s", srcfilename.toChars()); + isHtml = 1; + } + else + { + error("source file name '%s' must have .%s extension", srcfilename.toChars(), global.mars_ext); + fatal(); + } + } + + string argobj; + if (global.params.objname) + argobj = global.params.objname; + else if (global.params.preservePaths) + argobj = filename; + else + argobj = FileName.name(filename); + if (!FileName.absolute(argobj)) + { + argobj = FileName.combine(global.params.objdir, argobj); + } + + if (global.params.objname) + objfilename = new FileName(argobj); + else + objfilename = FileName.forceExt(argobj, global.obj_ext); + + FileName symfilename = FileName.forceExt(filename, global.sym_ext); + + srcfile = new File(srcfilename); + + if (doDocComment) { + setDocfile(); + } + + if (doHdrGen) { + setHdrfile(); + } + + objfile = new File(objfilename); + symfile = new File(symfilename); + } + + static Module load(Loc loc, Array packages, Identifier ident) + { + Module m; + string filename; + + //writef("Module.load(ident = '%s')\n", ident.toChars()); + + // Build module filename by turning: + // foo.bar.baz + // into: + // foo\bar\baz + filename = ident.toChars(); + if (packages && packages.dim) + { + scope OutBuffer buf = new OutBuffer(); + int i; + + for (i = 0; i < packages.dim; i++) + { + Identifier pid = cast(Identifier)packages.data[i]; + + buf.writestring(pid.toChars()); +version (_WIN32) { + buf.writeByte('\\'); +} else { + buf.writeByte('/'); +} + } + buf.writestring(filename); + filename = buf.extractString(); + } + + m = new Module(filename, ident, 0, 0); + m.loc = loc; + + /* Search along global.path for .di file, then .d file. + */ + string result = null; + FileName fdi = FileName.forceExt(filename, global.hdr_ext); + FileName fd = FileName.forceExt(filename, global.mars_ext); + string sdi = fdi.toChars(); + string sd = fd.toChars(); + + if (FileName.exists(sdi)) { + result = sdi; + } else if (FileName.exists(sd)) { + result = sd; + } else if (FileName.absolute(filename)) { + ; + } + else + { + foreach (p; global.path) + { + string n = FileName.combine(p, sdi); + + if (FileName.exists(n)) + { + result = n; + break; + } + + n = FileName.combine(p, sd); + if (FileName.exists(n)) + { + result = n; + break; + } + } + } + + if (result) + m.srcfile = new File(result); + + if (global.params.verbose) + { + writef("import "); + if (packages) + { + for (size_t i = 0; i < packages.dim; i++) + { + Identifier pid = cast(Identifier)packages.data[i]; + writef("%s.", pid.toChars()); + } + } + writef("%s\t(%s)\n", ident.toChars(), m.srcfile.toChars()); + } + + m.read(loc); + m.parse(); + +version (IN_GCC) { + d_gcc_magic_module(m); +} + + return m; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + string kind() + { + return "module"; + } + + void setDocfile() // set docfile member + { + assert(false); + } + + void read(Loc loc) // read file + { + //writef("Module.read('%s') file '%s'\n", toChars(), srcfile.toChars()); + if (srcfile.read()) + { + error(loc, "cannot read file '%s'", srcfile.toChars()); + fatal(); + } + } + +version (IN_GCC) { + void parse(bool dump_source = false) // syntactic parse + { + assert(false); + } +} else { + void parse() // syntactic parse + { + uint le; + uint bom; + + //printf("Module.parse()\n"); + + string srcname = srcfile.name.toChars(); + //printf("Module.parse(srcname = '%s')\n", srcname); + + ubyte* buf = srcfile.buffer; + uint buflen = srcfile.len; + + if (buflen >= 2) + { + /* Convert all non-UTF-8 formats to UTF-8. + * BOM : http://www.unicode.org/faq/utf_bom.html + * 00 00 FE FF UTF-32BE, big-endian + * FF FE 00 00 UTF-32LE, little-endian + * FE FF UTF-16BE, big-endian + * FF FE UTF-16LE, little-endian + * EF BB BF UTF-8 + */ + + bom = 1; // assume there's a BOM + if (buf[0] == 0xFF && buf[1] == 0xFE) + { + if (buflen >= 4 && buf[2] == 0 && buf[3] == 0) + { // UTF-32LE + le = 1; + + Lutf32: + OutBuffer dbuf; + uint* pu = cast(uint*)buf; + uint* pumax = &pu[buflen / 4]; + + if (buflen & 3) + { error("odd length of UTF-32 char source %u", buflen); + fatal(); + } + + dbuf.reserve(buflen / 4); + for (pu += bom; pu < pumax; pu++) + { + uint u = le ? readlongLE(pu) : readlongBE(pu); + if (u & ~0x7F) + { + if (u > 0x10FFFF) + { error("UTF-32 value %08x greater than 0x10FFFF", u); + fatal(); + } + dbuf.writeUTF8(u); + } + else + dbuf.writeByte(u); + } + dbuf.writeByte(0); // add 0 as sentinel for scanner + buflen = dbuf.offset - 1; // don't include sentinel in count + buf = cast(ubyte*) dbuf.extractData(); + } + else + { + // UTF-16LE (X86) + // Convert it to UTF-8 + le = 1; + + Lutf16: + OutBuffer dbuf; + ushort* pu = cast(ushort*)(buf); + ushort *pumax = &pu[buflen / 2]; + + if (buflen & 1) + { error("odd length of UTF-16 char source %u", buflen); + fatal(); + } + + dbuf.reserve(buflen / 2); + for (pu += bom; pu < pumax; pu++) + { + uint u = le ? readwordLE(pu) : readwordBE(pu); + if (u & ~0x7F) + { + if (u >= 0xD800 && u <= 0xDBFF) + { uint u2; + + if (++pu > pumax) + { error("surrogate UTF-16 high value %04x at EOF", u); + fatal(); + } + u2 = le ? readwordLE(pu) : readwordBE(pu); + if (u2 < 0xDC00 || u2 > 0xDFFF) + { error("surrogate UTF-16 low value %04x out of range", u2); + fatal(); + } + u = (u - 0xD7C0) << 10; + u |= (u2 - 0xDC00); + } + else if (u >= 0xDC00 && u <= 0xDFFF) + { + error("unpaired surrogate UTF-16 value %04x", u); + fatal(); + } + else if (u == 0xFFFE || u == 0xFFFF) + { + error("illegal UTF-16 value %04x", u); + fatal(); + } + dbuf.writeUTF8(u); + } + else + dbuf.writeByte(u); + } + dbuf.writeByte(0); // add 0 as sentinel for scanner + buflen = dbuf.offset - 1; // don't include sentinel in count + buf = cast(ubyte*) dbuf.extractData(); + } + } + else if (buf[0] == 0xFE && buf[1] == 0xFF) + { // UTF-16BE + le = 0; + goto Lutf16; + } + else if (buflen >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0xFE && buf[3] == 0xFF) + { // UTF-32BE + le = 0; + goto Lutf32; + } + else if (buflen >= 3 && buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF) + { // UTF-8 + + buf += 3; + buflen -= 3; + } + else + { + /* There is no BOM. Make use of Arcane Jill's insight that + * the first char of D source must be ASCII to + * figure out the encoding. + */ + + bom = 0; + if (buflen >= 4) + { if (buf[1] == 0 && buf[2] == 0 && buf[3] == 0) + { // UTF-32LE + le = 1; + goto Lutf32; + } + else if (buf[0] == 0 && buf[1] == 0 && buf[2] == 0) + { // UTF-32BE + le = 0; + goto Lutf32; + } + } + if (buflen >= 2) + { + if (buf[1] == 0) + { // UTF-16LE + le = 1; + goto Lutf16; + } + else if (buf[0] == 0) + { // UTF-16BE + le = 0; + goto Lutf16; + } + } + + // It's UTF-8 + if (buf[0] >= 0x80) + { error("source file must start with BOM or ASCII character, not \\x%02X", buf[0]); + fatal(); + } + } + } + +version (IN_GCC) { + // dump utf-8 encoded source + if (dump_source) + { // %% srcname could contain a path ... + d_gcc_dump_source(srcname, "utf-8", buf, buflen); + } +} + + /* If it starts with the string "Ddoc", then it's a documentation + * source file. + */ + if (buflen >= 4 && memcmp(buf, "Ddoc".ptr, 4) == 0) + { + comment = buf + 4; + isDocFile = 1; + if (!docfile) + setDocfile(); + return; + } + if (isHtml) + { + assert(false); + ///OutBuffer dbuf = new OutBuffer(); + ///Html h = new Html(srcname, buf, buflen); + ///h.extractCode(dbuf); + ///buf = dbuf.data; + ///buflen = dbuf.offset; + +version (IN_GCC) { + // dump extracted source + ///if (dump_source) + /// d_gcc_dump_source(srcname, "d.utf-8", buf, buflen); +} + } + + Parser p = new Parser(this, buf, buflen, docfile !is null); + p.nextToken(); + members = p.parseModule(); + md = p.md; + numlines = p.loc.linnum; + + DsymbolTable dst; + + if (md !is null) + { + this.ident = md.id; + this.safe = md.safe; + dst = super.resolve(md.packages, &this.parent, null); + } + else + { + dst = modules; + + /* Check to see if module name is a valid identifier + */ + if (!Lexer.isValidIdentifier(this.ident.toChars())) + error("has non-identifier characters in filename, use module declaration instead"); + } + + // Update global list of modules + if (!dst.insert(this)) + { + if (md) + error(loc, "is in multiple packages %s", md.toChars()); + else + error(loc, "is in multiple defined"); + } + else + { + amodules.push(cast(void*)this); + } + } + } + + void semantic() // semantic analysis + { + int i; + + if (semanticstarted) + return; + + //printf("+Module.semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent); + semanticstarted = 1; + + // Note that modules get their own scope, from scratch. + // This is so regardless of where in the syntax a module + // gets imported, it is unaffected by context. + Scope sc = Scope.createGlobal(this); // create root scope + + //printf("Module = %p, linkage = %d\n", sc.scopesym, sc.linkage); + + // Add import of "object" if this module isn't "object" + if (ident !is Id.object) + { + Import im = new Import(Loc(0), null, Id.object, null, 0); + members.shift(cast(void*)im); + } + + // Add all symbols into module's symbol table + symtab = new DsymbolTable(); + for (i = 0; i < members.dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + s.addMember(null, sc.scopesym, 1); + } + + /* Set scope for the symbols so that if we forward reference + * a symbol, it can possibly be resolved on the spot. + * If this works out well, it can be extended to all modules + * before any semantic() on any of them. + */ + for (i = 0; i < members.dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + s.setScope(sc); + } + + // Pass 1 semantic routines: do public side of the definition + for (i = 0; i < members.dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + + //writef("\tModule('%s'): '%s'.semantic()\n", toChars(), s.toChars()); + s.semantic(sc); + runDeferredSemantic(); + } + + sc = sc.pop(); + sc.pop(); // 2 pops because Scope.createGlobal() created 2 + semanticRun = semanticstarted; + //printf("-Module.semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent); + } + + void semantic2() // pass 2 semantic analysis + { + if (deferred.dim) + { + for (int i = 0; i < deferred.dim; i++) + { + Dsymbol sd = cast(Dsymbol)deferred.data[i]; + + sd.error("unable to resolve forward reference in definition"); + } + return; + } + //printf("Module.semantic2('%s'): parent = %p\n", toChars(), parent); + if (semanticstarted >= 2) + return; + assert(semanticstarted == 1); + semanticstarted = 2; + + // Note that modules get their own scope, from scratch. + // This is so regardless of where in the syntax a module + // gets imported, it is unaffected by context. + Scope sc = Scope.createGlobal(this); // create root scope + //printf("Module = %p\n", sc.scopesym); + + // Pass 2 semantic routines: do initializers and function bodies + for (int i = 0; i < members.dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + s.semantic2(sc); + } + + sc = sc.pop(); + sc.pop(); + semanticRun = semanticstarted; + //printf("-Module.semantic2('%s'): parent = %p\n", toChars(), parent); + } + + void semantic3() // pass 3 semantic analysis + { + //printf("Module.semantic3('%s'): parent = %p\n", toChars(), parent); + if (semanticstarted >= 3) + return; + assert(semanticstarted == 2); + semanticstarted = 3; + + // Note that modules get their own scope, from scratch. + // This is so regardless of where in the syntax a module + // gets imported, it is unaffected by context. + Scope sc = Scope.createGlobal(this); // create root scope + //printf("Module = %p\n", sc.scopesym); + + // Pass 3 semantic routines: do initializers and function bodies + for (int i = 0; i < members.dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + //printf("Module %s: %s.semantic3()\n", toChars(), s.toChars()); + s.semantic3(sc); + } + + sc = sc.pop(); + sc.pop(); + semanticRun = semanticstarted; + } + + void inlineScan() // scan for functions to inline + { + int i; + + if (semanticstarted >= 4) + return; + + assert(semanticstarted == 3); + semanticstarted = 4; + + // Note that modules get their own scope, from scratch. + // This is so regardless of where in the syntax a module + // gets imported, it is unaffected by context. + //printf("Module = %p\n", sc.scopesym); + + for (i = 0; i < members.dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + //if (global.params.verbose) + //printf("inline scan symbol %s\n", s.toChars()); + s.inlineScan(); + } + + semanticRun = semanticstarted; + } + + void setHdrfile() // set hdrfile member + { + FileName hdrfilename; + string arghdr; + + if (global.params.hdrname) + arghdr = global.params.hdrname; + else if (global.params.preservePaths) + arghdr = arg; + else + arghdr = FileName.name(arg); + if (!FileName.absolute(arghdr)) + { + //FileName.ensurePathExists(global.params.hdrdir); + arghdr = FileName.combine(global.params.hdrdir, arghdr); + } + if (global.params.hdrname) + hdrfilename = new FileName(arghdr); + else + hdrfilename = FileName.forceExt(arghdr, global.hdr_ext); + + if (hdrfilename.str == srcfile.name.str) + { + error("Source file and 'header' file have same name '%s'", srcfile.name.str); + fatal(); + } + + hdrfile = new File(hdrfilename); + } + +version (_DH) { + void genhdrfile() // generate D import file + { + assert(false); + } +} + + /************************************** + * Generate .obj file for Module. + */ + void genobjfile(int multiobj) + { + //EEcontext *ee = env.getEEcontext(); + + //printf("Module.genobjfile(multiobj = %d) %s\n", multiobj, toChars()); + + lastmname = srcfile.toChars(); /// global mutation + + obj_initfile(toStringz(lastmname), null, toStringz(toPrettyChars())); + + eictor = null; + ictorlocalgot = null; + ector = null; + ectorgates.setDim(0); + edtor = null; + etest = null; + dtorcount = 0; + + if (doppelganger) + { + /* Generate a reference to the moduleinfo, so the module constructors + * and destructors get linked in. + */ + Module m = cast(Module)aimports.data[0]; + assert(m); + if (m.sictor || m.sctor || m.sdtor) + { + Symbol* s = m.toSymbol(); + //objextern(s); + //if (!s.Sxtrnnum) objextdef(s.Sident); + if (!s.Sxtrnnum) + { + //printf("%s\n", s.Sident); +static if (false) { + /* This should work, but causes optlink to fail in common/newlib.asm */ + objextdef(s.Sident); +} else { + version (XXX) {///ELFOBJ || MACHOBJ + int nbytes = reftoident(DATA, Offset(DATA), s, 0, CFoff); + Offset(DATA) += nbytes; + } else { + int nbytes = reftoident(Segment.DATA, Doffset, s, 0, CF.CFoff); + Doffset() += nbytes; + } +} + } + } + } + + if (global.params.cov) + { + /* Create coverage identifier: + * private uint[numlines] __coverage; + */ + cov = symbol_calloc("__coverage"); + cov.Stype = type_fake(TYM.TYint); + cov.Stype.Tmangle = mTYman.mTYman_c; + cov.Stype.Tcount++; + cov.Sclass = SC.SCstatic; + cov.Sfl = FL.FLdata; +version (ELFOBJ_OR_MACHOBJ) { + cov.Sseg = Segment.UDATA; +} + dtnzeros(&cov.Sdt, 4 * numlines); + outdata(cov); + slist_add(cov); + + covb = cast(uint*)calloc((numlines + 32) / 32, (*covb).sizeof); + } + + for (int i = 0; i < members.dim; i++) + { + Dsymbol member = cast(Dsymbol)members.data[i]; + member.toObjFile(multiobj); + } + + if (global.params.cov) + { + /* Generate + * bit[numlines] __bcoverage; + */ + Symbol* bcov = symbol_calloc("__bcoverage"); + bcov.Stype = type_fake(TYM.TYuint); + bcov.Stype.Tcount++; + bcov.Sclass = SC.SCstatic; + bcov.Sfl = FL.FLdata; +version (ELFOBJ_OR_MACHOBJ) { + bcov.Sseg = Segment.DATA; +} + dtnbytes(&bcov.Sdt, (numlines + 32) / 32 * (*covb).sizeof, cast(char*)covb); + outdata(bcov); + + free(covb); + covb = null; + + /* Generate: + * _d_cover_register(uint[] __coverage, BitArray __bcoverage, string filename); + * and prepend it to the static constructor. + */ + + /* t will be the type of the functions generated: + * extern (C) void func(); + */ + type* t = type_alloc(TYM.TYnfunc); + t.Tflags |= TF.TFprototype | TF.TFfixed; + t.Tmangle = mTYman.mTYman_c; + t.Tnext = tsvoid; + tsvoid.Tcount++; + + sictor = toSymbolX("__modictor", SC.SCglobal, t, "FZv"); + cstate.CSpsymtab = &sictor.Sfunc.Flocsym; + localgot = ictorlocalgot; + elem* e; + + e = el_params(el_ptr(cov), el_long(TYM.TYuint, numlines), + el_ptr(bcov), el_long(TYM.TYuint, numlines), + toEfilename(), + null); + e = el_bin(OPER.OPcall, TYM.TYvoid, el_var(rtlsym[RTLSYM.RTLSYM_DCOVER]), e); + eictor = el_combine(e, eictor); + ictorlocalgot = localgot; + } + + // If coverage / static constructor / destructor / unittest calls + if (eictor || ector || ectorgates.dim || edtor || etest) + { + /* t will be the type of the functions generated: + * extern (C) void func(); + */ + type* t = type_alloc(TYM.TYnfunc); + t.Tflags |= TF.TFprototype | TF.TFfixed; + t.Tmangle = mTYman.mTYman_c; + t.Tnext = tsvoid; + tsvoid.Tcount++; + + static string moddeco = "FZv"; + + if (eictor) + { + localgot = ictorlocalgot; + + block* b = block_calloc(); + b.BC = BC.BCret; + b.Belem = eictor; + sictor.Sfunc.Fstartblock = b; + writefunc(sictor); + } + + if (ector || ectorgates.dim) + { + localgot = null; + sctor = toSymbolX("__modctor", SC.SCglobal, t, moddeco); + cstate.CSpsymtab = &sctor.Sfunc.Flocsym; + + for (int i = 0; i < ectorgates.dim; i++) + { + StaticDtorDeclaration f = cast(StaticDtorDeclaration)ectorgates.data[i]; + + Symbol* s = f.vgate.toSymbol(); + elem* e = el_var(s); + e = el_bin(OPER.OPaddass, TYM.TYint, e, el_long(TYM.TYint, 1)); + ector = el_combine(ector, e); + } + + block* b = block_calloc(); + b.BC = BC.BCret; + b.Belem = ector; + sctor.Sfunc.Fstartblock = b; + writefunc(sctor); +version (STATICCTOR) { + obj_staticctor(sctor, dtorcount, 1); +} + } + + if (edtor) + { + localgot = null; + sdtor = toSymbolX("__moddtor", SC.SCglobal, t, moddeco); + + block* b = block_calloc(); + b.BC = BC.BCret; + b.Belem = edtor; + sdtor.Sfunc.Fstartblock = b; + writefunc(sdtor); + } + + if (etest) + { + localgot = null; + stest = toSymbolX("__modtest", SC.SCglobal, t, moddeco); + + block* b = block_calloc(); + b.BC = BC.BCret; + b.Belem = etest; + stest.Sfunc.Fstartblock = b; + writefunc(stest); + } + + if (doppelganger) + genmoduleinfo(); + } + + if (doppelganger) + { + obj_termfile(); + return; + } + + if (global.params.multiobj) + { /* This is necessary because the main .obj for this module is written + * first, but determining whether marray or massert are needed is done + * possibly later in the doppelganger modules. + * Another way to fix it is do the main one last. + */ + toModuleAssert(); + toModuleArray(); + } + + // If module assert + for (int i = 0; i < 2; i++) + { + Symbol* ma = i ? marray : massert; + + if (ma) + { + elem* elinnum; + elem* efilename; + + localgot = null; + + // Call dassert(filename, line) + // Get sole parameter, linnum + { + Symbol* sp; + + sp = symbol_calloc("linnum".ptr); + sp.Stype = type_fake(TYM.TYint); + sp.Stype.Tcount++; + sp.Sclass = SC.SCfastpar; + sp.Spreg = REG.AX; + sp.Sflags &= ~SFL.SFLspill; + sp.Sfl = FL.FLpara; // FLauto? + cstate.CSpsymtab = &ma.Sfunc.Flocsym; + symbol_add(sp); + + elinnum = el_var(sp); + } + + efilename = toEmodulename(); + + elem *e = el_var(rtlsym[i ? RTLSYM.RTLSYM_DARRAY : RTLSYM.RTLSYM_DASSERT]); + e = el_bin(OPER.OPcall, TYM.TYvoid, e, el_param(elinnum, efilename)); + + block* b = block_calloc(); + b.BC = BC.BCret; + b.Belem = e; + ma.Sfunc.Fstartblock = b; + ma.Sclass = SC.SCglobal; + ma.Sfl = 0; + writefunc(ma); + } + } + +static if (true) { + // Always generate module info, because of templates and -cov + if (1 || needModuleInfo()) + genmoduleinfo(); + } + + obj_termfile(); + } + + void gensymfile() + { + assert(false); + } + + void gendocfile() + { + assert(false); + } + + /********************************** + * Determine if we need to generate an instance of ModuleInfo + * for this Module. + */ + bool needModuleInfo() + { + return needmoduleinfo || global.params.cov; + } + + Dsymbol search(Loc loc, Identifier ident, int flags) + { + /* Since modules can be circularly referenced, + * need to stop infinite recursive searches. + */ + + //printf("%s Module.search('%s', flags = %d) insearch = %d\n", toChars(), ident.toChars(), flags, insearch); + Dsymbol s; + if (insearch) + s = null; + else if (searchCacheIdent is ident && searchCacheFlags == flags) + s = searchCacheSymbol; + else + { + insearch = 1; + s = ScopeDsymbol.search(loc, ident, flags); + insearch = 0; + + searchCacheIdent = ident; + searchCacheSymbol = s; + searchCacheFlags = flags; + } + return s; + } + + void deleteObjFile() + { + if (global.params.obj) + objfile.remove(); + if (docfile) + docfile.remove(); + } + + void addDeferredSemantic(Dsymbol s) + { + assert(false); + } + + /****************************************** + * Run semantic() on deferred symbols. + */ + + void runDeferredSemantic() + { + size_t len; + + static int nested; + if (nested) + return; + //if (deferred.dim) printf("+Module.runDeferredSemantic('%s'), len = %d\n", toChars(), deferred.dim); + nested++; + + do + { + dprogress = 0; + len = deferred.dim; + if (!len) + break; + + Dsymbol *todo; + Dsymbol tmp; + if (len == 1) + { + todo = &tmp; + } + else + { + todo = cast(Dsymbol*)alloca(len * (Dsymbol*).sizeof); + assert(todo); + } + memcpy(todo, deferred.data, len * (Dsymbol*).sizeof); + deferred.setDim(0); + + for (int i = 0; i < len; i++) + { + Dsymbol s = todo[i]; + + s.semantic(null); + //printf("deferred: %s, parent = %s\n", s.toChars(), s.parent.toChars()); + } + //printf("\tdeferred.dim = %d, len = %d, dprogress = %d\n", deferred.dim, len, dprogress); + } while (deferred.dim < len || dprogress); // while making progress + nested--; + //printf("-Module.runDeferredSemantic('%s'), len = %d\n", toChars(), deferred.dim); + } + + int imports(Module m) + { + assert(false); + } + + // Back end + + int doppelganger; // sub-module + Symbol* cov; // private uint[] __coverage; + uint* covb; // bit array of valid code line numbers + + Symbol* sictor; // module order independent constructor + Symbol* sctor; // module constructor + Symbol* sdtor; // module destructor + Symbol* stest; // module unit test + + Symbol* sfilename; // symbol for filename + + Symbol* massert; // module assert function + Symbol* toModuleAssert() // get module assert function + { + if (!massert) + { + type* t; + + t = type_alloc(TYjfunc); + t.Tflags |= TFprototype | TFfixed; + t.Tmangle = mTYman_d; + t.Tnext = tsvoid; + tsvoid.Tcount++; + + massert = toSymbolX("__assert", SCextern, t, "FiZv"); + massert.Sfl = FLextern; + massert.Sflags |= SFLnodebug; + slist_add(massert); + } + return massert; + } + + Symbol* marray; // module array bounds function + + Symbol* toModuleArray() // get module array bounds function + { + if (!marray) + { + type* t; + + t = type_alloc(TYjfunc); + t.Tflags |= TFprototype | TFfixed; + t.Tmangle = mTYman_d; + t.Tnext = tsvoid; + tsvoid.Tcount++; + + marray = toSymbolX("__array", SCextern, t, "Z"); + marray.Sfl = FLextern; + marray.Sflags |= SFLnodebug; + slist_add(marray); + } + return marray; + } + + static Symbol* gencritsec() + { + assert(false); + } + + elem* toEfilename() + { + elem* efilename; + + if (!sfilename) + { + dt_t* dt = null; + + string id = srcfile.toChars(); + int len = id.length; + dtdword(&dt, len); + dtabytes(&dt,TYnptr, 0, len + 1, toStringz(id)); + + sfilename = symbol_generate(SCstatic,type_fake(TYdarray)); + sfilename.Sdt = dt; + sfilename.Sfl = FLdata; + version (ELFOBJ) { + sfilename.Sseg = Segment.CDATA; + } + version (MACHOBJ) { + // Because of PIC and CDATA being in the _TEXT segment, cannot + // have pointers in CDATA + sfilename.Sseg = Segment.DATA; + } + outdata(sfilename); + } + + efilename = el_var(sfilename); + return efilename; + } + + /************************************** + * Generate elem that is a pointer to the module file name. + */ + elem* toEmodulename() + { + elem *efilename; + + // Get filename + if (needModuleInfo()) + { + /* Class ModuleInfo is defined in std.moduleinfo. + * The first member is the name of it, char name[], + * which will be at offset 8. + */ + + Symbol* si = toSymbol(); + static if (true) { + // Use this instead so -fPIC will work + efilename = el_ptr(si); + efilename = el_bin(OPadd, TYnptr, efilename, el_long(TYuint, 8)); + efilename = el_una(OPind, TYdarray, efilename); + } else { + efilename = el_var(si); + efilename.Ety = TYdarray; + efilename.EV.sp.Voffset += 8; + } + } + else // generate our own filename + { + efilename = toEfilename(); + } + return efilename; + } + + /************************************* + * Create the "ModuleInfo" symbol + */ + Symbol* toSymbol() + { + if (!csym) + { + Symbol* s; + static Classsym* scc; + + if (!scc) { + scc = fake_classsym(Id.ClassInfo); + } + + s = toSymbolX("__ModuleInfo", SC.SCextern, scc.Stype, "Z"); + s.Sfl = FL.FLextern; + s.Sflags |= SFL.SFLnodebug; + csym = s; + slist_add(s); + } + return csym; + } + + // Put out instance of ModuleInfo for this Module + void genmoduleinfo() + { + //printf("Module.genmoduleinfo() %s\n", toChars()); + + Symbol* msym = toSymbol(); + + //dumpSymbol(msym); + + uint offset; + version (DMDV2) { + uint sizeof_ModuleInfo = 18 * PTRSIZE; + } else { + uint sizeof_ModuleInfo = 14 * PTRSIZE; + } + + ////////////////////////////////////////////// + + csym.Sclass = SC.SCglobal; + + csym.Sfl = FL.FLdata; + + /* The layout is: + { + void **vptr; + monitor_t monitor; + char[] name; // class name + ModuleInfo importedModules[]; + ClassInfo localClasses[]; + uint flags; // initialization state + void *ctor; + void *dtor; + void *unitTest; + const(MemberInfo[]) function(string) xgetMembers; // module getMembers() function + void *ictor; + void*[4] reserved; + } + */ + dt_t* dt = null; + + if (moduleinfo) + dtxoff(&dt, moduleinfo.toVtblSymbol(), 0, TYM.TYnptr); // vtbl for ModuleInfo + else + { + //printf("moduleinfo is null\n"); + dtdword(&dt, 0); // BUG: should be an assert() + } + dtdword(&dt, 0); // monitor + + // name[] + string name = toPrettyChars(); + size_t namelen = name.length; + dtdword(&dt, namelen); + dtabytes(&dt, TYM.TYnptr, 0, namelen + 1, toStringz(name)); + + ClassDeclarations aclasses = new ClassDeclarations(); + + //printf("members.dim = %d\n", members.dim); + for (int i = 0; i < members.dim; i++) + { + Dsymbol member = cast(Dsymbol)members.data[i]; + + //printf("\tmember '%s'\n", member.toChars()); + member.addLocalClass(aclasses); + } + + // importedModules[] + int aimports_dim = aimports.dim; + for (int i = 0; i < aimports.dim; i++) + { + Module m = cast(Module)aimports.data[i]; + if (!m.needModuleInfo()) + aimports_dim--; + } + + dtdword(&dt, aimports_dim); + if (aimports_dim) + dtxoff(&dt, csym, sizeof_ModuleInfo, TYM.TYnptr); + else + dtdword(&dt, 0); + + // localClasses[] + dtdword(&dt, aclasses.dim); + if (aclasses.dim) + dtxoff(&dt, csym, sizeof_ModuleInfo + aimports_dim * PTRSIZE, TYM.TYnptr); + else + dtdword(&dt, 0); + + if (needmoduleinfo) + dtdword(&dt, 8|0); // flags (4 means MIstandalone) + else + dtdword(&dt, 8|4); // flags (4 means MIstandalone) + + if (sctor) + dtxoff(&dt, sctor, 0, TYM.TYnptr); + else + dtdword(&dt, 0); + + if (sdtor) + dtxoff(&dt, sdtor, 0, TYM.TYnptr); + else + dtdword(&dt, 0); + + if (stest) + dtxoff(&dt, stest, 0, TYM.TYnptr); + else + dtdword(&dt, 0); + +/// version (DMDV2) { + FuncDeclaration sgetmembers = findGetMembers(); + if (sgetmembers) + dtxoff(&dt, sgetmembers.toSymbol(), 0, TYM.TYnptr); + else +/// } + dtdword(&dt, 0); // xgetMembers + + if (sictor) + dtxoff(&dt, sictor, 0, TYM.TYnptr); + else + dtdword(&dt, 0); + + version (DMDV2) { + // void*[4] reserved; + dtdword(&dt, 0); + dtdword(&dt, 0); + dtdword(&dt, 0); + dtdword(&dt, 0); + } + ////////////////////////////////////////////// + + for (int i = 0; i < aimports.dim; i++) + { + Module m = cast(Module)aimports.data[i]; + + if (m.needModuleInfo()) + { + Symbol* s = m.toSymbol(); + + /* Weak references don't pull objects in from the library, + * they resolve to 0 if not pulled in by something else. + * Don't pull in a module just because it was imported. + */ + version (OMFOBJ) {// Optlink crashes with weak symbols at EIP 41AFE7, 402000 + } else { + s.Sflags |= SFL.SFLweak; + } + dtxoff(&dt, s, 0, TYM.TYnptr); + } + } + + for (int i = 0; i < aclasses.dim; i++) + { + ClassDeclaration cd = cast(ClassDeclaration)aclasses.data[i]; + dtxoff(&dt, cd.toSymbol(), 0, TYM.TYnptr); + } + + csym.Sdt = dt; + version (ELFOBJ_OR_MACHOBJ) { + // Cannot be CONST because the startup code sets flag bits in it + csym.Sseg = Segment.DATA; + } + + outdata(csym); + + ////////////////////////////////////////////// + + obj_moduleinfo(msym); + } + + Module isModule() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ModuleDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ModuleDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,23 @@ +module dmd.ModuleDeclaration; + +import dmd.Identifier; +import dmd.Array; + +class ModuleDeclaration +{ + Identifier id; + Array packages; // array of Identifier's representing packages + bool safe; + + this(Array packages, Identifier id, bool safe) + { + this.packages = packages; + this.id = id; + this.safe = safe; + } + + string toChars() + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ModuleInfoDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ModuleInfoDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,40 @@ +module dmd.ModuleInfoDeclaration; + +import dmd.VarDeclaration; +import dmd.Module; +import dmd.Dsymbol; +import dmd.Scope; +import dmd.Loc; + +import dmd.backend.Symbol; + +class ModuleInfoDeclaration : VarDeclaration +{ + Module mod; + + this(Module mod) + { + assert(false); + super(Loc(0), null, null, null); + } + + Dsymbol syntaxCopy(Dsymbol) + { + assert(false); + } + + void semantic(Scope sc) + { + assert(false); + } + + void emitComment(Scope *sc) + { + assert(false); + } + + Symbol* toSymbol() + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/MulAssignExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/MulAssignExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,110 @@ +module dmd.MulAssignExp; + +import dmd.BinExp; +import dmd.Loc; +import dmd.Expression; +import dmd.Scope; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.Id; +import dmd.ArrayTypes; +import dmd.Identifier; +import dmd.IRState; +import dmd.TOK; +import dmd.Type; +import dmd.TY; + +import dmd.backend.elem; +import dmd.backend.OPER; +import dmd.expression.Util; + +class MulAssignExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKmulass, MulAssignExp.sizeof, e1, e2); + } + + Expression semantic(Scope sc) + { + Expression e; + + BinExp.semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + if (e1.op == TOKslice) + { // T[] -= ... + typeCombine(sc); + type = e1.type; + return arrayOp(sc); + } + + e1 = e1.modifiableLvalue(sc, e1); + e1.checkScalar(); + e1.checkNoBool(); + type = e1.type; + typeCombine(sc); + e1.checkArithmetic(); + e2.checkArithmetic(); + if (e2.type.isfloating()) + { + Type t1; + Type t2; + + t1 = e1.type; + t2 = e2.type; + if (t1.isreal()) + { + if (t2.isimaginary() || t2.iscomplex()) + { + e2 = e2.castTo(sc, t1); + } + } + else if (t1.isimaginary()) + { + if (t2.isimaginary() || t2.iscomplex()) + { + switch (t1.ty) + { + case Timaginary32: t2 = Type.tfloat32; break; + case Timaginary64: t2 = Type.tfloat64; break; + case Timaginary80: t2 = Type.tfloat80; break; + default: + assert(0); + } + e2 = e2.castTo(sc, t2); + } + } + } + return this; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void buildArrayIdent(OutBuffer buf, Expressions arguments) + { + assert(false); + } + + Expression buildArrayLoop(Arguments fparams) + { + assert(false); + } + + Identifier opId() /* For operator overloading */ + { + return Id.mulass; + } + + elem* toElem(IRState* irs) + { + return toElemBin(irs,OPmulass); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/MulExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/MulExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,148 @@ +module dmd.MulExp; + +import dmd.Expression; +import dmd.Identifier; +import dmd.backend.elem; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.NegExp; +import dmd.Loc; +import dmd.Id; +import dmd.Scope; +import dmd.IRState; +import dmd.BinExp; +import dmd.ArrayTypes; +import dmd.TOK; +import dmd.Type; +import dmd.TY; + +import dmd.expression.Util; +import dmd.expression.Mul; +import dmd.backend.OPER; +import dmd.backend.Util; + +class MulExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKmul, MulExp.sizeof, e1, e2); + } + + Expression semantic(Scope sc) + { + Expression e; + + static if (false) { + printf("MulExp.semantic() %s\n", toChars()); + } + if (type) + { + return this; + } + + BinExp.semanticp(sc); + e = op_overload(sc); + if (e) + return e; + + typeCombine(sc); + if (e1.op != TOKslice && e2.op != TOKslice) + { + e1.checkArithmetic(); + e2.checkArithmetic(); + } + if (type.isfloating()) + { + Type t1 = e1.type; + Type t2 = e2.type; + + if (t1.isreal()) + { + type = t2; + } + else if (t2.isreal()) + { + type = t1; + } + else if (t1.isimaginary()) + { + if (t2.isimaginary()) + { + switch (t1.ty) + { + case Timaginary32: type = Type.tfloat32; break; + case Timaginary64: type = Type.tfloat64; break; + case Timaginary80: type = Type.tfloat80; break; + default: assert(0); + } + + // iy * iv = -yv + e1.type = type; + e2.type = type; + Expression ee = new NegExp(loc, this); + ee = ee.semantic(sc); + return ee; + } + else + type = t2; // t2 is complex + } + else if (t2.isimaginary()) + { + type = t1; // t1 is complex + } + } + return this; + } + + Expression optimize(int result) + { + Expression e; + + //printf("MulExp.optimize(result = %d) %s\n", result, toChars()); + e1 = e1.optimize(result); + e2 = e2.optimize(result); + if (e1.isConst() == 1 && e2.isConst() == 1) + { + e = Mul(type, e1, e2); + } + else + e = this; + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void buildArrayIdent(OutBuffer buf, Expressions arguments) + { + assert(false); + } + + Expression buildArrayLoop(Arguments fparams) + { + assert(false); + } + + bool isCommutative() + { + return true; + } + + Identifier opId() + { + return Id.mul; + } + + Identifier opId_r() + { + return Id.mul_r; + } + + elem* toElem(IRState* irs) + { + return toElemBin(irs,OPmul); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/NegExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/NegExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,93 @@ +module dmd.NegExp; + +import dmd.Expression; +import dmd.Identifier; +import dmd.backend.elem; +import dmd.UnaExp; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.IRState; +import dmd.ArrayTypes; +import dmd.TOK; + +import dmd.expression.Neg; + +import dmd.backend.Util; +import dmd.backend.OPER; + +class NegExp : UnaExp +{ + this(Loc loc, Expression e) + { + super(loc, TOKneg, NegExp.sizeof, e); + } + + Expression semantic(Scope sc) + { + Expression e; + + version (LOGSEMANTIC) { + printf("NegExp::semantic('%s')\n", toChars()); + } + if (!type) + { + UnaExp.semantic(sc); + e1 = resolveProperties(sc, e1); + e = op_overload(sc); + if (e) + return e; + + e1.checkNoBool(); + if (e1.op != TOKslice) + e1.checkArithmetic(); + + type = e1.type; + } + return this; + } + + Expression optimize(int result) + { + Expression e; + + e1 = e1.optimize(result); + if (e1.isConst() == 1) + { + e = Neg(type, e1); + } + else + e = this; + + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void buildArrayIdent(OutBuffer buf, Expressions arguments) + { + assert(false); + } + + Expression buildArrayLoop(Arguments fparams) + { + assert(false); + } + + Identifier opId() + { + assert(false); + } + + elem* toElem(IRState* irs) + { + elem *e = el_una(OPneg, type.totym(), e1.toElem(irs)); + el_setLoc(e,loc); + return e; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/NewAnonClassExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/NewAnonClassExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,52 @@ +module dmd.NewAnonClassExp; + +import dmd.Expression; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.ClassDeclaration; +import dmd.HdrGenState; +import dmd.ArrayTypes; +import dmd.TOK; + +class NewAnonClassExp : Expression +{ + /* thisexp.new(newargs) class baseclasses { } (arguments) + */ + Expression thisexp; // if !NULL, 'this' for class being allocated + Expressions newargs; // Array of Expression's to call new operator + ClassDeclaration cd; // class being instantiated + Expressions arguments; // Array of Expression's to call class constructor + + this(Loc loc, Expression thisexp, Expressions newargs, ClassDeclaration cd, Expressions arguments) + { + assert(false); + super(loc, TOK.init, 0); + } + + Expression syntaxCopy() + { + assert(false); + } + + Expression semantic(Scope sc) + { + assert(false); + } + + bool checkSideEffect(int flag) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState hgs) + { + assert(false); + } + + bool canThrow() + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/NewDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/NewDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,59 @@ +module dmd.NewDeclaration; + +import dmd.FuncDeclaration; +import dmd.Loc; +import dmd.ArrayTypes; +import dmd.Dsymbol; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.STC; + +class NewDeclaration : FuncDeclaration +{ + Arguments arguments; + int varargs; + + this(Loc loc, Loc endloc, Arguments arguments, int varargs) + { + assert(false); + super(loc, loc, null, STC.init, null); + } + + Dsymbol syntaxCopy(Dsymbol) + { + assert(false); + } + + void semantic(Scope sc) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + string kind() + { + assert(false); + } + + bool isVirtual() + { + assert(false); + } + + bool addPreInvariant() + { + assert(false); + } + + bool addPostInvariant() + { + assert(false); + } + + NewDeclaration isNewDeclaration() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/NewExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/NewExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,762 @@ +module dmd.NewExp; + +import dmd.Expression; +import dmd.NewDeclaration; +import dmd.CtorDeclaration; +import dmd.ClassDeclaration; +import dmd.Type; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.IRState; +import dmd.InlineDoState; +import dmd.HdrGenState; +import dmd.ArrayTypes; +import dmd.TOK; +import dmd.TY; +import dmd.TypeFunction; +import dmd.TypeClass; +import dmd.TypeStruct; +import dmd.StructDeclaration; +import dmd.FuncDeclaration; +import dmd.TypeDArray; +import dmd.Dsymbol; +import dmd.ThisExp; +import dmd.DotIdExp; +import dmd.Id; +import dmd.WANT; +import dmd.Global; +import dmd.IntegerExp; +import dmd.TypePointer; + +import dmd.backend.elem; +import dmd.backend.TYM; +import dmd.backend.SC; +import dmd.backend.TYPE; +import dmd.backend.TYM; +import dmd.backend.Symbol; +import dmd.backend.Classsym; +import dmd.backend.Util; +import dmd.backend.OPER; +import dmd.backend.RTLSYM; +import dmd.expression.Util; +import dmd.codegen.Util; + +import std.string : toStringz; + +class NewExp : Expression +{ + /* thisexp.new(newargs) newtype(arguments) + */ + Expression thisexp; // if !null, 'this' for class being allocated + Expressions newargs; // Array of Expression's to call new operator + Type newtype; + Expressions arguments; // Array of Expression's + + CtorDeclaration member; // constructor function + NewDeclaration allocator; // allocator function + int onstack; // allocate on stack + + this(Loc loc, Expression thisexp, Expressions newargs, Type newtype, Expressions arguments) + { + super(loc, TOK.TOKnew, NewExp.sizeof); + this.thisexp = thisexp; + this.newargs = newargs; + this.newtype = newtype; + this.arguments = arguments; + } + + Expression syntaxCopy() + { + assert(false); + } + + Expression semantic(Scope sc) + { + int i; + Type tb; + ClassDeclaration cdthis = null; + + version (LOGSEMANTIC) { + printf("NewExp.semantic() %s\n", toChars()); + if (thisexp) + printf("\tthisexp = %s\n", thisexp.toChars()); + printf("\tnewtype: %s\n", newtype.toChars()); + } + if (type) // if semantic() already run + return this; + + Lagain: + if (thisexp) + { + thisexp = thisexp.semantic(sc); + cdthis = thisexp.type.isClassHandle(); + if (cdthis) + { + sc = sc.push(cdthis); + type = newtype.semantic(loc, sc); + sc = sc.pop(); + } + else + { + error("'this' for nested class must be a class type, not %s", thisexp.type.toChars()); + type = newtype.semantic(loc, sc); + } + } + else + type = newtype.semantic(loc, sc); + newtype = type; // in case type gets cast to something else + tb = type.toBasetype(); + //printf("tb: %s, deco = %s\n", tb.toChars(), tb.deco); + + arrayExpressionSemantic(newargs, sc); + preFunctionArguments(loc, sc, newargs); + arrayExpressionSemantic(arguments, sc); + preFunctionArguments(loc, sc, arguments); + + if (thisexp && tb.ty != Tclass) + error("e.new is only for allocating nested classes, not %s", tb.toChars()); + + if (tb.ty == Tclass) + { + TypeFunction tf; + + TypeClass tc = cast(TypeClass)tb; + ClassDeclaration cd = tc.sym.isClassDeclaration(); + if (cd.isInterfaceDeclaration()) + error("cannot create instance of interface %s", cd.toChars()); + else if (cd.isAbstract()) + { + error("cannot create instance of abstract class %s", cd.toChars()); + for (int j = 0; j < cd.vtbl.dim; j++) + { + FuncDeclaration fd = (cast(Dsymbol)cd.vtbl.data[j]).isFuncDeclaration(); + if (fd && fd.isAbstract()) + error("function %s is abstract", fd.toChars()); + } + } + checkDeprecated(sc, cd); + if (cd.isNested()) + { /* We need a 'this' pointer for the nested class. + * Ensure we have the right one. + */ + Dsymbol s = cd.toParent2(); + ClassDeclaration cdn = s.isClassDeclaration(); + FuncDeclaration fdn = s.isFuncDeclaration(); + + //printf("cd isNested, cdn = %s\n", cdn ? cdn.toChars() : "null"); + if (cdn) + { + if (!cdthis) + { + // Supply an implicit 'this' and try again + thisexp = new ThisExp(loc); + for (Dsymbol sp = sc.parent; 1; sp = sp.parent) + { + if (!sp) + { + error("outer class %s 'this' needed to 'new' nested class %s", cdn.toChars(), cd.toChars()); + break; + } + ClassDeclaration cdp = sp.isClassDeclaration(); + if (!cdp) + continue; + if (cdp == cdn || cdn.isBaseOf(cdp, null)) + break; + // Add a '.outer' and try again + thisexp = new DotIdExp(loc, thisexp, Id.outer); + } + if (!global.errors) + goto Lagain; + } + if (cdthis) + { + //printf("cdthis = %s\n", cdthis.toChars()); + if (cdthis != cdn && !cdn.isBaseOf(cdthis, null)) + error("'this' for nested class must be of type %s, not %s", cdn.toChars(), thisexp.type.toChars()); + } + else + { + static if (false) { + for (Dsymbol *sf = sc.func; 1; sf= sf.toParent2().isFuncDeclaration()) + { + if (!sf) + { + error("outer class %s 'this' needed to 'new' nested class %s", cdn.toChars(), cd.toChars()); + break; + } + printf("sf = %s\n", sf.toChars()); + AggregateDeclaration *ad = sf.isThis(); + if (ad && (ad == cdn || cdn.isBaseOf(ad.isClassDeclaration(), null))) + break; + } + } + } + } + ///static if (true) { + else if (thisexp) + error("e.new is only for allocating nested classes"); + else if (fdn) + { + // make sure the parent context fdn of cd is reachable from sc + for (Dsymbol sp = sc.parent; 1; sp = sp.parent) + { + if (fdn is sp) + break; + FuncDeclaration fsp = sp ? sp.isFuncDeclaration() : null; + if (!sp || (fsp && fsp.isStatic())) + { + error("outer function context of %s is needed to 'new' nested class %s", fdn.toPrettyChars(), cd.toPrettyChars()); + break; + } + } + } + ///} else { + /// else if (fdn) + /// { + /// /* The nested class cd is nested inside a function, + /// * we'll let getEthis() look for errors. + /// */ + /// //printf("nested class %s is nested inside function %s, we're in %s\n", cd.toChars(), fdn.toChars(), sc.func.toChars()); + /// if (thisexp) + /// // Because thisexp cannot be a function frame pointer + /// error("e.new is only for allocating nested classes"); + /// } + ///} + else + assert(0); + } + else if (thisexp) + error("e.new is only for allocating nested classes"); + + FuncDeclaration f = null; + if (cd.ctor) + f = resolveFuncCall(sc, loc, cd.ctor, null, null, arguments, 0); + if (f) + { + checkDeprecated(sc, f); + member = f.isCtorDeclaration(); + assert(member); + + cd.accessCheck(loc, sc, member); + + tf = cast(TypeFunction)f.type; + + if (!arguments) + arguments = new Expressions(); + functionArguments(loc, sc, tf, arguments); + } + else + { + if (arguments && arguments.dim) + error("no constructor for %s", cd.toChars()); + } + + if (cd.aggNew) + { + // Prepend the size argument to newargs[] + Expression e = new IntegerExp(loc, cd.size(loc), Type.tsize_t); + if (!newargs) + newargs = new Expressions(); + newargs.shift(cast(void*)e); + + f = cd.aggNew.overloadResolve(loc, null, newargs); + allocator = f.isNewDeclaration(); + assert(allocator); + + tf = cast(TypeFunction)f.type; + functionArguments(loc, sc, tf, newargs); + } + else + { + if (newargs && newargs.dim) + error("no allocator for %s", cd.toChars()); + } + } + else if (tb.ty == Tstruct) + { + TypeStruct ts = cast(TypeStruct)tb; + StructDeclaration sd = ts.sym; + TypeFunction tf; + + FuncDeclaration f = null; + if (sd.ctor) + f = resolveFuncCall(sc, loc, sd.ctor, null, null, arguments, 0); + if (f) + { + checkDeprecated(sc, f); + member = f.isCtorDeclaration(); + assert(member); + + sd.accessCheck(loc, sc, member); + + tf = cast(TypeFunction)f.type; + // type = tf.next; + + if (!arguments) + arguments = new Expressions(); + functionArguments(loc, sc, tf, arguments); + } + else + { + if (arguments && arguments.dim) + error("no constructor for %s", sd.toChars()); + } + + if (sd.aggNew) + { + // Prepend the uint size argument to newargs[] + Expression e = new IntegerExp(loc, sd.size(loc), Type.tuns32); + if (!newargs) + newargs = new Expressions(); + newargs.shift(cast(void*)e); + + f = sd.aggNew.overloadResolve(loc, null, newargs); + allocator = f.isNewDeclaration(); + assert(allocator); + + tf = cast(TypeFunction)f.type; + functionArguments(loc, sc, tf, newargs); + static if (false) { + e = new VarExp(loc, f); + e = new CallExp(loc, e, newargs); + e = e.semantic(sc); + e.type = type.pointerTo(); + return e; + } + } + else + { + if (newargs && newargs.dim) + error("no allocator for %s", sd.toChars()); + } + + type = type.pointerTo(); + } + else if (tb.ty == Tarray && (arguments && arguments.dim)) + { + for (size_t j = 0; j < arguments.dim; j++) + { + if (tb.ty != Tarray) + { + error("too many arguments for array"); + arguments.dim = i; + break; + } + + Expression arg = cast(Expression)arguments.data[j]; + arg = resolveProperties(sc, arg); + arg = arg.implicitCastTo(sc, Type.tsize_t); + arg = arg.optimize(WANTvalue); + if (arg.op == TOKint64 && cast(long)arg.toInteger() < 0) + error("negative array index %s", arg.toChars()); + arguments.data[j] = cast(void*) arg; + tb = (cast(TypeDArray)tb).next.toBasetype(); + } + } + else if (tb.isscalar()) + { + if (arguments && arguments.dim) + error("no constructor for %s", type.toChars()); + + type = type.pointerTo(); + } + else + { + error("new can only create structs, dynamic arrays or class objects, not %s's", type.toChars()); + type = type.pointerTo(); + } + + //printf("NewExp: '%s'\n", toChars()); + //printf("NewExp:type '%s'\n", type.toChars()); + + return this; + } + + Expression optimize(int result) + { + if (thisexp) + thisexp = thisexp.optimize(WANTvalue); + + // Optimize parameters + if (newargs) + { + for (size_t i = 0; i < newargs.dim; i++) + { + Expression e = cast(Expression)newargs.data[i]; + + e = e.optimize(WANTvalue); + newargs.data[i] = cast(void*)e; + } + } + + if (arguments) + { + for (size_t i = 0; i < arguments.dim; i++) + { + Expression e = cast(Expression)arguments.data[i]; + + e = e.optimize(WANTvalue); + arguments.data[i] = cast(void*)e; + } + } + return this; + } + + elem* toElem(IRState* irs) + { + elem* e; + Type t; + Type ectype; + + //printf("NewExp.toElem() %s\n", toChars()); + t = type.toBasetype(); + //printf("\ttype = %s\n", t.toChars()); + //if (member) + //printf("\tmember = %s\n", member.toChars()); + if (t.ty == Tclass) + { + Symbol* csym; + + t = newtype.toBasetype(); + assert(t.ty == Tclass); + TypeClass tclass = cast(TypeClass)t; + ClassDeclaration cd = tclass.sym; + + /* Things to do: + * 1) ex: call allocator + * 2) ey: set vthis for nested classes + * 3) ez: call constructor + */ + + elem *ex = null; + elem *ey = null; + elem *ez = null; + + if (allocator || onstack) + { + elem *ei; + Symbol *si; + + if (onstack) + { + /* Create an instance of the class on the stack, + * and call it stmp. + * Set ex to be the &stmp. + */ + Symbol* s = symbol_calloc(toStringz(tclass.sym.toChars())); + s.Sclass = SCstruct; + s.Sstruct = struct_calloc(); + s.Sstruct.Sflags |= 0; + s.Sstruct.Salignsize = tclass.sym.alignsize; + s.Sstruct.Sstructalign = cast(ubyte)tclass.sym.structalign; + s.Sstruct.Sstructsize = tclass.sym.structsize; + + .type* tc = type_alloc(TYstruct); + tc.Ttag = cast(Classsym*)s; // structure tag name + tc.Tcount++; + s.Stype = tc; + + Symbol *stmp = symbol_genauto(tc); + ex = el_ptr(stmp); + } + else + { + ex = el_var(allocator.toSymbol()); + ex = callfunc(loc, irs, 1, type, ex, allocator.type, + allocator, allocator.type, null, newargs); + } + + si = tclass.sym.toInitializer(); + ei = el_var(si); + + if (cd.isNested()) + { + ey = el_same(&ex); + ez = el_copytree(ey); + } + else if (member) + ez = el_same(&ex); + + ex = el_una(OPind, TYstruct, ex); + ex = el_bin(OPstreq, TYnptr, ex, ei); + ex.Enumbytes = cd.size(loc); + ex = el_una(OPaddr, TYnptr, ex); + ectype = tclass; + } + else + { + csym = cd.toSymbol(); + ex = el_bin(OPcall,TYnptr,el_var(rtlsym[RTLSYM_NEWCLASS]),el_ptr(csym)); + ectype = null; + + if (cd.isNested()) + { + ey = el_same(&ex); + ez = el_copytree(ey); + } + else if (member) + ez = el_same(&ex); + //elem_print(ex); + //elem_print(ey); + //elem_print(ez); + } + + if (thisexp) + { + ClassDeclaration cdthis = thisexp.type.isClassHandle(); + assert(cdthis); + //printf("cd = %s\n", cd.toChars()); + //printf("cdthis = %s\n", cdthis.toChars()); + assert(cd.isNested()); + int offset = 0; + Dsymbol cdp = cd.toParent2(); // class we're nested in + elem* ethis; + + //printf("member = %p\n", member); + //printf("cdp = %s\n", cdp.toChars()); + //printf("cdthis = %s\n", cdthis.toChars()); + if (cdp != cdthis) + { + int i = cdp.isClassDeclaration().isBaseOf(cdthis, &offset); + assert(i); + } + ethis = thisexp.toElem(irs); + if (offset) + ethis = el_bin(OPadd, TYnptr, ethis, el_long(TYint, offset)); + + if (!cd.vthis) + { + error("forward reference to %s", cd.toChars()); + } + else + { + ey = el_bin(OPadd, TYnptr, ey, el_long(TYint, cd.vthis.offset)); + ey = el_una(OPind, TYnptr, ey); + ey = el_bin(OPeq, TYnptr, ey, ethis); + } + //printf("ex: "); elem_print(ex); + //printf("ey: "); elem_print(ey); + //printf("ez: "); elem_print(ez); + } + else if (cd.isNested()) + { + /* Initialize cd.vthis: + * *(ey + cd.vthis.offset) = this; + */ + ey = setEthis(loc, irs, ey, cd); + } + + if (member) + // Call constructor + ez = callfunc(loc, irs, 1, type, ez, ectype, member, member.type, null, arguments); + + e = el_combine(ex, ey); + e = el_combine(e, ez); + } + else if (t.ty == Tpointer && t.nextOf().toBasetype().ty == Tstruct) + { + Symbol* csym; + + t = newtype.toBasetype(); + assert(t.ty == Tstruct); + TypeStruct tclass = cast(TypeStruct)t; + StructDeclaration cd = tclass.sym; + + /* Things to do: + * 1) ex: call allocator + * 2) ey: set vthis for nested classes + * 3) ez: call constructor + */ + + elem* ex = null; + elem* ey = null; + elem* ez = null; + + if (allocator) + { + elem *ei; + Symbol *si; + + ex = el_var(allocator.toSymbol()); + ex = callfunc(loc, irs, 1, type, ex, allocator.type, + allocator, allocator.type, null, newargs); + + si = tclass.sym.toInitializer(); + ei = el_var(si); + + if (cd.isNested()) + { + ey = el_same(&ex); + ez = el_copytree(ey); + } + else if (member) + ez = el_same(&ex); + + if (!member) + { + /* Statically intialize with default initializer + */ + ex = el_una(OPind, TYstruct, ex); + ex = el_bin(OPstreq, TYnptr, ex, ei); + ex.Enumbytes = cd.size(loc); + ex = el_una(OPaddr, TYnptr, ex); + } + ectype = tclass; + } + else + { + ulong elemsize = cd.size(loc); + + // call _d_newarrayT(ti, 1) + e = el_long(TYsize_t, 1); + e = el_param(e, type.getTypeInfo(null).toElem(irs)); + + int rtl = t.isZeroInit(Loc(0)) ? RTLSYM_NEWARRAYT : RTLSYM_NEWARRAYIT; + e = el_bin(OPcall,TYdarray,el_var(rtlsym[rtl]),e); + + // The new functions return an array, so convert to a pointer + // ex . (unsigned)(e >> 32) + e = el_bin(OPshr, TYdarray, e, el_long(TYint, 32)); + ex = el_una(OP64_32, TYnptr, e); + + ectype = null; + + if (cd.isNested()) + { + ey = el_same(&ex); + ez = el_copytree(ey); + } + else if (member) + ez = el_same(&ex); + //elem_print(ex); + //elem_print(ey); + //elem_print(ez); + } + + if (cd.isNested()) + { + /* Initialize cd.vthis: + * *(ey + cd.vthis.offset) = this; + */ + ey = setEthis(loc, irs, ey, cd); + } + + if (member) + { + // Call constructor + ez = callfunc(loc, irs, 1, type, ez, ectype, member, member.type, null, arguments); + version (STRUCTTHISREF) { + /* Structs return a ref, which gets automatically dereferenced. + * But we want a pointer to the instance. + */ + ez = el_una(OPaddr, TYnptr, ez); + } + } + + e = el_combine(ex, ey); + e = el_combine(e, ez); + } + else if (t.ty == Tarray) + { + TypeDArray tda = cast(TypeDArray)t; + + assert(arguments && arguments.dim >= 1); + if (arguments.dim == 1) + { + // Single dimension array allocations + Expression arg = cast(Expression)arguments.data[0]; // gives array length + e = arg.toElem(irs); + ulong elemsize = tda.next.size(); + + // call _d_newT(ti, arg) + e = el_param(e, type.getTypeInfo(null).toElem(irs)); + int rtl = tda.next.isZeroInit(Loc(0)) ? RTLSYM_NEWARRAYT : RTLSYM_NEWARRAYIT; + e = el_bin(OPcall,TYdarray,el_var(rtlsym[rtl]),e); + } + else + { + // Multidimensional array allocations + e = el_long(TYint, arguments.dim); + for (size_t i = 0; i < arguments.dim; i++) + { + Expression arg = cast(Expression)arguments.data[i]; // gives array length + e = el_param(arg.toElem(irs), e); + assert(t.ty == Tarray); + t = t.nextOf(); + assert(t); + } + + e = el_param(e, type.getTypeInfo(null).toElem(irs)); + + int rtl = t.isZeroInit(Loc(0)) ? RTLSYM_NEWARRAYMT : RTLSYM_NEWARRAYMIT; + e = el_bin(OPcall,TYdarray,el_var(rtlsym[rtl]),e); + } + } + else if (t.ty == Tpointer) + { + TypePointer tp = cast(TypePointer)t; + ulong elemsize = tp.next.size(); + Expression di = tp.next.defaultInit(Loc(0)); + ulong disize = di.type.size(); + + // call _d_newarrayT(ti, 1) + e = el_long(TYsize_t, 1); + e = el_param(e, type.getTypeInfo(null).toElem(irs)); + + int rtl = tp.next.isZeroInit(Loc(0)) ? RTLSYM_NEWARRAYT : RTLSYM_NEWARRAYIT; + e = el_bin(OPcall,TYdarray,el_var(rtlsym[rtl]),e); + + // The new functions return an array, so convert to a pointer + // e . (unsigned)(e >> 32) + e = el_bin(OPshr, TYdarray, e, el_long(TYint, 32)); + e = el_una(OP64_32, t.totym(), e); + } + else + { + assert(0); + } + + el_setLoc(e,loc); + return e; + } + + bool checkSideEffect(int flag) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + void scanForNestedRef(Scope sc) + { + assert(false); + } + +version (DMDV2) { + bool canThrow() + { + return 1; + } +} + + //int inlineCost(InlineCostState *ics); + + Expression doInline(InlineDoState ids) + { + //printf("NewExp.doInline(): %s\n", toChars()); + NewExp ne = cast(NewExp)copy(); + + if (thisexp) + ne.thisexp = thisexp.doInline(ids); + ne.newargs = arrayExpressiondoInline(ne.newargs, ids); + ne.arguments = arrayExpressiondoInline(ne.arguments, ids); + return ne; + } + + //Expression inlineScan(InlineScanState *iss); +} + diff -r 000000000000 -r 10317f0c89a5 dmd/NotExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/NotExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,63 @@ +module dmd.NotExp; + +import dmd.Expression; +import dmd.backend.elem; +import dmd.UnaExp; +import dmd.InterState; +import dmd.Loc; +import dmd.Scope; +import dmd.IRState; +import dmd.TOK; +import dmd.Type; + +import dmd.expression.Not; + +import dmd.backend.OPER; +import dmd.backend.Util; + +class NotExp : UnaExp +{ + this(Loc loc, Expression e) + { + super(loc, TOK.TOKnot, NotExp.sizeof, e); + } + + Expression semantic(Scope sc) + { + UnaExp.semantic(sc); + e1 = resolveProperties(sc, e1); + e1 = e1.checkToBoolean(); + type = Type.tboolean; + return this; + } + + Expression optimize(int result) + { + Expression e; + + e1 = e1.optimize(result); + if (e1.isConst() == 1) + e = Not(type, e1); + else + e = this; + + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + int isBit() + { + assert(false); + } + + elem* toElem(IRState* irs) + { + elem* e = el_una(OPnot, type.totym(), e1.toElem(irs)); + el_setLoc(e,loc); + return e; + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/NullExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/NullExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,154 @@ +module dmd.NullExp; + +import dmd.Expression; +import dmd.backend.elem; +import dmd.InterState; +import dmd.MATCH; +import dmd.Type; +import dmd.TY; +import dmd.TypeTypedef; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.IRState; +import dmd.HdrGenState; +import dmd.TOK; +import dmd.backend.dt_t; +import dmd.backend.Util; + +class NullExp : Expression +{ + ubyte committed; + + this(Loc loc) + { + super(loc, TOK.TOKnull, NullExp.sizeof); + } + + Expression semantic(Scope sc) + { +version (LOGSEMANTIC) { + printf("NullExp.semantic('%s')\n", toChars()); +} + // null is the same as (void*)0 + if (!type) + type = Type.tvoid.pointerTo(); + + return this; + } + + bool isBool(bool result) + { + assert(false); + } + + int isConst() + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + buf.writestring("null"); + } + + void toMangleBuffer(OutBuffer buf) + { + assert(false); + } + + MATCH implicitConvTo(Type t) + { +static if (false) { + printf("NullExp.implicitConvTo(this=%s, type=%s, t=%s, committed = %d)\n", + toChars(), type.toChars(), t.toChars(), committed); +} + if (this.type.equals(t)) + return MATCH.MATCHexact; + + /* Allow implicit conversions from invariant to mutable|const, + * and mutable to invariant. It works because, after all, a null + * doesn't actually point to anything. + */ + if (t.invariantOf().equals(type.invariantOf())) + return MATCH.MATCHconst; + + // null implicitly converts to any pointer type or dynamic array + if (type.ty == TY.Tpointer && type.nextOf().ty == TY.Tvoid) + { + if (t.ty == TY.Ttypedef) + t = (cast(TypeTypedef)t).sym.basetype; + if (t.ty == TY.Tpointer || t.ty == TY.Tarray || + t.ty == TY.Taarray || t.ty == TY.Tclass || + t.ty == TY.Tdelegate) + { + return committed ? MATCH.MATCHconvert : MATCH.MATCHexact; + } + } + + return Expression.implicitConvTo(t); + } + + Expression castTo(Scope sc, Type t) + { + NullExp e; + Type tb; + + //printf("NullExp::castTo(t = %p)\n", t); + if (type is t) + { + committed = 1; + return this; + } + + e = cast(NullExp)copy(); + e.committed = 1; + tb = t.toBasetype(); + e.type = type.toBasetype(); + + if (tb !is e.type) + { + // null implicitly converts to any pointer type or dynamic array + if (e.type.ty == TY.Tpointer && e.type.nextOf().ty == TY.Tvoid && + (tb.ty == TY.Tpointer || tb.ty == TY.Tarray || tb.ty == TY.Taarray || + tb.ty == TY.Tdelegate)) + { +static if (false) { + if (tb.ty == TY.Tdelegate) + { + TypeDelegate td = cast(TypeDelegate)tb; + TypeFunction tf = cast(TypeFunction)td.nextOf(); + + if (!tf.varargs && !(tf.arguments && tf.arguments.dim)) + { + return Expression.castTo(sc, t); + } + } +} + } + else + { + return e.Expression.castTo(sc, t); + } + } + e.type = t; + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + elem* toElem(IRState* irs) + { + return el_long(type.totym(), 0); + } + + dt_t** toDt(dt_t** pdt) + { + assert(type); + return dtnzeros(pdt, cast(uint)type.size()); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/ObjModule.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ObjModule.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,13 @@ +module dmd.ObjModule; + +struct ObjModule +{ + ubyte* base; // where are we holding it in memory + uint length; // in bytes + ushort page; // page module starts in output file + ubyte flags; + string name; // module name +} + +enum MFgentheadr = 1; // generate THEADR record +enum MFtheadr = 2; // module name comes from THEADR record \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/OnScopeStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/OnScopeStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,114 @@ +module dmd.OnScopeStatement; + +import dmd.Statement; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Scope; +import dmd.IRState; +import dmd.TOK; +import dmd.Loc; +import dmd.BE; +import dmd.Identifier; +import dmd.ExpInitializer; +import dmd.IntegerExp; +import dmd.VarDeclaration; +import dmd.Type; +import dmd.AssignExp; +import dmd.VarExp; +import dmd.NotExp; +import dmd.IfStatement; +import dmd.DeclarationStatement; +import dmd.ExpStatement; +import dmd.Expression; +import dmd.Lexer; + +class OnScopeStatement : Statement +{ + TOK tok; + Statement statement; + + this(Loc loc, TOK tok, Statement statement) + { + super(loc); + + this.tok = tok; + this.statement = statement; + } + + Statement syntaxCopy() + { + assert(false); + } + + BE blockExit() + { + // At this point, this statement is just an empty placeholder + return BE.BEfallthru; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + Statement semantic(Scope sc) + { + /* semantic is called on results of scopeCode() */ + return this; + } + + bool usesEH() + { + assert(false); + } + + void scopeCode(Scope sc, Statement* sentry, Statement* sexception, Statement* sfinally) + { + //printf("OnScopeStatement::scopeCode()\n"); + //print(); + *sentry = null; + *sexception = null; + *sfinally = null; + switch (tok) + { + case TOKon_scope_exit: + *sfinally = statement; + break; + + case TOKon_scope_failure: + *sexception = statement; + break; + + case TOKon_scope_success: + { + /* Create: + * sentry: int x = 0; + * sexception: x = 1; + * sfinally: if (!x) statement; + */ + Identifier id = Lexer.uniqueId("__os"); + + ExpInitializer ie = new ExpInitializer(loc, new IntegerExp(0)); + VarDeclaration v = new VarDeclaration(loc, Type.tint32, id, ie); + *sentry = new DeclarationStatement(loc, v); + + Expression e = new IntegerExp(1); + e = new AssignExp(Loc(0), new VarExp(Loc(0), v), e); + *sexception = new ExpStatement(Loc(0), e); + + e = new VarExp(Loc(0), v); + e = new NotExp(Loc(0), e); + *sfinally = new IfStatement(Loc(0), null, e, statement, null); + + break; + } + + default: + assert(0); + } + } + + void toIR(IRState* irs) + { + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/Optimize.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Optimize.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,100 @@ +module dmd.Optimize; + +import dmd.Expression; +import dmd.TOK; +import dmd.VarExp; +import dmd.VarDeclaration; +import dmd.STC; +import dmd.AssignExp; +import dmd.Type; +import dmd.WANT; +import dmd.TY; + +/************************************* + * If variable has a const initializer, + * return that initializer. + */ + +Expression expandVar(int result, VarDeclaration v) +{ + //printf("expandVar(result = %d, v = %p, %s)\n", result, v, v ? v.toChars() : "null"); + + Expression e = null; + if (!v) + return e; + + if (v.isConst() || v.isInvariant() || v.storage_class & STC.STCmanifest) + { + if (!v.type) + { + //error("ICE"); + return e; + } + + Type tb = v.type.toBasetype(); + if (result & WANT.WANTinterpret || + v.storage_class & STC.STCmanifest || + (tb.ty != TY.Tsarray && tb.ty != TY.Tstruct) + ) + { + if (v.init) + { + if (v.inuse) + { if (v.storage_class & STC.STCmanifest) + v.error("recursive initialization of constant"); + goto L1; + } + Expression ei = v.init.toExpression(); + if (!ei) + goto L1; + if (ei.op == TOK.TOKconstruct || ei.op == TOK.TOKblit) + { AssignExp ae = cast(AssignExp)ei; + ei = ae.e2; + if (ei.isConst() != 1 && ei.op != TOK.TOKstring) + goto L1; + if (ei.type != v.type) + goto L1; + } + if (v.scope_) + { + v.inuse++; + e = ei.syntaxCopy(); + e = e.semantic(v.scope_); + e = e.implicitCastTo(v.scope_, v.type); + // enabling this line causes test22 in test suite to fail + //ei.type = e.type; + v.scope_ = null; + v.inuse--; + } + else if (!ei.type) + { + goto L1; + } + else + // Should remove the copy() operation by + // making all mods to expressions copy-on-write + e = ei.copy(); + } + else + { +static if (true) { + goto L1; +} else { + // BUG: what if const is initialized in constructor? + e = v.type.defaultInit(); + e.loc = e1.loc; +} + } + if (e.type != v.type) + { + e = e.castTo(null, v.type); + } + v.inuse++; + e = e.optimize(result); + v.inuse--; + } + } +L1: + //if (e) printf("\te = %s, e.type = %s\n", e.toChars(), e.type.toChars()); + return e; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/OrAssignExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/OrAssignExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,54 @@ +module dmd.OrAssignExp; + +import dmd.BinExp; +import dmd.Loc; +import dmd.Expression; +import dmd.Scope; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.ArrayTypes; +import dmd.Identifier; +import dmd.IRState; +import dmd.TOK; +import dmd.Id; + +import dmd.backend.elem; +import dmd.backend.OPER; + +class OrAssignExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKorass, OrAssignExp.sizeof, e1, e2); + } + + Expression semantic(Scope sc) + { + return commonSemanticAssignIntegral(sc); + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void buildArrayIdent(OutBuffer buf, Expressions arguments) + { + assert(false); + } + + Expression buildArrayLoop(Arguments fparams) + { + assert(false); + } + + Identifier opId() /* For operator overloading */ + { + return Id.orass; + } + + elem* toElem(IRState* irs) + { + return toElemBin(irs, OPorass); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/OrExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/OrExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,133 @@ +module dmd.OrExp; + +import dmd.Expression; +import dmd.Identifier; +import dmd.InterState; +import dmd.MATCH; +import dmd.Type; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.IntRange; +import dmd.IRState; +import dmd.ArrayTypes; +import dmd.BinExp; +import dmd.TOK; +import dmd.TY; +import dmd.Id; + +import dmd.backend.elem; +import dmd.backend.OPER; + +import dmd.expression.Or; + +class OrExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKor, OrExp.sizeof, e1, e2); + } + + Expression semantic(Scope sc) + { + Expression e; + + if (!type) + { + BinExp.semanticp(sc); + e = op_overload(sc); + + if (e) + return e; + + if (e1.type.toBasetype().ty == TY.Tbool && e2.type.toBasetype().ty == TY.Tbool) + { + type = e1.type; + e = this; + } + else + { + typeCombine(sc); + if (e1.op != TOK.TOKslice && e2.op != TOK.TOKslice) + { + e1.checkIntegral(); + e2.checkIntegral(); + } + } + } + + return this; + } + + Expression optimize(int result) + { + Expression e; + + e1 = e1.optimize(result); + e2 = e2.optimize(result); + + if (e1.isConst() == 1 && e2.isConst() == 1) + e = Or(type, e1, e2); + else + e = this; + + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void buildArrayIdent(OutBuffer buf, Expressions arguments) + { + assert(false); + } + + Expression buildArrayLoop(Arguments fparams) + { + assert(false); + } + + MATCH implicitConvTo(Type t) + { + MATCH result = Expression.implicitConvTo(t); + + if (result == MATCH.MATCHnomatch) + { + MATCH m1 = e1.implicitConvTo(t); + MATCH m2 = e2.implicitConvTo(t); + + // Pick the worst match + result = (m1 < m2) ? m1 : m2; + } + + return result; + } + + IntRange getIntRange() + { + assert(false); + } + + bool isCommutative() + { + return true; + } + + Identifier opId() + { + return Id.ior; + } + + Identifier opId_r() + { + return Id.ior_r; + } + + elem* toElem(IRState* irs) + { + return toElemBin(irs, OPER.OPor); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/OrOrExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/OrOrExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,128 @@ +module dmd.OrOrExp; + +import dmd.BinExp; +import dmd.Scope; +import dmd.InterState; +import dmd.TOK; +import dmd.Expression; +import dmd.Loc; +import dmd.IRState; +import dmd.TY; +import dmd.WANT; +import dmd.IntegerExp; +import dmd.Type; +import dmd.CommaExp; +import dmd.Global; +import dmd.BoolExp; + +import dmd.expression.Util; + +import dmd.backend.elem; +import dmd.backend.OPER; +import dmd.backend.Util; + +class OrOrExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKoror, OrOrExp.sizeof, e1, e2); + } + + Expression semantic(Scope sc) + { + uint cs1; + + // same as for AndAnd + e1 = e1.semantic(sc); + e1 = resolveProperties(sc, e1); + e1 = e1.checkToPointer(); + e1 = e1.checkToBoolean(); + cs1 = sc.callSuper; + + if (sc.flags & SCOPE.SCOPEstaticif) + { + /* If in static if, don't evaluate e2 if we don't have to. + */ + e1 = e1.optimize(WANTflags); + if (e1.isBool(true)) + { + return new IntegerExp(loc, 1, Type.tboolean); + } + } + + e2 = e2.semantic(sc); + sc.mergeCallSuper(loc, cs1); + e2 = resolveProperties(sc, e2); + e2 = e2.checkToPointer(); + + type = Type.tboolean; + if (e2.type.ty == Tvoid) + type = Type.tvoid; + if (e2.op == TOKtype || e2.op == TOKimport) + error("%s is not an expression", e2.toChars()); + return this; + } + + Expression checkToBoolean() + { + e2 = e2.checkToBoolean(); + return this; + } + + int isBit() + { + assert(false); + } + + Expression optimize(int result) + { + Expression e; + + e1 = e1.optimize(WANTflags | (result & WANTinterpret)); + e = this; + if (e1.isBool(true)) + { + // Replace with (e1, 1) + e = new CommaExp(loc, e1, new IntegerExp(loc, 1, type)); + e.type = type; + e = e.optimize(result); + } + else + { + e2 = e2.optimize(WANTflags | (result & WANTinterpret)); + if (result && e2.type.toBasetype().ty == Tvoid && !global.errors) + error("void has no value"); + if (e1.isConst()) + { + if (e2.isConst()) + { + int n1 = e1.isBool(1); + int n2 = e2.isBool(1); + + e = new IntegerExp(loc, n1 || n2, type); + } + else if (e1.isBool(false)) + e = new BoolExp(loc, e2, type); + } + } + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + bool checkSideEffect(int flag) + { + assert(false); + } + + elem* toElem(IRState* irs) + { + elem* e = toElemBin(irs,OPoror); + if (global.params.cov && e2.loc.linnum) + e.E2() = el_combine(incUsageElem(irs, e2.loc), e.E2); + return e; + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/OutBuffer.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/OutBuffer.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,285 @@ +module dmd.OutBuffer; + +import std.stdarg; +import std.contracts; + +import core.stdc.stdlib; +import core.stdc.string; + +class OutBuffer +{ + ubyte* data; + uint offset; + uint size; + + this() + { + // do nothing + } + + final void* extractData() + { + void* p = cast(void*)data; + + data = null; + offset = 0; + size = 0; + + return p; + } + + void mark() + { + assert(false); + } + + final void reserve(uint nbytes) + { + //printf("OutBuffer::reserve: size = %d, offset = %d, nbytes = %d\n", size, offset, nbytes); + if (size - offset < nbytes) + { + size = (offset + nbytes) * 2; + data = cast(ubyte*)realloc(data, size); + } + } + + final void setsize(uint size) + { + assert(false); + } + + final void reset() + { + offset = 0; + } + + final void write(const(void)* data, uint nbytes) + { + reserve(nbytes); + memcpy(this.data + offset, data, nbytes); + offset += nbytes; + } + + final void writebstring(ubyte* string_) + { + assert(false); + } + + final void writestring(const(char)[] string_) + { + write(string_.ptr , string_.length); + } + + final void writedstring(const(char)* string_) + { + assert(false); + } + + final void writedstring(const(wchar)* string_) + { + assert(false); + } + + final void prependstring(const(char)[] string_) + { + uint len = string_.length; + reserve(len); + memmove(data + len, data, offset); + memcpy(data, string_.ptr, len); + offset += len; + } + + final void writenl() // write newline + { + assert(false); + } + + final void writeByte(uint b) + { + reserve(1); + this.data[offset] = cast(ubyte)b; + offset++; + } + + final void writebyte(uint b) { writeByte(b); } + + final void writeUTF8(uint b) + { + reserve(6); + if (b <= 0x7F) + { + this.data[offset] = cast(ubyte)b; + offset++; + } + else if (b <= 0x7FF) + { + this.data[offset + 0] = cast(ubyte)((b >> 6) | 0xC0); + this.data[offset + 1] = cast(ubyte)((b & 0x3F) | 0x80); + offset += 2; + } + else if (b <= 0xFFFF) + { + this.data[offset + 0] = cast(ubyte)((b >> 12) | 0xE0); + this.data[offset + 1] = cast(ubyte)(((b >> 6) & 0x3F) | 0x80); + this.data[offset + 2] = cast(ubyte)((b & 0x3F) | 0x80); + offset += 3; + } + else if (b <= 0x1FFFFF) + { + this.data[offset + 0] = cast(ubyte)((b >> 18) | 0xF0); + this.data[offset + 1] = cast(ubyte)(((b >> 12) & 0x3F) | 0x80); + this.data[offset + 2] = cast(ubyte)(((b >> 6) & 0x3F) | 0x80); + this.data[offset + 3] = cast(ubyte)((b & 0x3F) | 0x80); + offset += 4; + } + else if (b <= 0x3FFFFFF) + { + this.data[offset + 0] = cast(ubyte)((b >> 24) | 0xF8); + this.data[offset + 1] = cast(ubyte)(((b >> 18) & 0x3F) | 0x80); + this.data[offset + 2] = cast(ubyte)(((b >> 12) & 0x3F) | 0x80); + this.data[offset + 3] = cast(ubyte)(((b >> 6) & 0x3F) | 0x80); + this.data[offset + 4] = cast(ubyte)((b & 0x3F) | 0x80); + offset += 5; + } + else if (b <= 0x7FFFFFFF) + { + this.data[offset + 0] = cast(ubyte)((b >> 30) | 0xFC); + this.data[offset + 1] = cast(ubyte)(((b >> 24) & 0x3F) | 0x80); + this.data[offset + 2] = cast(ubyte)(((b >> 18) & 0x3F) | 0x80); + this.data[offset + 3] = cast(ubyte)(((b >> 12) & 0x3F) | 0x80); + this.data[offset + 4] = cast(ubyte)(((b >> 6) & 0x3F) | 0x80); + this.data[offset + 5] = cast(ubyte)((b & 0x3F) | 0x80); + offset += 6; + } + else + assert(0); + } + + final void writedchar(uint b) + { + assert(false); + } + + final void prependbyte(uint b) + { + assert(false); + } + + final void writeword(uint w) + { + reserve(2); + *cast(ushort*)(this.data + offset) = cast(ushort)w; + offset += 2; + } + + final void writeUTF16(uint w) + { + reserve(4); + if (w <= 0xFFFF) + { + *cast(ushort*)(this.data + offset) = cast(ushort)w; + offset += 2; + } + else if (w <= 0x10FFFF) + { + *cast(ushort*)(this.data + offset) = cast(ushort)((w >> 10) + 0xD7C0); + *cast(ushort*)(this.data + offset + 2) = cast(ushort)((w & 0x3FF) | 0xDC00); + offset += 4; + } + else + assert(0); + } + + final void write4(uint w) + { + assert(false); + } + + final void write(OutBuffer buf) + { + if (buf) + { + reserve(buf.offset); + memcpy(data + offset, buf.data, buf.offset); + offset += buf.offset; + } + } + + final void write(Object obj) + { + assert(false); + } + + final void fill0(uint nbytes) + { + reserve(nbytes); + memset(data + offset, 0, nbytes); + offset += nbytes; + } + + final void align_(uint size) + { + assert(false); + } + + void vprintf(const(char)* format, va_list args) + { + assert(false); + } + + void printf(T...)(string format, T t) + { + string s = std.string.format(format, t); + writestring(s); + } + +version (M_UNICODE) { +/// void vprintf(const uint short *format, va_list args); +/// void printf(const uint short *format, ...); +} + final void bracket(char left, char right) + { + assert(false); + } + + final uint bracket(uint i, const(char)* left, uint j, const(char)* right) + { + assert(false); + } + + final void spread(uint offset, uint nbytes) + { + assert(false); + } + + final uint insert(uint offset, const(void)* data, uint nbytes) + { + assert(false); + } + + final void remove(uint offset, uint nbytes) + { + assert(false); + } + + string toChars() + { + return getString().idup; + } + + final string extractString() + { + char[] s = getString(); + data = null; + offset = 0; + size = 0; + + return assumeUnique(s); + } + + final char[] getString() + { + char* s = cast(char*)data; + return s[0..offset]; + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/OverExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/OverExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,29 @@ +module dmd.OverExp; + +import dmd.Expression; +import dmd.OverloadSet; +import dmd.Scope; +import dmd.Loc; +import dmd.TOK; + +class OverExp : Expression +{ + OverloadSet vars; + + this(OverloadSet s) + { + assert(false); + super(Loc(0), TOK.init, 0); + } + + int isLvalue() + { + assert(false); + } + + Expression toLvalue(Scope sc, Expression e) + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/OverloadSet.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/OverloadSet.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,26 @@ +module dmd.OverloadSet; + +import dmd.Dsymbol; +import dmd.ArrayTypes; + +class OverloadSet : Dsymbol +{ + Dsymbols a; // array of Dsymbols + + this() + { + assert(false); + } + + void push(Dsymbol s) + { + assert(false); + } + + OverloadSet isOverloadSet() { return this; } + + string kind() + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/PREC.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/PREC.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,31 @@ +module dmd.PREC; + +import dmd.TOK; + +/********************************** + * Set operator precedence for each operator. + */ + +// Operator precedence - greater values are higher precedence + +enum PREC +{ + PREC_zero, + PREC_expr, + PREC_assign, + PREC_cond, + PREC_oror, + PREC_andand, + PREC_or, + PREC_xor, + PREC_and, + PREC_equal, + PREC_rel, + PREC_shift, + PREC_add, + PREC_mul, + PREC_unary, + PREC_primary, +} + +PREC precedence[TOK.TOKMAX]; \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/PROT.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/PROT.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,12 @@ +module dmd.PROT; + +enum PROT +{ + PROTundefined, + PROTnone, // no access + PROTprivate, + PROTpackage, + PROTprotected, + PROTpublic, + PROTexport, +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/Package.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Package.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,75 @@ +module dmd.Package; + +import dmd.ScopeDsymbol; +import dmd.Identifier; +import dmd.Array; +import dmd.DsymbolTable; +import dmd.Scope; +import dmd.Dsymbol; +import dmd.Module; +import dmd.Util; + +class Package : ScopeDsymbol +{ + this(Identifier ident) + { + super(ident); + } + + string kind() + { + assert(false); + } + + static DsymbolTable resolve(Array packages, Dsymbol* pparent, Package* ppkg) + { + DsymbolTable dst = Module.modules; + Dsymbol parent = null; + + //printf("Package::resolve()\n"); + if (ppkg) + *ppkg = null; + + if (packages) + { + for (int i = 0; i < packages.dim; i++) + { + Identifier pid = cast(Identifier)packages.data[i]; + Dsymbol p = dst.lookup(pid); + if (!p) + { + p = new Package(pid); + dst.insert(p); + p.parent = parent; + (cast(ScopeDsymbol)p).symtab = new DsymbolTable(); + } + else + { + assert(p.isPackage()); +version (TARGET_NET) { //dot net needs modules and packages with same name +} else { + if (p.isModule()) + { + p.error("module and package have the same name"); + fatal(); + break; + } +} + } + parent = p; + dst = (cast(Package)p).symtab; + if (ppkg && !*ppkg) + *ppkg = cast(Package)p; + } + if (pparent) + { + *pparent = parent; + } + } + return dst; + } + + Package isPackage() { return this; } + + void semantic(Scope sc) { } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/Param.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Param.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,100 @@ +module dmd.Param; + +import dmd.Array; +import dmd.OutBuffer; + +// Put command line switches in here +struct Param +{ + bool obj; // write object file + bool link; // perform link + bool lib; // write library file instead of object file(s) + bool multiobj; // break one object file into multiple ones + bool oneobj; // write one object file instead of multiple ones + bool trace; // insert profiling hooks + bool quiet; // suppress non-error messages + bool verbose; // verbose compile + bool vtls; // identify thread local variables + byte symdebug; // insert debug symbolic information + bool optimize; // run optimizer + bool cpu; // target CPU + bool isX86_64; // generate X86_64 bit code + bool isLinux; // generate code for linux + bool isOSX; // generate code for Mac OSX + bool isWindows; // generate code for Windows + bool isFreeBSD; // generate code for FreeBSD + bool isSolaris; // generate code for Solaris + bool scheduler; // which scheduler to use + bool useDeprecated; // allow use of deprecated features + bool useAssert; // generate runtime code for assert()'s + bool useInvariants; // generate class invariant checks + bool useIn; // generate precondition checks + bool useOut; // generate postcondition checks + bool useArrayBounds; // generate array bounds checks + bool useSwitchError; // check for switches without a default + bool useUnitTests; // generate unittest code + bool useInline; // inline expand functions + bool release; // build release version + bool preservePaths; // !=0 means don't strip path from source file + bool warnings; // enable warnings + bool pic; // generate position-independent-code for shared libs + bool cov; // generate code coverage data + bool nofloat; // code should not pull in floating point support + byte Dversion; // D version number + bool ignoreUnsupportedPragmas; // rather than error on them + bool safe; // enforce safe memory model + + string argv0; // program name + Array imppath; // array of char*'s of where to look for import modules + Array fileImppath; // array of char*'s of where to look for file import modules + string objdir; // .obj/.lib file output directory + string objname; // .obj file output name + string libname; // .lib file output name + + bool doDocComments; // process embedded documentation comments + string docdir; // write documentation file to docdir directory + string docname; // write documentation file to docname + Array ddocfiles; // macro include files for Ddoc + + bool doHdrGeneration; // process embedded documentation comments + string hdrdir; // write 'header' file to docdir directory + string hdrname; // write 'header' file to docname + + uint debuglevel; // debug level + Array debugids; // debug identifiers + + uint versionlevel; // version level + Array versionids; // version identifiers + + bool dump_source; + + const(char)* defaultlibname; // default library for non-debug builds + const(char)* debuglibname; // default library for debug builds + + const(char)* xmlname; // filename for XML output + + string moduleDepsFile; // filename for deps output + OutBuffer moduleDeps; // contents to be written to deps file + + // Hidden debug switches + bool debuga; + bool debugb; + bool debugc; + bool debugf; + bool debugr; + bool debugw; + bool debugx; + bool debugy; + + bool run; // run resulting executable + size_t runargs_length; + string[] runargs; // arguments for executable + + // Linker stuff + Array objfiles; + Array linkswitches; + Array libfiles; + string deffile; + string resfile; + string exefile; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ParseStatementFlags.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ParseStatementFlags.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,9 @@ +module dmd.ParseStatementFlags; + +enum ParseStatementFlags +{ + PSsemi = 1, // empty ';' statements are allowed + PSscope = 2, // start a new scope + PScurly = 4, // { } statement is required + PScurlyscope = 8, // { } starts a new scope +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/Parser.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Parser.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,5951 @@ +module dmd.Parser; + +import dmd.Lexer; +import dmd.PostBlitDeclaration; +import dmd.FileInitExp; +import dmd.LineInitExp; +import dmd.EnumMember; +import dmd.CtorDeclaration; +import dmd.ShlAssignExp; +import dmd.ShrAssignExp; +import dmd.UshrAssignExp; +import dmd.CatAssignExp; +import dmd.StaticIfCondition; +import dmd.TraitsExp; +import dmd.BaseClass; +import dmd.AssignExp; +import dmd.TemplateInstance; +import dmd.NewExp; +import dmd.ArrayExp; +import dmd.DotTemplateInstanceExp; +import dmd.ClassDeclaration; +import dmd.NewAnonClassExp; +import dmd.InterfaceDeclaration; +import dmd.StructDeclaration; +import dmd.UnionDeclaration; +import dmd.AnonDeclaration; +import dmd.StructInitializer; +import dmd.ArrayInitializer; +import dmd.ExpInitializer; +import dmd.TemplateAliasParameter; +import dmd.TemplateTupleParameter; +import dmd.TemplateThisParameter; +import dmd.TemplateValueParameter; +import dmd.VoidInitializer; +import dmd.VersionCondition; +import dmd.DotIdExp; +import dmd.DebugCondition; +import dmd.PostExp; +import dmd.CallExp; +import dmd.SliceExp; +import dmd.FuncExp; +import dmd.AssocArrayLiteralExp; +import dmd.ArrayLiteralExp; +import dmd.IsExp; +import dmd.FuncLiteralDeclaration; +import dmd.AssertExp; +import dmd.CompileExp; +import dmd.FileExp; +import dmd.TemplateParameter; +import dmd.TemplateTypeParameter; +import dmd.TypeidExp; +import dmd.StringExp; +import dmd.ScopeExp; +import dmd.IdentifierExp; +import dmd.DollarExp; +import dmd.ThisExp; +import dmd.SuperExp; +import dmd.NullExp; +import dmd.RealExp; +import dmd.TypeExp; +import dmd.AddrExp; +import dmd.MOD; +import dmd.IntegerExp; +import dmd.CastExp; +import dmd.PtrExp; +import dmd.NegExp; +import dmd.XorAssignExp; +import dmd.OrAssignExp; +import dmd.UAddExp; +import dmd.NotExp; +import dmd.ComExp; +import dmd.DeleteExp; +import dmd.MulAssignExp; +import dmd.ModAssignExp; +import dmd.MinAssignExp; +import dmd.DivAssignExp; +import dmd.AndAssignExp; +import dmd.AddAssignExp; +import dmd.ModuleDeclaration; +import dmd.CaseRangeStatement; +import dmd.CommaExp; +import dmd.XorExp; +import dmd.CondExp; +import dmd.CmpExp; +import dmd.InExp; +import dmd.OrOrExp; +import dmd.OrExp; +import dmd.AddExp; +import dmd.MinExp; +import dmd.CatExp; +import dmd.AndAndExp; +import dmd.EqualExp; +import dmd.ShlExp; +import dmd.ShrExp; +import dmd.DivExp; +import dmd.MulExp; +import dmd.ModExp; +import dmd.UshrExp; +import dmd.IdentityExp; +import dmd.AndExp; +import dmd.Id; +import dmd.LabelStatement; +import dmd.ExpStatement; +import dmd.StaticAssertStatement; +import dmd.DeclarationStatement; +import dmd.ScopeStatement; +import dmd.PragmaStatement; +import dmd.WhileStatement; +import dmd.DoStatement; +import dmd.ForStatement; +import dmd.OnScopeStatement; +import dmd.IfStatement; +import dmd.SwitchStatement; +import dmd.CaseStatement; +import dmd.DefaultStatement; +import dmd.GotoDefaultStatement; +import dmd.GotoCaseStatement; +import dmd.GotoStatement; +import dmd.SynchronizedStatement; +import dmd.WithStatement; +import dmd.Catch; +import dmd.TryCatchStatement; +import dmd.TryFinallyStatement; +import dmd.ThrowStatement; +import dmd.VolatileStatement; +import dmd.ReturnStatement; +import dmd.BreakStatement; +import dmd.ContinueStatement; +import dmd.AsmStatement; +import dmd.TypeReturn; +import dmd.TypeTypeof; +import dmd.ForeachRangeStatement; +import dmd.ForeachStatement; +import dmd.CompileStatement; +import dmd.CompoundStatement; +import dmd.ConditionalStatement; +import dmd.CompoundDeclarationStatement; +import dmd.Argument; +import dmd.ParseStatementFlags; +import dmd.TypeNext; +import dmd.TypeInstance; +import dmd.TypePointer; +import dmd.TypeDArray; +import dmd.TypeAArray; +import dmd.TypeSlice; +import dmd.TypeSArray; +import dmd.TemplateInstance; +import dmd.TypeIdentifier; +import dmd.VarDeclaration; +import dmd.TypeFunction; +import dmd.TypeDelegate; +import dmd.TY; +import dmd.LinkDeclaration; +import dmd.Declaration; +import dmd.AggregateDeclaration; +import dmd.TypedefDeclaration; +import dmd.AliasDeclaration; +import dmd.LINK; +import dmd.Loc; +import dmd.Module; +import dmd.Array; +import dmd.Expression; +import dmd.TemplateDeclaration; +import dmd.ArrayTypes; +import dmd.Dsymbol; +import dmd.StaticAssert; +import dmd.TypeQualified; +import dmd.Condition; +import dmd.PostBlitDeclaration; +import dmd.DtorDeclaration; +import dmd.ConditionalDeclaration; +import dmd.StaticCtorDeclaration; +import dmd.StaticDtorDeclaration; +import dmd.InvariantDeclaration; +import dmd.UnitTestDeclaration; +import dmd.NewDeclaration; +import dmd.DeleteDeclaration; +import dmd.EnumDeclaration; +import dmd.Import; +import dmd.Type; +import dmd.Identifier; +import dmd.FuncDeclaration; +import dmd.Statement; +import dmd.Initializer; +import dmd.Token; +import dmd.TOK; +import dmd.ParseStatementFlags; +import dmd.PROT; +import dmd.STC; +import dmd.Util; +import dmd.CompileDeclaration; +import dmd.StaticIfDeclaration; +import dmd.StorageClassDeclaration; +import dmd.LinkDeclaration; +import dmd.ProtDeclaration; +import dmd.AlignDeclaration; +import dmd.PragmaDeclaration; +import dmd.DebugSymbol; +import dmd.VersionSymbol; +import dmd.AliasThis; +import dmd.Global; + +import core.stdc.string : memcpy; +import core.stdc.stdlib : malloc; + +import std.contracts; + +class Parser : Lexer +{ + ModuleDeclaration md; + LINK linkage; + Loc endloc; // set to location of last right curly + int inBrackets; // inside [] of array index or slice + + this(Module module_, ubyte* base, uint length, int doDocComment) + { + super(module_, base, 0, length, doDocComment, 0); + //printf("Parser.Parser()\n"); + linkage = LINK.LINKd; + //nextToken(); // start up the scanner + } + + Array parseModule() + { + Array decldefs; + + // ModuleDeclation leads off + if (token.value == TOK.TOKmodule) + { + ubyte* comment = token.blockComment; + bool safe = false; + + nextToken(); +version (DMDV2) { + if (token.value == TOK.TOKlparen) + { + nextToken(); + if (token.value != TOK.TOKidentifier) + { + error("module (system) identifier expected"); + goto Lerr; + } + Identifier id = token.ident; + + if (id is Id.system) + safe = true; + else + error("(safe) expected, not %s", id.toChars()); + nextToken(); + check(TOK.TOKrparen); + } +} + + if (token.value != TOK.TOKidentifier) + { + error("Identifier expected following module"); + goto Lerr; + } + else + { + Array a = null; + Identifier id = token.ident; + while (nextToken() == TOK.TOKdot) + { + if (!a) + a = new Array(); + a.push(cast(void*)id); + nextToken(); + if (token.value != TOK.TOKidentifier) + { error("Identifier expected following package"); + goto Lerr; + } + id = token.ident; + } + + md = new ModuleDeclaration(a, id, safe); + + if (token.value != TOK.TOKsemicolon) + error("';' expected following module declaration instead of %s", token.toChars()); + + nextToken(); + addComment(mod, comment); + } + } + + decldefs = parseDeclDefs(0); + if (token.value != TOK.TOKeof) + { + error("unrecognized declaration"); + goto Lerr; + } + + return decldefs; + + Lerr: + while (token.value != TOK.TOKsemicolon && token.value != TOK.TOKeof) + nextToken(); + + nextToken(); + return new Array(); + } + + Array parseDeclDefs(int once) + { + Dsymbol s; + Array decldefs; + Array a; + Array aelse; + PROT prot; + STC stc; + STC storageClass; + Condition condition; + ubyte* comment; + + //printf("Parser.parseDeclDefs()\n"); + decldefs = new Array(); + do + { + comment = token.blockComment; + storageClass = STC.STCundefined; + switch (token.value) + { + case TOK.TOKenum: + { /* Determine if this is a manifest constant declaration, + * or a conventional enum. + */ + Token *t = peek(&token); + if (t.value == TOK.TOKlcurly || t.value == TOK.TOKcolon) + s = parseEnum(); + else if (t.value != TOK.TOKidentifier) + goto Ldeclaration; + else + { + t = peek(t); + if (t.value == TOK.TOKlcurly || t.value == TOK.TOKcolon || + t.value == TOK.TOKsemicolon) + s = parseEnum(); + else + goto Ldeclaration; + } + break; + } + + case TOK.TOKstruct: + case TOK.TOKunion: + case TOK.TOKclass: + case TOK.TOKinterface: + s = parseAggregate(); + break; + + case TOK.TOKimport: + s = parseImport(decldefs, 0); + break; + + case TOK.TOKtemplate: + s = cast(Dsymbol)parseTemplateDeclaration(); + break; + + case TOK.TOKmixin: + { Loc loc = this.loc; + if (peek(&token).value == TOK.TOKlparen) + { // mixin(string) + nextToken(); + check(TOK.TOKlparen, "mixin"); + Expression e = parseAssignExp(); + check(TOK.TOKrparen); + check(TOK.TOKsemicolon); + s = new CompileDeclaration(loc, e); + break; + } + s = parseMixin(); + break; + } + + case TOK.TOKwchar: case TOK.TOKdchar: + case TOK.TOKbit: case TOK.TOKbool: case TOK.TOKchar: + case TOK.TOKint8: case TOK.TOKuns8: + case TOK.TOKint16: case TOK.TOKuns16: + case TOK.TOKint32: case TOK.TOKuns32: + case TOK.TOKint64: case TOK.TOKuns64: + case TOK.TOKfloat32: case TOK.TOKfloat64: case TOK.TOKfloat80: + case TOK.TOKimaginary32: case TOK.TOKimaginary64: case TOK.TOKimaginary80: + case TOK.TOKcomplex32: case TOK.TOKcomplex64: case TOK.TOKcomplex80: + case TOK.TOKvoid: + case TOK.TOKalias: + case TOK.TOKtypedef: + case TOK.TOKidentifier: + case TOK.TOKtypeof: + case TOK.TOKdot: + Ldeclaration: + a = parseDeclarations(STC.STCundefined); + decldefs.append(a); + continue; + + case TOK.TOKthis: + s = parseCtor(); + break; + +static if (false) { // dead end, use this(this){} instead + case TOK.TOKassign: + s = parsePostBlit(); + break; +} + case TOK.TOKtilde: + s = parseDtor(); + break; + + case TOK.TOKinvariant: + { Token *t; + t = peek(&token); + if (t.value == TOK.TOKlparen) + { + if (peek(t).value == TOK.TOKrparen) + // invariant() forms start of class invariant + s = parseInvariant(); + else + // invariant(type) + goto Ldeclaration; + } + else + { + stc = STC.STCimmutable; + goto Lstc; + } + break; + } + + case TOK.TOKunittest: + s = parseUnitTest(); + break; + + case TOK.TOKnew: + s = parseNew(); + break; + + case TOK.TOKdelete: + s = parseDelete(); + break; + + case TOK.TOKeof: + case TOK.TOKrcurly: + return decldefs; + + case TOK.TOKstatic: + nextToken(); + if (token.value == TOK.TOKthis) + s = parseStaticCtor(); + else if (token.value == TOK.TOKtilde) + s = parseStaticDtor(); + else if (token.value == TOK.TOKassert) + s = parseStaticAssert(); + else if (token.value == TOK.TOKif) + { condition = parseStaticIfCondition(); + a = parseBlock(); + aelse = null; + if (token.value == TOK.TOKelse) + { nextToken(); + aelse = parseBlock(); + } + s = new StaticIfDeclaration(condition, a, aelse); + break; + } + else if (token.value == TOK.TOKimport) + { + s = parseImport(decldefs, 1); + } + else + { stc = STC.STCstatic; + goto Lstc2; + } + break; + + case TOK.TOKconst: + if (peek(&token).value == TOK.TOKlparen) + goto Ldeclaration; + stc = STC.STCconst; + goto Lstc; + + case TOK.TOKimmutable: + if (peek(&token).value == TOK.TOKlparen) + goto Ldeclaration; + stc = STC.STCimmutable; + goto Lstc; + + case TOK.TOKshared: + if (peek(&token).value == TOK.TOKlparen) + goto Ldeclaration; + stc = STC.STCshared; + goto Lstc; + + case TOK.TOKfinal: stc = STC.STCfinal; goto Lstc; + case TOK.TOKauto: stc = STC.STCauto; goto Lstc; + case TOK.TOKscope: stc = STC.STCscope; goto Lstc; + case TOK.TOKoverride: stc = STC.STCoverride; goto Lstc; + case TOK.TOKabstract: stc = STC.STCabstract; goto Lstc; + case TOK.TOKsynchronized: stc = STC.STCsynchronized; goto Lstc; + case TOK.TOKdeprecated: stc = STC.STCdeprecated; goto Lstc; +version (DMDV2) { + case TOK.TOKnothrow: stc = STC.STCnothrow; goto Lstc; + case TOK.TOKpure: stc = STC.STCpure; goto Lstc; + case TOK.TOKref: stc = STC.STCref; goto Lstc; + case TOK.TOKtls: stc = STC.STCtls; goto Lstc; + case TOK.TOKgshared: + stc = STC.STCgshared; goto Lstc; + //case TOK.TOKmanifest: stc = STC.STCmanifest; goto Lstc; +} + + Lstc: + if (storageClass & stc) + error("redundant storage class %s", Token.toChars(token.value)); + composeStorageClass(storageClass | stc); + nextToken(); + Lstc2: + storageClass |= stc; + switch (token.value) + { + case TOK.TOKconst: + case TOK.TOKinvariant: + case TOK.TOKimmutable: + case TOK.TOKshared: + // If followed by a (, it is not a storage class + if (peek(&token).value == TOK.TOKlparen) + break; + if (token.value == TOK.TOKconst) + stc = STC.STCconst; + else if (token.value == TOK.TOKshared) + stc = STC.STCshared; + else + stc = STC.STCimmutable; + goto Lstc; + case TOK.TOKfinal: stc = STC.STCfinal; goto Lstc; + case TOK.TOKauto: stc = STC.STCauto; goto Lstc; + case TOK.TOKscope: stc = STC.STCscope; goto Lstc; + case TOK.TOKoverride: stc = STC.STCoverride; goto Lstc; + case TOK.TOKabstract: stc = STC.STCabstract; goto Lstc; + case TOK.TOKsynchronized: stc = STC.STCsynchronized; goto Lstc; + case TOK.TOKdeprecated: stc = STC.STCdeprecated; goto Lstc; + case TOK.TOKnothrow: stc = STC.STCnothrow; goto Lstc; + case TOK.TOKpure: stc = STC.STCpure; goto Lstc; + case TOK.TOKref: stc = STC.STCref; goto Lstc; + case TOK.TOKtls: stc = STC.STCtls; goto Lstc; + case TOK.TOKgshared: stc = STC.STCgshared; goto Lstc; + //case TOK.TOKmanifest: stc = STC.STCmanifest; goto Lstc; + default: + break; + } + + /* Look for auto initializers: + * storage_class identifier = initializer; + */ + if (token.value == TOK.TOKidentifier && + peek(&token).value == TOK.TOKassign) + { + a = parseAutoDeclarations(storageClass, comment); + decldefs.append(a); + continue; + } + + /* Look for return type inference for template functions. + */ + Token *tk; + if (token.value == TOK.TOKidentifier && + (tk = peek(&token)).value == TOK.TOKlparen && + skipParens(tk, &tk) && + (peek(tk).value == TOK.TOKlparen || + peek(tk).value == TOK.TOKlcurly) + ) + { + a = parseDeclarations(storageClass); + decldefs.append(a); + continue; + } + a = parseBlock(); + s = new StorageClassDeclaration(storageClass, a); + break; + + case TOK.TOKextern: + if (peek(&token).value != TOK.TOKlparen) + { + stc = STC.STCextern; + goto Lstc; + } + { + LINK linksave = linkage; + linkage = parseLinkage(); + a = parseBlock(); + s = new LinkDeclaration(linkage, a); + linkage = linksave; + break; + } + + case TOK.TOKprivate: prot = PROT.PROTprivate; goto Lprot; + case TOK.TOKpackage: prot = PROT.PROTpackage; goto Lprot; + case TOK.TOKprotected: prot = PROT.PROTprotected; goto Lprot; + case TOK.TOKpublic: prot = PROT.PROTpublic; goto Lprot; + case TOK.TOKexport: prot = PROT.PROTexport; goto Lprot; + Lprot: + nextToken(); + switch (token.value) + { + case TOK.TOKprivate: + case TOK.TOKpackage: + case TOK.TOKprotected: + case TOK.TOKpublic: + case TOK.TOKexport: + error("redundant protection attribute"); + break; + default: + break; + } + a = parseBlock(); + s = new ProtDeclaration(prot, a); + break; + + case TOK.TOKalign: + { uint n; + + s = null; + nextToken(); + if (token.value == TOK.TOKlparen) + { + nextToken(); + if (token.value == TOK.TOKint32v) + n = cast(uint)token.uns64value; + else + { error("integer expected, not %s", token.toChars()); + n = 1; + } + nextToken(); + check(TOK.TOKrparen); + } + else + n = global.structalign; // default + + a = parseBlock(); + s = new AlignDeclaration(n, a); + break; + } + + case TOK.TOKpragma: + { Identifier ident; + Expressions args = null; + + nextToken(); + check(TOK.TOKlparen); + if (token.value != TOK.TOKidentifier) + { error("pragma(identifier expected"); + goto Lerror; + } + ident = token.ident; + nextToken(); + if (token.value == TOK.TOKcomma && peekNext() != TOK.TOKrparen) + args = parseArguments(); // pragma(identifier, args...) + else + check(TOK.TOKrparen); // pragma(identifier) + + if (token.value == TOK.TOKsemicolon) + a = null; + else + a = parseBlock(); + s = new PragmaDeclaration(loc, ident, args, a); + break; + } + + case TOK.TOKdebug: + nextToken(); + if (token.value == TOK.TOKassign) + { + nextToken(); + if (token.value == TOK.TOKidentifier) + s = new DebugSymbol(loc, token.ident); + else if (token.value == TOK.TOKint32v) + s = new DebugSymbol(loc, cast(uint)token.uns64value); + else + { error("identifier or integer expected, not %s", token.toChars()); + s = null; + } + nextToken(); + if (token.value != TOK.TOKsemicolon) + error("semicolon expected"); + nextToken(); + break; + } + + condition = parseDebugCondition(); + goto Lcondition; + + case TOK.TOKversion: + nextToken(); + if (token.value == TOK.TOKassign) + { + nextToken(); + if (token.value == TOK.TOKidentifier) + s = new VersionSymbol(loc, token.ident); + else if (token.value == TOK.TOKint32v) + s = new VersionSymbol(loc, cast(uint)token.uns64value); + else + { error("identifier or integer expected, not %s", token.toChars()); + s = null; + } + nextToken(); + if (token.value != TOK.TOKsemicolon) + error("semicolon expected"); + nextToken(); + break; + } + condition = parseVersionCondition(); + goto Lcondition; + + Lcondition: + a = parseBlock(); + aelse = null; + if (token.value == TOK.TOKelse) + { nextToken(); + aelse = parseBlock(); + } + s = new ConditionalDeclaration(condition, a, aelse); + break; + + case TOK.TOKsemicolon: // empty declaration + nextToken(); + continue; + + default: + error("Declaration expected, not '%s'",token.toChars()); + Lerror: + while (token.value != TOK.TOKsemicolon && token.value != TOK.TOKeof) + nextToken(); + nextToken(); + s = null; + continue; + } + if (s) + { decldefs.push(cast(void*)s); + addComment(s, comment); + } + } while (!once); + return decldefs; + } + + /***************************************** + * Parse auto declarations of the form: + * storageClass ident = init, ident = init, ... ; + * and return the array of them. + * Starts with token on the first ident. + * Ends with scanner past closing ';' + */ +version (DMDV2) { + Array parseAutoDeclarations(STC storageClass, ubyte* comment) + { + Array a = new Array; + + while (true) + { + Identifier ident = token.ident; + nextToken(); // skip over ident + assert(token.value == TOKassign); + nextToken(); // skip over '=' + Initializer init = parseInitializer(); + VarDeclaration v = new VarDeclaration(loc, null, ident, init); + v.storage_class = storageClass; + a.push(cast(void*)v); + if (token.value == TOKsemicolon) + { + nextToken(); + addComment(v, comment); + } + else if (token.value == TOKcomma) + { + nextToken(); + if (token.value == TOKidentifier && + peek(&token).value == TOKassign) + { + addComment(v, comment); + continue; + } + else + error("Identifier expected following comma"); + } + else + error("semicolon expected following auto declaration, not '%s'", token.toChars()); + break; + } + return a; + } +} + /******************************************** + * Parse declarations after an align, protection, or extern decl. + */ + Array parseBlock() + { + Array a = null; + Dsymbol ss; + + //printf("parseBlock()\n"); + switch (token.value) + { + case TOK.TOKsemicolon: + error("declaration expected following attribute, not ';'"); + nextToken(); + break; + + case TOK.TOKeof: + error("declaration expected following attribute, not EOF"); + break; + + case TOK.TOKlcurly: + nextToken(); + a = parseDeclDefs(0); + if (token.value != TOK.TOKrcurly) + { /* { */ + error("matching '}' expected, not %s", token.toChars()); + } + else + nextToken(); + break; + + case TOK.TOKcolon: + nextToken(); +static if (false) { + a = null; +} else { + a = parseDeclDefs(0); // grab declarations up to closing curly bracket +} + break; + + default: + a = parseDeclDefs(1); + break; + } + return a; + } + + void composeStorageClass(STC stc) + { + STC u = stc; + u &= STC.STCconst | STC.STCimmutable | STC.STCmanifest; + if (u & (u - 1)) + error("conflicting storage class %s", Token.toChars(token.value)); + + u = stc; + u &= STC.STCgshared | STC.STCshared | STC.STCtls; + if (u & (u - 1)) + error("conflicting storage class %s", Token.toChars(token.value)); + } + + /************************************** + * Parse constraint. + * Constraint is of the form: + * if ( ConstraintExpression ) + */ +version (DMDV2) { + Expression parseConstraint() + { + Expression e = null; + + if (token.value == TOKif) + { + nextToken(); // skip over 'if' + check(TOKlparen); + e = parseExpression(); + check(TOKrparen); + } + return e; + } +} + /************************************** + * Parse a TemplateDeclaration. + */ + TemplateDeclaration parseTemplateDeclaration() + { + TemplateDeclaration tempdecl; + Identifier id; + TemplateParameters tpl; + Array decldefs; + Expression constraint = null; + Loc loc = this.loc; + + nextToken(); + if (token.value != TOKidentifier) + { + error("TemplateIdentifier expected following template"); + goto Lerr; + } + id = token.ident; + nextToken(); + tpl = parseTemplateParameterList(); + if (!tpl) + goto Lerr; + + constraint = parseConstraint(); + + if (token.value != TOKlcurly) + { + error("members of template declaration expected"); + goto Lerr; + } + else + { + nextToken(); + decldefs = parseDeclDefs(0); + if (token.value != TOKrcurly) + { + error("template member expected"); + goto Lerr; + } + nextToken(); + } + + tempdecl = new TemplateDeclaration(loc, id, tpl, constraint, decldefs); + return tempdecl; + + Lerr: + return null; + } + + /****************************************** + * Parse template parameter list. + * Input: + * flag 0: parsing "( list )" + * 1: parsing non-empty "list )" + */ + TemplateParameters parseTemplateParameterList(int flag = 0) + { + TemplateParameters tpl = new TemplateParameters(); + + if (!flag && token.value != TOKlparen) + { + error("parenthesized TemplateParameterList expected following TemplateIdentifier"); + goto Lerr; + } + nextToken(); + + // Get array of TemplateParameters + if (flag || token.value != TOKrparen) + { + int isvariadic = 0; + + while (true) + { + TemplateParameter tp; + Identifier tp_ident = null; + Type tp_spectype = null; + Type tp_valtype = null; + Type tp_defaulttype = null; + Expression tp_specvalue = null; + Expression tp_defaultvalue = null; + Token* t; + + // Get TemplateParameter + + // First, look ahead to see if it is a TypeParameter or a ValueParameter + t = peek(&token); + if (token.value == TOKalias) + { + // AliasParameter + nextToken(); + Type spectype = null; + if (isDeclaration(&token, 2, TOKreserved, null)) + { + spectype = parseType(&tp_ident); + } + else + { + if (token.value != TOKidentifier) + { + error("identifier expected for template alias parameter"); + goto Lerr; + } + tp_ident = token.ident; + nextToken(); + } + Object spec = null; + if (token.value == TOKcolon) // : Type + { + nextToken(); + if (isDeclaration(&token, 0, TOKreserved, null)) + spec = parseType(); + else + spec = parseCondExp(); + } + Object def = null; + if (token.value == TOKassign) // = Type + { + nextToken(); + if (isDeclaration(&token, 0, TOKreserved, null)) + def = parseType(); + else + def = parseCondExp(); + } + tp = new TemplateAliasParameter(loc, tp_ident, spectype, spec, def); + } + else if (t.value == TOKcolon || t.value == TOKassign || + t.value == TOKcomma || t.value == TOKrparen) + { // TypeParameter + if (token.value != TOKidentifier) + { error("identifier expected for template type parameter"); + goto Lerr; + } + tp_ident = token.ident; + nextToken(); + if (token.value == TOKcolon) // : Type + { + nextToken(); + tp_spectype = parseType(); + } + if (token.value == TOKassign) // = Type + { + nextToken(); + tp_defaulttype = parseType(); + } + tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype); + } + else if (token.value == TOKidentifier && t.value == TOKdotdotdot) + { // ident... + if (isvariadic) + error("variadic template parameter must be last"); + isvariadic = 1; + tp_ident = token.ident; + nextToken(); + nextToken(); + tp = new TemplateTupleParameter(loc, tp_ident); + } +/// version (DMDV2) { + else if (token.value == TOKthis) + { // ThisParameter + nextToken(); + if (token.value != TOKidentifier) + { error("identifier expected for template this parameter"); + goto Lerr; + } + tp_ident = token.ident; + nextToken(); + if (token.value == TOKcolon) // : Type + { + nextToken(); + tp_spectype = parseType(); + } + if (token.value == TOKassign) // = Type + { + nextToken(); + tp_defaulttype = parseType(); + } + tp = new TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype); + } +/// } + else + { // ValueParameter + tp_valtype = parseType(&tp_ident); + if (!tp_ident) + { + error("identifier expected for template value parameter"); + tp_ident = new Identifier("error", TOKidentifier); + } + if (token.value == TOKcolon) // : CondExpression + { + nextToken(); + tp_specvalue = parseCondExp(); + } + if (token.value == TOKassign) // = CondExpression + { + nextToken(); + tp_defaultvalue = parseDefaultInitExp(); + } + tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue); + } + tpl.push(cast(void*)tp); + if (token.value != TOKcomma) + break; + nextToken(); + } + } + check(TOKrparen); + + Lerr: + return tpl; + } + + Dsymbol parseMixin() + { + assert(false); + } + + /****************************************** + * Parse template argument list. + * Input: + * current token is opening '(' + * Output: + * current token is one after closing ')' + */ + Objects parseTemplateArgumentList() + { + //printf("Parser.parseTemplateArgumentList()\n"); + if (token.value != TOKlparen && token.value != TOKlcurly) + { + error("!(TemplateArgumentList) expected following TemplateIdentifier"); + return new Objects(); + } + return parseTemplateArgumentList2(); + } + + Objects parseTemplateArgumentList2() + { + //printf("Parser.parseTemplateArgumentList2()\n"); + Objects tiargs = new Objects(); + TOK endtok = TOKrparen; + nextToken(); + + // Get TemplateArgumentList + if (token.value != endtok) + { + while (1) + { + // See if it is an Expression or a Type + if (isDeclaration(&token, 0, TOKreserved, null)) + { // Template argument is a type + Type ta = parseType(); + tiargs.push(cast(void*)ta); + } + else + { // Template argument is an expression + Expression ea = parseAssignExp(); + + if (ea.op == TOKfunction) + { + FuncLiteralDeclaration fd = (cast(FuncExp)ea).fd; + if (fd.type.ty == Tfunction) + { + TypeFunction tf = cast(TypeFunction)fd.type; + /* If there are parameters that consist of only an identifier, + * rather than assuming the identifier is a type, as we would + * for regular function declarations, assume the identifier + * is the parameter name, and we're building a template with + * a deduced type. + */ + TemplateParameters tpl = null; + for (int i = 0; i < tf.parameters.dim; i++) + { + Argument param = cast(Argument)tf.parameters.data[i]; + if (param.ident is null && + param.type && + param.type.ty == Tident && + (cast(TypeIdentifier)param.type).idents.dim == 0 + ) + { + /* Switch parameter type to parameter identifier, + * parameterize with template type parameter _T + */ + TypeIdentifier pt = cast(TypeIdentifier)param.type; + param.ident = pt.ident; + Identifier id = Lexer.uniqueId("__T"); + param.type = new TypeIdentifier(pt.loc, id); + TemplateParameter tp = new TemplateTypeParameter(fd.loc, id, null, null); + if (!tpl) + tpl = new TemplateParameters(); + tpl.push(cast(void*)tp); + } + } + + if (tpl) + { + // Wrap a template around function fd + Array decldefs = new Array(); + decldefs.push(cast(void*)fd); + TemplateDeclaration tempdecl = new TemplateDeclaration(fd.loc, fd.ident, tpl, null, decldefs); + tempdecl.literal = 1; // it's a template 'literal' + tiargs.push(cast(void*)tempdecl); + goto L1; + } + } + } + + tiargs.push(cast(void*)ea); + } + L1: + if (token.value != TOKcomma) + break; + nextToken(); + } + } + check(endtok, "template argument list"); + return tiargs; + } + + Objects parseTemplateArgument() + { + assert(false); + } + + /********************************** + * Parse a static assertion. + */ + StaticAssert parseStaticAssert() + { + Loc loc = this.loc; + Expression exp; + Expression msg = null; + + //printf("parseStaticAssert()\n"); + nextToken(); + check(TOK.TOKlparen); + exp = parseAssignExp(); + if (token.value == TOK.TOKcomma) + { + nextToken(); + msg = parseAssignExp(); + } + + check(TOK.TOKrparen); + check(TOK.TOKsemicolon); + + return new StaticAssert(loc, exp, msg); + } + + TypeQualified parseTypeof() + { + TypeQualified t; + Loc loc = this.loc; + + nextToken(); + check(TOK.TOKlparen); + if (token.value == TOK.TOKreturn) // typeof(return) + { + nextToken(); + t = new TypeReturn(loc); + } + else + { + Expression exp = parseExpression(); // typeof(expression) + t = new TypeTypeof(loc, exp); + } + check(TOK.TOKrparen); + return t; + } + + /*********************************** + * Parse extern (linkage) + * The parser is on the 'extern' token. + */ + LINK parseLinkage() + { + LINK link = LINK.LINKdefault; + nextToken(); + assert(token.value == TOK.TOKlparen); + nextToken(); + if (token.value == TOK.TOKidentifier) + { + Identifier id = token.ident; + + nextToken(); + if (id == Id.Windows) + link = LINK.LINKwindows; + else if (id == Id.Pascal) + link = LINK.LINKpascal; + else if (id == Id.D) + link = LINK.LINKd; + else if (id == Id.C) + { + link = LINK.LINKc; + if (token.value == TOK.TOKplusplus) + { + link = LINK.LINKcpp; + nextToken(); + } + } + else if (id == Id.System) + { +version (_WIN32) { + link = LINK.LINKwindows; +} else { + link = LINK.LINKc; +} + } + else + { + error("valid linkage identifiers are D, C, C++, Pascal, Windows, System"); + link = LINK.LINKd; + } + } + else + { + link = LINK.LINKd; // default + } + check(TOK.TOKrparen); + + return link; + } + + + /************************************** + * Parse a debug conditional + */ + Condition parseDebugCondition() + { + Condition c; + + if (token.value == TOK.TOKlparen) + { + nextToken(); + uint level = 1; + Identifier id = null; + + if (token.value == TOK.TOKidentifier) + id = token.ident; + else if (token.value == TOK.TOKint32v) + level = cast(uint)token.uns64value; + else + error("identifier or integer expected, not %s", token.toChars()); + + nextToken(); + check(TOK.TOKrparen); + + c = new DebugCondition(mod, level, id); + } + else + c = new DebugCondition(mod, 1, null); + + return c; + } + + /************************************** + * Parse a version conditional + */ + Condition parseVersionCondition() + { + Condition c; + uint level = 1; + Identifier id = null; + + if (token.value == TOK.TOKlparen) + { + nextToken(); + if (token.value == TOK.TOKidentifier) + id = token.ident; + else if (token.value == TOK.TOKint32v) + level = cast(uint)token.uns64value; + else { +version (DMDV2) { + /* Allow: + * version (unittest) + * even though unittest is a keyword + */ + if (token.value == TOK.TOKunittest) + id = Lexer.idPool(Token.toChars(TOK.TOKunittest)); + else + error("identifier or integer expected, not %s", token.toChars()); + } else { + error("identifier or integer expected, not %s", token.toChars()); +} + } + nextToken(); + check(TOK.TOKrparen); + } + else + error("(condition) expected following version"); + + c = new VersionCondition(mod, level, id); + + return c; + } + + /*********************************************** + * static if (expression) + * body + * else + * body + */ + Condition parseStaticIfCondition() + { + Expression exp; + Condition condition; + Array aif; + Array aelse; + Loc loc = this.loc; + + nextToken(); + if (token.value == TOKlparen) + { + nextToken(); + exp = parseAssignExp(); + check(TOKrparen); + } + else + { + error("(expression) expected following static if"); + exp = null; + } + condition = new StaticIfCondition(loc, exp); + return condition; + } + + /***************************************** + * Parse a constructor definition: + * this(parameters) { body } + * or postblit: + * this(this) { body } + * or constructor template: + * this(templateparameters)(parameters) { body } + * Current token is 'this'. + */ + + Dsymbol parseCtor() + { + Loc loc = this.loc; + + nextToken(); + if (token.value == TOK.TOKlparen && peek(&token).value == TOK.TOKthis) + { // this(this) { ... } + nextToken(); + nextToken(); + check(TOK.TOKrparen); + PostBlitDeclaration f = new PostBlitDeclaration(loc, Loc(0)); + parseContracts(f); + return f; + } + + /* Look ahead to see if: + * this(...)(...) + * which is a constructor template + */ + TemplateParameters tpl = null; + if (token.value == TOK.TOKlparen && peekPastParen(&token).value == TOK.TOKlparen) + { tpl = parseTemplateParameterList(); + + int varargs; + Arguments arguments = parseParameters(&varargs); + + Expression constraint = null; + if (tpl) + constraint = parseConstraint(); + + CtorDeclaration f = new CtorDeclaration(loc, Loc(0), arguments, varargs); + parseContracts(f); + + // Wrap a template around it + Array decldefs = new Array(); + decldefs.push(cast(void*)f); + TemplateDeclaration tempdecl = + new TemplateDeclaration(loc, f.ident, tpl, constraint, decldefs); + return tempdecl; + } + + /* Just a regular constructor + */ + int varargs; + Arguments arguments = parseParameters(&varargs); + CtorDeclaration f = new CtorDeclaration(loc, Loc(0), arguments, varargs); + parseContracts(f); + return f; + } + + PostBlitDeclaration parsePostBlit() + { + assert(false); + } + + /***************************************** + * Parse a destructor definition: + * ~this() { body } + * Current token is '~'. + */ + DtorDeclaration parseDtor() + { + DtorDeclaration f; + Loc loc = this.loc; + + nextToken(); + check(TOKthis); + check(TOKlparen); + check(TOKrparen); + + f = new DtorDeclaration(loc, Loc(0)); + parseContracts(f); + return f; + } + + /***************************************** + * Parse a static constructor definition: + * static this() { body } + * Current token is 'this'. + */ + StaticCtorDeclaration parseStaticCtor() + { + StaticCtorDeclaration f; + Loc loc = this.loc; + + nextToken(); + check(TOKlparen); + check(TOKrparen); + + f = new StaticCtorDeclaration(loc, Loc(0)); + parseContracts(f); + return f; + } + + /***************************************** + * Parse a static destructor definition: + * static ~this() { body } + * Current token is '~'. + */ + StaticDtorDeclaration parseStaticDtor() + { + StaticDtorDeclaration f; + Loc loc = this.loc; + + nextToken(); + check(TOKthis); + check(TOKlparen); + check(TOKrparen); + + f = new StaticDtorDeclaration(loc, Loc(0)); + parseContracts(f); + return f; + } + + /***************************************** + * Parse an invariant definition: + * invariant() { body } + * Current token is 'invariant'. + */ + InvariantDeclaration parseInvariant() + { + InvariantDeclaration f; + Loc loc = this.loc; + + nextToken(); + if (token.value == TOKlparen) // optional () + { + nextToken(); + check(TOKrparen); + } + + f = new InvariantDeclaration(loc, Loc(0)); + f.fbody = parseStatement(ParseStatementFlags.PScurly); + return f; + } + + /***************************************** + * Parse a unittest definition: + * unittest { body } + * Current token is 'unittest'. + */ + UnitTestDeclaration parseUnitTest() + { + Loc loc = this.loc; + + nextToken(); + + UnitTestDeclaration f = new UnitTestDeclaration(loc, this.loc); + f.fbody = parseStatement(ParseStatementFlags.PScurly); + + return f; + } + + NewDeclaration parseNew() + { + assert(false); + } + + DeleteDeclaration parseDelete() + { + assert(false); + } + + Arguments parseParameters(int* pvarargs) + { + Arguments arguments = new Arguments(); + int varargs = 0; + int hasdefault = 0; + + check(TOK.TOKlparen); + while (1) + { Type *tb; + Identifier ai = null; + Type at; + Argument a; + STC storageClass = STC.STCundefined; + STC stc; + Expression ae; + + for ( ;1; nextToken()) + { + switch (token.value) + { + case TOK.TOKrparen: + break; + + case TOK.TOKdotdotdot: + varargs = 1; + nextToken(); + break; + + case TOK.TOKconst: + if (peek(&token).value == TOK.TOKlparen) + goto Ldefault; + stc = STC.STCconst; + goto L2; + + case TOK.TOKinvariant: + case TOK.TOKimmutable: + if (peek(&token).value == TOK.TOKlparen) + goto Ldefault; + stc = STC.STCimmutable; + goto L2; + + case TOK.TOKshared: + if (peek(&token).value == TOK.TOKlparen) + goto Ldefault; + stc = STC.STCshared; + goto L2; + + case TOK.TOKin: stc = STC.STCin; goto L2; + case TOK.TOKout: stc = STC.STCout; goto L2; + case TOK.TOKinout: + case TOK.TOKref: stc = STC.STCref; goto L2; + case TOK.TOKlazy: stc = STC.STClazy; goto L2; + case TOK.TOKscope: stc = STC.STCscope; goto L2; + case TOK.TOKfinal: stc = STC.STCfinal; goto L2; + L2: + if (storageClass & stc || + (storageClass & STC.STCin && stc & (STC.STCconst | STC.STCscope)) || + (stc & STC.STCin && storageClass & (STC.STCconst | STC.STCscope)) + ) + error("redundant storage class %s", Token.toChars(token.value)); + storageClass |= stc; + composeStorageClass(storageClass); + continue; + +static if (false) { + case TOK.TOKstatic: stc = STC.STCstatic; goto L2; + case TOK.TOKauto: storageClass = STC.STCauto; goto L4; + case TOK.TOKalias: storageClass = STC.STCalias; goto L4; + L4: + nextToken(); + if (token.value == TOK.TOKidentifier) + { ai = token.ident; + nextToken(); + } + else + ai = null; + at = null; // no type + ae = null; // no default argument + if (token.value == TOK.TOKassign) // = defaultArg + { nextToken(); + ae = parseDefaultInitExp(); + hasdefault = 1; + } + else + { if (hasdefault) + error("default argument expected for alias %s", + ai ? ai.toChars() : ""); + } + goto L3; +} + + default: + Ldefault: + stc = (storageClass & (STC.STCin | STC.STCout | STC.STCref | STC.STClazy)); + if (stc & (stc - 1)) // if stc is not a power of 2 + error("incompatible parameter storage classes"); + if ((storageClass & (STC.STCconst | STC.STCout)) == (STC.STCconst | STC.STCout)) + error("out cannot be const"); + if ((storageClass & (STC.STCimmutable | STC.STCout)) == (STC.STCimmutable | STC.STCout)) + error("out cannot be immutable"); + if ((storageClass & STC.STCscope) && + (storageClass & (STC.STCref | STC.STCout))) + error("scope cannot be ref or out"); + at = parseType(&ai); + ae = null; + if (token.value == TOK.TOKassign) // = defaultArg + { nextToken(); + ae = parseDefaultInitExp(); + hasdefault = 1; + } + else + { if (hasdefault) + error("default argument expected for %s", + ai ? ai.toChars() : at.toChars()); + } + if (token.value == TOK.TOKdotdotdot) + { /* This is: + * at ai ... + */ + + if (storageClass & (STC.STCout | STC.STCref)) + error("variadic argument cannot be out or ref"); + varargs = 2; + a = new Argument(storageClass, at, ai, ae); + arguments.push(cast(void*)a); + nextToken(); + break; + } + L3: + a = new Argument(storageClass, at, ai, ae); + arguments.push(cast(void*)a); + if (token.value == TOK.TOKcomma) + { nextToken(); + goto L1; + } + break; + } + break; + } + break; + + L1: ; + } + check(TOK.TOKrparen); + *pvarargs = varargs; + return arguments; + } + + EnumDeclaration parseEnum() + { + EnumDeclaration e; + Identifier id; + Type memtype; + Loc loc = this.loc; + + //printf("Parser.parseEnum()\n"); + nextToken(); + if (token.value == TOK.TOKidentifier) + { + id = token.ident; + nextToken(); + } + else + id = null; + + if (token.value == TOK.TOKcolon) + { + nextToken(); + memtype = parseBasicType(); + memtype = parseDeclarator(memtype, null, null); + } + else + memtype = null; + + e = new EnumDeclaration(loc, id, memtype); + if (token.value == TOK.TOKsemicolon && id) + nextToken(); + else if (token.value == TOK.TOKlcurly) + { + //printf("enum definition\n"); + e.members = new Array(); + nextToken(); + ubyte* comment = token.blockComment; + while (token.value != TOK.TOKrcurly) + { + /* Can take the following forms: + * 1. ident + * 2. ident = value + * 3. type ident = value + */ + + loc = this.loc; + + Type type = null; + Identifier ident; + Token* tp = peek(&token); + if (token.value == TOK.TOKidentifier && + (tp.value == TOK.TOKassign || tp.value == TOK.TOKcomma || tp.value == TOK.TOKrcurly)) + { + ident = token.ident; + type = null; + nextToken(); + } + else + { + type = parseType(&ident, null); + if (id || memtype) + error("type only allowed if anonymous enum and no enum type"); + } + + Expression value; + if (token.value == TOK.TOKassign) + { + nextToken(); + value = parseAssignExp(); + } + else + { + value = null; + if (type) + error("if type, there must be an initializer"); + } + + EnumMember em = new EnumMember(loc, ident, value, type); + e.members.push(cast(void*)em); + + if (token.value == TOK.TOKrcurly) { + ; + } else { + addComment(em, comment); + comment = null; + check(TOK.TOKcomma); + } + addComment(em, comment); + comment = token.blockComment; + } + nextToken(); + } + else + error("enum declaration is invalid"); + + //printf("-parseEnum() %s\n", e.toChars()); + return e; + } + + Dsymbol parseAggregate() + { + AggregateDeclaration a = null; + int anon = 0; + TOK tok; + Identifier id; + TemplateParameters tpl = null; + Expression constraint = null; + + //printf("Parser.parseAggregate()\n"); + tok = token.value; + nextToken(); + if (token.value != TOK.TOKidentifier) + { + id = null; + } + else + { + id = token.ident; + nextToken(); + + if (token.value == TOK.TOKlparen) + { + // Class template declaration. + + // Gather template parameter list + tpl = parseTemplateParameterList(); + constraint = parseConstraint(); + } + } + + Loc loc = this.loc; + switch (tok) + { case TOK.TOKclass: + case TOK.TOKinterface: + { + if (!id) + error("anonymous classes not allowed"); + + // Collect base class(es) + BaseClasses baseclasses = null; + if (token.value == TOK.TOKcolon) + { + nextToken(); + baseclasses = parseBaseClasses(); + + if (token.value != TOK.TOKlcurly) + error("members expected"); + } + + if (tok == TOK.TOKclass) + a = new ClassDeclaration(loc, id, baseclasses); + else + a = new InterfaceDeclaration(loc, id, baseclasses); + break; + } + + case TOK.TOKstruct: + if (id) + a = new StructDeclaration(loc, id); + else + anon = 1; + break; + + case TOK.TOKunion: + if (id) + a = new UnionDeclaration(loc, id); + else + anon = 2; + break; + + default: + assert(0); + break; + } + if (a && token.value == TOK.TOKsemicolon) + { nextToken(); + } + else if (token.value == TOK.TOKlcurly) + { + //printf("aggregate definition\n"); + nextToken(); + Array decl = parseDeclDefs(0); + if (token.value != TOK.TOKrcurly) + error("} expected following member declarations in aggregate"); + nextToken(); + if (anon) + { + /* Anonymous structs/unions are more like attributes. + */ + return new AnonDeclaration(loc, anon - 1, decl); + } + else + a.members = decl; + } + else + { + error("{ } expected following aggregate declaration"); + a = new StructDeclaration(loc, null); + } + + if (tpl) + { // Wrap a template around the aggregate declaration + + Array decldefs = new Array(); + decldefs.push(cast(void*)a); + TemplateDeclaration tempdecl = + new TemplateDeclaration(loc, id, tpl, constraint, decldefs); + return tempdecl; + } + + return a; + } + + BaseClasses parseBaseClasses() + { + BaseClasses baseclasses = new BaseClasses(); + + for (; 1; nextToken()) + { + PROT protection = PROT.PROTpublic; + switch (token.value) + { + case TOK.TOKprivate: + protection = PROT.PROTprivate; + nextToken(); + break; + case TOK.TOKpackage: + protection = PROT.PROTpackage; + nextToken(); + break; + case TOK.TOKprotected: + protection = PROT.PROTprotected; + nextToken(); + break; + case TOK.TOKpublic: + protection = PROT.PROTpublic; + nextToken(); + break; + default: + break; /// + } + if (token.value == TOK.TOKidentifier) + { + BaseClass b = new BaseClass(parseBasicType(), protection); + baseclasses.push(cast(void*)b); + if (token.value != TOK.TOKcomma) + break; + } + else + { + error("base classes expected instead of %s", token.toChars()); + return null; + } + } + return baseclasses; + } + + Import parseImport(Array decldefs, int isstatic) + { + Import s; + Identifier id; + Identifier aliasid = null; + Array a; + Loc loc; + + //printf("Parser.parseImport()\n"); + do + { + L1: + nextToken(); + if (token.value != TOK.TOKidentifier) + { + error("Identifier expected following import"); + break; + } + + loc = this.loc; + a = null; + id = token.ident; + nextToken(); + if (!aliasid && token.value == TOK.TOKassign) + { + aliasid = id; + goto L1; + } + while (token.value == TOK.TOKdot) + { + if (!a) + a = new Array(); + a.push(cast(void*)id); + nextToken(); + if (token.value != TOK.TOKidentifier) + { + error("identifier expected following package"); + break; + } + id = token.ident; + nextToken(); + } + + s = new Import(loc, a, id, aliasid, isstatic); + decldefs.push(cast(void*)s); + + /* Look for + * : alias=name, alias=name; + * syntax. + */ + if (token.value == TOK.TOKcolon) + { + do + { + Identifier name; + + nextToken(); + if (token.value != TOK.TOKidentifier) + { + error("Identifier expected following :"); + break; + } + Identifier alias_ = token.ident; + nextToken(); + if (token.value == TOK.TOKassign) + { + nextToken(); + if (token.value != TOK.TOKidentifier) + { + error("Identifier expected following %s=", alias_.toChars()); + break; + } + name = token.ident; + nextToken(); + } + else + { + name = alias_; + alias_ = null; + } + s.addAlias(name, alias_); + } while (token.value == TOK.TOKcomma); + + break; // no comma-separated imports of this form + } + + aliasid = null; + + } while (token.value == TOK.TOKcomma); + + if (token.value == TOK.TOKsemicolon) + nextToken(); + else + { + error("';' expected"); + nextToken(); + } + + return null; + } + + Type parseType(Identifier* pident = null, TemplateParameters* tpl = null) + { + Type t; + + /* Take care of the storage class prefixes that + * serve as type attributes: + * const shared, shared const, const, invariant, shared + */ + if (token.value == TOK.TOKconst && peekNext() == TOK.TOKshared && peekNext2() != TOK.TOKlparen || + token.value == TOK.TOKshared && peekNext() == TOK.TOKconst && peekNext2() != TOK.TOKlparen) + { + nextToken(); + nextToken(); + /* shared const type + */ + t = parseType(pident, tpl); + t = t.makeSharedConst(); + return t; + } + else if (token.value == TOK.TOKconst && peekNext() != TOK.TOKlparen) + { + nextToken(); + /* const type + */ + t = parseType(pident, tpl); + t = t.makeConst(); + return t; + } + else if ((token.value == TOK.TOKinvariant || token.value == TOK.TOKimmutable) && + peekNext() != TOK.TOKlparen) + { + nextToken(); + /* invariant type + */ + t = parseType(pident, tpl); + t = t.makeInvariant(); + return t; + } + else if (token.value == TOK.TOKshared && peekNext() != TOK.TOKlparen) + { + nextToken(); + /* shared type + */ + t = parseType(pident, tpl); + t = t.makeShared(); + return t; + } + else + t = parseBasicType(); + t = parseDeclarator(t, pident, tpl); + return t; + } + + Type parseBasicType() + { + Type t; + Identifier id; + TypeQualified tid; + + //printf("parseBasicType()\n"); + switch (token.value) + { + case TOK.TOKvoid: t = Type.tvoid; goto LabelX; + case TOK.TOKint8: t = Type.tint8; goto LabelX; + case TOK.TOKuns8: t = Type.tuns8; goto LabelX; + case TOK.TOKint16: t = Type.tint16; goto LabelX; + case TOK.TOKuns16: t = Type.tuns16; goto LabelX; + case TOK.TOKint32: t = Type.tint32; goto LabelX; + case TOK.TOKuns32: t = Type.tuns32; goto LabelX; + case TOK.TOKint64: t = Type.tint64; goto LabelX; + case TOK.TOKuns64: t = Type.tuns64; goto LabelX; + case TOK.TOKfloat32: t = Type.tfloat32; goto LabelX; + case TOK.TOKfloat64: t = Type.tfloat64; goto LabelX; + case TOK.TOKfloat80: t = Type.tfloat80; goto LabelX; + case TOK.TOKimaginary32: t = Type.timaginary32; goto LabelX; + case TOK.TOKimaginary64: t = Type.timaginary64; goto LabelX; + case TOK.TOKimaginary80: t = Type.timaginary80; goto LabelX; + case TOK.TOKcomplex32: t = Type.tcomplex32; goto LabelX; + case TOK.TOKcomplex64: t = Type.tcomplex64; goto LabelX; + case TOK.TOKcomplex80: t = Type.tcomplex80; goto LabelX; + case TOK.TOKbit: t = Type.tbit; goto LabelX; + case TOK.TOKbool: t = Type.tbool; goto LabelX; + case TOK.TOKchar: t = Type.tchar; goto LabelX; + case TOK.TOKwchar: t = Type.twchar; goto LabelX; + case TOK.TOKdchar: t = Type.tdchar; goto LabelX; + LabelX: + nextToken(); + break; + + case TOK.TOKidentifier: + id = token.ident; + nextToken(); + if (token.value == TOK.TOKnot) + { // ident!(template_arguments) + TemplateInstance tempinst = new TemplateInstance(loc, id); + nextToken(); + if (token.value == TOK.TOKlparen) + // ident!(template_arguments) + tempinst.tiargs = parseTemplateArgumentList(); + else + // ident!template_argument + tempinst.tiargs = parseTemplateArgument(); + tid = new TypeInstance(loc, tempinst); + goto Lident2; + } + Lident: + tid = new TypeIdentifier(loc, id); + Lident2: + while (token.value == TOK.TOKdot) + { nextToken(); + if (token.value != TOK.TOKidentifier) + { error("identifier expected following '.' instead of '%s'", token.toChars()); + break; + } + id = token.ident; + nextToken(); + if (token.value == TOK.TOKnot) + { + TemplateInstance tempinst = new TemplateInstance(loc, id); + nextToken(); + if (token.value == TOK.TOKlparen) + // ident!(template_arguments) + tempinst.tiargs = parseTemplateArgumentList(); + else + // ident!template_argument + tempinst.tiargs = parseTemplateArgument(); + tid.addIdent(cast(Identifier)tempinst); + } + else + tid.addIdent(id); + } + t = tid; + break; + + case TOK.TOKdot: + // Leading . as in .foo + id = Id.empty; + goto Lident; + + case TOK.TOKtypeof: + // typeof(expression) + tid = parseTypeof(); + goto Lident2; + + case TOK.TOKconst: + // const(type) + nextToken(); + check(TOK.TOKlparen); + t = parseType(); + check(TOK.TOKrparen); + if (t.isShared()) + t = t.makeSharedConst(); + else + t = t.makeConst(); + break; + + case TOK.TOKinvariant: + case TOK.TOKimmutable: + // invariant(type) + nextToken(); + check(TOK.TOKlparen); + t = parseType(); + check(TOK.TOKrparen); + t = t.makeInvariant(); + break; + + case TOK.TOKshared: + // shared(type) + nextToken(); + check(TOK.TOKlparen); + t = parseType(); + check(TOK.TOKrparen); + if (t.isConst()) + t = t.makeSharedConst(); + else + t = t.makeShared(); + break; + + default: + error("basic type expected, not %s", token.toChars()); + t = Type.tint32; + break; + } + return t; + } + + Type parseBasicType2(Type t) + { + //printf("parseBasicType2()\n"); + while (1) + { + switch (token.value) + { + case TOK.TOKmul: + t = new TypePointer(t); + nextToken(); + continue; + + case TOK.TOKlbracket: + // Handle []. Make sure things like + // int[3][1] a; + // is (array[1] of array[3] of int) + nextToken(); + if (token.value == TOK.TOKrbracket) + { + t = new TypeDArray(t); // [] + nextToken(); + } + else if (isDeclaration(&token, 0, TOK.TOKrbracket, null)) + { // It's an associative array declaration + + //printf("it's an associative array\n"); + Type index = parseType(); // [ type ] + t = new TypeAArray(t, index); + check(TOK.TOKrbracket); + } + else + { + //printf("it's type[expression]\n"); + inBrackets++; + Expression e = parseExpression(); // [ expression ] + if (token.value == TOK.TOKslice) + { + nextToken(); + Expression e2 = parseExpression(); // [ exp .. exp ] + t = new TypeSlice(t, e, e2); + } + else + t = new TypeSArray(t,e); + inBrackets--; + check(TOK.TOKrbracket); + } + continue; + + case TOK.TOKdelegate: + case TOK.TOKfunction: + { // Handle delegate declaration: + // t delegate(parameter list) nothrow pure + // t function(parameter list) nothrow pure + Arguments arguments; + int varargs; + bool ispure = false; + bool isnothrow = false; + TOK save = token.value; + + nextToken(); + arguments = parseParameters(&varargs); + while (1) + { // Postfixes + if (token.value == TOK.TOKpure) + ispure = true; + else if (token.value == TOK.TOKnothrow) + isnothrow = true; + else + break; + nextToken(); + } + TypeFunction tf = new TypeFunction(arguments, t, varargs, linkage); + tf.ispure = ispure; + tf.isnothrow = isnothrow; + if (save == TOK.TOKdelegate) + t = new TypeDelegate(tf); + else + t = new TypePointer(tf); // pointer to function + continue; + } + + default: + return t; + } + assert(0); + } + assert(0); + return null; + } + + Type parseDeclarator(Type t, Identifier* pident, TemplateParameters* tpl = null) + { + Type ts; + + //printf("parseDeclarator(tpl = %p)\n", tpl); + t = parseBasicType2(t); + + switch (token.value) + { + + case TOK.TOKidentifier: + if (pident) + *pident = token.ident; + else + error("unexpected identifer '%s' in declarator", token.ident.toChars()); + ts = t; + nextToken(); + break; + + case TOK.TOKlparen: + /* Parse things with parentheses around the identifier, like: + * int (*ident[3])[] + * although the D style would be: + * int[]*[3] ident + */ + nextToken(); + ts = parseDeclarator(t, pident); + check(TOK.TOKrparen); + break; + + default: + ts = t; + break; + } + + // parse DeclaratorSuffixes + while (1) + { + switch (token.value) + { +version (CARRAYDECL) { + /* Support C style array syntax: + * int ident[] + * as opposed to D-style: + * int[] ident + */ + case TOK.TOKlbracket: + { // This is the old C-style post [] syntax. + TypeNext ta; + nextToken(); + if (token.value == TOK.TOKrbracket) + { // It's a dynamic array + ta = new TypeDArray(t); // [] + nextToken(); + } + else if (isDeclaration(&token, 0, TOK.TOKrbracket, null)) + { // It's an associative array + + //printf("it's an associative array\n"); + Type index = parseType(); // [ type ] + check(TOK.TOKrbracket); + ta = new TypeAArray(t, index); + } + else + { + //printf("It's a static array\n"); + Expression e = parseExpression(); // [ expression ] + ta = new TypeSArray(t, e); + check(TOK.TOKrbracket); + } + + /* Insert ta into + * ts . ... . t + * so that + * ts . ... . ta . t + */ + Type* pt; + for (pt = &ts; *pt !is t; pt = &(cast(TypeNext)*pt).next) { + ; + } + *pt = ta; + continue; + } +} + case TOK.TOKlparen: + { + if (tpl) + { + /* Look ahead to see if this is (...)(...), + * i.e. a function template declaration + */ + if (peekPastParen(&token).value == TOK.TOKlparen) + { + //printf("function template declaration\n"); + + // Gather template parameter list + *tpl = parseTemplateParameterList(); + } + } + + int varargs; + Arguments arguments = parseParameters(&varargs); + Type tf = new TypeFunction(arguments, t, varargs, linkage); + + /* Parse const/invariant/nothrow/pure postfix + */ + while (1) + { + switch (token.value) + { + case TOK.TOKconst: + if (tf.isShared()) + tf = tf.makeSharedConst(); + else + tf = tf.makeConst(); + nextToken(); + continue; + + case TOK.TOKinvariant: + case TOK.TOKimmutable: + tf = tf.makeInvariant(); + nextToken(); + continue; + + case TOK.TOKshared: + if (tf.isConst()) + tf = tf.makeSharedConst(); + else + tf = tf.makeShared(); + nextToken(); + continue; + + case TOK.TOKnothrow: + (cast(TypeFunction)tf).isnothrow = 1; + nextToken(); + continue; + + case TOK.TOKpure: + (cast(TypeFunction)tf).ispure = 1; + nextToken(); + continue; + + case TOK.TOKat: + nextToken(); + if (token.value != TOK.TOKidentifier) + { error("attribute identifier expected"); + nextToken(); + continue; + } + Identifier id = token.ident; + if (id is Id.property) + (cast(TypeFunction)tf).ispure = 1; + else + error("valid attribute identifiers are property, not %s", id.toChars()); + nextToken(); + continue; + default: + break; /// + } + break; + } + + /* Insert tf into + * ts . ... . t + * so that + * ts . ... . tf . t + */ + Type* pt; + for (pt = &ts; *pt !is t; pt = &(cast(TypeNext)*pt).next) { + ; + } + *pt = tf; + break; + } + + default: + break; /// + } + break; + } + + return ts; + } + + Array parseDeclarations(STC storage_class) + { + STC stc; + Type ts; + Type t; + Type tfirst; + Identifier ident; + Array a; + TOK tok = TOK.TOKreserved; + ubyte* comment = token.blockComment; + LINK link = linkage; + + //printf("parseDeclarations() %s\n", token.toChars()); + if (storage_class) + { ts = null; // infer type + goto L2; + } + + switch (token.value) + { + case TOK.TOKalias: + /* Look for: + * alias identifier this; + */ + tok = token.value; + nextToken(); + if (token.value == TOK.TOKidentifier && peek(&token).value == TOK.TOKthis) + { + AliasThis s = new AliasThis(this.loc, token.ident); + nextToken(); + check(TOK.TOKthis); + check(TOK.TOKsemicolon); + a = new Array(); + a.push(cast(void*)s); + addComment(s, comment); + return a; + } + break; + case TOK.TOKtypedef: + tok = token.value; + nextToken(); + break; + default: + break; + } + + storage_class = STC.STCundefined; + while (1) + { + switch (token.value) + { + case TOK.TOKconst: + if (peek(&token).value == TOK.TOKlparen) + break; // const as type constructor + stc = STC.STCconst; // const as storage class + goto L1; + + case TOK.TOKinvariant: + case TOK.TOKimmutable: + if (peek(&token).value == TOK.TOKlparen) + break; + stc = STC.STCimmutable; + goto L1; + + case TOK.TOKshared: + if (peek(&token).value == TOK.TOKlparen) + break; + stc = STC.STCshared; + goto L1; + + case TOK.TOKstatic: stc = STC.STCstatic; goto L1; + case TOK.TOKfinal: stc = STC.STCfinal; goto L1; + case TOK.TOKauto: stc = STC.STCauto; goto L1; + case TOK.TOKscope: stc = STC.STCscope; goto L1; + case TOK.TOKoverride: stc = STC.STCoverride; goto L1; + case TOK.TOKabstract: stc = STC.STCabstract; goto L1; + case TOK.TOKsynchronized: stc = STC.STCsynchronized; goto L1; + case TOK.TOKdeprecated: stc = STC.STCdeprecated; goto L1; +version (DMDV2) { + case TOK.TOKnothrow: stc = STC.STCnothrow; goto L1; + case TOK.TOKpure: stc = STC.STCpure; goto L1; + case TOK.TOKref: stc = STC.STCref; goto L1; + case TOK.TOKtls: stc = STC.STCtls; goto L1; + case TOK.TOKgshared: stc = STC.STCgshared; goto L1; + case TOK.TOKenum: stc = STC.STCmanifest; goto L1; +} + L1: + if (storage_class & stc) + error("redundant storage class '%s'", token.toChars()); + storage_class = (storage_class | stc); + composeStorageClass(storage_class); + nextToken(); + continue; + + case TOK.TOKextern: + if (peek(&token).value != TOK.TOKlparen) + { stc = STC.STCextern; + goto L1; + } + + link = parseLinkage(); + continue; + + default: + break; + } + break; + } + + /* Look for auto initializers: + * storage_class identifier = initializer; + */ + if (storage_class && + token.value == TOK.TOKidentifier && + peek(&token).value == TOK.TOKassign) + { + return parseAutoDeclarations(storage_class, comment); + } + + if (token.value == TOK.TOKclass) + { + AggregateDeclaration s = cast(AggregateDeclaration)parseAggregate(); + s.storage_class |= storage_class; + a = new Array(); + a.push(cast(void*)s); + addComment(s, comment); + return a; + } + + /* Look for return type inference for template functions. + */ + { + Token *tk; + if (storage_class && + token.value == TOK.TOKidentifier && + (tk = peek(&token)).value == TOK.TOKlparen && + skipParens(tk, &tk) && + peek(tk).value == TOK.TOKlparen) + { + ts = null; + } + else + { + ts = parseBasicType(); + ts = parseBasicType2(ts); + } + } + + L2: + tfirst = null; + a = new Array(); + + while (1) + { + Loc loc = this.loc; + TemplateParameters tpl = null; + + ident = null; + t = parseDeclarator(ts, &ident, &tpl); + assert(t); + if (!tfirst) + tfirst = t; + else if (t != tfirst) + error("multiple declarations must have the same type, not %s and %s", + tfirst.toChars(), t.toChars()); + if (!ident) + error("no identifier for declarator %s", t.toChars()); + + if (tok == TOK.TOKtypedef || tok == TOK.TOKalias) + { Declaration v; + Initializer init = null; + + if (token.value == TOK.TOKassign) + { + nextToken(); + init = parseInitializer(); + } + if (tok == TOK.TOKtypedef) + v = new TypedefDeclaration(loc, ident, t, init); + else + { if (init) + error("alias cannot have initializer"); + v = new AliasDeclaration(loc, ident, t); + } + v.storage_class = storage_class; + if (link == linkage) + a.push(cast(void*)v); + else + { + Array ax = new Array(); + ax.push(cast(void*)v); + Dsymbol s = new LinkDeclaration(link, ax); + a.push(cast(void*)s); + } + switch (token.value) + { case TOK.TOKsemicolon: + nextToken(); + addComment(v, comment); + break; + + case TOK.TOKcomma: + nextToken(); + addComment(v, comment); + continue; + + default: + error("semicolon expected to close %s declaration", Token.toChars(tok)); + break; + } + } + else if (t.ty == TY.Tfunction) + { + TypeFunction tf = cast(TypeFunction)t; + Expression constraint = null; +static if (false) { + if (Argument.isTPL(tf.parameters)) + { + if (!tpl) + tpl = new TemplateParameters(); + } +} + FuncDeclaration f = + new FuncDeclaration(loc, Loc(0), ident, storage_class, t); + addComment(f, comment); + if (tpl) + constraint = parseConstraint(); + parseContracts(f); + addComment(f, null); + Dsymbol s; + if (link == linkage) + { + s = f; + } + else + { + Array ax = new Array(); + ax.push(cast(void*)f); + s = new LinkDeclaration(link, ax); + } + /* A template parameter list means it's a function template + */ + if (tpl) + { + // Wrap a template around the function declaration + Array decldefs = new Array(); + decldefs.push(cast(void*)s); + TemplateDeclaration tempdecl = + new TemplateDeclaration(loc, s.ident, tpl, constraint, decldefs); + s = tempdecl; + } + addComment(s, comment); + a.push(cast(void*)s); + } + else + { + Initializer init = null; + if (token.value == TOK.TOKassign) + { + nextToken(); + init = parseInitializer(); + } + + VarDeclaration v = new VarDeclaration(loc, t, ident, init); + v.storage_class = storage_class; + if (link == linkage) + a.push(cast(void*)v); + else + { + Array ax = new Array(); + ax.push(cast(void*)v); + Dsymbol s = new LinkDeclaration(link, ax); + a.push(cast(void*)s); + } + switch (token.value) + { case TOK.TOKsemicolon: + nextToken(); + addComment(v, comment); + break; + + case TOK.TOKcomma: + nextToken(); + addComment(v, comment); + continue; + + default: + error("semicolon expected, not '%s'", token.toChars()); + break; + } + } + break; + } + return a; + } + + void parseContracts(FuncDeclaration f) + { + Type tb; + LINK linksave = linkage; + + // The following is irrelevant, as it is overridden by sc.linkage in + // TypeFunction.semantic + linkage = LINK.LINKd; // nested functions have D linkage + L1: + switch (token.value) + { + case TOK.TOKlcurly: + if (f.frequire || f.fensure) + error("missing body { ... } after in or out"); + f.fbody = parseStatement(ParseStatementFlags.PSsemi); + f.endloc = endloc; + break; + + case TOK.TOKbody: + nextToken(); + f.fbody = parseStatement(ParseStatementFlags.PScurly); + f.endloc = endloc; + break; + + case TOK.TOKsemicolon: + if (f.frequire || f.fensure) + error("missing body { ... } after in or out"); + nextToken(); + break; + +static if (false) { // Do we want this for function declarations, so we can do: + // int x, y, foo(), z; + case TOK.TOKcomma: + nextToken(); + continue; +} + +static if (false) { // Dumped feature + case TOK.TOKthrow: + if (!f.fthrows) + f.fthrows = new Array(); + nextToken(); + check(TOK.TOKlparen); + while (1) + { + tb = parseBasicType(); + f.fthrows.push(tb); + if (token.value == TOK.TOKcomma) + { nextToken(); + continue; + } + break; + } + check(TOK.TOKrparen); + goto L1; +} + + case TOK.TOKin: + nextToken(); + if (f.frequire) + error("redundant 'in' statement"); + f.frequire = parseStatement(ParseStatementFlags.PScurly | ParseStatementFlags.PSscope); + goto L1; + + case TOK.TOKout: + // parse: out (identifier) { statement } + nextToken(); + if (token.value != TOK.TOKlcurly) + { + check(TOK.TOKlparen); + if (token.value != TOK.TOKidentifier) + error("(identifier) following 'out' expected, not %s", token.toChars()); + f.outId = token.ident; + nextToken(); + check(TOK.TOKrparen); + } + if (f.fensure) + error("redundant 'out' statement"); + f.fensure = parseStatement(ParseStatementFlags.PScurly | ParseStatementFlags.PSscope); + goto L1; + + default: + error("semicolon expected following function declaration"); + break; + } + linkage = linksave; + } + + Statement parseStatement(ParseStatementFlags flags) + { + Statement s; + Token* t; + Condition condition; + Statement ifbody; + Statement elsebody; + bool isfinal; + Loc loc = this.loc; + + //printf("parseStatement()\n"); + + if (flags & ParseStatementFlags.PScurly && token.value != TOK.TOKlcurly) + error("statement expected to be { }, not %s", token.toChars()); + + switch (token.value) + { + case TOK.TOKidentifier: + /* A leading identifier can be a declaration, label, or expression. + * The easiest case to check first is label: + */ + t = peek(&token); + if (t.value == TOK.TOKcolon) + { // It's a label + + Identifier ident = token.ident; + nextToken(); + nextToken(); + s = parseStatement(ParseStatementFlags.PSsemi); + s = new LabelStatement(loc, ident, s); + break; + } + // fallthrough to TOK.TOKdot + case TOK.TOKdot: + case TOK.TOKtypeof: + if (isDeclaration(&token, 2, TOK.TOKreserved, null)) + goto Ldeclaration; + else + goto Lexp; + break; + + case TOK.TOKassert: + case TOK.TOKthis: + case TOK.TOKsuper: + case TOK.TOKint32v: + case TOK.TOKuns32v: + case TOK.TOKint64v: + case TOK.TOKuns64v: + case TOK.TOKfloat32v: + case TOK.TOKfloat64v: + case TOK.TOKfloat80v: + case TOK.TOKimaginary32v: + case TOK.TOKimaginary64v: + case TOK.TOKimaginary80v: + case TOK.TOKcharv: + case TOK.TOKwcharv: + case TOK.TOKdcharv: + case TOK.TOKnull: + case TOK.TOKtrue: + case TOK.TOKfalse: + case TOK.TOKstring: + case TOK.TOKlparen: + case TOK.TOKcast: + case TOK.TOKmul: + case TOK.TOKmin: + case TOK.TOKadd: + case TOK.TOKplusplus: + case TOK.TOKminusminus: + case TOK.TOKnew: + case TOK.TOKdelete: + case TOK.TOKdelegate: + case TOK.TOKfunction: + case TOK.TOKtypeid: + case TOK.TOKis: + case TOK.TOKlbracket: +version (DMDV2) { + case TOK.TOKtraits: + case TOK.TOKfile: + case TOK.TOKline: +} + Lexp: + { Expression exp; + + exp = parseExpression(); + check(TOK.TOKsemicolon, "statement"); + s = new ExpStatement(loc, exp); + break; + } + + case TOK.TOKstatic: + { // Look ahead to see if it's static assert() or static if() + Token *tt; + + tt = peek(&token); + if (tt.value == TOK.TOKassert) + { + nextToken(); + s = new StaticAssertStatement(parseStaticAssert()); + break; + } + if (tt.value == TOK.TOKif) + { + nextToken(); + condition = parseStaticIfCondition(); + goto Lcondition; + } + goto Ldeclaration; + } + + case TOK.TOKfinal: + if (peekNext() == TOK.TOKswitch) + { + nextToken(); + isfinal = true; + goto Lswitch; + } + goto Ldeclaration; + + case TOK.TOKwchar: case TOK.TOKdchar: + case TOK.TOKbit: case TOK.TOKbool: case TOK.TOKchar: + case TOK.TOKint8: case TOK.TOKuns8: + case TOK.TOKint16: case TOK.TOKuns16: + case TOK.TOKint32: case TOK.TOKuns32: + case TOK.TOKint64: case TOK.TOKuns64: + case TOK.TOKfloat32: case TOK.TOKfloat64: case TOK.TOKfloat80: + case TOK.TOKimaginary32: case TOK.TOKimaginary64: case TOK.TOKimaginary80: + case TOK.TOKcomplex32: case TOK.TOKcomplex64: case TOK.TOKcomplex80: + case TOK.TOKvoid: + case TOK.TOKtypedef: + case TOK.TOKalias: + case TOK.TOKconst: + case TOK.TOKauto: + case TOK.TOKextern: + case TOK.TOKinvariant: +version (DMDV2) { + case TOK.TOKimmutable: + case TOK.TOKshared: + case TOK.TOKnothrow: + case TOK.TOKpure: + case TOK.TOKtls: + case TOK.TOKgshared: +} + // case TOK.TOKtypeof: + Ldeclaration: + { Array a; + + a = parseDeclarations(STC.STCundefined); + if (a.dim > 1) + { + Statements as = new Statements(); + as.reserve(a.dim); + for (int i = 0; i < a.dim; i++) + { + Dsymbol d = cast(Dsymbol)a.data[i]; + s = new DeclarationStatement(loc, d); + as.push(cast(void*)s); + } + s = new CompoundDeclarationStatement(loc, as); + } + else if (a.dim == 1) + { + Dsymbol d = cast(Dsymbol)a.data[0]; + s = new DeclarationStatement(loc, d); + } + else + assert(0); + if (flags & ParseStatementFlags.PSscope) + s = new ScopeStatement(loc, s); + break; + } + + case TOK.TOKstruct: + case TOK.TOKunion: + case TOK.TOKclass: + case TOK.TOKinterface: + { Dsymbol d; + + d = parseAggregate(); + s = new DeclarationStatement(loc, d); + break; + } + + case TOK.TOKenum: + { /* Determine if this is a manifest constant declaration, + * or a conventional enum. + */ + Dsymbol d; + Token* tt = peek(&token); + if (tt.value == TOK.TOKlcurly || tt.value == TOK.TOKcolon) + d = parseEnum(); + else if (tt.value != TOK.TOKidentifier) + goto Ldeclaration; + else + { + tt = peek(tt); + if (tt.value == TOK.TOKlcurly || tt.value == TOK.TOKcolon || + tt.value == TOK.TOKsemicolon) + d = parseEnum(); + else + goto Ldeclaration; + } + s = new DeclarationStatement(loc, d); + break; + } + + case TOK.TOKmixin: + { t = peek(&token); + if (t.value == TOK.TOKlparen) + { // mixin(string) + nextToken(); + check(TOK.TOKlparen, "mixin"); + Expression e = parseAssignExp(); + check(TOK.TOKrparen); + check(TOK.TOKsemicolon); + s = new CompileStatement(loc, e); + break; + } + Dsymbol d = parseMixin(); + s = new DeclarationStatement(loc, d); + break; + } + + case TOK.TOKlcurly: + { Statements statements; + + nextToken(); + statements = new Statements(); + while (token.value != TOK.TOKrcurly) + { + statements.push(cast(void*)parseStatement(ParseStatementFlags.PSsemi | ParseStatementFlags.PScurlyscope)); + } + endloc = this.loc; + s = new CompoundStatement(loc, statements); + if (flags & (ParseStatementFlags.PSscope | ParseStatementFlags.PScurlyscope)) + s = new ScopeStatement(loc, s); + nextToken(); + break; + } + + case TOK.TOKwhile: + { Expression condition2; + Statement body_; + + nextToken(); + check(TOK.TOKlparen); + condition2 = parseExpression(); + check(TOK.TOKrparen); + body_ = parseStatement(ParseStatementFlags.PSscope); + s = new WhileStatement(loc, condition2, body_); + break; + } + + case TOK.TOKsemicolon: + if (!(flags & ParseStatementFlags.PSsemi)) + error("use '{ }' for an empty statement, not a ';'"); + nextToken(); + s = new ExpStatement(loc, null); + break; + + case TOK.TOKdo: + { Statement body_; + Expression condition2; + + nextToken(); + body_ = parseStatement(ParseStatementFlags.PSscope); + check(TOK.TOKwhile); + check(TOK.TOKlparen); + condition2 = parseExpression(); + check(TOK.TOKrparen); + s = new DoStatement(loc, body_, condition2); + break; + } + + case TOK.TOKfor: + { + Statement init; + Expression condition2; + Expression increment; + Statement body_; + + nextToken(); + check(TOK.TOKlparen); + if (token.value == TOK.TOKsemicolon) + { init = null; + nextToken(); + } + else + { init = parseStatement(cast(ParseStatementFlags)0); + } + if (token.value == TOK.TOKsemicolon) + { + condition2 = null; + nextToken(); + } + else + { + condition2 = parseExpression(); + check(TOK.TOKsemicolon, "for condition"); + } + if (token.value == TOK.TOKrparen) + { increment = null; + nextToken(); + } + else + { increment = parseExpression(); + check(TOK.TOKrparen); + } + body_ = parseStatement(ParseStatementFlags.PSscope); + s = new ForStatement(loc, init, condition2, increment, body_); + if (init) + s = new ScopeStatement(loc, s); + break; + } + + case TOK.TOKforeach: + case TOK.TOKforeach_reverse: + { + TOK op = token.value; + Arguments arguments; + + Statement d; + Statement body_; + Expression aggr; + + nextToken(); + check(TOK.TOKlparen); + + arguments = new Arguments(); + + while (1) + { + Type tb; + Identifier ai = null; + Type at; + STC storageClass = STC.STCundefined; + Argument a; + + if (token.value == TOK.TOKinout || token.value == TOK.TOKref) + { storageClass = STC.STCref; + nextToken(); + } + if (token.value == TOK.TOKidentifier) + { + Token *tt = peek(&token); + if (tt.value == TOK.TOKcomma || tt.value == TOK.TOKsemicolon) + { ai = token.ident; + at = null; // infer argument type + nextToken(); + goto Larg; + } + } + at = parseType(&ai); + if (!ai) + error("no identifier for declarator %s", at.toChars()); + Larg: + a = new Argument(storageClass, at, ai, null); + arguments.push(cast(void*)a); + if (token.value == TOK.TOKcomma) + { nextToken(); + continue; + } + break; + } + check(TOK.TOKsemicolon); + + aggr = parseExpression(); + if (token.value == TOK.TOKslice && arguments.dim == 1) + { + Argument a = cast(Argument)arguments.data[0]; + delete arguments; + nextToken(); + Expression upr = parseExpression(); + check(TOK.TOKrparen); + body_ = parseStatement(cast(ParseStatementFlags)0); + s = new ForeachRangeStatement(loc, op, a, aggr, upr, body_); + } + else + { + check(TOK.TOKrparen); + body_ = parseStatement(cast(ParseStatementFlags)0); + s = new ForeachStatement(loc, op, arguments, aggr, body_); + } + break; + } + + case TOK.TOKif: + { Argument arg = null; + Expression condition2; + Statement ifbody2; + Statement elsebody2; + + nextToken(); + check(TOK.TOKlparen); + + if (token.value == TOK.TOKauto) + { + nextToken(); + if (token.value == TOK.TOKidentifier) + { + Token *tt = peek(&token); + if (tt.value == TOK.TOKassign) + { + arg = new Argument(STC.STCundefined, null, token.ident, null); + nextToken(); + nextToken(); + } + else + { error("= expected following auto identifier"); + goto Lerror; + } + } + else + { error("identifier expected following auto"); + goto Lerror; + } + } + else if (isDeclaration(&token, 2, TOK.TOKassign, null)) + { + Type at; + Identifier ai; + + at = parseType(&ai); + check(TOK.TOKassign); + arg = new Argument(STC.STCundefined, at, ai, null); + } + + // Check for " ident;" + else if (token.value == TOK.TOKidentifier) + { + Token *tt = peek(&token); + if (tt.value == TOK.TOKcomma || tt.value == TOK.TOKsemicolon) + { + arg = new Argument(STC.STCundefined, null, token.ident, null); + nextToken(); + nextToken(); + if (1 || !global.params.useDeprecated) + error("if (v; e) is deprecated, use if (auto v = e)"); + } + } + + condition2 = parseExpression(); + check(TOK.TOKrparen); + ifbody2 = parseStatement(ParseStatementFlags.PSscope); + if (token.value == TOK.TOKelse) + { + nextToken(); + elsebody2 = parseStatement(ParseStatementFlags.PSscope); + } + else + elsebody2 = null; + s = new IfStatement(loc, arg, condition2, ifbody2, elsebody2); + break; + } + + case TOK.TOKscope: + if (peek(&token).value != TOK.TOKlparen) + goto Ldeclaration; // scope used as storage class + nextToken(); + check(TOK.TOKlparen); + if (token.value != TOK.TOKidentifier) + { error("scope identifier expected"); + goto Lerror; + } + else + { TOK tt = TOK.TOKon_scope_exit; + Identifier id = token.ident; + + if (id == Id.exit) + tt = TOK.TOKon_scope_exit; + else if (id == Id.failure) + tt = TOK.TOKon_scope_failure; + else if (id == Id.success) + tt = TOK.TOKon_scope_success; + else + error("valid scope identifiers are exit, failure, or success, not %s", id.toChars()); + nextToken(); + check(TOK.TOKrparen); + Statement st = parseStatement(ParseStatementFlags.PScurlyscope); + s = new OnScopeStatement(loc, tt, st); + break; + } + + case TOK.TOKdebug: + nextToken(); + condition = parseDebugCondition(); + goto Lcondition; + + case TOK.TOKversion: + nextToken(); + condition = parseVersionCondition(); + goto Lcondition; + + Lcondition: + ifbody = parseStatement(cast(ParseStatementFlags)0 /*ParseStatementFlags.PSsemi*/); + elsebody = null; + if (token.value == TOK.TOKelse) + { + nextToken(); + elsebody = parseStatement(cast(ParseStatementFlags)0 /*ParseStatementFlags.PSsemi*/); + } + s = new ConditionalStatement(loc, condition, ifbody, elsebody); + break; + + case TOK.TOKpragma: + { Identifier ident; + Expressions args = null; + Statement body_; + + nextToken(); + check(TOK.TOKlparen); + if (token.value != TOK.TOKidentifier) + { error("pragma(identifier expected"); + goto Lerror; + } + ident = token.ident; + nextToken(); + if (token.value == TOK.TOKcomma && peekNext() != TOK.TOKrparen) + args = parseArguments(); // pragma(identifier, args...); + else + check(TOK.TOKrparen); // pragma(identifier); + if (token.value == TOK.TOKsemicolon) + { nextToken(); + body_ = null; + } + else + body_ = parseStatement(ParseStatementFlags.PSsemi); + s = new PragmaStatement(loc, ident, args, body_); + break; + } + + case TOK.TOKswitch: + isfinal = false; + goto Lswitch; + + Lswitch: + { + nextToken(); + check(TOK.TOKlparen); + Expression condition2 = parseExpression(); + check(TOK.TOKrparen); + Statement body_ = parseStatement(ParseStatementFlags.PSscope); + s = new SwitchStatement(loc, condition2, body_, isfinal); + break; + } + + case TOK.TOKcase: + { Expression exp; + Statements statements; + scope Array cases = new Array(); // array of Expression's + Expression last = null; + + while (1) + { + nextToken(); + exp = parseAssignExp(); + cases.push(cast(void*)exp); + if (token.value != TOK.TOKcomma) + break; + } + check(TOK.TOKcolon); + +version (DMDV2) { + /* case exp: .. case last: + */ + if (token.value == TOK.TOKslice) + { + if (cases.dim > 1) + error("only one case allowed for start of case range"); + nextToken(); + check(TOK.TOKcase); + last = parseAssignExp(); + check(TOK.TOKcolon); + } +} + + statements = new Statements(); + while (token.value != TOK.TOKcase && + token.value != TOK.TOKdefault && + token.value != TOK.TOKrcurly) + { + statements.push(cast(void*)parseStatement(ParseStatementFlags.PSsemi | ParseStatementFlags.PScurlyscope)); + } + s = new CompoundStatement(loc, statements); + s = new ScopeStatement(loc, s); + +///version (DMDV2) { + if (last) + { + s = new CaseRangeStatement(loc, exp, last, s); + } + else +///} + { + // Keep cases in order by building the case statements backwards + for (int i = cases.dim; i; i--) + { + exp = cast(Expression)cases.data[i - 1]; + s = new CaseStatement(loc, exp, s); + } + } + break; + } + + case TOK.TOKdefault: + { + Statements statements; + + nextToken(); + check(TOK.TOKcolon); + + statements = new Statements(); + while (token.value != TOK.TOKcase && + token.value != TOK.TOKdefault && + token.value != TOK.TOKrcurly) + { + statements.push(cast(void*)parseStatement(ParseStatementFlags.PSsemi | ParseStatementFlags.PScurlyscope)); + } + s = new CompoundStatement(loc, statements); + s = new ScopeStatement(loc, s); + s = new DefaultStatement(loc, s); + break; + } + + case TOK.TOKreturn: + { Expression exp; + + nextToken(); + if (token.value == TOK.TOKsemicolon) + exp = null; + else + exp = parseExpression(); + check(TOK.TOKsemicolon, "return statement"); + s = new ReturnStatement(loc, exp); + break; + } + + case TOK.TOKbreak: + { Identifier ident; + + nextToken(); + if (token.value == TOK.TOKidentifier) + { ident = token.ident; + nextToken(); + } + else + ident = null; + check(TOK.TOKsemicolon, "break statement"); + s = new BreakStatement(loc, ident); + break; + } + + case TOK.TOKcontinue: + { Identifier ident; + + nextToken(); + if (token.value == TOK.TOKidentifier) + { ident = token.ident; + nextToken(); + } + else + ident = null; + check(TOK.TOKsemicolon, "continue statement"); + s = new ContinueStatement(loc, ident); + break; + } + + case TOK.TOKgoto: + { Identifier ident; + + nextToken(); + if (token.value == TOK.TOKdefault) + { + nextToken(); + s = new GotoDefaultStatement(loc); + } + else if (token.value == TOK.TOKcase) + { + Expression exp = null; + + nextToken(); + if (token.value != TOK.TOKsemicolon) + exp = parseExpression(); + s = new GotoCaseStatement(loc, exp); + } + else + { + if (token.value != TOK.TOKidentifier) + { error("Identifier expected following goto"); + ident = null; + } + else + { ident = token.ident; + nextToken(); + } + s = new GotoStatement(loc, ident); + } + check(TOK.TOKsemicolon, "goto statement"); + break; + } + + case TOK.TOKsynchronized: + { Expression exp; + Statement body_; + + nextToken(); + if (token.value == TOK.TOKlparen) + { + nextToken(); + exp = parseExpression(); + check(TOK.TOKrparen); + } + else + exp = null; + body_ = parseStatement(ParseStatementFlags.PSscope); + s = new SynchronizedStatement(loc, exp, body_); + break; + } + + case TOK.TOKwith: + { Expression exp; + Statement body_; + + nextToken(); + check(TOK.TOKlparen); + exp = parseExpression(); + check(TOK.TOKrparen); + body_ = parseStatement(ParseStatementFlags.PSscope); + s = new WithStatement(loc, exp, body_); + break; + } + + case TOK.TOKtry: + { Statement body_; + Array catches = null; + Statement finalbody = null; + + nextToken(); + body_ = parseStatement(ParseStatementFlags.PSscope); + while (token.value == TOK.TOKcatch) + { + Statement handler; + Catch c; + Type tt; + Identifier id; + Loc loc2 = this.loc; + + nextToken(); + if (token.value == TOK.TOKlcurly) + { + tt = null; + id = null; + } + else + { + check(TOK.TOKlparen); + id = null; + tt = parseType(&id); + check(TOK.TOKrparen); + } + handler = parseStatement(cast(ParseStatementFlags)0); + c = new Catch(loc2, tt, id, handler); + if (!catches) + catches = new Array(); + catches.push(cast(void*)c); + } + + if (token.value == TOK.TOKfinally) + { nextToken(); + finalbody = parseStatement(cast(ParseStatementFlags)0); + } + + s = body_; + if (!catches && !finalbody) + error("catch or finally expected following try"); + else + { if (catches) + s = new TryCatchStatement(loc, body_, catches); + if (finalbody) + s = new TryFinallyStatement(loc, s, finalbody); + } + break; + } + + case TOK.TOKthrow: + { Expression exp; + + nextToken(); + exp = parseExpression(); + check(TOK.TOKsemicolon, "throw statement"); + s = new ThrowStatement(loc, exp); + break; + } + + case TOK.TOKvolatile: + nextToken(); + s = parseStatement(ParseStatementFlags.PSsemi | ParseStatementFlags.PScurlyscope); +version (DMDV2) { + if (!global.params.useDeprecated) + error("volatile statements deprecated; used synchronized statements instead"); +} + s = new VolatileStatement(loc, s); + break; + + case TOK.TOKasm: + { Statements statements; + Identifier label; + Loc labelloc; + Token* toklist; + Token** ptoklist; + + // Parse the asm block into a sequence of AsmStatements, + // each AsmStatement is one instruction. + // Separate out labels. + // Defer parsing of AsmStatements until semantic processing. + + nextToken(); + check(TOK.TOKlcurly); + toklist = null; + ptoklist = &toklist; + label = null; + statements = new Statements(); + while (1) + { + switch (token.value) + { + case TOK.TOKidentifier: + if (!toklist) + { + // Look ahead to see if it is a label + t = peek(&token); + if (t.value == TOK.TOKcolon) + { // It's a label + label = token.ident; + labelloc = this.loc; + nextToken(); + nextToken(); + continue; + } + } + goto Ldefault; + + case TOK.TOKrcurly: + if (toklist || label) + { + error("asm statements must end in ';'"); + } + break; + + case TOK.TOKsemicolon: + s = null; + if (toklist || label) + { // Create AsmStatement from list of tokens we've saved + s = new AsmStatement(this.loc, toklist); + toklist = null; + ptoklist = &toklist; + if (label) + { + s = new LabelStatement(labelloc, label, s); + label = null; + } + statements.push(cast(void*)s); + } + nextToken(); + continue; + + case TOK.TOKeof: + /* { */ + error("matching '}' expected, not end of file"); + break; + + default: + Ldefault: + *ptoklist = new Token(); + memcpy(*ptoklist, &token, Token.sizeof); + ptoklist = &(*ptoklist).next; + *ptoklist = null; + + nextToken(); + continue; + } + break; + } + s = new CompoundStatement(loc, statements); + nextToken(); + break; + } + + default: + error("found '%s' instead of statement", token.toChars()); + goto Lerror; + + Lerror: + while (token.value != TOK.TOKrcurly && + token.value != TOK.TOKsemicolon && + token.value != TOK.TOKeof) + nextToken(); + if (token.value == TOK.TOKsemicolon) + nextToken(); + s = null; + break; + } + + return s; + } + + /***************************************** + * Parse initializer for variable declaration. + */ + Initializer parseInitializer() + { + StructInitializer is_; + ArrayInitializer ia; + ExpInitializer ie; + Expression e; + Identifier id; + Initializer value; + int comma; + Loc loc = this.loc; + Token* t; + int braces; + int brackets; + + switch (token.value) + { + case TOK.TOKlcurly: + /* Scan ahead to see if it is a struct initializer or + * a function literal. + * If it contains a ';', it is a function literal. + * Treat { } as a struct initializer. + */ + braces = 1; + for (t = peek(&token); 1; t = peek(t)) + { + switch (t.value) + { + case TOK.TOKsemicolon: + case TOK.TOKreturn: + goto Lexpression; + + case TOK.TOKlcurly: + braces++; + continue; + + case TOK.TOKrcurly: + if (--braces == 0) + break; + continue; + + case TOK.TOKeof: + break; + + default: + continue; + } + break; + } + + is_ = new StructInitializer(loc); + nextToken(); + comma = 0; + while (1) + { + switch (token.value) + { + case TOK.TOKidentifier: + if (comma == 1) + error("comma expected separating field initializers"); + t = peek(&token); + if (t.value == TOK.TOKcolon) + { + id = token.ident; + nextToken(); + nextToken(); // skip over ':' + } + else + { + id = null; + } + value = parseInitializer(); + is_.addInit(id, value); + comma = 1; + continue; + + case TOK.TOKcomma: + nextToken(); + comma = 2; + continue; + + case TOK.TOKrcurly: // allow trailing comma's + nextToken(); + break; + + case TOK.TOKeof: + error("found EOF instead of initializer"); + break; + + default: + value = parseInitializer(); + is_.addInit(null, value); + comma = 1; + continue; + //error("found '%s' instead of field initializer", token.toChars()); + //break; + } + break; + } + return is_; + + case TOK.TOKlbracket: + /* Scan ahead to see if it is an array initializer or + * an expression. + * If it ends with a ';' ',' or '}', it is an array initializer. + */ + brackets = 1; + for (t = peek(&token); 1; t = peek(t)) + { + switch (t.value) + { + case TOK.TOKlbracket: + brackets++; + continue; + + case TOK.TOKrbracket: + if (--brackets == 0) + { + t = peek(t); + if (t.value != TOK.TOKsemicolon && + t.value != TOK.TOKcomma && + t.value != TOK.TOKrcurly) + goto Lexpression; + break; + } + continue; + + case TOK.TOKeof: + break; + + default: + continue; + } + break; + } + + ia = new ArrayInitializer(loc); + nextToken(); + comma = 0; + while (true) + { + switch (token.value) + { + default: + if (comma == 1) + { + error("comma expected separating array initializers, not %s", token.toChars()); + nextToken(); + break; + } + e = parseAssignExp(); + if (!e) + break; + if (token.value == TOK.TOKcolon) + { + nextToken(); + value = parseInitializer(); + } + else + { value = new ExpInitializer(e.loc, e); + e = null; + } + ia.addInit(e, value); + comma = 1; + continue; + + case TOK.TOKlcurly: + case TOK.TOKlbracket: + if (comma == 1) + error("comma expected separating array initializers, not %s", token.toChars()); + value = parseInitializer(); + ia.addInit(null, value); + comma = 1; + continue; + + case TOK.TOKcomma: + nextToken(); + comma = 2; + continue; + + case TOK.TOKrbracket: // allow trailing comma's + nextToken(); + break; + + case TOK.TOKeof: + error("found '%s' instead of array initializer", token.toChars()); + break; + } + break; + } + return ia; + + case TOK.TOKvoid: + t = peek(&token); + if (t.value == TOK.TOKsemicolon || t.value == TOK.TOKcomma) + { + nextToken(); + return new VoidInitializer(loc); + } + goto Lexpression; + + default: + Lexpression: + e = parseAssignExp(); + ie = new ExpInitializer(loc, e); + return ie; + } + } + + /***************************************** + * Parses default argument initializer expression that is an assign expression, + * with special handling for __FILE__ and __LINE__. + */ +version (DMDV2) { + Expression parseDefaultInitExp() + { + if (token.value == TOK.TOKfile || + token.value == TOK.TOKline) + { + Token* t = peek(&token); + if (t.value == TOK.TOKcomma || t.value == TOK.TOKrparen) + { + Expression e; + + if (token.value == TOK.TOKfile) + e = new FileInitExp(loc); + else + e = new LineInitExp(loc); + nextToken(); + return e; + } + } + + Expression e = parseAssignExp(); + return e; + } +} + void check(Loc loc, TOK value) + { + if (token.value != value) + error(loc, "found '%s' when expecting '%s'", token.toChars(), Token.toChars(value)); + nextToken(); + } + + void check(TOK value) + { + check(loc, value); + } + + void check(TOK value, string string_) + { + if (token.value != value) { + error("found '%s' when expecting '%s' following '%s'", token.toChars(), Token.toChars(value), string_); + } + nextToken(); + } + + /************************************ + * Determine if the scanner is sitting on the start of a declaration. + * Input: + * needId 0 no identifier + * 1 identifier optional + * 2 must have identifier + * Output: + * if *pt is not null, it is set to the ending token, which would be endtok + */ + + bool isDeclaration(Token* t, int needId, TOK endtok, Token** pt) + { + //printf("isDeclaration(needId = %d)\n", needId); + int haveId = 0; + +version (DMDV2) { + if ((t.value == TOK.TOKconst || + t.value == TOK.TOKinvariant || + t.value == TOK.TOKimmutable || + t.value == TOK.TOKshared) && + peek(t).value != TOK.TOKlparen) + { + /* const type + * immutable type + * shared type + */ + t = peek(t); + } +} + + if (!isBasicType(&t)) + { + goto Lisnot; + } + if (!isDeclarator(&t, &haveId, endtok)) + goto Lisnot; + if ( needId == 1 || + (needId == 0 && !haveId) || + (needId == 2 && haveId)) + { + if (pt) + *pt = t; + goto Lis; + } + else + goto Lisnot; + + Lis: + //printf("\tis declaration, t = %s\n", t.toChars()); + return true; + + Lisnot: + //printf("\tis not declaration\n"); + return false; + } + + bool isBasicType(Token** pt) + { + // This code parallels parseBasicType() + Token* t = *pt; + Token* t2; + int parens; + int haveId = 0; + + switch (t.value) + { + case TOKwchar: + case TOKdchar: + case TOKbit: + case TOKbool: + case TOKchar: + case TOKint8: + case TOKuns8: + case TOKint16: + case TOKuns16: + case TOKint32: + case TOKuns32: + case TOKint64: + case TOKuns64: + case TOKfloat32: + case TOKfloat64: + case TOKfloat80: + case TOKimaginary32: + case TOKimaginary64: + case TOKimaginary80: + case TOKcomplex32: + case TOKcomplex64: + case TOKcomplex80: + case TOKvoid: + t = peek(t); + break; + + case TOK.TOKidentifier: + L5: + t = peek(t); + if (t.value == TOK.TOKnot) + { + goto L4; + } + goto L3; + while (1) + { + L2: + t = peek(t); + L3: + if (t.value == TOK.TOKdot) + { + Ldot: + t = peek(t); + if (t.value != TOK.TOKidentifier) + goto Lfalse; + t = peek(t); + if (t.value != TOK.TOKnot) + goto L3; + L4: + /* Seen a ! + * Look for: + * !( args ), !identifier, etc. + */ + t = peek(t); + switch (t.value) + { case TOK.TOKidentifier: + goto L5; + case TOK.TOKlparen: + if (!skipParens(t, &t)) + goto Lfalse; + break; + case TOK.TOKwchar: case TOK.TOKdchar: + case TOK.TOKbit: case TOK.TOKbool: case TOK.TOKchar: + case TOK.TOKint8: case TOK.TOKuns8: + case TOK.TOKint16: case TOK.TOKuns16: + case TOK.TOKint32: case TOK.TOKuns32: + case TOK.TOKint64: case TOK.TOKuns64: + case TOK.TOKfloat32: case TOK.TOKfloat64: case TOK.TOKfloat80: + case TOK.TOKimaginary32: case TOK.TOKimaginary64: case TOK.TOKimaginary80: + case TOK.TOKcomplex32: case TOK.TOKcomplex64: case TOK.TOKcomplex80: + case TOK.TOKvoid: + case TOK.TOKint32v: + case TOK.TOKuns32v: + case TOK.TOKint64v: + case TOK.TOKuns64v: + case TOK.TOKfloat32v: + case TOK.TOKfloat64v: + case TOK.TOKfloat80v: + case TOK.TOKimaginary32v: + case TOK.TOKimaginary64v: + case TOK.TOKimaginary80v: + case TOK.TOKnull: + case TOK.TOKtrue: + case TOK.TOKfalse: + case TOK.TOKcharv: + case TOK.TOKwcharv: + case TOK.TOKdcharv: + case TOK.TOKstring: + case TOK.TOKfile: + case TOK.TOKline: + goto L2; + default: + goto Lfalse; + } + } + else + break; + } + break; + + case TOK.TOKdot: + goto Ldot; + + case TOK.TOKtypeof: + /* typeof(exp).identifier... + */ + t = peek(t); + if (t.value != TOK.TOKlparen) + goto Lfalse; + if (!skipParens(t, &t)) + goto Lfalse; + goto L2; + + case TOK.TOKconst: + case TOK.TOKinvariant: + case TOK.TOKimmutable: + case TOK.TOKshared: + // const(type) or immutable(type) or shared(type) + t = peek(t); + if (t.value != TOK.TOKlparen) + goto Lfalse; + t = peek(t); + if (!isDeclaration(t, 0, TOK.TOKrparen, &t)) + { + goto Lfalse; + } + t = peek(t); + break; + + default: + goto Lfalse; + } + *pt = t; + //printf("is\n"); + return true; + + Lfalse: + //printf("is not\n"); + return false; + } + + bool isDeclarator(Token** pt, int* haveId, TOK endtok) + { + // This code parallels parseDeclarator() + Token* t = *pt; + bool parens; + + //printf("Parser.isDeclarator()\n"); + //t.print(); + if (t.value == TOK.TOKassign) + return false; + + while (true) + { + parens = false; + switch (t.value) + { + case TOK.TOKmul: + //case TOKand: + t = peek(t); + continue; + + case TOK.TOKlbracket: + t = peek(t); + if (t.value == TOK.TOKrbracket) + { + t = peek(t); + } + else if (isDeclaration(t, 0, TOK.TOKrbracket, &t)) + { + // It's an associative array declaration + t = peek(t); + } + else + { + // [ expression ] + // [ expression .. expression ] + if (!isExpression(&t)) + return false; + if (t.value == TOK.TOKslice) + { + t = peek(t); + if (!isExpression(&t)) + return false; + } + if (t.value != TOK.TOKrbracket) + return false; + t = peek(t); + } + continue; + + case TOK.TOKidentifier: + if (*haveId) + return false; + *haveId = true; + t = peek(t); + break; + + case TOK.TOKlparen: + t = peek(t); + + if (t.value == TOK.TOKrparen) + return false; // () is not a declarator + + /* Regard ( identifier ) as not a declarator + * BUG: what about ( *identifier ) in + * f(*p)(x); + * where f is a class instance with overloaded () ? + * Should we just disallow C-style function pointer declarations? + */ + if (t.value == TOK.TOKidentifier) + { + Token *t2 = peek(t); + if (t2.value == TOK.TOKrparen) + return false; + } + + if (!isDeclarator(&t, haveId, TOK.TOKrparen)) + return false; + t = peek(t); + parens = true; + break; + + case TOK.TOKdelegate: + case TOK.TOKfunction: + t = peek(t); + if (!isParameters(&t)) + return false; + continue; + default: + break; /// + } + break; + } + + while (1) + { + switch (t.value) + { +version (CARRAYDECL) { + case TOK.TOKlbracket: + parens = false; + t = peek(t); + if (t.value == TOK.TOKrbracket) + { + t = peek(t); + } + else if (isDeclaration(t, 0, TOKrbracket, &t)) + { + // It's an associative array declaration + t = peek(t); + } + else + { + // [ expression ] + if (!isExpression(&t)) + return false; + if (t.value != TOK.TOKrbracket) + return false; + t = peek(t); + } + continue; +} + + case TOK.TOKlparen: + parens = false; + if (!isParameters(&t)) + return false; +version (DMDV2) { + while (true) + { + switch (t.value) + { + case TOK.TOKconst: + case TOK.TOKinvariant: + case TOK.TOKimmutable: + case TOK.TOKshared: + case TOK.TOKpure: + case TOK.TOKnothrow: + t = peek(t); + continue; + case TOK.TOKat: + t = peek(t); // skip '@' + t = peek(t); // skip identifier + continue; + default: + break; + } + break; + } +} + continue; + + // Valid tokens that follow a declaration + case TOK.TOKrparen: + case TOK.TOKrbracket: + case TOK.TOKassign: + case TOK.TOKcomma: + case TOK.TOKsemicolon: + case TOK.TOKlcurly: + case TOK.TOKin: + // The !parens is to disallow unnecessary parentheses + if (!parens && (endtok == TOK.TOKreserved || endtok == t.value)) + { + *pt = t; + return true; + } + return false; + + default: + return false; + } + } + } + + bool isParameters(Token** pt) + { + // This code parallels parseParameters() + Token* t = *pt; + + //printf("isParameters()\n"); + if (t.value != TOKlparen) + return false; + + t = peek(t); + for (;1; t = peek(t)) + { + L1: + switch (t.value) + { + case TOKrparen: + break; + + case TOKdotdotdot: + t = peek(t); + break; + + case TOKin: + case TOKout: + case TOKinout: + case TOKref: + case TOKlazy: + case TOKfinal: + continue; + + case TOKconst: + case TOKinvariant: + case TOKimmutable: + case TOKshared: + t = peek(t); + if (t.value == TOKlparen) + { + t = peek(t); + if (!isDeclaration(t, 0, TOKrparen, &t)) + return false; + t = peek(t); // skip past closing ')' + goto L2; + } + goto L1; + + static if (false) { + case TOKstatic: + continue; + case TOKauto: + case TOKalias: + t = peek(t); + if (t.value == TOKidentifier) + t = peek(t); + if (t.value == TOKassign) + { t = peek(t); + if (!isExpression(&t)) + return false; + } + goto L3; + } + + default: + { + if (!isBasicType(&t)) + return false; + L2: + int tmp = false; + if (t.value != TOKdotdotdot && + !isDeclarator(&t, &tmp, TOKreserved)) + return false; + if (t.value == TOKassign) + { + t = peek(t); + if (!isExpression(&t)) + return false; + } + if (t.value == TOKdotdotdot) + { + t = peek(t); + break; + } + } + L3: + if (t.value == TOKcomma) + { + continue; + } + break; + } + break; + } + + if (t.value != TOKrparen) + return false; + + t = peek(t); + *pt = t; + return true; + } + + bool isExpression(Token** pt) + { + // This is supposed to determine if something is an expression. + // What it actually does is scan until a closing right bracket + // is found. + + Token* t = *pt; + int brnest = 0; + int panest = 0; + int curlynest = 0; + + for (;; t = peek(t)) + { + switch (t.value) + { + case TOKlbracket: + brnest++; + continue; + + case TOKrbracket: + if (--brnest >= 0) + continue; + break; + + case TOKlparen: + panest++; + continue; + + case TOKcomma: + if (brnest || panest) + continue; + break; + + case TOKrparen: + if (--panest >= 0) + continue; + break; + + case TOKlcurly: + curlynest++; + continue; + + case TOKrcurly: + if (--curlynest >= 0) + continue; + return false; + + case TOKslice: + if (brnest) + continue; + break; + + case TOKsemicolon: + if (curlynest) + continue; + return false; + + case TOKeof: + return false; + + default: + continue; + } + break; + } + + *pt = t; + return true; + } + + int isTemplateInstance(Token t, Token* pt) + { + assert(false); + } + + /******************************************* + * Skip parens, brackets. + * Input: + * t is on opening ( + * Output: + * *pt is set to closing token, which is ')' on success + * Returns: + * !=0 successful + * 0 some parsing error + */ + bool skipParens(Token* t, Token** pt) + { + int parens = 0; + + while (1) + { + switch (t.value) + { + case TOKlparen: + parens++; + break; + + case TOKrparen: + parens--; + if (parens < 0) + goto Lfalse; + if (parens == 0) + goto Ldone; + break; + + case TOKeof: + case TOKsemicolon: + goto Lfalse; + + default: + break; + } + t = peek(t); + } + + Ldone: + if (*pt) + *pt = t; + return true; + + Lfalse: + return false; + } + + Expression parseExpression() + { + Expression e; + Expression e2; + Loc loc = this.loc; + + //printf("Parser.parseExpression() loc = %d\n", loc.linnum); + e = parseAssignExp(); + while (token.value == TOK.TOKcomma) + { + nextToken(); + e2 = parseAssignExp(); + e = new CommaExp(loc, e, e2); + loc = this.loc; + } + return e; + } + + Expression parsePrimaryExp() + { + Expression e; + Type t; + Identifier id; + TOK save; + Loc loc = this.loc; + + //printf("parsePrimaryExp(): loc = %d\n", loc.linnum); + switch (token.value) + { + case TOK.TOKidentifier: + id = token.ident; + nextToken(); + if (token.value == TOK.TOKnot && peekNext() != TOK.TOKis) + { // identifier!(template-argument-list) + TemplateInstance tempinst; + + tempinst = new TemplateInstance(loc, id); + nextToken(); + if (token.value == TOK.TOKlparen) + // ident!(template_arguments) + tempinst.tiargs = parseTemplateArgumentList(); + else + // ident!template_argument + tempinst.tiargs = parseTemplateArgument(); + e = new ScopeExp(loc, tempinst); + } + else + e = new IdentifierExp(loc, id); + break; + + case TOK.TOKdollar: + if (!inBrackets) + error("'$' is valid only inside [] of index or slice"); + e = new DollarExp(loc); + nextToken(); + break; + + case TOK.TOKdot: + // Signal global scope '.' operator with "" identifier + e = new IdentifierExp(loc, Id.empty); + break; + + case TOK.TOKthis: + e = new ThisExp(loc); + nextToken(); + break; + + case TOK.TOKsuper: + e = new SuperExp(loc); + nextToken(); + break; + + case TOK.TOKint32v: + e = new IntegerExp(loc, token.int32value, Type.tint32); + nextToken(); + break; + + case TOK.TOKuns32v: + e = new IntegerExp(loc, token.uns32value, Type.tuns32); + nextToken(); + break; + + case TOK.TOKint64v: + e = new IntegerExp(loc, token.int64value, Type.tint64); + nextToken(); + break; + + case TOK.TOKuns64v: + e = new IntegerExp(loc, token.uns64value, Type.tuns64); + nextToken(); + break; + + case TOK.TOKfloat32v: + e = new RealExp(loc, token.float80value, Type.tfloat32); + nextToken(); + break; + + case TOK.TOKfloat64v: + e = new RealExp(loc, token.float80value, Type.tfloat64); + nextToken(); + break; + + case TOK.TOKfloat80v: + e = new RealExp(loc, token.float80value, Type.tfloat80); + nextToken(); + break; + + case TOK.TOKimaginary32v: + e = new RealExp(loc, token.float80value, Type.timaginary32); + nextToken(); + break; + + case TOK.TOKimaginary64v: + e = new RealExp(loc, token.float80value, Type.timaginary64); + nextToken(); + break; + + case TOK.TOKimaginary80v: + e = new RealExp(loc, token.float80value, Type.timaginary80); + nextToken(); + break; + + case TOK.TOKnull: + e = new NullExp(loc); + nextToken(); + break; + +version (DMDV2) { + case TOK.TOKfile: + { + string s = loc.filename ? loc.filename : mod.ident.toChars(); + e = new StringExp(loc, s, 0); + nextToken(); + break; + } + + case TOK.TOKline: + e = new IntegerExp(loc, loc.linnum, Type.tint32); + nextToken(); + break; +} + + case TOK.TOKtrue: + e = new IntegerExp(loc, 1, Type.tbool); + nextToken(); + break; + + case TOK.TOKfalse: + e = new IntegerExp(loc, 0, Type.tbool); + nextToken(); + break; + + case TOK.TOKcharv: + e = new IntegerExp(loc, token.uns32value, Type.tchar); + nextToken(); + break; + + case TOK.TOKwcharv: + e = new IntegerExp(loc, token.uns32value, Type.twchar); + nextToken(); + break; + + case TOK.TOKdcharv: + e = new IntegerExp(loc, token.uns32value, Type.tdchar); + nextToken(); + break; + + case TOK.TOKstring: + { + const(char)* s; + uint len; + ubyte postfix; + + // cat adjacent strings + s = token.ustring; + len = token.len; + postfix = token.postfix; + while (1) + { + nextToken(); + if (token.value == TOK.TOKstring) + { uint len1; + uint len2; + char* s2; + + if (token.postfix) + { if (token.postfix != postfix) + error("mismatched string literal postfixes '%c' and '%c'", postfix, token.postfix); + postfix = token.postfix; + } + + len1 = len; + len2 = token.len; + len = len1 + len2; + s2 = cast(char*)malloc((len + 1) * ubyte.sizeof); + memcpy(s2, s, len1 * ubyte.sizeof); + memcpy(s2 + len1, token.ustring, (len2 + 1) * ubyte.sizeof); + s = s2; + } + else + break; + } + e = new StringExp(loc, assumeUnique(s[0..len]), postfix); + break; + } + + case TOK.TOKvoid: t = Type.tvoid; goto LabelX; + case TOK.TOKint8: t = Type.tint8; goto LabelX; + case TOK.TOKuns8: t = Type.tuns8; goto LabelX; + case TOK.TOKint16: t = Type.tint16; goto LabelX; + case TOK.TOKuns16: t = Type.tuns16; goto LabelX; + case TOK.TOKint32: t = Type.tint32; goto LabelX; + case TOK.TOKuns32: t = Type.tuns32; goto LabelX; + case TOK.TOKint64: t = Type.tint64; goto LabelX; + case TOK.TOKuns64: t = Type.tuns64; goto LabelX; + case TOK.TOKfloat32: t = Type.tfloat32; goto LabelX; + case TOK.TOKfloat64: t = Type.tfloat64; goto LabelX; + case TOK.TOKfloat80: t = Type.tfloat80; goto LabelX; + case TOK.TOKimaginary32: t = Type.timaginary32; goto LabelX; + case TOK.TOKimaginary64: t = Type.timaginary64; goto LabelX; + case TOK.TOKimaginary80: t = Type.timaginary80; goto LabelX; + case TOK.TOKcomplex32: t = Type.tcomplex32; goto LabelX; + case TOK.TOKcomplex64: t = Type.tcomplex64; goto LabelX; + case TOK.TOKcomplex80: t = Type.tcomplex80; goto LabelX; + case TOK.TOKbit: t = Type.tbit; goto LabelX; + case TOK.TOKbool: t = Type.tbool; goto LabelX; + case TOK.TOKchar: t = Type.tchar; goto LabelX; + case TOK.TOKwchar: t = Type.twchar; goto LabelX; + case TOK.TOKdchar: t = Type.tdchar; goto LabelX; + LabelX: + nextToken(); + L1: + check(TOK.TOKdot, t.toChars()); + if (token.value != TOK.TOKidentifier) + { error("found '%s' when expecting identifier following '%s.'", token.toChars(), t.toChars()); + goto Lerr; + } + e = typeDotIdExp(loc, t, token.ident); + nextToken(); + break; + + case TOK.TOKtypeof: + { + t = parseTypeof(); + e = new TypeExp(loc, t); + break; + } + + case TOK.TOKtypeid: + { Type tt; + + nextToken(); + check(TOK.TOKlparen, "typeid"); + tt = parseType(); // ( type ) + check(TOK.TOKrparen); + e = new TypeidExp(loc, tt); + break; + } + +version (DMDV2) { + case TOK.TOKtraits: + { /* __traits(identifier, args...) + */ + Identifier ident; + Objects args = null; + + nextToken(); + check(TOK.TOKlparen); + if (token.value != TOK.TOKidentifier) + { error("__traits(identifier, args...) expected"); + goto Lerr; + } + ident = token.ident; + nextToken(); + if (token.value == TOK.TOKcomma) + args = parseTemplateArgumentList2(); // __traits(identifier, args...) + else + check(TOK.TOKrparen); // __traits(identifier) + + e = new TraitsExp(loc, ident, args); + break; + } +} + + case TOK.TOKis: + { Type targ; + Identifier ident = null; + Type tspec = null; + TOK tok = TOK.TOKreserved; + TOK tok2 = TOK.TOKreserved; + TemplateParameters tpl = null; + Loc loc2 = this.loc; + + nextToken(); + if (token.value == TOK.TOKlparen) + { + nextToken(); + targ = parseType(&ident); + if (token.value == TOK.TOKcolon || token.value == TOK.TOKequal) + { + tok = token.value; + nextToken(); + if (tok == TOK.TOKequal && + (token.value == TOK.TOKtypedef || + token.value == TOK.TOKstruct || + token.value == TOK.TOKunion || + token.value == TOK.TOKclass || + token.value == TOK.TOKsuper || + token.value == TOK.TOKenum || + token.value == TOK.TOKinterface || + ///version (DMDV2) { + token.value == TOK.TOKconst && peek(&token).value == TOK.TOKrparen || + token.value == TOK.TOKinvariant && peek(&token).value == TOK.TOKrparen || + token.value == TOK.TOKimmutable && peek(&token).value == TOK.TOKrparen || + token.value == TOK.TOKshared && peek(&token).value == TOK.TOKrparen || + ///} + token.value == TOK.TOKfunction || + token.value == TOK.TOKdelegate || + token.value == TOK.TOKreturn)) + { + tok2 = token.value; + nextToken(); + } + else + { + tspec = parseType(); + } + } + if (ident && tspec) + { + if (token.value == TOK.TOKcomma) + tpl = parseTemplateParameterList(1); + else + { tpl = new TemplateParameters(); + check(TOK.TOKrparen); + } + TemplateParameter tp = new TemplateTypeParameter(loc2, ident, null, null); + tpl.insert(0, cast(void*)tp); + } + else + check(TOK.TOKrparen); + } + else + { error("(type identifier : specialization) expected following is"); + goto Lerr; + } + e = new IsExp(loc2, targ, ident, tok, tspec, tok2, tpl); + break; + } + + case TOK.TOKassert: + { + Expression msg = null; + + nextToken(); + check(TOK.TOKlparen, "assert"); + e = parseAssignExp(); + if (token.value == TOK.TOKcomma) + { nextToken(); + msg = parseAssignExp(); + } + check(TOK.TOKrparen); + e = new AssertExp(loc, e, msg); + break; + } + + case TOK.TOKmixin: + { + nextToken(); + check(TOK.TOKlparen, "mixin"); + e = parseAssignExp(); + check(TOK.TOKrparen); + e = new CompileExp(loc, e); + break; + } + + case TOK.TOKimport: + { + nextToken(); + check(TOK.TOKlparen, "import"); + e = parseAssignExp(); + check(TOK.TOKrparen); + e = new FileExp(loc, e); + break; + } + + case TOK.TOKlparen: + if (peekPastParen(&token).value == TOK.TOKlcurly) + { // (arguments) { statements... } + save = TOK.TOKdelegate; + goto case_delegate; + } + // ( expression ) + nextToken(); + e = parseExpression(); + check(loc, TOK.TOKrparen); + break; + + case TOK.TOKlbracket: + { /* Parse array literals and associative array literals: + * [ value, value, value ... ] + * [ key:value, key:value, key:value ... ] + */ + Expressions values = new Expressions(); + Expressions keys = null; + + nextToken(); + if (token.value != TOK.TOKrbracket) + { + while (token.value != TOK.TOKeof) + { + Expression e2 = parseAssignExp(); + if (token.value == TOK.TOKcolon && (keys || values.dim == 0)) + { + nextToken(); + if (!keys) + keys = new Expressions(); + keys.push(cast(void*)e2); + e2 = parseAssignExp(); + } + else if (keys) + { + error("'key:value' expected for associative array literal"); + delete keys; + keys = null; + } + values.push(cast(void*)e2); + if (token.value == TOK.TOKrbracket) + break; + check(TOK.TOKcomma); + } + } + check(TOK.TOKrbracket); + + if (keys) + e = new AssocArrayLiteralExp(loc, keys, values); + else + e = new ArrayLiteralExp(loc, values); + break; + } + + case TOK.TOKlcurly: + // { statements... } + save = TOK.TOKdelegate; + goto case_delegate; + + case TOK.TOKfunction: + case TOK.TOKdelegate: + save = token.value; + nextToken(); + case_delegate: + { + /* function type(parameters) { body } pure nothrow + * delegate type(parameters) { body } pure nothrow + * (parameters) { body } + * { body } + */ + Arguments arguments; + int varargs; + FuncLiteralDeclaration fd; + Type tt; + bool isnothrow = false; + bool ispure = false; + + if (token.value == TOK.TOKlcurly) + { + tt = null; + varargs = 0; + arguments = new Arguments(); + } + else + { + if (token.value == TOK.TOKlparen) + tt = null; + else + { + tt = parseBasicType(); + tt = parseBasicType2(tt); // function return type + } + arguments = parseParameters(&varargs); + while (1) + { + if (token.value == TOK.TOKpure) + ispure = true; + else if (token.value == TOK.TOKnothrow) + isnothrow = true; + else + break; + nextToken(); + } + } + + TypeFunction tf = new TypeFunction(arguments, tt, varargs, linkage); + tf.ispure = ispure; + tf.isnothrow = isnothrow; + fd = new FuncLiteralDeclaration(loc, Loc(0), tf, save, null); + parseContracts(fd); + e = new FuncExp(loc, fd); + break; + } + + default: + error("expression expected, not '%s'", token.toChars()); + Lerr: + // Anything for e, as long as it's not null + e = new IntegerExp(loc, 0, Type.tint32); + nextToken(); + break; + } + return e; + } + + Expression parseUnaryExp() + { + Expression e; + Loc loc = this.loc; + + switch (token.value) + { + case TOK.TOKand: + nextToken(); + e = parseUnaryExp(); + e = new AddrExp(loc, e); + break; + + case TOK.TOKplusplus: + nextToken(); + e = parseUnaryExp(); + e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type.tint32)); + break; + + case TOK.TOKminusminus: + nextToken(); + e = parseUnaryExp(); + e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type.tint32)); + break; + + case TOK.TOKmul: + nextToken(); + e = parseUnaryExp(); + e = new PtrExp(loc, e); + break; + + case TOK.TOKmin: + nextToken(); + e = parseUnaryExp(); + e = new NegExp(loc, e); + break; + + case TOK.TOKadd: + nextToken(); + e = parseUnaryExp(); + e = new UAddExp(loc, e); + break; + + case TOK.TOKnot: + nextToken(); + e = parseUnaryExp(); + e = new NotExp(loc, e); + break; + + case TOK.TOKtilde: + nextToken(); + e = parseUnaryExp(); + e = new ComExp(loc, e); + break; + + case TOK.TOKdelete: + nextToken(); + e = parseUnaryExp(); + e = new DeleteExp(loc, e); + break; + + case TOK.TOKnew: + e = parseNewExp(null); + break; + + case TOK.TOKcast: // cast(type) expression + { + nextToken(); + check(TOK.TOKlparen); + /* Look for cast(), cast(const), cast(immutable), + * cast(shared), cast(shared const) + */ + MOD m; + if (token.value == TOK.TOKrparen) + { + m = MOD.MODundefined; + goto Lmod1; + } + else if (token.value == TOK.TOKconst && peekNext() == TOK.TOKrparen) + { + m = MOD.MODconst; + goto Lmod2; + } + else if ((token.value == TOK.TOKimmutable || token.value == TOK.TOKinvariant) && peekNext() == TOK.TOKrparen) + { + m = MOD.MODinvariant; + goto Lmod2; + } + else if (token.value == TOK.TOKshared && peekNext() == TOK.TOKrparen) + { + m = MOD.MODshared; + goto Lmod2; + } + else if (token.value == TOK.TOKconst && peekNext() == TOK.TOKshared && peekNext2() == TOK.TOKrparen || + token.value == TOK.TOKshared && peekNext() == TOK.TOKconst && peekNext2() == TOK.TOKrparen) + { + m = MOD.MODshared | MOD.MODconst; + nextToken(); + Lmod2: + nextToken(); + Lmod1: + nextToken(); + e = parseUnaryExp(); + e = new CastExp(loc, e, m); + } + else + { + Type t = parseType(); // ( type ) + check(TOK.TOKrparen); + e = parseUnaryExp(); + e = new CastExp(loc, e, t); + } + break; + } + + case TOK.TOKlparen: + { Token *tk; + + tk = peek(&token); +version (CCASTSYNTAX) { + // If cast + if (isDeclaration(tk, 0, TOK.TOKrparen, &tk)) + { + tk = peek(tk); // skip over right parenthesis + switch (tk.value) + { + case TOK.TOKnot: + tk = peek(tk); + if (tk.value == TOK.TOKis) // !is + break; + case TOK.TOKdot: + case TOK.TOKplusplus: + case TOK.TOKminusminus: + case TOK.TOKdelete: + case TOK.TOKnew: + case TOK.TOKlparen: + case TOK.TOKidentifier: + case TOK.TOKthis: + case TOK.TOKsuper: + case TOK.TOKint32v: + case TOK.TOKuns32v: + case TOK.TOKint64v: + case TOK.TOKuns64v: + case TOK.TOKfloat32v: + case TOK.TOKfloat64v: + case TOK.TOKfloat80v: + case TOK.TOKimaginary32v: + case TOK.TOKimaginary64v: + case TOK.TOKimaginary80v: + case TOK.TOKnull: + case TOK.TOKtrue: + case TOK.TOKfalse: + case TOK.TOKcharv: + case TOK.TOKwcharv: + case TOK.TOKdcharv: + case TOK.TOKstring: +static if (false) { + case TOK.TOKtilde: + case TOK.TOKand: + case TOK.TOKmul: + case TOK.TOKmin: + case TOK.TOKadd: +} + case TOK.TOKfunction: + case TOK.TOKdelegate: + case TOK.TOKtypeof: +version (DMDV2) { + case TOK.TOKfile: + case TOK.TOKline: +} + case TOK.TOKwchar: case TOK.TOKdchar: + case TOK.TOKbit: case TOK.TOKbool: case TOK.TOKchar: + case TOK.TOKint8: case TOK.TOKuns8: + case TOK.TOKint16: case TOK.TOKuns16: + case TOK.TOKint32: case TOK.TOKuns32: + case TOK.TOKint64: case TOK.TOKuns64: + case TOK.TOKfloat32: case TOK.TOKfloat64: case TOK.TOKfloat80: + case TOK.TOKimaginary32: case TOK.TOKimaginary64: case TOK.TOKimaginary80: + case TOK.TOKcomplex32: case TOK.TOKcomplex64: case TOK.TOKcomplex80: + case TOK.TOKvoid: // (type)int.size + { + // (type) una_exp + nextToken(); + Type t = parseType(); + check(TOK.TOKrparen); + + // if .identifier + if (token.value == TOK.TOKdot) + { + nextToken(); + if (token.value != TOK.TOKidentifier) + { + error("Identifier expected following (type)."); + return null; + } + e = typeDotIdExp(loc, t, token.ident); + nextToken(); + e = parsePostExp(e); + } + else + { + e = parseUnaryExp(); + e = new CastExp(loc, e, t); + error("C style cast illegal, use %s", e.toChars()); + } + return e; + } + + default: + break; /// + } + } +} + e = parsePrimaryExp(); + e = parsePostExp(e); + break; + } + default: + e = parsePrimaryExp(); + e = parsePostExp(e); + break; + } + assert(e); + return e; + } + + Expression parsePostExp(Expression e) + { + Loc loc; + + while (1) + { + loc = this.loc; + switch (token.value) + { + case TOK.TOKdot: + nextToken(); + if (token.value == TOK.TOKidentifier) + { Identifier id = token.ident; + + nextToken(); + if (token.value == TOK.TOKnot && peekNext() != TOK.TOKis) + { // identifier!(template-argument-list) + TemplateInstance tempinst = new TemplateInstance(loc, id); + nextToken(); + if (token.value == TOK.TOKlparen) + // ident!(template_arguments) + tempinst.tiargs = parseTemplateArgumentList(); + else + // ident!template_argument + tempinst.tiargs = parseTemplateArgument(); + e = new DotTemplateInstanceExp(loc, e, tempinst); + } + else + e = new DotIdExp(loc, e, id); + continue; + } + else if (token.value == TOK.TOKnew) + { + e = parseNewExp(e); + continue; + } + else + error("identifier expected following '.', not '%s'", token.toChars()); + break; + + case TOK.TOKplusplus: + e = new PostExp(TOK.TOKplusplus, loc, e); + break; + + case TOK.TOKminusminus: + e = new PostExp(TOK.TOKminusminus, loc, e); + break; + + case TOK.TOKlparen: + e = new CallExp(loc, e, parseArguments()); + continue; + + case TOK.TOKlbracket: + { // array dereferences: + // array[index] + // array[] + // array[lwr .. upr] + Expression index; + Expression upr; + + inBrackets++; + nextToken(); + if (token.value == TOK.TOKrbracket) + { // array[] + e = new SliceExp(loc, e, null, null); + nextToken(); + } + else + { + index = parseAssignExp(); + if (token.value == TOK.TOKslice) + { // array[lwr .. upr] + nextToken(); + upr = parseAssignExp(); + e = new SliceExp(loc, e, index, upr); + } + else + { // array[index, i2, i3, i4, ...] + Expressions arguments = new Expressions(); + arguments.push(cast(void*)index); + if (token.value == TOK.TOKcomma) + { + nextToken(); + while (1) + { Expression arg; + + arg = parseAssignExp(); + arguments.push(cast(void*)arg); + if (token.value == TOK.TOKrbracket) + break; + check(TOK.TOKcomma); + } + } + e = new ArrayExp(loc, e, arguments); + } + check(TOK.TOKrbracket); + inBrackets--; + } + continue; + } + + default: + return e; + } + nextToken(); + } + + assert(false); + } + + Expression parseMulExp() + { + Expression e; + Expression e2; + Loc loc = this.loc; + + e = parseUnaryExp(); + while (1) + { + switch (token.value) + { + case TOK.TOKmul: nextToken(); e2 = parseUnaryExp(); e = new MulExp(loc,e,e2); continue; + case TOK.TOKdiv: nextToken(); e2 = parseUnaryExp(); e = new DivExp(loc,e,e2); continue; + case TOK.TOKmod: nextToken(); e2 = parseUnaryExp(); e = new ModExp(loc,e,e2); continue; + + default: + break; + } + break; + } + return e; + } + + Expression parseShiftExp() + { + Expression e; + Expression e2; + Loc loc = this.loc; + + e = parseAddExp(); + while (1) + { + switch (token.value) + { + case TOK.TOKshl: nextToken(); e2 = parseAddExp(); e = new ShlExp(loc,e,e2); continue; + case TOK.TOKshr: nextToken(); e2 = parseAddExp(); e = new ShrExp(loc,e,e2); continue; + case TOK.TOKushr: nextToken(); e2 = parseAddExp(); e = new UshrExp(loc,e,e2); continue; + + default: + break; + } + break; + } + return e; + } + + Expression parseAddExp() + { + Expression e; + Expression e2; + Loc loc = this.loc; + + e = parseMulExp(); + while (1) + { + switch (token.value) + { + case TOK.TOKadd: nextToken(); e2 = parseMulExp(); e = new AddExp(loc,e,e2); continue; + case TOK.TOKmin: nextToken(); e2 = parseMulExp(); e = new MinExp(loc,e,e2); continue; + case TOK.TOKtilde: nextToken(); e2 = parseMulExp(); e = new CatExp(loc,e,e2); continue; + + default: + break; + } + break; + } + return e; + } + + Expression parseRelExp() + { + assert(false); + } + + Expression parseEqualExp() + { + assert(false); + } + + Expression parseCmpExp() + { + Expression e; + Expression e2; + Token* t; + Loc loc = this.loc; + + e = parseShiftExp(); + TOK op = token.value; + + switch (op) + { + case TOK.TOKequal: + case TOK.TOKnotequal: + nextToken(); + e2 = parseShiftExp(); + e = new EqualExp(op, loc, e, e2); + break; + + case TOK.TOKis: + op = TOK.TOKidentity; + goto L1; + + case TOK.TOKnot: + // Attempt to identify '!is' + t = peek(&token); + if (t.value != TOK.TOKis) + break; + nextToken(); + op = TOK.TOKnotidentity; + goto L1; + + L1: + nextToken(); + e2 = parseShiftExp(); + e = new IdentityExp(op, loc, e, e2); + break; + + case TOK.TOKlt: + case TOK.TOKle: + case TOK.TOKgt: + case TOK.TOKge: + case TOK.TOKunord: + case TOK.TOKlg: + case TOK.TOKleg: + case TOK.TOKule: + case TOK.TOKul: + case TOK.TOKuge: + case TOK.TOKug: + case TOK.TOKue: + nextToken(); + e2 = parseShiftExp(); + e = new CmpExp(op, loc, e, e2); + break; + + case TOK.TOKin: + nextToken(); + e2 = parseShiftExp(); + e = new InExp(loc, e, e2); + break; + + default: + break; + } + return e; + } + + Expression parseAndExp() + { + Expression e; + Expression e2; + Loc loc = this.loc; + + if (global.params.Dversion == 1) + { + e = parseEqualExp(); + while (token.value == TOK.TOKand) + { + nextToken(); + e2 = parseEqualExp(); + e = new AndExp(loc,e,e2); + loc = this.loc; + } + } + else + { + e = parseCmpExp(); + while (token.value == TOK.TOKand) + { + nextToken(); + e2 = parseCmpExp(); + e = new AndExp(loc,e,e2); + loc = this.loc; + } + } + return e; + } + + Expression parseXorExp() + { + Expression e; + Expression e2; + Loc loc = this.loc; + + e = parseAndExp(); + while (token.value == TOK.TOKxor) + { + nextToken(); + e2 = parseAndExp(); + e = new XorExp(loc, e, e2); + } + + return e; + } + + Expression parseOrExp() + { + Expression e; + Expression e2; + Loc loc = this.loc; + + e = parseXorExp(); + while (token.value == TOK.TOKor) + { + nextToken(); + e2 = parseXorExp(); + e = new OrExp(loc, e, e2); + } + return e; + } + + Expression parseAndAndExp() + { + Expression e; + Expression e2; + Loc loc = this.loc; + + e = parseOrExp(); + while (token.value == TOK.TOKandand) + { + nextToken(); + e2 = parseOrExp(); + e = new AndAndExp(loc, e, e2); + } + return e; + } + + Expression parseOrOrExp() + { + Expression e; + Expression e2; + Loc loc = this.loc; + + e = parseAndAndExp(); + while (token.value == TOK.TOKoror) + { + nextToken(); + e2 = parseAndAndExp(); + e = new OrOrExp(loc, e, e2); + } + + return e; + } + + Expression parseCondExp() + { + Expression e; + Expression e1; + Expression e2; + Loc loc = this.loc; + + e = parseOrOrExp(); + if (token.value == TOK.TOKquestion) + { + nextToken(); + e1 = parseExpression(); + check(TOK.TOKcolon); + e2 = parseCondExp(); + e = new CondExp(loc, e, e1, e2); + } + return e; + } + + Expression parseAssignExp() + { + Expression e; + Expression e2; + Loc loc; + + e = parseCondExp(); + while (1) + { + loc = this.loc; + switch (token.value) + { + case TOK.TOKassign: nextToken(); e2 = parseAssignExp(); e = new AssignExp(loc,e,e2); continue; + case TOK.TOKaddass: nextToken(); e2 = parseAssignExp(); e = new AddAssignExp(loc,e,e2); continue; + case TOK.TOKminass: nextToken(); e2 = parseAssignExp(); e = new MinAssignExp(loc,e,e2); continue; + case TOK.TOKmulass: nextToken(); e2 = parseAssignExp(); e = new MulAssignExp(loc,e,e2); continue; + case TOK.TOKdivass: nextToken(); e2 = parseAssignExp(); e = new DivAssignExp(loc,e,e2); continue; + case TOK.TOKmodass: nextToken(); e2 = parseAssignExp(); e = new ModAssignExp(loc,e,e2); continue; + case TOK.TOKandass: nextToken(); e2 = parseAssignExp(); e = new AndAssignExp(loc,e,e2); continue; + case TOK.TOKorass: nextToken(); e2 = parseAssignExp(); e = new OrAssignExp(loc,e,e2); continue; + case TOK.TOKxorass: nextToken(); e2 = parseAssignExp(); e = new XorAssignExp(loc,e,e2); continue; + case TOK.TOKshlass: nextToken(); e2 = parseAssignExp(); e = new ShlAssignExp(loc,e,e2); continue; + case TOK.TOKshrass: nextToken(); e2 = parseAssignExp(); e = new ShrAssignExp(loc,e,e2); continue; + case TOK.TOKushrass: nextToken(); e2 = parseAssignExp(); e = new UshrAssignExp(loc,e,e2); continue; + case TOK.TOKcatass: nextToken(); e2 = parseAssignExp(); e = new CatAssignExp(loc,e,e2); continue; + + default: + break; + } + break; + } + + return e; + } + + /************************* + * Collect argument list. + * Assume current token is ',', '(' or '['. + */ + Expressions parseArguments() + { + // function call + Expressions arguments = new Expressions(); + Expression arg; + TOK endtok; + + if (token.value == TOK.TOKlbracket) + endtok = TOK.TOKrbracket; + else + endtok = TOK.TOKrparen; + + { + nextToken(); + if (token.value != endtok) + { + while (1) + { + arg = parseAssignExp(); + arguments.push(cast(void*)arg); + if (token.value == endtok) + break; + check(TOK.TOKcomma); + } + } + check(endtok); + } + return arguments; + } + + Expression parseNewExp(Expression thisexp) + { + Type t; + Expressions newargs; + Expressions arguments = null; + Expression e; + Loc loc = this.loc; + + nextToken(); + newargs = null; + if (token.value == TOKlparen) + { + newargs = parseArguments(); + } + + // An anonymous nested class starts with "class" + if (token.value == TOKclass) + { + nextToken(); + if (token.value == TOKlparen) + arguments = parseArguments(); + + BaseClasses baseclasses = null; + if (token.value != TOKlcurly) + baseclasses = parseBaseClasses(); + + Identifier id = null; + ClassDeclaration cd = new ClassDeclaration(loc, id, baseclasses); + + if (token.value != TOKlcurly) + { + error("{ members } expected for anonymous class"); + cd.members = null; + } + else + { + nextToken(); + Array decl = parseDeclDefs(0); + if (token.value != TOKrcurly) + error("class member expected"); + nextToken(); + cd.members = decl; + } + + e = new NewAnonClassExp(loc, thisexp, newargs, cd, arguments); + + return e; + } + + t = parseBasicType(); + t = parseBasicType2(t); + if (t.ty == Taarray) + { + TypeAArray taa = cast(TypeAArray)t; + Type index = taa.index; + + Expression e2 = index.toExpression(); + if (e2) + { + arguments = new Expressions(); + arguments.push(cast(void*)e2); + t = new TypeDArray(taa.next); + } + else + { + error("need size of rightmost array, not type %s", index.toChars()); + return new NullExp(loc); + } + } + else if (t.ty == Tsarray) + { + TypeSArray tsa = cast(TypeSArray)t; + Expression ee = tsa.dim; + + arguments = new Expressions(); + arguments.push(cast(void*)ee); + t = new TypeDArray(tsa.next); + } + else if (token.value == TOKlparen) + { + arguments = parseArguments(); + } + + e = new NewExp(loc, thisexp, newargs, t, arguments); + return e; + } + + void addComment(Dsymbol s, ubyte* blockComment) + { + s.addComment(combineComments(blockComment, token.lineComment)); + token.lineComment = null; + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/PeelStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/PeelStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,22 @@ +module dmd.PeelStatement; + +import dmd.Statement; +import dmd.Scope; +import dmd.Loc; + +class PeelStatement : Statement +{ + Statement s; + + this(Statement s) + { + assert(false); + super(Loc(0)); + } + + Statement semantic(Scope sc) + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/Port.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Port.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,22 @@ +module dmd.Port; + +import core.stdc.math; + +struct Port +{ + static int isSignallingNan(double r) + { + /* A signalling NaN is a NaN with 0 as the most significant bit of + * its significand, which is bit 51 of 0..63 for 64 bit doubles. + */ + return isnan(r) && !(((cast(ubyte*)&r)[6]) & 8); + } + + static int isSignallingNan(ref real r) + { + /* A signalling NaN is a NaN with 0 as the most significant bit of + * its significand, which is bit 62 of 0..79 for 80 bit reals. + */ + return isnan(r) && !(((cast(ubyte*)&r)[7]) & 0x40); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/PostBlitDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/PostBlitDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,67 @@ +module dmd.PostBlitDeclaration; + +import dmd.FuncDeclaration; +import dmd.Loc; +import dmd.Identifier; +import dmd.Dsymbol; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.STC; + +class PostBlitDeclaration : FuncDeclaration +{ + this(Loc loc, Loc endloc) + { + assert(false); + super(loc, loc, null, STC.init, null); + } + + this(Loc loc, Loc endloc, Identifier id) + { + assert(false); + super(loc, loc, null, STC.init, null); + } + + Dsymbol syntaxCopy(Dsymbol) + { + assert(false); + } + + void semantic(Scope sc) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + bool isVirtual() + { + assert(false); + } + + bool addPreInvariant() + { + assert(false); + } + + bool addPostInvariant() + { + assert(false); + } + + bool overloadInsert(Dsymbol s) + { + assert(false); + } + + void emitComment(Scope sc) + { + assert(false); + } + + PostBlitDeclaration isPostBlitDeclaration() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/PostExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/PostExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,83 @@ +module dmd.PostExp; + +import dmd.Expression; +import dmd.Identifier; +import dmd.backend.elem; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.IRState; +import dmd.BinExp; +import dmd.HdrGenState; +import dmd.IntegerExp; +import dmd.TOK; +import dmd.Type; +import dmd.TY; +import dmd.Id; + +import dmd.backend.Util; +import dmd.backend.OPER; + +class PostExp : BinExp +{ + this(TOK op, Loc loc, Expression e) + { + super(loc, op, PostExp.sizeof, e, new IntegerExp(loc, 1, Type.tint32)); + } + + Expression semantic(Scope sc) + { + Expression e = this; + + if (!type) + { + BinExp.semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + e = this; + e1 = e1.modifiableLvalue(sc, e1); + e1.checkScalar(); + e1.checkNoBool(); + if (e1.type.ty == Tpointer) + e = scaleFactor(sc); + else + e2 = e2.castTo(sc, e1.type); + e.type = e1.type; + } + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + Identifier opId() + { + return (op == TOKplusplus) ? Id.postinc : Id.postdec; + } + + elem* toElem(IRState* irs) + { + elem* e; + elem* einc; + + e = e1.toElem(irs); + einc = e2.toElem(irs); + e = el_bin((op == TOKplusplus) ? OPpostinc : OPpostdec, + e.Ety,e,einc); + el_setLoc(e,loc); + return e; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/PragmaDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/PragmaDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,287 @@ +module dmd.PragmaDeclaration; + +import dmd.ArrayTypes; +import dmd.AttribDeclaration; +import dmd.Loc; +import dmd.Identifier; +import dmd.StringExp; +import dmd.TOK; +import dmd.WANT; +import dmd.Global; +import dmd.Id; +import dmd.Array; +import dmd.Dsymbol; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Expression; +import dmd.FuncDeclaration; + +import dmd.backend.Util; +import dmd.backend.Symbol; + +class PragmaDeclaration : AttribDeclaration +{ + Expressions args; // array of Expression's + + this(Loc loc, Identifier ident, Expressions args, Array decl) + { + super(decl); + this.loc = loc; + this.ident = ident; + this.args = args; + } + + Dsymbol syntaxCopy(Dsymbol s) + { + //printf("PragmaDeclaration.syntaxCopy(%s)\n", toChars()); + PragmaDeclaration pd; + + assert(!s); + pd = new PragmaDeclaration(loc, ident, Expression.arraySyntaxCopy(args), Dsymbol.arraySyntaxCopy(decl)); + return pd; + } + + void semantic(Scope sc) + { + // Should be merged with PragmaStatement + + //printf("\tPragmaDeclaration.semantic '%s'\n",toChars()); + if (ident == Id.msg) + { + if (args) + { + for (size_t i = 0; i < args.dim; i++) + { + Expression e = cast(Expression)args.data[i]; + + e = e.semantic(sc); + e = e.optimize(WANTvalue | WANTinterpret); + if (e.op == TOKstring) + { + StringExp se = cast(StringExp)e; + writef("%.*s", cast(int)se.len, cast(char*)se.string_); + } + else + error("string expected for message, not '%s'", e.toChars()); + } + writef("\n"); + } + goto Lnodecl; + } + else if (ident == Id.lib) + { + if (!args || args.dim != 1) + error("string expected for library name"); + else + { + Expression e = cast(Expression)args.data[0]; + + e = e.semantic(sc); + e = e.optimize(WANTvalue | WANTinterpret); + args.data[0] = cast(void*)e; + if (e.op != TOKstring) + error("string expected for library name, not '%s'", e.toChars()); + else if (global.params.verbose) + { + StringExp se = cast(StringExp)e; + writef("library %.*s\n", cast(int)se.len, cast(char*)se.string_); + } + } + goto Lnodecl; + } +/// version (IN_GCC) { +/// else if (ident == Id.GNU_asm) +/// { +/// if (! args || args.dim != 2) +/// error("identifier and string expected for asm name"); +/// else +/// { +/// Expression *e; +/// Declaration *d = null; +/// StringExp *s = null; +/// +/// e = (Expression *)args.data[0]; +/// e = e.semantic(sc); +/// if (e.op == TOKvar) +/// { +/// d = ((VarExp *)e).var; +/// if (! d.isFuncDeclaration() && ! d.isVarDeclaration()) +/// d = null; +/// } +/// if (!d) +/// error("first argument of GNU_asm must be a function or variable declaration"); +/// +/// e = (Expression *)args.data[1]; +/// e = e.semantic(sc); +/// e = e.optimize(WANTvalue); +/// if (e.op == TOKstring && ((StringExp *)e).sz == 1) +/// s = ((StringExp *)e); +/// else +/// error("second argument of GNU_asm must be a char string"); +/// +/// if (d && s) +/// d.c_ident = Lexer.idPool((char*) s.string); +/// } +/// goto Lnodecl; +/// } +/// } + else if (ident == Id.startaddress) + { + if (!args || args.dim != 1) + error("function name expected for start address"); + else + { + Expression e = cast(Expression)args.data[0]; + e = e.semantic(sc); + e = e.optimize(WANTvalue | WANTinterpret); + args.data[0] = cast(void*)e; + Dsymbol sa = getDsymbol(e); + if (!sa || !sa.isFuncDeclaration()) + error("function name expected for start address, not '%s'", e.toChars()); + } + goto Lnodecl; + } +/// version (TARGET_NET) { +/// else if (ident == Lexer.idPool("assembly")) +/// { +/// } +/// } // TARGET_NET + else if (global.params.ignoreUnsupportedPragmas) + { + if (global.params.verbose) + { + /* Print unrecognized pragmas + */ + writef("pragma %s", ident.toChars()); + if (args) + { + for (size_t i = 0; i < args.dim; i++) + { + Expression e = cast(Expression)args.data[i]; + e = e.semantic(sc); + e = e.optimize(WANTvalue | WANTinterpret); + if (i == 0) + writef(" ("); + else + writef(","); + writef("%s", e.toChars()); + } + if (args.dim) + writef(")"); + } + writef("\n"); + } + goto Lnodecl; + } + else + error("unrecognized pragma(%s)", ident.toChars()); + + if (decl) + { + for (uint i = 0; i < decl.dim; i++) + { + Dsymbol s = cast(Dsymbol)decl.data[i]; + s.semantic(sc); + } + } + return; + + Lnodecl: + if (decl) + error("pragma is missing closing ';'"); + } + + void setScope(Scope sc) + { +version (TARGET_NET) { + if (ident == Lexer.idPool("assembly")) + { + if (!args || args.dim != 1) + { + error("pragma has invalid number of arguments"); + } + else + { + Expression e = cast(Expression)args.data[0]; + e = e.semantic(sc); + e = e.optimize(WANTvalue | WANTinterpret); + args.data[0] = cast(void*)e; + if (e.op != TOKstring) + { + error("string expected, not '%s'", e.toChars()); + } + PragmaScope pragma_ = new PragmaScope(this, sc.parent, cast(StringExp)e); + + assert(sc); + pragma_.setScope(sc); + + //add to module members + assert(sc.module_); + assert(sc.module_.members); + sc.module_.members.push(cast(void*)pragma_); + } + } +} + } + + bool oneMember(Dsymbol* ps) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + string kind() + { + assert(false); + } + + void toObjFile(int multiobj) // compile to .obj file + { + if (ident == Id.lib) + { + assert(args && args.dim == 1); + + Expression e = cast(Expression)args.data[0]; + + assert(e.op == TOKstring); + + StringExp se = cast(StringExp)e; + char* name = cast(char*)malloc(se.len + 1); + memcpy(name, se.string_, se.len); + name[se.len] = 0; + version (OMFOBJ) { + /* The OMF format allows library names to be inserted + * into the object file. The linker will then automatically + * search that library, too. + */ + obj_includelib(name); + } else version (ELFOBJ_OR_MACHOBJ) { + /* The format does not allow embedded library names, + * so instead append the library name to the list to be passed + * to the linker. + */ + global.params.libfiles.push(cast(void*) name); + } else { + error("pragma lib not supported"); + } + } +/// version (DMDV2) { + else if (ident == Id.startaddress) + { + assert(args && args.dim == 1); + Expression e = cast(Expression)args.data[0]; + Dsymbol sa = getDsymbol(e); + FuncDeclaration f = sa.isFuncDeclaration(); + assert(f); + Symbol* s = f.toSymbol(); + obj_startaddress(s); + } +/// } + AttribDeclaration.toObjFile(multiobj); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/PragmaStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/PragmaStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,55 @@ +module dmd.PragmaStatement; + +import dmd.Statement; +import dmd.Identifier; +import dmd.ArrayTypes; +import dmd.Loc; +import dmd.Identifier; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.IRState; +import dmd.BE; + +class PragmaStatement : Statement +{ + Identifier ident; + Expressions args; // array of Expression's + Statement body_; + + this(Loc loc, Identifier ident, Expressions args, Statement body_) + { + assert(false); + super(loc); + } + + Statement syntaxCopy() + { + assert(false); + } + + Statement semantic(Scope sc) + { + assert(false); + } + + bool usesEH() + { + assert(false); + } + + BE blockExit() + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + void toIR(IRState* irs) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ProtDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ProtDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,53 @@ +module dmd.ProtDeclaration; + +import dmd.AttribDeclaration; +import dmd.PROT; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Scope; +import dmd.Dsymbol; +import dmd.Array; + +class ProtDeclaration : AttribDeclaration +{ + PROT protection; + + this(PROT p, Array decl) + { + super(decl); + + protection = p; + //printf("decl = %p\n", decl); + } + + Dsymbol syntaxCopy(Dsymbol s) + { + assert(false); + } + + void setScope(Scope sc) + { + if (decl) + { + setScopeNewSc(sc, sc.stc, sc.linkage, protection, 1, sc.structalign); + } + } + + void semantic(Scope sc) + { + if (decl) + { + semanticNewSc(sc, sc.stc, sc.linkage, protection, 1, sc.structalign); + } + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + static void protectionToCBuffer(OutBuffer buf, PROT protection) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/PtrExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/PtrExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,193 @@ +module dmd.PtrExp; + +import dmd.Expression; +import dmd.Identifier; +import dmd.backend.elem; +import dmd.UnaExp; +import dmd.InterState; +import dmd.Type; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.IRState; +import dmd.HdrGenState; +import dmd.TOK; +import dmd.GlobalExpressions; +import dmd.SymOffExp; +import dmd.AddrExp; +import dmd.VarDeclaration; +import dmd.StructLiteralExp; +import dmd.TypePointer; +import dmd.TypeArray; +import dmd.ErrorExp; +import dmd.TY; +import dmd.expression.Ptr; +import dmd.expression.Util; + +import dmd.backend.Util; +import dmd.backend.TYM; +import dmd.backend.mTY; +import dmd.backend.OPER; + +class PtrExp : UnaExp +{ + this(Loc loc, Expression e) + { + super(loc, TOK.TOKstar, PtrExp.sizeof, e); + // if (e.type) + // type = ((TypePointer *)e.type).next; + } + + this(Loc loc, Expression e, Type t) + { + super(loc, TOKstar, PtrExp.sizeof, e); + type = t; + } + + Expression semantic(Scope sc) + { + version (LOGSEMANTIC) { + printf("PtrExp::semantic('%s')\n", toChars()); + } + if (!type) + { + UnaExp.semantic(sc); + e1 = resolveProperties(sc, e1); + if (!e1.type) + writef("PtrExp.semantic('%s')\n", toChars()); + Expression e = op_overload(sc); + if (e) + return e; + Type tb = e1.type.toBasetype(); + switch (tb.ty) + { + case Tpointer: + type = (cast(TypePointer)tb).next; + break; + + case Tsarray: + case Tarray: + type = (cast(TypeArray)tb).next; + e1 = e1.castTo(sc, type.pointerTo()); + break; + + default: + error("can only * a pointer, not a '%s'", e1.type.toChars()); + return new ErrorExp(); + } + rvalue(); + } + return this; + } + + int isLvalue() + { + assert(false); + } + + Expression toLvalue(Scope sc, Expression e) + { +static if (false) { + tym = tybasic(e1.ET.Tty); + if (!(tyscalar(tym) || + tym == TYstruct || + tym == TYarray && e.Eoper == TOKaddr) + ) + synerr(EM_lvalue); // lvalue expected +} + return this; + } + +version (DMDV2) { + Expression modifiableLvalue(Scope sc, Expression e) + { + //printf("PtrExp.modifiableLvalue() %s, type %s\n", toChars(), type.toChars()); + + if (e1.op == TOKsymoff) + { + SymOffExp se = cast(SymOffExp)e1; + se.var.checkModify(loc, sc, type); + //return toLvalue(sc, e); + } + + return Expression.modifiableLvalue(sc, e); + } +} + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + elem* toElem(IRState* irs) + { + elem* e; + + //printf("PtrExp::toElem() %s\n", toChars()); + e = e1.toElem(irs); + e = el_una(OPER.OPind, type.totym(), e); + + if (tybasic(e.Ety) == TYM.TYstruct) + { + e.Enumbytes = cast(uint)type.size(); + } + + el_setLoc(e,loc); + return e; + } + + Expression optimize(int result) + { + //printf("PtrExp.optimize(result = x%x) %s\n", result, toChars()); + e1 = e1.optimize(result); + // Convert *&ex to ex + if (e1.op == TOK.TOKaddress) + { + Expression e; + Expression ex; + + ex = (cast(AddrExp)e1).e1; + if (type.equals(ex.type)) + e = ex; + else + { + e = ex.copy(); + e.type = type; + } + return e; + } + // Constant fold *(&structliteral + offset) + if (e1.op == TOK.TOKadd) + { + Expression e; + e = Ptr(type, e1); + if (e !is EXP_CANT_INTERPRET) + return e; + } + + if (e1.op == TOK.TOKsymoff) + { + SymOffExp se = cast(SymOffExp)e1; + VarDeclaration v = se.var.isVarDeclaration(); + Expression e = expandVar(result, v); + if (e && e.op == TOK.TOKstructliteral) + { + StructLiteralExp sle = cast(StructLiteralExp)e; + e = sle.getField(type, se.offset); + if (e && e !is EXP_CANT_INTERPRET) + return e; + } + } + return this; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + Identifier opId() + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/RET.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/RET.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,7 @@ +module dmd.RET; + +enum RET +{ + RETregs = 1, // returned in registers + RETstack = 2, // returned on stack +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/RealExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/RealExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,207 @@ +module dmd.RealExp; + +import dmd.Expression; +import dmd.backend.elem; +import dmd.InterState; +import dmd.Type; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.TOK; +import dmd.Scope; +import dmd.IRState; +import dmd.Type; +import dmd.HdrGenState; +import dmd.Port; +import dmd.TY; + +import dmd.backend.dt_t; +import dmd.backend.Util; +import dmd.backend.TYM; +import dmd.backend.mTY; + +import dmd.Complex; + +class RealExp : Expression +{ + real value; + + this(Loc loc, real value, Type type) + { + super(loc, TOK.TOKfloat64, RealExp.sizeof); + //printf("RealExp.RealExp(%Lg)\n", value); + this.value = value; + this.type = type; + } + + int equals(Object o) + { + assert(false); + } + + Expression semantic(Scope sc) + { + if (!type) + type = Type.tfloat64; + else + type = type.semantic(loc, sc); + return this; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + string toChars() + { + assert(false); + } + + ulong toInteger() + { + assert(false); + } + + ulong toUInteger() + { + assert(false); + } + + real toReal() + { + return type.isreal() ? value : 0; + } + + real toImaginary() + { + return type.isreal() ? 0 : value; + } + + Complex!(real) toComplex() + { + return Complex!(real)(toReal(), toImaginary()); + } + + Expression castTo(Scope sc, Type t) + { + Expression e = this; + if (type != t) + { + if ((type.isreal() && t.isreal()) || + (type.isimaginary() && t.isimaginary()) + ) + { + e = copy(); + e.type = t; + } + else + e = Expression.castTo(sc, t); + } + return e; + } + + int isConst() + { + return 1; + } + + bool isBool(bool result) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + void toMangleBuffer(OutBuffer buf) + { + assert(false); + } + + elem* toElem(IRState* irs) + { + eve c; + tym_t ty; + + //printf("RealExp.toElem(%p) %s\n", this, toChars()); + ///memset(&c, 0, sizeof(c)); + ty = type.toBasetype().totym(); + switch (tybasic(ty)) + { + case TYfloat: + case TYifloat: + c.Vfloat = value; + if (Port.isSignallingNan(value)) { + std.stdio.writeln("signalling float"); + (cast(uint*)&c.Vfloat)[0] &= 0xFFBFFFFFL; + } + break; + + case TYdouble: + case TYidouble: + c.Vdouble = value; // unfortunately, this converts SNAN to QNAN + if (Port.isSignallingNan(value)) { + std.stdio.writeln("signalling double"); + // Put SNAN back + (cast(uint*)&c.Vdouble)[1] &= 0xFFF7FFFFL; + } + break; + + case TYldouble: + case TYildouble: + c.Vldouble = value; + break; + + default: + print(); + ///type.print(); + ///type.toBasetype().print(); + writef("ty = %d, tym = %x\n", type.ty, ty); + assert(0); + } + return el_const(ty, &c); + } + + static private char[6] zeropad; + + dt_t** toDt(dt_t** pdt) + { + float fvalue; + double dvalue; + real evalue; + + //printf("RealExp.toDt(%Lg)\n", value); + switch (type.toBasetype().ty) + { + case Tfloat32: + case Timaginary32: + fvalue = value; + pdt = dtnbytes(pdt,4,cast(char*)&fvalue); + break; + + case Tfloat64: + case Timaginary64: + dvalue = value; + pdt = dtnbytes(pdt,8,cast(char*)&dvalue); + break; + + case Tfloat80: + case Timaginary80: + evalue = value; + pdt = dtnbytes(pdt,REALSIZE - REALPAD,cast(char*)&evalue); + pdt = dtnbytes(pdt,REALPAD,zeropad.ptr); + assert(REALPAD <= zeropad.sizeof); + break; + + default: + writef("%s\n", toChars()); + ///type.print(); + assert(0); + break; + } + return pdt; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/RemoveExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/RemoveExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,57 @@ +module dmd.RemoveExp; + +import dmd.Expression; +import dmd.backend.elem; +import dmd.Loc; +import dmd.IRState; +import dmd.BinExp; +import dmd.TOK; +import dmd.Type; +import dmd.TypeAArray; +import dmd.TY; + +import dmd.backend.Util; +import dmd.backend.OPER; +import dmd.backend.Symbol; +import dmd.backend.TYM; +import dmd.backend.mTY; + +/* This deletes the key e1 from the associative array e2 + */ + +class RemoveExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOKremove, RemoveExp.sizeof, e1, e2); + type = Type.tvoid; + } + + elem* toElem(IRState* irs) + { + elem* e; + Type tb = e1.type.toBasetype(); + assert(tb.ty == Taarray); + TypeAArray taa = cast(TypeAArray)tb; + elem* ea = e1.toElem(irs); + elem* ekey = e2.toElem(irs); + elem* ep; + elem* keyti; + + if (tybasic(ekey.Ety) == TYstruct) + { + ekey = el_una(OPstrpar, TYstruct, ekey); + ekey.Enumbytes = ekey.E1.Enumbytes; + assert(ekey.Enumbytes); + } + + Symbol* s = taa.aaGetSymbol("Del", 0); + keyti = taa.index.getInternalTypeInfo(null).toElem(irs); + ep = el_params(ekey, keyti, ea, null); + e = el_bin(OPcall, TYnptr, el_var(s), ep); + + el_setLoc(e,loc); + return e; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/ReturnStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ReturnStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,501 @@ +module dmd.ReturnStatement; + +import dmd.Loc; +import dmd.Statement; +import dmd.GotoStatement; +import dmd.STC; +import dmd.CompoundStatement; +import dmd.Id; +import dmd.AssignExp; +import dmd.ExpStatement; +import dmd.FuncDeclaration; +import dmd.IntegerExp; +import dmd.ThisExp; +import dmd.StructDeclaration; +import dmd.TypeFunction; +import dmd.CSX; +import dmd.RET; +import dmd.TOK; +import dmd.Type; +import dmd.Expression; +import dmd.StructLiteralExp; +import dmd.TypeStruct; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.InterState; +import dmd.InlineCostState; +import dmd.InlineDoState; +import dmd.InlineScanState; +import dmd.IRState; +import dmd.TY; +import dmd.WANT; +import dmd.VarExp; +import dmd.VarDeclaration; +import dmd.BE; +import dmd.codegen.Util; + +import dmd.backend.Blockx; +import dmd.backend.elem; +import dmd.backend.TYM; +import dmd.backend.Util; +import dmd.backend.OPER; +import dmd.backend.mTY; +import dmd.backend.BC; + +class ReturnStatement : Statement +{ + Expression exp; + + this(Loc loc, Expression exp) + { + super(loc); + this.exp = exp; + } + + Statement syntaxCopy() + { + Expression e = exp ? exp.syntaxCopy() : null; + return new ReturnStatement(loc, e); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + Statement semantic(Scope sc) + { + //printf("ReturnStatement.semantic() %s\n", toChars()); + + FuncDeclaration fd = sc.parent.isFuncDeclaration(); + Scope scx = sc; + int implicit0 = 0; + + if (sc.fes) + { + // Find scope of function foreach is in + for (; 1; scx = scx.enclosing) + { + assert(scx); + if (scx.func !is fd) + { + fd = scx.func; // fd is now function enclosing foreach + break; + } + } + } + + Type tret = fd.type.nextOf(); + if (fd.tintro) { + /* We'll be implicitly casting the return expression to tintro + */ + tret = fd.tintro.nextOf(); + } + + Type tbret = null; + + if (tret) { + tbret = tret.toBasetype(); + } + + // main() returns 0, even if it returns void + if (!exp && (!tbret || tbret.ty == TY.Tvoid) && fd.isMain()) + { + implicit0 = 1; + exp = new IntegerExp(0); + } + + if (sc.incontract || scx.incontract) + error("return statements cannot be in contracts"); + + if (sc.tf || scx.tf) + error("return statements cannot be in finally, scope(exit) or scope(success) bodies"); + + if (fd.isCtorDeclaration()) + { + // Constructors implicitly do: + // return this; + if (exp && exp.op != TOK.TOKthis) { + error("cannot return expression from constructor"); + } + + exp = new ThisExp(Loc(0)); + } + + if (!exp) { + fd.nrvo_can = 0; + } + + if (exp) + { + fd.hasReturnExp |= 1; + + exp = exp.semantic(sc); + exp = resolveProperties(sc, exp); + exp = exp.optimize(WANT.WANTvalue); + + if (fd.nrvo_can && exp.op == TOK.TOKvar) { + VarExp ve = cast(VarExp)exp; + VarDeclaration v = ve.var.isVarDeclaration(); + + if ((cast(TypeFunction)fd.type).isref) { + // Function returns a reference + fd.nrvo_can = 0; + } else if (!v || v.isOut() || v.isRef()) { + fd.nrvo_can = 0; + } else if (tbret.ty == TY.Tstruct && (cast(TypeStruct)tbret).sym.dtor) { + // Struct being returned has destructors + fd.nrvo_can = 0; + } else if (fd.nrvo_var is null) { + if (!v.isDataseg() && !v.isParameter() && v.toParent2() == fd) { + //printf("Setting nrvo to %s\n", v.toChars()); + fd.nrvo_var = v; + } else { + fd.nrvo_can = 0; + } + } else if (fd.nrvo_var != v) { + fd.nrvo_can = 0; + } + } else { + fd.nrvo_can = 0; + } + + if (fd.returnLabel && tbret.ty != TY.Tvoid) { + ; + } else if (fd.inferRetType) { + if (fd.type.nextOf()) { + if (!exp.type.equals(fd.type.nextOf())) + error("mismatched function return type inference of %s and %s", exp.type.toChars(), fd.type.nextOf().toChars()); + } + else + { + (cast(TypeFunction)fd.type).next = exp.type; + fd.type = fd.type.semantic(loc, sc); + if (!fd.tintro) + { + tret = fd.type.nextOf(); + tbret = tret.toBasetype(); + } + } + } else if (tbret.ty != TY.Tvoid) + { + exp = exp.implicitCastTo(sc, tret); + exp = exp.optimize(WANT.WANTvalue); + } + } else if (fd.inferRetType) { + if (fd.type.nextOf()) + { + if (fd.type.nextOf().ty != TY.Tvoid) { + error("mismatched function return type inference of void and %s", fd.type.nextOf().toChars()); + } + } + else + { + (cast(TypeFunction*)fd.type).next = Type.tvoid; + fd.type = fd.type.semantic(loc, sc); + if (!fd.tintro) + { + tret = Type.tvoid; + tbret = tret; + } + } + } + else if (tbret.ty != TY.Tvoid) {// if non-void return + error("return expression expected"); + } + + if (sc.fes) + { + Statement s; + + if (exp && !implicit0) + { + exp = exp.implicitCastTo(sc, tret); + } + if (!exp || exp.op == TOK.TOKint64 || exp.op == TOK.TOKfloat64 || + exp.op == TOK.TOKimaginary80 || exp.op == TOK.TOKcomplex80 || + exp.op == TOK.TOKthis || exp.op == TOK.TOKsuper || exp.op == TOK.TOKnull || + exp.op == TOK.TOKstring) + { + sc.fes.cases.push(cast(void*)this); + // Construct: return cases.dim+1; + s = new ReturnStatement(Loc(0), new IntegerExp(sc.fes.cases.dim + 1)); + } + else if (fd.type.nextOf().toBasetype() == Type.tvoid) + { + s = new ReturnStatement(Loc(0), null); + sc.fes.cases.push(cast(void*)s); + + // Construct: { exp; return cases.dim + 1; } + Statement s1 = new ExpStatement(loc, exp); + Statement s2 = new ReturnStatement(Loc(0), new IntegerExp(sc.fes.cases.dim + 1)); + s = new CompoundStatement(loc, s1, s2); + } + else + { + // Construct: return vresult; + if (!fd.vresult) + { + // Declare vresult + VarDeclaration v = new VarDeclaration(loc, tret, Id.result, null); + v.noauto = true; + v.semantic(scx); + if (!scx.insert(v)) { + assert(0); + } + v.parent = fd; + fd.vresult = v; + } + + s = new ReturnStatement(Loc(0), new VarExp(Loc(0), fd.vresult)); + sc.fes.cases.push(cast(void*)s); + + // Construct: { vresult = exp; return cases.dim + 1; } + exp = new AssignExp(loc, new VarExp(Loc(0), fd.vresult), exp); + exp.op = TOK.TOKconstruct; + exp = exp.semantic(sc); + Statement s1 = new ExpStatement(loc, exp); + Statement s2 = new ReturnStatement(Loc(0), new IntegerExp(sc.fes.cases.dim + 1)); + s = new CompoundStatement(loc, s1, s2); + } + return s; + } + + if (exp) + { + if (fd.returnLabel && tbret.ty != TY.Tvoid) + { + assert(fd.vresult); + VarExp v = new VarExp(Loc(0), fd.vresult); + + exp = new AssignExp(loc, v, exp); + exp.op = TOK.TOKconstruct; + exp = exp.semantic(sc); + } + + if ((cast(TypeFunction)fd.type).isref && !fd.isCtorDeclaration()) + { // Function returns a reference + if (tbret.isMutable()) + exp = exp.modifiableLvalue(sc, exp); + else + exp = exp.toLvalue(sc, exp); + + if (exp.op == TOK.TOKvar) + { + VarExp ve = cast(VarExp)exp; + VarDeclaration v = ve.var.isVarDeclaration(); + if (v && !v.isDataseg() && !(v.storage_class & (STC.STCref | STC.STCout))) { + error("escaping reference to local variable %s", v.toChars()); + } + } + } + + //exp.dump(0); + //exp.print(); + exp.checkEscape(); + } + + /* BUG: need to issue an error on: + * this + * { if (x) return; + * super(); + * } + */ + + if (sc.callSuper & CSX.CSXany_ctor && !(sc.callSuper & (CSX.CSXthis_ctor | CSX.CSXsuper_ctor))) { + error("return without calling constructor"); + } + + sc.callSuper |= CSX.CSXreturn; + + // See if all returns are instead to be replaced with a goto returnLabel; + if (fd.returnLabel) + { + GotoStatement gs = new GotoStatement(loc, Id.returnLabel); + + gs.label = fd.returnLabel; + if (exp) + { + /* Replace: return exp; + * with: exp; goto returnLabel; + */ + Statement s = new ExpStatement(Loc(0), exp); + return new CompoundStatement(loc, s, gs); + } + return gs; + } + + if (exp && tbret.ty == TY.Tvoid && !fd.isMain()) + { + /* Replace: + * return exp; + * with: + * exp; return; + */ + Statement s = new ExpStatement(loc, exp); + loc = Loc(0); + exp = null; + return new CompoundStatement(loc, s, this); + } + + return this; + } + + BE blockExit() + { + BE result = BE.BEreturn; + if (exp && exp.canThrow()) + result |= BE.BEthrow; + + return result; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + int inlineCost(InlineCostState* ics) + { + // Can't handle return statements nested in if's + if (ics.nested) + return COST_MAX; + return exp ? exp.inlineCost(ics) : 0; + } + + Expression doInline(InlineDoState ids) + { + //printf("ReturnStatement.doInline() '%s'\n", exp ? exp.toChars() : ""); + return exp ? exp.doInline(ids) : null; + } + + Statement inlineScan(InlineScanState* iss) + { + //printf("ReturnStatement.inlineScan()\n"); + if (exp) + { + exp = exp.inlineScan(iss); + } + return this; + } + + void toIR(IRState* irs) + { + Blockx* blx = irs.blx; + + incUsage(irs, loc); + if (exp) + { + elem *e; + + FuncDeclaration func = irs.getFunc(); + assert(func); + assert(func.type.ty == TY.Tfunction); + TypeFunction tf = cast(TypeFunction)(func.type); + + RET retmethod = tf.retStyle(); + if (retmethod == RET.RETstack) + { + elem* es; + + /* If returning struct literal, write result + * directly into return value + */ + if (exp.op == TOK.TOKstructliteral) + { + assert(false); + /* + StructLiteralExp se = cast(StructLiteralExp)exp; + char save[(StructLiteralExp).sizeof]; + memcpy(save, se, sizeof(StructLiteralExp)); + se.sym = irs.shidden; + se.soffset = 0; + se.fillHoles = 1; + e = exp.toElem(irs); + memcpy(se, save, sizeof(StructLiteralExp)); + */ + } + else + e = exp.toElem(irs); + + assert(e); + + if (exp.op == TOK.TOKstructliteral || (func.nrvo_can && func.nrvo_var)) + { + // Return value via hidden pointer passed as parameter + // Write exp; return shidden; + es = e; + } + else + { + // Return value via hidden pointer passed as parameter + // Write *shidden=exp; return shidden; + int op; + tym_t ety; + + ety = e.Ety; + es = el_una(OPER.OPind,ety,el_var(irs.shidden)); + op = (tybasic(ety) == TYM.TYstruct) ? OPER.OPstreq : OPER.OPeq; + es = el_bin(op, ety, es, e); + if (op == OPER.OPstreq) + es.Enumbytes = cast(uint)exp.type.size(); +version (DMDV2) { + /* Call postBlit() on *shidden + */ + Type tb = exp.type.toBasetype(); + //if (tb.ty == TY.Tstruct) exp.dump(0); + if ((exp.op == TOK.TOKvar || exp.op == TOK.TOKdotvar || exp.op == TOK.TOKstar) && + tb.ty == TY.Tstruct) + { StructDeclaration sd = (cast(TypeStruct)tb).sym; + if (sd.postblit) + { + FuncDeclaration fd = sd.postblit; + elem* ec = el_var(irs.shidden); + ec = callfunc(loc, irs, 1, Type.tvoid, ec, tb.pointerTo(), fd, fd.type, null, null); + es = el_bin(OPER.OPcomma, ec.Ety, es, ec); + } + +static if (false) { + /* It has been moved, so disable destructor + */ + if (exp.op == TOK.TOKvar) + { + VarExp ve = cast(VarExp)exp; + VarDeclaration v = ve.var.isVarDeclaration(); + if (v && v.rundtor) + { + elem* er = el_var(v.rundtor.toSymbol()); + er = el_bin(OPER.OPeq, TYM.TYint, er, el_long(TYM.TYint, 0)); + es = el_bin(OPER.OPcomma, TYM.TYint, es, er); + } + } +} + } +} + } + e = el_var(irs.shidden); + e = el_bin(OPER.OPcomma, e.Ety, es, e); + } +///version (DMDV2) { + else if (tf.isref) + { // Reference return, so convert to a pointer + Expression ae = exp.addressOf(null); + e = ae.toElem(irs); + } +///} + else + { + e = exp.toElem(irs); + assert(e); + } + + block_appendexp(blx.curblock, e); + block_next(blx, BC.BCretexp, null); + } + else + block_next(blx, BC.BCret, null); + } + + ReturnStatement isReturnStatement() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/STC.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/STC.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,43 @@ +module dmd.STC; + +enum STC +{ + STCundefined = 0, + STCstatic = 1, + STCextern = 2, + STCconst = 4, + STCfinal = 8, + STCabstract = 0x10, + STCparameter = 0x20, + STCfield = 0x40, + STCoverride = 0x80, + STCauto = 0x100, + STCsynchronized = 0x200, + STCdeprecated = 0x400, + STCin = 0x800, // in parameter + STCout = 0x1000, // out parameter + STClazy = 0x2000, // lazy parameter + STCforeach = 0x4000, // variable for foreach loop + STCcomdat = 0x8000, // should go into COMDAT record + STCvariadic = 0x10000, // variadic function argument + STCctorinit = 0x20000, // can only be set inside constructor + STCtemplateparameter = 0x40000, // template parameter + STCscope = 0x80000, // template parameter + STCinvariant = 0x100000, + STCimmutable = 0x100000, + STCref = 0x200000, + STCinit = 0x400000, // has explicit initializer + STCmanifest = 0x800000, // manifest constant + STCnodtor = 0x1000000, // don't run destructor + STCnothrow = 0x2000000, // never throws exceptions + STCpure = 0x4000000, // pure function + STCtls = 0x8000000, // thread local + STCalias = 0x10000000, // alias parameter + STCshared = 0x20000000, // accessible from multiple threads + STCgshared = 0x40000000, // accessible from multiple threads + // but not typed as "shared" + STC_TYPECTOR = (STCconst | STCimmutable | STCshared), +} + +import dmd.EnumUtils; +mixin(BringToCurrentScope!(STC)); \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/Scope.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Scope.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,355 @@ +module dmd.Scope; + +import dmd.Module; +import dmd.ScopeDsymbol; +import dmd.FuncDeclaration; +import dmd.Id; +import dmd.Dsymbol; +import dmd.LabelStatement; +import dmd.SwitchStatement; +import dmd.TryFinallyStatement; +import dmd.TemplateInstance; +import dmd.Statement; +import dmd.ForeachStatement; +import dmd.LINK; +import dmd.PROT; +import dmd.STC; +import dmd.AnonymousAggregateDeclaration; +import dmd.AggregateDeclaration; +import dmd.ClassDeclaration; +import dmd.Identifier; +import dmd.Loc; +import dmd.OutBuffer; +import dmd.DocComment; +import dmd.DsymbolTable; +import dmd.Global; +import dmd.CSX; +import dmd.Util; + +enum SCOPE +{ + SCOPEctor = 1, // constructor type + SCOPEstaticif = 2, // inside static if + SCOPEfree = 4, // is on free list +} + +class Scope +{ + Scope enclosing; // enclosing Scope + + Module module_; // Root module + ScopeDsymbol scopesym; // current symbol + ScopeDsymbol sd; // if in static if, and declaring new symbols, + // sd gets the addMember() + FuncDeclaration func; // function we are in + Dsymbol parent; // parent to use + LabelStatement slabel; // enclosing labelled statement + SwitchStatement sw; // enclosing switch statement + TryFinallyStatement tf; // enclosing try finally statement + TemplateInstance tinst; // enclosing template instance + Statement sbreak; // enclosing statement that supports "break" + Statement scontinue; // enclosing statement that supports "continue" + ForeachStatement fes; // if nested function for ForeachStatement, this is it + uint offset; // next offset to use in aggregate + int inunion; // we're processing members of a union + int incontract; // we're inside contract code + int nofree; // set if shouldn't free it + int noctor; // set if constructor calls aren't allowed + int intypeof; // in typeof(exp) + int parameterSpecialization; // if in template parameter specialization + int noaccesscheck; // don't do access checks + int mustsemantic; // cannot defer semantic() + + uint callSuper; // primitive flow analysis for constructors +///#define CSXthis_ctor 1 // called this() +///#define CSXsuper_ctor 2 // called super() +///#define CSXthis 4 // referenced this +///#define CSXsuper 8 // referenced super +///#define CSXlabel 0x10 // seen a label +///#define CSXreturn 0x20 // seen a return statement +///#define CSXany_ctor 0x40 // either this() or super() was called + + uint structalign; // alignment for struct members + LINK linkage = LINK.LINKd; // linkage for external functions + + PROT protection = PROT.PROTpublic; // protection for class members + int explicitProtection; // set if in an explicit protection attribute + + STC stc; // storage class + + SCOPE flags; + + AnonymousAggregateDeclaration anonAgg; // for temporary analysis + + DocComment lastdc; // documentation comment for last symbol at this scope + uint lastoffset; // offset in docbuf of where to insert next dec + OutBuffer docbuf; // buffer for documentation output + + static Scope freelist; +/// static void *operator new(size_t sz); + static Scope createGlobal(Module module_) + { + Scope sc = new Scope(); + sc.module_ = module_; + sc.scopesym = new ScopeDsymbol(); + sc.scopesym.symtab = new DsymbolTable(); + + // Add top level package as member of this global scope + Dsymbol m = module_; + while (m.parent !is null) + m = m.parent; + + m.addMember(null, sc.scopesym, 1); + m.parent = null; // got changed by addMember() + + // Create the module scope underneath the global scope + sc = sc.push(module_); + sc.parent = module_; + return sc; + } + + this() + { + // Create root scope + + //printf("Scope.Scope() %p\n", this); + this.structalign = global.structalign; + } + + this(Module module_) + { + assert(false); + } + + this(Scope enclosing) + { + //printf("Scope.Scope(enclosing = %p) %p\n", enclosing, this); + assert(!(enclosing.flags & SCOPE.SCOPEfree)); + this.module_ = enclosing.module_; + this.func = enclosing.func; + this.parent = enclosing.parent; + this.sw = enclosing.sw; + this.tf = enclosing.tf; + this.tinst = enclosing.tinst; + this.sbreak = enclosing.sbreak; + this.scontinue = enclosing.scontinue; + this.fes = enclosing.fes; + this.structalign = enclosing.structalign; + this.enclosing = enclosing; +debug { + if (enclosing.enclosing) + assert(!(enclosing.enclosing.flags & SCOPE.SCOPEfree)); + + if (this is enclosing.enclosing) /// huh? + { + writef("this = %p, enclosing = %p, enclosing.enclosing = %p\n", this, enclosing, enclosing.enclosing); + } + assert(this !is enclosing.enclosing); +} + this.linkage = enclosing.linkage; + this.protection = enclosing.protection; + this.explicitProtection = enclosing.explicitProtection; + this.stc = enclosing.stc; + this.inunion = enclosing.inunion; + this.incontract = enclosing.incontract; + this.noctor = enclosing.noctor; + this.noaccesscheck = enclosing.noaccesscheck; + this.mustsemantic = enclosing.mustsemantic; + this.intypeof = enclosing.intypeof; + this.parameterSpecialization = enclosing.parameterSpecialization; + this.callSuper = enclosing.callSuper; + this.docbuf = enclosing.docbuf; + assert(this !is enclosing); /// huh? + } + + Scope push() + { + //printf("Scope.push()\n"); + Scope s = new Scope(this); + assert(this !is s); /// huh? + return s; + } + + Scope push(ScopeDsymbol ss) + { + //printf("Scope.push(%s)\n", ss.toChars()); + Scope s = push(); + s.scopesym = ss; + return s; + } + + Scope pop() + { + //printf("Scope.pop() %p nofree = %d\n", this, nofree); + Scope enc = enclosing; + + if (enclosing) + enclosing.callSuper |= callSuper; + + if (!nofree) + { + enclosing = freelist; + freelist = this; + flags |= SCOPE.SCOPEfree; + } + + return enc; + } + + void mergeCallSuper(Loc loc, uint cs) + { + // This does a primitive flow analysis to support the restrictions + // regarding when and how constructors can appear. + // It merges the results of two paths. + // The two paths are callSuper and cs; the result is merged into callSuper. + + if (cs != callSuper) + { + int a; + int b; + + callSuper |= cs & (CSX.CSXany_ctor | CSX.CSXlabel); + if (cs & CSX.CSXreturn) + { + ; + } + else if (callSuper & CSX.CSXreturn) + { + callSuper = cs | (callSuper & (CSX.CSXany_ctor | CSX.CSXlabel)); + } + else + { + a = (cs & (CSX.CSXthis_ctor | CSX.CSXsuper_ctor)) != 0; + b = (callSuper & (CSX.CSXthis_ctor | CSX.CSXsuper_ctor)) != 0; + + if (a != b) + error(loc, "one path skips constructor"); + callSuper |= cs; + } + } + } + + Dsymbol search(Loc loc, Identifier ident, Dsymbol* pscopesym) + { + Dsymbol s; + Scope sc; + + //printf("Scope.search(%p, '%s')\n", this, ident.toChars()); + if (ident is Id.empty) + { + // Look for module scope + for (sc = this; sc; sc = sc.enclosing) + { + assert(sc != sc.enclosing); + if (sc.scopesym) + { + s = sc.scopesym.isModule(); + if (s) + { + //printf("\tfound %s.%s\n", s.parent ? s.parent.toChars() : "", s.toChars()); + if (pscopesym) + *pscopesym = sc.scopesym; + return s; + } + } + } + return null; + } + + for (sc = this; sc; sc = sc.enclosing) + { + assert(sc != sc.enclosing); + if (sc.scopesym) + { + //printf("\tlooking in scopesym '%s', kind = '%s'\n", sc.scopesym.toChars(), sc.scopesym.kind()); + s = sc.scopesym.search(loc, ident, 0); + if (s) + { + if ((global.params.warnings || + global.params.Dversion > 1) && + ident == Id.length && + sc.scopesym.isArrayScopeSymbol() && + sc.enclosing && + sc.enclosing.search(loc, ident, null)) + { + warning(s.loc, "array 'length' hides other 'length' name in outer scope"); + } + + //printf("\tfound %s.%s, kind = '%s'\n", s.parent ? s.parent.toChars() : "", s.toChars(), s.kind()); + if (pscopesym) + *pscopesym = sc.scopesym; + return s; + } + } + } + + return null; + } + + Dsymbol insert(Dsymbol s) + { + for (Scope sc = this; sc; sc = sc.enclosing) + { + //printf("\tsc = %p\n", sc); + if (sc.scopesym) + { + //printf("\t\tsc.scopesym = %p\n", sc.scopesym); + if (!sc.scopesym.symtab) + sc.scopesym.symtab = new DsymbolTable(); + + return sc.scopesym.symtab.insert(s); + } + } + + assert(false); + } + + ClassDeclaration getClassScope() + { + assert(false); + } + + /******************************************** + * Search enclosing scopes for ClassDeclaration. + */ + AggregateDeclaration getStructClassScope() + { + for (Scope sc = this; sc; sc = sc.enclosing) + { + AggregateDeclaration ad; + + if (sc.scopesym) + { + ad = sc.scopesym.isClassDeclaration(); + if (ad) + return ad; + else + { + ad = sc.scopesym.isStructDeclaration(); + if (ad) + return ad; + } + } + } + + return null; + } + + void setNoFree() + { + //int i = 0; + + //printf("Scope.setNoFree(this = %p)\n", this); + for (Scope sc = this; sc; sc = sc.enclosing) + { + //printf("\tsc = %p\n", sc); + sc.nofree = 1; + + assert(!(flags & SCOPE.SCOPEfree)); + //assert(sc != sc.enclosing); + //assert(!sc.enclosing || sc != sc.enclosing.enclosing); + //if (++i == 10) + //assert(0); + } + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ScopeDsymbol.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ScopeDsymbol.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,271 @@ +module dmd.ScopeDsymbol; + +import dmd.Dsymbol; +import dmd.Declaration; +import dmd.Array; +import dmd.OverloadSet; +import dmd.Import; +import dmd.DsymbolTable; +import dmd.Identifier; +import dmd.Loc; +import dmd.PROT; +import dmd.FuncDeclaration; +import dmd.Scope; +import dmd.Util; +import dmd.Id; +import dmd.expression.Util; + +import core.stdc.stdlib; + +class ScopeDsymbol : Dsymbol +{ + Array members; // all Dsymbol's in this scope + DsymbolTable symtab; // members[] sorted into table + + Array imports; // imported ScopeDsymbol's + PROT* prots; // array of PROT, one for each import + + this() + { + // do nothing + } + + this(Identifier id) + { + super(id); + } + + Dsymbol syntaxCopy(Dsymbol s) + { + assert(false); + } + + Dsymbol search(Loc loc, Identifier ident, int flags) + { + //printf("%s.ScopeDsymbol.search(ident='%s', flags=x%x)\n", toChars(), ident.toChars(), flags); + //if (strcmp(ident.toChars(),"c") == 0) *(char*)0=0; + + // Look in symbols declared in this module + Dsymbol s = symtab ? symtab.lookup(ident) : null; + + if (s) + { + //printf("\ts = '%s.%s'\n",toChars(),s.toChars()); + } + else if (imports) + { + OverloadSet a = null; + + // Look in imported modules + for (int i = 0; i < imports.dim; i++) + { + ScopeDsymbol ss = cast(ScopeDsymbol)imports.data[i]; + Dsymbol s2; + + // If private import, don't search it + if (flags & 1 && prots[i] == PROT.PROTprivate) + continue; + + //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss.toChars(), prots[i], ss.isModule(), ss.isImport()); + /* Don't find private members if ss is a module + */ + s2 = ss.search(loc, ident, ss.isModule() ? 1 : 0); + if (!s) + s = s2; + else if (s2 && s != s2) + { + if (s.toAlias() == s2.toAlias()) + { + /* After following aliases, we found the same symbol, + * so it's not an ambiguity. + * But if one alias is deprecated, prefer the other. + */ + if (s.isDeprecated()) + s = s2; + } + else + { + /* Two imports of the same module should be regarded as + * the same. + */ + Import i1 = s.isImport(); + Import i2 = s2.isImport(); + if (!(i1 && i2 && + (i1.mod == i2.mod || + (!i1.parent.isImport() && !i2.parent.isImport() && + i1.ident.equals(i2.ident)) + ) + ) + ) + { + /* If both s2 and s are overloadable (though we only + * need to check s once) + */ + if (s2.isOverloadable() && (a || s.isOverloadable())) + { if (!a) + a = new OverloadSet(); + /* Don't add to a[] if s2 is alias of previous sym + */ + for (int j = 0; j < a.a.dim; j++) + { + Dsymbol s3 = cast(Dsymbol)a.a.data[j]; + if (s2.toAlias() == s3.toAlias()) + { + if (s3.isDeprecated()) + a.a.data[j] = cast(void*)s2; + goto Lcontinue; + } + } + a.push(s2); + Lcontinue: + continue; + } + if (flags & 4) // if return null on ambiguity + return null; + if (!(flags & 2)) + ss.multiplyDefined(loc, s, s2); + break; + } + } + } + } + + /* Build special symbol if we had multiple finds + */ + if (a) + { + assert(s); + a.push(s); + s = a; + } + + if (s) + { + Declaration d = s.isDeclaration(); + if (d && d.protection == PROT.PROTprivate && !d.parent.isTemplateMixin() && !(flags & 2)) + error("%s is private", d.toPrettyChars()); + } + } + return s; + } + + void importScope(ScopeDsymbol s, PROT protection) + { + //printf("%s.ScopeDsymbol.importScope(%s, %d)\n", toChars(), s.toChars(), protection); + + // No circular or redundant import's + if (s != this) + { + if (!imports) + imports = new Array(); + else + { + for (int i = 0; i < imports.dim; i++) + { + ScopeDsymbol ss = cast(ScopeDsymbol)imports.data[i]; + if (ss is s) // if already imported + { + if (protection > prots[i]) + prots[i] = protection; // upgrade access + return; + } + } + } + imports.push(cast(void*)s); + prots = cast(PROT*)realloc(prots, imports.dim * prots[0].sizeof); + prots[imports.dim - 1] = protection; + } + } + + int isforwardRef() + { + assert(false); + } + + void defineRef(Dsymbol s) + { + assert(false); + } + + static void multiplyDefined(Loc loc, Dsymbol s1, Dsymbol s2) + { +static if (false) { + printf("ScopeDsymbol::multiplyDefined()\n"); + printf("s1 = %p, '%s' kind = '%s', parent = %s\n", s1, s1.toChars(), s1.kind(), s1.parent ? s1.parent.toChars() : ""); + printf("s2 = %p, '%s' kind = '%s', parent = %s\n", s2, s2.toChars(), s2.kind(), s2.parent ? s2.parent.toChars() : ""); +} + if (loc.filename) + { + .error(loc, "%s at %s conflicts with %s at %s", + s1.toPrettyChars(), + s1.locToChars(), + s2.toPrettyChars(), + s2.locToChars()); + } + else + { + s1.error(loc, "conflicts with %s %s at %s", s2.kind(), s2.toPrettyChars(), s2.locToChars()); + } + } + + Dsymbol nameCollision(Dsymbol s) + { + assert(false); + } + + string kind() + { + assert(false); + } + + /******************************************* + * Look for member of the form: + * const(MemberInfo)[] getMembers(string); + * Returns NULL if not found + */ + FuncDeclaration findGetMembers() + { + Dsymbol s = search_function(this, Id.getmembers); + FuncDeclaration fdx = s ? s.isFuncDeclaration() : null; + +static if (false) { // Finish + static __gshared TypeFunction tfgetmembers; + + if (!tfgetmembers) + { + Scope sc; + Arguments arguments = new Arguments(); + Arguments arg = new Argument(STCin, Type.tchar.constOf().arrayOf(), null, null); + arguments.push(arg); + + Type tret = null; + tfgetmembers = new TypeFunction(arguments, tret, 0, LINK.LINKd); + tfgetmembers = cast(TypeFunction)tfgetmembers.semantic(0, &sc); + } + if (fdx) + fdx = fdx.overloadExactMatch(tfgetmembers); +} + if (fdx && fdx.isVirtual()) { + fdx = null; + } + + return fdx; + } + + void emitMemberComments(Scope sc) + { + assert(false); + } + + static size_t dim(Array members) + { + assert(false); + } + + static Dsymbol getNth(Array members, size_t nth, size_t* pn = null) + { + assert(false); + } + + ScopeDsymbol isScopeDsymbol() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ScopeExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ScopeExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,110 @@ +module dmd.ScopeExp; + +import dmd.Expression; +import dmd.backend.elem; +import dmd.ScopeDsymbol; +import dmd.OutBuffer; +import dmd.TemplateInstance; +import dmd.Loc; +import dmd.TOK; +import dmd.Scope; +import dmd.IRState; +import dmd.HdrGenState; +import dmd.Global; +import dmd.Dsymbol; +import dmd.VarExp; +import dmd.DotVarExp; +import dmd.DsymbolExp; +import dmd.Type; + +class ScopeExp : Expression +{ + ScopeDsymbol sds; + + this(Loc loc, ScopeDsymbol pkg) + { + super(loc, TOK.TOKimport, ScopeExp.sizeof); + //printf("ScopeExp.ScopeExp(pkg = '%s')\n", pkg.toChars()); + //static int count; if (++count == 38) *(char*)0=0; + this.sds = pkg; + } + + Expression syntaxCopy() + { + ScopeExp se = new ScopeExp(loc, cast(ScopeDsymbol)sds.syntaxCopy(null)); + return se; + } + + Expression semantic(Scope sc) + { + TemplateInstance ti; + ScopeDsymbol sds2; + + version (LOGSEMANTIC) { + printf("+ScopeExp.semantic('%s')\n", toChars()); + } + Lagain: + ti = sds.isTemplateInstance(); + if (ti && !global.errors) + { + Dsymbol s; + if (!ti.semanticRun) + ti.semantic(sc); + s = ti.inst.toAlias(); + sds2 = s.isScopeDsymbol(); + if (!sds2) + { + Expression e; + + //printf("s = %s, '%s'\n", s.kind(), s.toChars()); + if (ti.withsym) + { + // Same as wthis.s + e = new VarExp(loc, ti.withsym.withstate.wthis); + e = new DotVarExp(loc, e, s.isDeclaration()); + } + else + e = new DsymbolExp(loc, s); + + e = e.semantic(sc); + //printf("-1ScopeExp.semantic()\n"); + return e; + } + if (sds2 != sds) + { + sds = sds2; + goto Lagain; + } + //printf("sds = %s, '%s'\n", sds.kind(), sds.toChars()); + } + else + { + //printf("sds = %s, '%s'\n", sds.kind(), sds.toChars()); + //printf("\tparent = '%s'\n", sds.parent.toChars()); + sds.semantic(sc); + } + type = Type.tvoid; + //printf("-2ScopeExp.semantic() %s\n", toChars()); + return this; + } + + elem* toElem(IRState* irs) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + if (sds.isTemplateInstance()) + { + sds.toCBuffer(buf, hgs); + } + else + { + buf.writestring(sds.kind()); + buf.writestring(" "); + buf.writestring(sds.toChars()); + } + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/ScopeStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ScopeStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,153 @@ +module dmd.ScopeStatement; + +import dmd.Statement; +import dmd.Loc; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Expression; +import dmd.InterState; +import dmd.InlineScanState; +import dmd.ScopeDsymbol; +import dmd.ArrayTypes; +import dmd.CompoundStatement; +import dmd.IRState; +import dmd.BE; + +import dmd.backend.Blockx; +import dmd.backend.BC; +import dmd.backend.Util; + +class ScopeStatement : Statement +{ + Statement statement; + + this(Loc loc, Statement s) + { + super(loc); + this.statement = s; + } + + Statement syntaxCopy() + { + Statement s = statement ? statement.syntaxCopy() : null; + s = new ScopeStatement(loc, s); + return s; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + buf.writeByte('{'); + buf.writenl(); + + if (statement) + statement.toCBuffer(buf, hgs); + + buf.writeByte('}'); + buf.writenl(); + } + + ScopeStatement isScopeStatement() { return this; } + + Statement semantic(Scope sc) + { + ScopeDsymbol sym; + + //printf("ScopeStatement.semantic(sc = %p)\n", sc); + if (statement) + { + Statements a; + + sym = new ScopeDsymbol(); + sym.parent = sc.scopesym; + sc = sc.push(sym); + + a = statement.flatten(sc); + if (a) + { + statement = new CompoundStatement(loc, a); + } + + statement = statement.semantic(sc); + if (statement) + { + Statement sentry; + Statement sexception; + Statement sfinally; + + statement.scopeCode(sc, &sentry, &sexception, &sfinally); + if (sfinally) + { + //printf("adding sfinally\n"); + statement = new CompoundStatement(loc, statement, sfinally); + } + } + + sc.pop(); + } + return this; + } + + bool hasBreak() + { + //printf("ScopeStatement.hasBreak() %s\n", toChars()); + return statement ? statement.hasBreak() : false; + } + + bool hasContinue() + { + return statement ? statement.hasContinue() : false; + } + + bool usesEH() + { + return statement ? statement.usesEH() : false; + } + + BE blockExit() + { + //printf("ScopeStatement::blockExit(%p)\n", statement); + return statement ? statement.blockExit() : BE.BEfallthru; + } + + bool comeFrom() + { + //printf("ScopeStatement.comeFrom()\n"); + return statement ? statement.comeFrom() : false; + } + + bool isEmpty() + { + //printf("ScopeStatement::isEmpty() %d\n", statement ? statement->isEmpty() : TRUE); + return statement ? statement.isEmpty() : true; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + Statement inlineScan(InlineScanState* iss) + { + if (statement) + statement = statement.inlineScan(iss); + return this; + } + + void toIR(IRState* irs) + { + if (statement) + { + Blockx* blx = irs.blx; + IRState mystate = IRState(irs,this); + + if (mystate.prev.ident) + mystate.ident = mystate.prev.ident; + + statement.toIR(&mystate); + + if (mystate.breakBlock) + block_goto(blx, BC.BCgoto, mystate.breakBlock); + } + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/Section.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Section.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,22 @@ +module dmd.Section; + +import dmd.DocComment; +import dmd.Scope; +import dmd.Dsymbol; +import dmd.OutBuffer; + +class Section +{ + ubyte* name; + uint namelen; + + ubyte* body_; + uint bodylen; + + int nooutput; + + void write(DocComment dc, Scope sc, Dsymbol s, OutBuffer buf) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ShlAssignExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ShlAssignExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,61 @@ +module dmd.ShlAssignExp; + +import dmd.BinExp; +import dmd.Loc; +import dmd.Expression; +import dmd.Scope; +import dmd.InterState; +import dmd.Identifier; +import dmd.IRState; +import dmd.TOK; +import dmd.Id; +import dmd.Type; +import dmd.backend.elem; +import dmd.backend.OPER; +import dmd.expression.Util; + +class ShlAssignExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKshlass, ShlAssignExp.sizeof, e1, e2); + } + + Expression semantic(Scope sc) + { + Expression e; + + //printf("ShlAssignExp.semantic()\n"); + BinExp.semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + e1 = e1.modifiableLvalue(sc, e1); + e1.checkScalar(); + e1.checkNoBool(); + type = e1.type; + typeCombine(sc); + e1.checkIntegral(); + e2 = e2.checkIntegral(); + e2 = e2.castTo(sc, Type.tshiftcnt); + return this; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + Identifier opId() /* For operator overloading */ + { + return Id.shlass; + } + + elem* toElem(IRState* irs) + { + return toElemBin(irs,OPshlass); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ShlExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ShlExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,82 @@ +module dmd.ShlExp; + +import dmd.Expression; +import dmd.Identifier; +import dmd.backend.elem; +import dmd.InterState; +import dmd.Loc; +import dmd.Scope; +import dmd.IntRange; +import dmd.IRState; +import dmd.BinExp; +import dmd.TOK; +import dmd.Id; +import dmd.Type; + +import dmd.expression.shift_optimize; +import dmd.expression.Shl; + +import dmd.backend.OPER; + +class ShlExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKshl, ShlExp.sizeof, e1, e2); + } + + Expression semantic(Scope sc) + { + Expression e; + + //printf("ShlExp.semantic(), type = %p\n", type); + if (!type) + { + BinExp.semanticp(sc); + e = op_overload(sc); + + if (e) + return e; + + e1 = e1.checkIntegral(); + e2 = e2.checkIntegral(); + e1 = e1.integralPromotions(sc); + e2 = e2.castTo(sc, Type.tshiftcnt); + type = e1.type; + } + + return this; + } + + Expression optimize(int result) + { + //printf("ShlExp::optimize(result = %d) %s\n", result, toChars()); + return shift_optimize(result, this, &Shl); + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + IntRange getIntRange() + { + assert(false); + } + + Identifier opId() + { + return Id.shl; + } + + Identifier opId_r() + { + return Id.shl_r; + } + + elem* toElem(IRState* irs) + { + return toElemBin(irs, OPER.OPshl); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/ShrAssignExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ShrAssignExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,63 @@ +module dmd.ShrAssignExp; + +import dmd.BinExp; +import dmd.Loc; +import dmd.Expression; +import dmd.Scope; +import dmd.InterState; +import dmd.Identifier; +import dmd.IRState; +import dmd.Id; +import dmd.TOK; +import dmd.Type; + +import dmd.backend.elem; +import dmd.backend.OPER; + +import dmd.expression.Util; + +class ShrAssignExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKshrass, ShrAssignExp.sizeof, e1, e2); + } + + Expression semantic(Scope sc) + { + Expression e; + + BinExp.semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + e1 = e1.modifiableLvalue(sc, e1); + e1.checkScalar(); + e1.checkNoBool(); + type = e1.type; + typeCombine(sc); + e1.checkIntegral(); + e2 = e2.checkIntegral(); + e2 = e2.castTo(sc, Type.tshiftcnt); + + return this; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + Identifier opId() /* For operator overloading */ + { + return Id.shrass; + } + + elem* toElem(IRState* irs) + { + return toElemBin(irs, OPshrass); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ShrExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ShrExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,80 @@ +module dmd.ShrExp; + +import dmd.Expression; +import dmd.Identifier; +import dmd.InterState; +import dmd.Loc; +import dmd.Scope; +import dmd.IntRange; +import dmd.IRState; +import dmd.BinExp; +import dmd.TOK; +import dmd.Type; +import dmd.Id; + +import dmd.backend.elem; +import dmd.backend.OPER; + +import dmd.expression.shift_optimize; +import dmd.expression.Shr; + +class ShrExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKshr, ShrExp.sizeof, e1, e2); + } + + Expression semantic(Scope sc) + { + Expression e; + + if (!type) + { + BinExp.semanticp(sc); + e = op_overload(sc); + + if (e) + return e; + + e1 = e1.checkIntegral(); + e2 = e2.checkIntegral(); + e1 = e1.integralPromotions(sc); + e2 = e2.castTo(sc, Type.tshiftcnt); + type = e1.type; + } + return this; + } + + Expression optimize(int result) + { + //printf("ShrExp::optimize(result = %d) %s\n", result, toChars()); + return shift_optimize(result, this, &Shr); + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + IntRange getIntRange() + { + assert(false); + } + + Identifier opId() + { + return Id.shr; + } + + Identifier opId_r() + { + return Id.shr_r; + } + + elem* toElem(IRState* irs) + { + return toElemBin(irs, OPER.OPshr); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/SliceExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/SliceExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,518 @@ +module dmd.SliceExp; + +import dmd.Expression; +import dmd.backend.elem; +import dmd.UnaExp; +import dmd.InterState; +import dmd.ScopeDsymbol; +import dmd.WANT; +import dmd.ArrayScopeSymbol; +import dmd.CallExp; +import dmd.DotIdExp; +import dmd.Id; +import dmd.expression.Util; +import dmd.TypeTuple; +import dmd.TupleExp; +import dmd.TypeStruct; +import dmd.TypeClass; +import dmd.TY; +import dmd.Type; +import dmd.AggregateDeclaration; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.InlineCostState; +import dmd.VarDeclaration; +import dmd.ErrorExp; +import dmd.TypeExp; +import dmd.Argument; +import dmd.ExpInitializer; +import dmd.IRState; +import dmd.InlineDoState; +import dmd.ArrayTypes; +import dmd.HdrGenState; +import dmd.InlineScanState; +import dmd.TOK; +import dmd.TypeSArray; +import dmd.GlobalExpressions; +import dmd.Global; +import dmd.PREC; + +import dmd.expression.Slice; +import dmd.expression.Util; + +import dmd.backend.Util; +import dmd.backend.Symbol; +import dmd.backend.OPER; +import dmd.backend.TYM; +import dmd.codegen.Util; + +import core.stdc.string; + +class SliceExp : UnaExp +{ + Expression upr; // null if implicit 0 + Expression lwr; // null if implicit [length - 1] + + VarDeclaration lengthVar = null; + + this(Loc loc, Expression e1, Expression lwr, Expression upr) + { + super(loc, TOK.TOKslice, SliceExp.sizeof, e1); + this.upr = upr; + this.lwr = lwr; + } + + Expression syntaxCopy() + { + assert(false); + } + + Expression semantic(Scope sc) + { + Expression e; + AggregateDeclaration ad; + //FuncDeclaration fd; + ScopeDsymbol sym; + + version (LOGSEMANTIC) { + printf("SliceExp.semantic('%s')\n", toChars()); + } + if (type) + return this; + + UnaExp.semantic(sc); + e1 = resolveProperties(sc, e1); + + e = this; + + Type t = e1.type.toBasetype(); + if (t.ty == Tpointer) + { + if (!lwr || !upr) + error("need upper and lower bound to slice pointer"); + } + else if (t.ty == Tarray) + { + } + else if (t.ty == Tsarray) + { + } + else if (t.ty == Tclass) + { + ad = (cast(TypeClass)t).sym; + goto L1; + } + else if (t.ty == Tstruct) + { + ad = (cast(TypeStruct)t).sym; + + L1: + if (search_function(ad, Id.slice)) + { + // Rewrite as e1.slice(lwr, upr) + e = new DotIdExp(loc, e1, Id.slice); + + if (lwr) + { + assert(upr); + e = new CallExp(loc, e, lwr, upr); + } + else + { + assert(!upr); + e = new CallExp(loc, e); + } + e = e.semantic(sc); + return e; + } + goto Lerror; + } + else if (t.ty == Ttuple) + { + if (!lwr && !upr) + return e1; + if (!lwr || !upr) + { error("need upper and lower bound to slice tuple"); + goto Lerror; + } + } + else + goto Lerror; + + { + Scope sc2 = sc; + if (t.ty == Tsarray || t.ty == Tarray || t.ty == Ttuple) + { + sym = new ArrayScopeSymbol(sc, this); + sym.loc = loc; + sym.parent = sc.scopesym; + sc2 = sc.push(sym); + } + + if (lwr) + { + lwr = lwr.semantic(sc2); + lwr = resolveProperties(sc2, lwr); + lwr = lwr.implicitCastTo(sc2, Type.tsize_t); + } + if (upr) + { + upr = upr.semantic(sc2); + upr = resolveProperties(sc2, upr); + upr = upr.implicitCastTo(sc2, Type.tsize_t); + } + + if (sc2 != sc) + sc2.pop(); + } + + if (t.ty == Ttuple) + { + lwr = lwr.optimize(WANTvalue); + upr = upr.optimize(WANTvalue); + ulong i1 = lwr.toUInteger(); + ulong i2 = upr.toUInteger(); + + size_t length; + TupleExp te; + TypeTuple tup; + + if (e1.op == TOKtuple) // slicing an expression tuple + { + te = cast(TupleExp)e1; + length = te.exps.dim; + } + else if (e1.op == TOKtype) // slicing a type tuple + { + tup = cast(TypeTuple)t; + length = Argument.dim(tup.arguments); + } + else + assert(0); + + if (i1 <= i2 && i2 <= length) + { + size_t j1 = cast(size_t) i1; + size_t j2 = cast(size_t) i2; + + if (e1.op == TOKtuple) + { + Expressions exps = new Expressions; + exps.setDim(j2 - j1); + for (size_t i = 0; i < j2 - j1; i++) + { + Expression e2 = cast(Expression)te.exps.data[j1 + i]; + exps.data[i] = cast(void*)e2; + } + e = new TupleExp(loc, exps); + } + else + { + Arguments args = new Arguments; + args.reserve(j2 - j1); + for (size_t i = j1; i < j2; i++) + { + Argument arg = Argument.getNth(tup.arguments, i); + args.push(cast(void*)arg); + } + e = new TypeExp(e1.loc, new TypeTuple(args)); + } + e = e.semantic(sc); + } + else + { + error("string slice [%ju .. %ju] is out of bounds", i1, i2); + e = new ErrorExp(); + } + return e; + } + + if (t.ty == Tarray) + { + type = e1.type; + } + else + type = t.nextOf().arrayOf(); + return e; + + Lerror: + string s; + if (t.ty == Tvoid) + s = e1.toChars(); + else + s = t.toChars(); + error("%s cannot be sliced with []", s); + e = new ErrorExp(); + return e; + } + + void checkEscape() + { + e1.checkEscape(); + } + +version (DMDV2) { + int isLvalue() + { + return 1; + } +} + Expression toLvalue(Scope sc, Expression e) + { + return this; + } + + Expression modifiableLvalue(Scope sc, Expression e) + { + error("slice expression %s is not a modifiable lvalue", toChars()); + return this; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + expToCBuffer(buf, hgs, e1, precedence[op]); + buf.writeByte('['); + if (upr || lwr) + { + if (lwr) + expToCBuffer(buf, hgs, lwr, PREC.PREC_assign); + else + buf.writeByte('0'); + buf.writestring(".."); + if (upr) + expToCBuffer(buf, hgs, upr, PREC.PREC_assign); + else + buf.writestring("length"); // BUG: should be array.length + } + buf.writeByte(']'); + } + + Expression optimize(int result) + { + Expression e; + + //printf("SliceExp::optimize(result = %d) %s\n", result, toChars()); + e = this; + e1 = e1.optimize(WANTvalue | (result & WANTinterpret)); + if (!lwr) + { + if (e1.op == TOKstring) + { + // Convert slice of string literal into dynamic array + Type t = e1.type.toBasetype(); + if (t.nextOf()) + e = e1.castTo(null, t.nextOf().arrayOf()); + } + return e; + } + e1 = fromConstInitializer(result, e1); + lwr = lwr.optimize(WANTvalue | (result & WANTinterpret)); + upr = upr.optimize(WANTvalue | (result & WANTinterpret)); + e = Slice(type, e1, lwr, upr); + if (e is EXP_CANT_INTERPRET) + e = this; + //printf("-SliceExp::optimize() %s\n", e->toChars()); + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void dump(int indent) + { + assert(false); + } + + elem* toElem(IRState* irs) + { + elem* e; + Type t1; + + //printf("SliceExp.toElem()\n"); + t1 = e1.type.toBasetype(); + e = e1.toElem(irs); + if (lwr) + { + elem* elwr; + elem* elwr2; + elem* eupr; + elem* eptr; + elem* einit; + int sz; + + einit = resolveLengthVar(lengthVar, &e, t1); + + sz = cast(uint)t1.nextOf().size(); + + elwr = lwr.toElem(irs); + eupr = upr.toElem(irs); + + elwr2 = el_same(&elwr); + + // Create an array reference where: + // length is (upr - lwr) + // pointer is (ptr + lwr*sz) + // Combine as (length pair ptr) + + if (global.params.useArrayBounds) + { + // Checks (unsigned compares): + // upr <= array.length + // lwr <= upr + + elem *c1; + elem *c2; + elem *ea; + elem *eb; + elem *eupr2; + elem *elength; + + if (t1.ty == Tpointer) + { + // Just do lwr <= upr check + + eupr2 = el_same(&eupr); + eupr2.Ety = TYuint; // make sure unsigned comparison + c1 = el_bin(OPle, TYint, elwr2, eupr2); + c1 = el_combine(eupr, c1); + goto L2; + } + else if (t1.ty == Tsarray) + { + TypeSArray tsa = cast(TypeSArray)t1; + ulong length = tsa.dim.toInteger(); + + elength = el_long(TYuint, length); + goto L1; + } + else if (t1.ty == Tarray) + { + if (lengthVar) + elength = el_var(lengthVar.toSymbol()); + else + { + elength = e; + e = el_same(&elength); + elength = el_una(OP64_32, TYuint, elength); + } + L1: + eupr2 = el_same(&eupr); + c1 = el_bin(OPle, TYint, eupr, elength); + eupr2.Ety = TYuint; // make sure unsigned comparison + c2 = el_bin(OPle, TYint, elwr2, eupr2); + c1 = el_bin(OPandand, TYint, c1, c2); // (c1 && c2) + + L2: + // Construct: (c1 || ModuleArray(line)) + Symbol* sassert; + + sassert = irs.blx.module_.toModuleArray(); + ea = el_bin(OPcall,TYvoid,el_var(sassert), el_long(TYint, loc.linnum)); + eb = el_bin(OPoror,TYvoid,c1,ea); + elwr = el_combine(elwr, eb); + + elwr2 = el_copytree(elwr2); + eupr = el_copytree(eupr2); + } + } + + eptr = array_toPtr(e1.type, e); + + elem *elength = el_bin(OPmin, TYint, eupr, elwr2); + eptr = el_bin(OPadd, TYnptr, eptr, el_bin(OPmul, TYint, el_copytree(elwr2), el_long(TYint, sz))); + + e = el_pair(TYullong, elength, eptr); + e = el_combine(elwr, e); + e = el_combine(einit, e); + } + else if (t1.ty == Tsarray) + { + e = sarray_toDarray(loc, t1, null, e); + } + + el_setLoc(e,loc); + return e; + } + + void scanForNestedRef(Scope sc) + { + assert(false); + } + + void buildArrayIdent(OutBuffer buf, Expressions arguments) + { + assert(false); + } + + Expression buildArrayLoop(Arguments fparams) + { + assert(false); + } + + int inlineCost(InlineCostState* ics) + { + int cost = 1 + e1.inlineCost(ics); + if (lwr) + cost += lwr.inlineCost(ics); + if (upr) + cost += upr.inlineCost(ics); + return cost; + } + + Expression doInline(InlineDoState ids) + { + SliceExp are = cast(SliceExp)copy(); + + are.e1 = e1.doInline(ids); + + if (lengthVar) + { + //printf("lengthVar\n"); + VarDeclaration vd = lengthVar; + ExpInitializer ie; + ExpInitializer ieto; + VarDeclaration vto; + + vto = new VarDeclaration(vd.loc, vd.type, vd.ident, vd.init); + ///*vto = *vd; + memcpy(cast(void*)vto, cast(void*)vd, VarDeclaration.classinfo.init.length); + + vto.parent = ids.parent; + vto.csym = null; + vto.isym = null; + + ids.from.push(cast(void*)vd); + ids.to.push(cast(void*)vto); + + if (vd.init) + { + ie = vd.init.isExpInitializer(); + assert(ie); + ieto = new ExpInitializer(ie.loc, ie.exp.doInline(ids)); + vto.init = ieto; + } + + are.lengthVar = vto; + } + + if (lwr) + are.lwr = lwr.doInline(ids); + if (upr) + are.upr = upr.doInline(ids); + return are; + } + + Expression inlineScan(InlineScanState* iss) + { + e1 = e1.inlineScan(iss); + if (lwr) + lwr = lwr.inlineScan(iss); + if (upr) + upr = upr.inlineScan(iss); + return this; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/Statement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Statement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,193 @@ +module dmd.Statement; + +import dmd.TryCatchStatement; +import dmd.GotoStatement; +import dmd.AsmStatement; +import dmd.ScopeStatement; +import dmd.DeclarationStatement; +import dmd.CompoundStatement; +import dmd.ReturnStatement; +import dmd.IfStatement; +import dmd.Scope; +import dmd.Loc; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.ArrayTypes; +import dmd.Expression; +import dmd.InterState; +import dmd.InlineCostState; +import dmd.InlineDoState; +import dmd.InlineScanState; +import dmd.IRState; +import dmd.BE; +import dmd.Global; +import dmd.Util; + +class Statement +{ + Loc loc; + + this(Loc loc) + { + this.loc = loc; + } + + Statement syntaxCopy() + { + assert(false); + } + + void print() + { + assert(false); + } + + string toChars() + { + assert(false); + } + + void error(T...)(string format, T t) + { + assert(false); + } + + void warning(T...)(string format, T t) + { + if (global.params.warnings && !global.gag) + { + writef("warning - "); + .error(loc, format, t); + } + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + TryCatchStatement isTryCatchStatement() { return null; } + + GotoStatement isGotoStatement() { return null; } + + AsmStatement isAsmStatement() { return null; } + +version (_DH) { + int incontract; +} + ScopeStatement isScopeStatement() { return null; } + + Statement semantic(Scope sc) + { + assert(false); + } + + Statement semanticScope(Scope sc, Statement sbreak, Statement scontinue) + { + Scope scd; + Statement s; + + scd = sc.push(); + if (sbreak) + scd.sbreak = sbreak; + if (scontinue) + scd.scontinue = scontinue; + s = semantic(scd); + scd.pop(); + return s; + } + + bool hasBreak() + { + assert(false); + } + + bool hasContinue() + { + assert(false); + } + + bool usesEH() + { + assert(false); + } + + BE blockExit() + { + assert(false); + } + + // true if statement 'comes from' somewhere else, like a goto + bool comeFrom() + { + //printf("Statement::comeFrom()\n"); + return false; + } + + // Return TRUE if statement has no code in it + bool isEmpty() + { + //printf("Statement::isEmpty()\n"); + return false; + } + + /**************************************** + * If this statement has code that needs to run in a finally clause + * at the end of the current scope, return that code in the form of + * a Statement. + * Output: + * *sentry code executed upon entry to the scope + * *sexception code executed upon exit from the scope via exception + * *sfinally code executed in finally block + */ + void scopeCode(Scope sc, Statement* sentry, Statement* sexception, Statement* sfinally) + { + //printf("Statement::scopeCode()\n"); + //print(); + *sentry = null; + *sexception = null; + *sfinally = null; + } + + /********************************* + * Flatten out the scope by presenting the statement + * as an array of statements. + * Returns NULL if no flattening necessary. + */ + Statements flatten(Scope sc) + { + return null; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + int inlineCost(InlineCostState* ics) + { + return COST_MAX; // default is we can't inline it + } + + Expression doInline(InlineDoState ids) + { + assert(false); + } + + Statement inlineScan(InlineScanState* iss) + { + return this; + } + + // Back end + void toIR(IRState* irs) + { + assert(false); + } + + // Avoid dynamic_cast + DeclarationStatement isDeclarationStatement() { return null; } + CompoundStatement isCompoundStatement() { return null; } + ReturnStatement isReturnStatement() { return null; } + IfStatement isIfStatement() { return null; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/StaticAssert.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/StaticAssert.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,103 @@ +module dmd.StaticAssert; + +import dmd.Dsymbol; +import dmd.Expression; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.ScopeDsymbol; +import dmd.Loc; +import dmd.Scope; +import dmd.Id; +import dmd.WANT; +import dmd.Global; +import dmd.Util; + +class StaticAssert : Dsymbol +{ + Expression exp; + Expression msg; + + this(Loc loc, Expression exp, Expression msg) + { + super(Id.empty); + + this.loc = loc; + this.exp = exp; + this.msg = msg; + } + + Dsymbol syntaxCopy(Dsymbol s) + { + assert(false); + } + + bool addMember(Scope sc, ScopeDsymbol sd, int memnum) + { + return false; // we didn't add anything + } + + void semantic(Scope sc) + { + } + + void semantic2(Scope sc) + { + Expression e; + + //printf("StaticAssert::semantic2() %s\n", toChars()); + e = exp.semantic(sc); + e = e.optimize(WANT.WANTvalue | WANT.WANTinterpret); + if (e.isBool(false)) + { + if (msg) + { + HdrGenState hgs; + scope OutBuffer buf = new OutBuffer(); + + msg = msg.semantic(sc); + msg = msg.optimize(WANT.WANTvalue | WANT.WANTinterpret); + hgs.console = 1; + msg.toCBuffer(buf, &hgs); + error("%s", buf.toChars()); + } + else + error("(%s) is false", exp.toChars()); + + if(sc.tinst) + sc.tinst.printInstantiationTrace(); + + if (!global.gag) { + fatal(); + } + } + else if (!e.isBool(true)) + { + error("(%s) is not evaluatable at compile time", exp.toChars()); + } + } + + void inlineScan() + { + assert(false); + } + + bool oneMember(Dsymbol* ps) + { + assert(false); + } + + void toObjFile(int multiobj) + { + assert(false); + } + + string kind() + { + return "static assert"; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/StaticAssertStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/StaticAssertStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,35 @@ +module dmd.StaticAssertStatement; + +import dmd.Statement; +import dmd.StaticAssert; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Scope; +import dmd.Loc; + +class StaticAssertStatement : Statement +{ + StaticAssert sa; + + this(StaticAssert sa) + { + super(sa.loc); + this.sa = sa; + } + + Statement syntaxCopy() + { + assert(false); + } + + Statement semantic(Scope sc) + { + sa.semantic2(sc); + return null; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/StaticCtorDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/StaticCtorDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,129 @@ +module dmd.StaticCtorDeclaration; + +import dmd.FuncDeclaration; +import dmd.Loc; +import dmd.Dsymbol; +import dmd.AggregateDeclaration; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.STC; +import dmd.Identifier; +import dmd.TypeFunction; +import dmd.Type; +import dmd.LINK; +import dmd.Lexer; +import dmd.VarDeclaration; +import dmd.ArrayTypes; +import dmd.Expression; +import dmd.Statement; +import dmd.DeclarationStatement; +import dmd.AddAssignExp; +import dmd.EqualExp; +import dmd.TOK; +import dmd.IfStatement; +import dmd.CompoundStatement; +import dmd.Module; +import dmd.IntegerExp; +import dmd.ReturnStatement; +import dmd.IdentifierExp; + +class StaticCtorDeclaration : FuncDeclaration +{ + this(Loc loc, Loc endloc) + { + super(loc, endloc, Identifier.generateId("_staticCtor"), STCstatic, null); + } + + Dsymbol syntaxCopy(Dsymbol) + { + assert(false); + } + + void semantic(Scope sc) + { + //printf("StaticCtorDeclaration.semantic()\n"); + + type = new TypeFunction(null, Type.tvoid, false, LINK.LINKd); + + /* If the static ctor appears within a template instantiation, + * it could get called multiple times by the module constructors + * for different modules. Thus, protect it with a gate. + */ + if (inTemplateInstance()) + { + /* Add this prefix to the function: + * static int gate; + * if (++gate != 1) return; + * Note that this is not thread safe; should not have threads + * during static construction. + */ + Identifier id = Lexer.idPool("__gate"); + VarDeclaration v = new VarDeclaration(Loc(0), Type.tint32, id, null); + v.storage_class = STCstatic; + Statements sa = new Statements(); + Statement s = new DeclarationStatement(Loc(0), v); + sa.push(cast(void*)s); + Expression e = new IdentifierExp(Loc(0), id); + e = new AddAssignExp(Loc(0), e, new IntegerExp(1)); + e = new EqualExp(TOKnotequal, Loc(0), e, new IntegerExp(1)); + s = new IfStatement(Loc(0), null, e, new ReturnStatement(Loc(0), null), null); + sa.push(cast(void*)s); + if (fbody) + sa.push(cast(void*)fbody); + fbody = new CompoundStatement(Loc(0), sa); + } + + FuncDeclaration.semantic(sc); + + // We're going to need ModuleInfo + Module m = getModule(); + if (!m) + m = sc.module_; + + if (m) + { + m.needmoduleinfo = 1; + version (IN_GCC) { + m.strictlyneedmoduleinfo = 1; + } + } + } + + AggregateDeclaration isThis() + { + return null; + } + + bool isStaticConstructor() + { + return true; + } + + bool isVirtual() + { + return false; + } + + bool addPreInvariant() + { + return false; + } + + bool addPostInvariant() + { + return false; + } + + void emitComment(Scope sc) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + StaticCtorDeclaration isStaticCtorDeclaration() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/StaticDtorDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/StaticDtorDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,138 @@ +module dmd.StaticDtorDeclaration; + +import dmd.FuncDeclaration; +import dmd.VarDeclaration; +import dmd.Dsymbol; +import dmd.Loc; +import dmd.Scope; +import dmd.AggregateDeclaration; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.STC; +import dmd.Identifier; +import dmd.ClassDeclaration; +import dmd.Type; +import dmd.TypeFunction; +import dmd.LINK; +import dmd.Lexer; +import dmd.Statement; +import dmd.Expression; +import dmd.EqualExp; +import dmd.ArrayTypes; +import dmd.DeclarationStatement; +import dmd.IdentifierExp; +import dmd.AddAssignExp; +import dmd.IntegerExp; +import dmd.TOK; +import dmd.IfStatement; +import dmd.ReturnStatement; +import dmd.CompoundStatement; +import dmd.Module; + +class StaticDtorDeclaration : FuncDeclaration +{ + VarDeclaration vgate; // 'gate' variable + + this(Loc loc, Loc endloc) + { + super(loc, endloc, Identifier.generateId("_staticDtor"), STCstatic, null); + } + + Dsymbol syntaxCopy(Dsymbol) + { + assert(false); + } + + void semantic(Scope sc) + { + ClassDeclaration cd; + Type tret; + + cd = sc.scopesym.isClassDeclaration(); + if (!cd) + { + } + type = new TypeFunction(null, Type.tvoid, false, LINK.LINKd); + + /* If the static ctor appears within a template instantiation, + * it could get called multiple times by the module constructors + * for different modules. Thus, protect it with a gate. + */ + if (inTemplateInstance()) + { + /* Add this prefix to the function: + * static int gate; + * if (--gate != 0) return; + * Increment gate during constructor execution. + * Note that this is not thread safe; should not have threads + * during static destruction. + */ + Identifier id = Lexer.idPool("__gate"); + VarDeclaration v = new VarDeclaration(Loc(0), Type.tint32, id, null); + v.storage_class = STCstatic; + Statements sa = new Statements(); + Statement s = new DeclarationStatement(Loc(0), v); + sa.push(cast(void*)s); + Expression e = new IdentifierExp(Loc(0), id); + e = new AddAssignExp(Loc(0), e, new IntegerExp(-1)); + e = new EqualExp(TOKnotequal, Loc(0), e, new IntegerExp(0)); + s = new IfStatement(Loc(0), null, e, new ReturnStatement(Loc(0), null), null); + sa.push(cast(void*)s); + if (fbody) + sa.push(cast(void*)fbody); + fbody = new CompoundStatement(Loc(0), sa); + vgate = v; + } + + FuncDeclaration.semantic(sc); + + // We're going to need ModuleInfo + Module m = getModule(); + if (!m) + m = sc.module_; + if (m) + { + m.needmoduleinfo = 1; + version (IN_GCC) { + m.strictlyneedmoduleinfo = 1; + } + } + } + + AggregateDeclaration isThis() + { + return null; + } + + bool isStaticDestructor() + { + return true; + } + + bool isVirtual() + { + return false; + } + + bool addPreInvariant() + { + return false; + } + + bool addPostInvariant() + { + return false; + } + + void emitComment(Scope sc) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + StaticDtorDeclaration isStaticDtorDeclaration() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/StaticIfCondition.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/StaticIfCondition.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,70 @@ +module dmd.StaticIfCondition; + +import dmd.Expression; +import dmd.ScopeDsymbol; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.Condition; +import dmd.HdrGenState; +import dmd.WANT; +import dmd.Util; + +class StaticIfCondition : Condition +{ + Expression exp; + + this(Loc loc, Expression exp) + { + super(loc); + this.exp = exp; + } + + Condition syntaxCopy() + { + assert(false); + } + + bool include(Scope sc, ScopeDsymbol s) + { + static if (false) { + printf("StaticIfCondition.include(sc = %p, s = %p)\n", sc, s); + if (s) + { + printf("\ts = '%s', kind = %s\n", s.toChars(), s.kind()); + } + } + if (inc == 0) + { + if (!sc) + { + error(loc, "static if conditional cannot be at global scope"); + inc = 2; + return 0; + } + + sc = sc.push(sc.scopesym); + sc.sd = s; // s gets any addMember() + sc.flags |= SCOPE.SCOPEstaticif; + Expression e = exp.semantic(sc); + sc.pop(); + e = e.optimize(WANTvalue | WANTinterpret); + if (e.isBool(true)) + inc = 1; + else if (e.isBool(false)) + inc = 2; + else + { + e.error("expression %s is not constant or does not evaluate to a bool", e.toChars()); + inc = 2; + } + } + return (inc == 1); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/StaticIfDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/StaticIfDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,78 @@ +module dmd.StaticIfDeclaration; + +import dmd.ConditionalDeclaration; +import dmd.ScopeDsymbol; +import dmd.AttribDeclaration; +import dmd.Scope; +import dmd.Condition; +import dmd.Array; +import dmd.Dsymbol; + +class StaticIfDeclaration : ConditionalDeclaration +{ + ScopeDsymbol sd; + int addisdone; + + this(Condition condition, Array decl, Array elsedecl) + { + super(condition, decl, elsedecl); + //printf("StaticIfDeclaration::StaticIfDeclaration()\n"); + } + + Dsymbol syntaxCopy(Dsymbol s) + { + assert(false); + } + + bool addMember(Scope sc, ScopeDsymbol sd, int memnum) + { + //printf("StaticIfDeclaration.addMember() '%s'\n",toChars()); + /* This is deferred until semantic(), so that + * expressions in the condition can refer to declarations + * in the same scope, such as: + * + * template Foo(int i) + * { + * const int j = i + 1; + * static if (j == 3) + * const int k; + * } + */ + this.sd = sd; + bool m = false; + + if (memnum == 0) + { + m = AttribDeclaration.addMember(sc, sd, memnum); + addisdone = 1; + } + return m; + } + + void semantic(Scope sc) + { + Array d = include(sc, sd); + + //printf("\tStaticIfDeclaration.semantic '%s', d = %p\n",toChars(), d); + if (d) + { + if (!addisdone) + { + AttribDeclaration.addMember(sc, sd, 1); + addisdone = 1; + } + + for (uint i = 0; i < d.dim; i++) + { + Dsymbol s = cast(Dsymbol)d.data[i]; + + s.semantic(sc); + } + } + } + + string kind() + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/StorageClassDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/StorageClassDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,124 @@ +module dmd.StorageClassDeclaration; + +import dmd.AttribDeclaration; +import dmd.Array; +import dmd.TOK; +import dmd.Token; +import dmd.Scope; +import dmd.Dsymbol; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.STC; + +class StorageClassDeclaration: AttribDeclaration +{ + STC stc; + + this(STC stc, Array decl) + { + super(decl); + + this.stc = stc; + } + + Dsymbol syntaxCopy(Dsymbol s) + { + assert(false); + } + + void setScope(Scope sc) + { + if (decl) + { + STC scstc = sc.stc; + + /* These sets of storage classes are mutually exclusive, + * so choose the innermost or most recent one. + */ + if (stc & (STC.STCauto | STC.STCscope | STC.STCstatic | STC.STCextern | STC.STCmanifest)) + scstc &= ~(STC.STCauto | STC.STCscope | STC.STCstatic | STC.STCextern | STC.STCmanifest); + if (stc & (STC.STCauto | STC.STCscope | STC.STCstatic | STC.STCtls | STC.STCmanifest | STC.STCgshared)) + scstc &= ~(STC.STCauto | STC.STCscope | STC.STCstatic | STC.STCtls | STC.STCmanifest | STC.STCgshared); + if (stc & (STC.STCconst | STC.STCimmutable | STC.STCmanifest)) + scstc &= ~(STC.STCconst | STC.STCimmutable | STC.STCmanifest); + if (stc & (STC.STCgshared | STC.STCshared | STC.STCtls)) + scstc &= ~(STC.STCgshared | STC.STCshared | STC.STCtls); + scstc |= stc; + + setScopeNewSc(sc, scstc, sc.linkage, sc.protection, sc.explicitProtection, sc.structalign); + } + } + + void semantic(Scope sc) + { + if (decl) + { + STC scstc = sc.stc; + + /* These sets of storage classes are mutually exclusive, + * so choose the innermost or most recent one. + */ + if (stc & (STC.STCauto | STC.STCscope | STC.STCstatic | STC.STCextern | STC.STCmanifest)) + scstc &= ~(STC.STCauto | STC.STCscope | STC.STCstatic | STC.STCextern | STC.STCmanifest); + if (stc & (STC.STCauto | STC.STCscope | STC.STCstatic | STC.STCtls | STC.STCmanifest | STC.STCgshared)) + scstc &= ~(STC.STCauto | STC.STCscope | STC.STCstatic | STC.STCtls | STC.STCmanifest | STC.STCgshared); + if (stc & (STC.STCconst | STC.STCimmutable | STC.STCmanifest)) + scstc &= ~(STC.STCconst | STC.STCimmutable | STC.STCmanifest); + if (stc & (STC.STCgshared | STC.STCshared | STC.STCtls)) + scstc &= ~(STC.STCgshared | STC.STCshared | STC.STCtls); + scstc |= stc; + + semanticNewSc(sc, scstc, sc.linkage, sc.protection, sc.explicitProtection, sc.structalign); + } + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + static void stcToCBuffer(OutBuffer buf, int stc) + { + struct SCstring + { + int stc; + TOK tok; + }; + + static SCstring[] table = + [ + { STCauto, TOKauto }, + { STCscope, TOKscope }, + { STCstatic, TOKstatic }, + { STCextern, TOKextern }, + { STCconst, TOKconst }, + { STCfinal, TOKfinal }, + { STCabstract, TOKabstract }, + { STCsynchronized, TOKsynchronized }, + { STCdeprecated, TOKdeprecated }, + { STCoverride, TOKoverride }, + { STClazy, TOKlazy }, + { STCalias, TOKalias }, + { STCout, TOKout }, + { STCin, TOKin }, +/// version (DMDV2) { +/// { STCimmutable, TOKimmutable }, +/// { STCshared, TOKshared }, +/// { STCnothrow, TOKnothrow }, +/// { STCpure, TOKpure }, +/// { STCref, TOKref }, +/// { STCtls, TOKtls }, +/// { STCgshared, TOKgshared }, +/// } + ]; + + for (int i = 0; i < table.length; i++) + { + if (stc & table[i].stc) + { + buf.writestring(Token.toChars(table[i].tok)); + buf.writeByte(' '); + } + } + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/String.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/String.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,90 @@ +module dmd.String; + +import dmd.Array; + +import core.stdc.string : strlen; +import std.string : cmp; + +import std.stdio : writefln; + +class String +{ + string str; + + this(string str) + { + this.str = str; + } + + static hash_t calcHash(const(char)* str, size_t len) + { + hash_t hash = 0; + + for (;;) + { + switch (len) + { + case 0: + return hash; + + case 1: + hash *= 37; + hash += *cast(ubyte*)str; + return hash; + + case 2: + hash *= 37; + hash += *cast(ushort*)str; + return hash; + + case 3: + hash *= 37; + hash += (*(cast(ushort*)str) << 8) + + (cast(ubyte*)str)[2]; + return hash; + + default: + hash *= 37; + hash += *cast(uint*)str; + str += 4; + len -= 4; + break; + } + } + } + + static hash_t calcHash(string str) + { + return calcHash(str.ptr, str.length); + } + + hash_t hashCode() + { + return calcHash(str.ptr, str.length); + } + + uint len() + { + return str.length; + } + + int equals(Object obj) + { + return str == (cast(String)obj).str; + } + + int compare(Object obj) + { + return cmp(str, (cast(String)obj).str); + } + + string toChars() + { + return str; + } + + void print() + { + writefln("String '%s'", str); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/StringEntry.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/StringEntry.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,22 @@ +module dmd.StringEntry; + +import dmd.StringValue; +import dmd.Dchar; +import dmd.Lstring; + +import core.stdc.stdlib; + +struct StringEntry +{ + StringEntry* left; + StringEntry* right; + hash_t hash; + + StringValue value; + + this(immutable(dchar_t)[] s) + { + hash = Dchar.calcHash(s.ptr, s.length); + value.lstring.string_ = s; + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/StringExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/StringExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,669 @@ +module dmd.StringExp; + +import dmd.Expression; +import dmd.backend.elem; +import dmd.InterState; +import dmd.TypeSArray; +import dmd.CastExp; +import dmd.MATCH; +import dmd.TY; +import dmd.TypeDArray; +import dmd.Type; +import dmd.TOK; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.IRState; +import dmd.StringExp; +import dmd.HdrGenState; +import dmd.Utf; +import dmd.backend.dt_t; +import dmd.backend.Symbol; +import dmd.backend.StringTab; +import dmd.backend.Util; +import dmd.backend.SC; +import dmd.backend.TYM; +import dmd.backend.FL; +import dmd.backend.TYPE; +import dmd.backend.OPER; + +import core.stdc.string; + +class StringExp : Expression +{ + void* string_; // char, wchar, or dchar data + size_t len; // number of chars, wchars, or dchars + ubyte sz; // 1: char, 2: wchar, 4: dchar + ubyte committed; // !=0 if type is committed + ubyte postfix; // 'c', 'w', 'd' + + this(Loc loc, string s) + { + this(loc, s, 0); + } + + this(Loc loc, string s, ubyte postfix) + { + super(loc, TOK.TOKstring, StringExp.sizeof); + + this.string_ = cast(void*)s.ptr; + this.len = s.length; + this.sz = 1; + this.committed = 0; + this.postfix = postfix; + } + + int equals(Object o) + { + assert(false); + } + + string toChars() + { + assert(false); + } + + Expression semantic(Scope sc) + { +version (LOGSEMANTIC) { + printf("StringExp.semantic() %s\n", toChars()); +} + if (!type) + { + scope OutBuffer buffer = new OutBuffer(); + size_t newlen = 0; + string p; + size_t u; + dchar c; + + switch (postfix) + { + case 'd': + for (u = 0; u < len;) + { + p = utf_decodeChar(cast(string)string_[0..len], &u, &c); + if (p !is null) + { + error("%s", p); + break; + } + else + { + buffer.write4(c); + newlen++; + } + } + buffer.write4(0); + string_ = buffer.extractData(); + len = newlen; + sz = 4; + //type = new TypeSArray(Type.tdchar, new IntegerExp(loc, len, Type.tindex)); + type = new TypeDArray(Type.tdchar.invariantOf()); + committed = 1; + break; + + case 'w': + for (u = 0; u < len;) + { + p = utf_decodeChar(cast(string)string_[0..len], &u, &c); + if (p !is null) + { + error("%s", p); + break; + } + else + { + buffer.writeUTF16(c); + newlen++; + if (c >= 0x10000) + newlen++; + } + } + buffer.writeUTF16(0); + string_ = buffer.extractData(); + len = newlen; + sz = 2; + //type = new TypeSArray(Type.twchar, new IntegerExp(loc, len, Type.tindex)); + type = new TypeDArray(Type.twchar.invariantOf()); + committed = 1; + break; + + case 'c': + committed = 1; + default: + //type = new TypeSArray(Type.tchar, new IntegerExp(loc, len, Type.tindex)); + type = new TypeDArray(Type.tchar.invariantOf()); + break; + } + type = type.semantic(loc, sc); + //type = type.invariantOf(); + //printf("type = %s\n", type.toChars()); + } + return this; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + size_t length() + { + assert(false); + } + + StringExp toUTF8(Scope sc) + { + assert(false); + } + + Expression implicitCastTo(Scope sc, Type t) + { + //printf("StringExp.implicitCastTo(%s of type %s) => %s\n", toChars(), type.toChars(), t.toChars()); + ubyte committed = this.committed; + Expression e = Expression.implicitCastTo(sc, t); + if (e.op == TOK.TOKstring) + { + // Retain polysemous nature if it started out that way + (cast(StringExp)e).committed = committed; + } + return e; + } + + MATCH implicitConvTo(Type t) + { + MATCH m; + +static if (false) { + printf("StringExp.implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n", + toChars(), committed, type.toChars(), t.toChars()); +} + if (!committed) + { + if (!committed && t.ty == TY.Tpointer && t.nextOf().ty == TY.Tvoid) + { + return MATCH.MATCHnomatch; + } + if (type.ty == TY.Tsarray || type.ty == TY.Tarray || type.ty == TY.Tpointer) + { + TY tyn = type.nextOf().ty; + if (tyn == TY.Tchar || tyn == TY.Twchar || tyn == TY.Tdchar) + { + Type tn; + MATCH mm; + + switch (t.ty) + { + case TY.Tsarray: + if (type.ty == TY.Tsarray) + { + if ((cast(TypeSArray)type).dim.toInteger() != + (cast(TypeSArray)t).dim.toInteger()) + return MATCH.MATCHnomatch; + TY tynto = t.nextOf().ty; + if (tynto == TY.Tchar || tynto == TY.Twchar || tynto == TY.Tdchar) + return MATCH.MATCHexact; + } + else if (type.ty == TY.Tarray) + { + if (length() > (cast(TypeSArray)t).dim.toInteger()) + return MATCH.MATCHnomatch; + TY tynto = t.nextOf().ty; + if (tynto == TY.Tchar || tynto == TY.Twchar || tynto == TY.Tdchar) + return MATCH.MATCHexact; + } + case TY.Tarray: + case TY.Tpointer: + tn = t.nextOf(); + mm = MATCH.MATCHexact; + if (type.nextOf().mod != tn.mod) + { + if (!tn.isConst()) + return MATCH.MATCHnomatch; + mm = MATCH.MATCHconst; + } + switch (tn.ty) + { + case TY.Tchar: + case TY.Twchar: + case TY.Tdchar: + return mm; + } + break; + default: + break; /// + } + } + } + } + return Expression.implicitConvTo(t); +static if (false) { + m = cast(MATCH)type.implicitConvTo(t); + if (m) + { + return m; + } + + return MATCH.MATCHnomatch; +} + } + + static uint X(TY tf, TY tt) { + return ((tf) * 256 + (tt)); + } + + Expression castTo(Scope sc, Type t) + { + /* This follows copy-on-write; any changes to 'this' + * will result in a copy. + * The this.string member is considered immutable. + */ + StringExp se; + Type tb; + int copied = 0; + + //printf("StringExp.castTo(t = %s), '%s' committed = %d\n", t.toChars(), toChars(), committed); + + if (!committed && t.ty == TY.Tpointer && t.nextOf().ty == TY.Tvoid) + { + error("cannot convert string literal to void*"); + } + + se = this; + if (!committed) + { + se = cast(StringExp)copy(); + se.committed = 1; + copied = 1; + } + + if (type == t) + { + return se; + } + + tb = t.toBasetype(); + //printf("\ttype = %s\n", type.toChars()); + if (tb.ty == TY.Tdelegate && type.toBasetype().ty != TY.Tdelegate) + return Expression.castTo(sc, t); + + Type typeb = type.toBasetype(); + if (typeb == tb) + { + if (!copied) + { + se = cast(StringExp)copy(); + copied = 1; + } + se.type = t; + return se; + } + + if (committed && tb.ty == TY.Tsarray && typeb.ty == TY.Tarray) + { + se = cast(StringExp)copy(); + se.sz = cast(ubyte)tb.nextOf().size(); + se.len = (len * sz) / se.sz; + se.committed = 1; + se.type = t; + return se; + } + + if (tb.ty != TY.Tsarray && tb.ty != TY.Tarray && tb.ty != TY.Tpointer) + { + if (!copied) + { + se = cast(StringExp)copy(); + copied = 1; + } + goto Lcast; + } + if (typeb.ty != TY.Tsarray && typeb.ty != TY.Tarray && typeb.ty != TY.Tpointer) + { + if (!copied) + { + se = cast(StringExp)copy(); + copied = 1; + } + goto Lcast; + } + + if (typeb.nextOf().size() == tb.nextOf().size()) + { + if (!copied) + { + se = cast(StringExp)copy(); + copied = 1; + } + + if (tb.ty == TY.Tsarray) + goto L2; // handle possible change in static array dimension + se.type = t; + return se; + } + + if (committed) + goto Lcast; + + { + scope OutBuffer buffer = new OutBuffer(); + size_t newlen = 0; + TY tfty = typeb.nextOf().toBasetype().ty; + TY ttty = tb.nextOf().toBasetype().ty; + switch (X(tfty, ttty)) + { + case X(TY.Tchar, TY.Tchar): + case X(TY.Twchar,TY.Twchar): + case X(TY.Tdchar,TY.Tdchar): + break; + + case X(TY.Tchar, TY.Twchar): + for (size_t u = 0; u < len;) + { + dchar c; + string p = utf_decodeChar(cast(string)se.string_[0..len], &u, &c); + if (p !is null) + error("%s", p); + else + buffer.writeUTF16(c); + } + newlen = buffer.offset / 2; + buffer.writeUTF16(0); + goto L1; + + case X(TY.Tchar, TY.Tdchar): + for (size_t u = 0; u < len;) + { + dchar c; + string p = utf_decodeChar(cast(string)se.string_[0..len], &u, &c); + if (p !is null) + error("%s", p); + buffer.write4(c); + newlen++; + } + buffer.write4(0); + goto L1; + + case X(TY.Twchar,TY.Tchar): + for (size_t u = 0; u < len;) + { + dchar c; + string p = utf_decodeWchar(cast(wstring)se.string_[0..len], &u, &c); + if (p) + error("%s", p); + else + buffer.writeUTF8(c); + } + newlen = buffer.offset; + buffer.writeUTF8(0); + goto L1; + + case X(TY.Twchar,TY.Tdchar): + for (size_t u = 0; u < len;) + { + dchar c; + string p = utf_decodeWchar(cast(wstring)se.string_[0..len], &u, &c); + if (p) + error("%s", p); + buffer.write4(c); + newlen++; + } + buffer.write4(0); + goto L1; + + case X(TY.Tdchar,TY.Tchar): + for (size_t u = 0; u < len; u++) + { + dchar c = (cast(dchar*)se.string_)[u]; + if (!utf_isValidDchar(c)) + error("invalid UCS-32 char \\U%08x", c); + else + buffer.writeUTF8(c); + newlen++; + } + newlen = buffer.offset; + buffer.writeUTF8(0); + goto L1; + + case X(TY.Tdchar,TY.Twchar): + for (size_t u = 0; u < len; u++) + { + dchar c = (cast(dchar*)se.string_)[u]; + if (!utf_isValidDchar(c)) + error("invalid UCS-32 char \\U%08x", c); + else + buffer.writeUTF16(c); + newlen++; + } + newlen = buffer.offset / 2; + buffer.writeUTF16(0); + goto L1; + + L1: + if (!copied) + { + se = cast(StringExp)copy(); + copied = 1; + } + se.string_ = buffer.extractData(); + se.len = newlen; + se.sz = cast(ubyte)tb.nextOf().size(); + break; + + default: + assert(typeb.nextOf().size() != tb.nextOf().size()); + goto Lcast; + } + } + L2: + assert(copied); + + // See if need to truncate or extend the literal + if (tb.ty == TY.Tsarray) + { + int dim2 = cast(int)(cast(TypeSArray)tb).dim.toInteger(); + + //printf("dim from = %d, to = %d\n", se.len, dim2); + + // Changing dimensions + if (dim2 != se.len) + { + // Copy when changing the string literal + uint newsz = se.sz; + void *s; + int d; + + d = (dim2 < se.len) ? dim2 : se.len; + s = cast(ubyte*)malloc((dim2 + 1) * newsz); + memcpy(s, se.string_, d * newsz); + // Extend with 0, add terminating 0 + memset(cast(char*)s + d * newsz, 0, (dim2 + 1 - d) * newsz); + se.string_ = s; + se.len = dim2; + } + } + se.type = t; + return se; + + Lcast: + Expression e = new CastExp(loc, se, t); + e.type = t; // so semantic() won't be run on e + return e; + } + + int compare(Object obj) + { + assert(false); + } + + bool isBool(bool result) + { + assert(false); + } + + uint charAt(size_t i) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + void toMangleBuffer(OutBuffer buf) + { + assert(false); + } + + elem* toElem(IRState* irs) + { + elem* e; + Type tb = type.toBasetype(); + +static if (false) { + printf("StringExp.toElem() %s, type = %s\n", toChars(), type.toChars()); +} + + if (tb.ty == TY.Tarray) + { + Symbol* si; + dt_t* dt; + StringTab* st; + +static if (false) { + printf("irs.m = %p\n", irs.m); + printf(" m = %s\n", irs.m.toChars()); + printf(" len = %d\n", len); + printf(" sz = %d\n", sz); +} + for (size_t i = 0; i < STSIZE; i++) + { + st = &stringTab[(stidx + i) % STSIZE]; + //if (!st.m) continue; + //printf(" st.m = %s\n", st.m.toChars()); + //printf(" st.len = %d\n", st.len); + //printf(" st.sz = %d\n", st.sz); + if (st.m is irs.m && + st.si && + st.len == len && + st.sz == sz && + memcmp(st.string_, string_, sz * len) == 0) + { + //printf("use cached value\n"); + si = st.si; // use cached value + goto L1; + } + } + + stidx = (stidx + 1) % STSIZE; + st = &stringTab[stidx]; + + dt = null; + toDt(&dt); + + si = symbol_generate(SC.SCstatic, type_fake(TYM.TYdarray)); + si.Sdt = dt; + si.Sfl = FL.FLdata; +version (ELFOBJ) {// Burton + si.Sseg = Segment.CDATA; +} +version (MACHOBJ) { + si.Sseg = Segment.DATA; +} + outdata(si); + + st.m = irs.m; + st.si = si; + st.string_ = string_; + st.len = len; + st.sz = sz; + L1: + e = el_var(si); + } + else if (tb.ty == TY.Tsarray) + { + Symbol *si; + dt_t *dt = null; + + toDt(&dt); + dtnzeros(&dt, sz); // leave terminating 0 + + si = symbol_generate(SC.SCstatic,type_allocn(TYM.TYarray, tschar)); + si.Sdt = dt; + si.Sfl = FL.FLdata; + +version (ELFOBJ_OR_MACHOBJ) { // Burton + si.Sseg = Segment.CDATA; + } + outdata(si); + + e = el_var(si); + } + else if (tb.ty == TY.Tpointer) + { + e = el_calloc(); + e.Eoper = OPER.OPstring; +static if (true) { + // Match MEM_PH_FREE for OPstring in ztc\el.c + e.EV.ss.Vstring = cast(char*)malloc((len + 1) * sz); + memcpy(e.EV.ss.Vstring, string_, (len + 1) * sz); +} else { + e.EV.ss.Vstring = cast(char*)string_; +} + e.EV.ss.Vstrlen = (len + 1) * sz; + e.Ety = TYM.TYnptr; + } + else + { + writef("type is %s\n", type.toChars()); + assert(0); + } + el_setLoc(e,loc); + return e; + } + + dt_t** toDt(dt_t** pdt) + { + //printf("StringExp.toDt() '%s', type = %s\n", toChars(), type.toChars()); + Type t = type.toBasetype(); + + // BUG: should implement some form of static string pooling + switch (t.ty) + { + case TY.Tarray: + dtdword(pdt, len); + pdt = dtabytes(pdt, TYM.TYnptr, 0, (len + 1) * sz, cast(char*)string_); + break; + + case TY.Tsarray: + { + TypeSArray tsa = cast(TypeSArray)type; + long dim; + + pdt = dtnbytes(pdt, len * sz, cast(const(char)*)string_); + if (tsa.dim) + { + dim = tsa.dim.toInteger(); + if (len < dim) + { + // Pad remainder with 0 + pdt = dtnzeros(pdt, cast(uint)((dim - len) * tsa.next.size())); + } + } + break; + } + + case TY.Tpointer: + pdt = dtabytes(pdt, TYM.TYnptr, 0, (len + 1) * sz, cast(char*)string_); + break; + + default: + writef("StringExp.toDt(type = %s)\n", type.toChars()); + assert(0); + } + + return pdt; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/StringTable.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/StringTable.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,108 @@ +module dmd.StringTable; + +import dmd.StringValue; +import dmd.StringEntry; +import dmd.Dchar; + +import core.stdc.stdlib; +import core.stdc.string; + +class StringTable +{ + void** table; + uint count; + uint tabledim; + + this(uint size = 37) + { + table = cast(void**)calloc(size, (void*).sizeof); + memset(table, 0, size * (void*).sizeof); + tabledim = size; + count = 0; + } + + ~this() + { + /// TODO: is it *really* needed? + // Zero out dangling pointers to help garbage collector. + // Should zero out StringEntry's too. + ///for (uint i = 0; i < count; i++) { + /// table[i] = null; + ///} + + free(table); + //table = null; + } + + StringValue* lookup(immutable(dchar_t)[] s) + { + StringEntry* se = *cast(StringEntry**)search(s); + if (se !is null) + return &se.value; + else + return null; + } + + StringValue* insert(immutable(dchar_t)[] s) + { + StringEntry** pse = cast(StringEntry**)search(s); + StringEntry* se = *pse; + if (se !is null) + return null; // error: already in table + else + { + se = new StringEntry(s); + *pse = se; + } + + return &se.value; + } + + StringValue* update(immutable(dchar_t)[] s) + { + StringEntry **pse; + StringEntry *se; + + pse = cast(StringEntry**)search(s); + se = *pse; + if (se is null) // not in table: so create new entry + { + se = new StringEntry(s); + *pse = se; + } + return &se.value; + } + +private: + void** search(immutable(dchar_t)[] s) + { + int cmp; + + //printf("StringTable::search(%p,%d)\n",s,len); + hash_t hash = Dchar.calcHash(s.ptr, s.length); + uint u = hash % tabledim; + StringEntry** se = cast(StringEntry**)&table[u]; + //printf("\thash = %d, u = %d\n",hash,u); + while (*se) + { + cmp = (*se).hash - hash; + if (cmp == 0) + { + cmp = (*se).value.lstring.len() - s.length; + if (cmp == 0) + { + cmp = Dchar.memcmp(s.ptr, (*se).value.lstring.toDchars().ptr, s.length); + if (cmp == 0) + break; + } + } + if (cmp < 0) + se = &(*se).left; + else + se = &(*se).right; + } + + //printf("\treturn %p, %p\n",se, (*se)); + return cast(void**)se; + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/StringValue.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/StringValue.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,16 @@ +module dmd.StringValue; + +import dmd.Lstring; +import dmd.Dchar; + +struct StringValue +{ + union + { + int intvalue = 0; + void* ptrvalue; + dchar_t* string_; + } + + Lstring lstring; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/StructDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/StructDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,851 @@ +module dmd.StructDeclaration; + +import dmd.AggregateDeclaration; +import dmd.FuncDeclaration; +import dmd.DeclarationExp; +import dmd.VoidInitializer; +import dmd.Initializer; +import dmd.ExpInitializer; +import dmd.TOK; +import dmd.Statement; +import dmd.VarExp; +import dmd.CompoundStatement; +import dmd.AssignExp; +import dmd.DotVarExp; +import dmd.AddrExp; +import dmd.CastExp; +import dmd.PostBlitDeclaration; +import dmd.Lexer; +import dmd.ExpStatement; +import dmd.DotIdExp; +import dmd.TypeSArray; +import dmd.ThisExp; +import dmd.ThisDeclaration; +import dmd.TypeFunction; +import dmd.Argument; +import dmd.Id; +import dmd.TY; +import dmd.LINK; +import dmd.Type; +import dmd.DsymbolTable; +import dmd.ArrayTypes; +import dmd.Loc; +import dmd.STC; +import dmd.Identifier; +import dmd.TemplateInstance; +import dmd.Dsymbol; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.PROT; +import dmd.TypeStruct; +import dmd.expression.Util; +import dmd.Expression; +import dmd.IdentifierExp; +import dmd.PtrExp; +import dmd.CallExp; +import dmd.ReturnStatement; +import dmd.ScopeDsymbol; +import dmd.Module; +import dmd.VarDeclaration; +import dmd.InvariantDeclaration; +import dmd.NewDeclaration; +import dmd.DeleteDeclaration; +import dmd.Global; + +import dmd.backend.dt_t; +import dmd.backend.Util; +import dmd.backend.SC; +import dmd.backend.DT; +import dmd.backend.FL; +import dmd.backend.glue; + +class StructDeclaration : AggregateDeclaration +{ + bool zeroInit; // true if initialize with 0 fill + +version (DMDV2) { + int hasIdentityAssign; // !=0 if has identity opAssign + FuncDeclaration cpctor; // generated copy-constructor, if any + + FuncDeclarations postblits; // Array of postblit functions + FuncDeclaration postblit; // aggregate postblit +} + + this(Loc loc, Identifier id) + { + super(loc, id); + + // For forward references + type = new TypeStruct(this); + + postblits = new FuncDeclarations(); /// + } + + Dsymbol syntaxCopy(Dsymbol s) + { + assert(false); + } + + void semantic(Scope sc) + { + int i; + Scope sc2; + + //printf("+StructDeclaration.semantic(this=%p, '%s')\n", this, toChars()); + + //static int count; if (++count == 20) *(char*)0=0; + + assert(type); + if (!members) // if forward reference + return; + + if (symtab) + { if (!scope_) + return; // semantic() already completed + } + else + symtab = new DsymbolTable(); + + Scope scx = null; + if (scope_) + { sc = scope_; + scx = scope_; // save so we don't make redundant copies + scope_ = null; + } + + parent = sc.parent; + type = type.semantic(loc, sc); +version (STRUCTTHISREF) { + handle = type; +} else { + handle = type.pointerTo(); +} + structalign = sc.structalign; + protection = sc.protection; + storage_class |= sc.stc; + if (sc.stc & STC.STCdeprecated) + isdeprecated = 1; + assert(!isAnonymous()); + if (sc.stc & STC.STCabstract) + error("structs, unions cannot be abstract"); +version (DMDV2) { + if (storage_class & STC.STCimmutable) + type = type.invariantOf(); + else if (storage_class & STC.STCconst) + type = type.constOf(); + else if (storage_class & STC.STCshared) + type = type.sharedOf(); +} + + if (sizeok == 0) // if not already done the addMember step + { + int hasfunctions = 0; + for (i = 0; i < members.dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + //printf("adding member '%s' to '%s'\n", s.toChars(), this.toChars()); + s.addMember(sc, this, 1); + if (s.isFuncDeclaration()) + hasfunctions = 1; + } + + // If nested struct, add in hidden 'this' pointer to outer scope + if (hasfunctions && !(storage_class & STC.STCstatic)) + { Dsymbol s = toParent2(); + if (s) + { + AggregateDeclaration ad = s.isAggregateDeclaration(); + FuncDeclaration fd = s.isFuncDeclaration(); + + TemplateInstance ti; + if (ad && (ti = ad.parent.isTemplateInstance()) !is null && ti.isnested || fd) + { isnested = true; + Type t; + if (ad) + t = ad.handle; + else if (fd) + { + AggregateDeclaration add = fd.isMember2(); + if (add) + t = add.handle; + else + t = Type.tvoidptr; + } + else + assert(0); + if (t.ty == TY.Tstruct) + t = Type.tvoidptr; // t should not be a ref type + assert(!vthis); + vthis = new ThisDeclaration(loc, t); + //vthis.storage_class |= STC.STCref; + members.push(cast(void*)vthis); + } + } + } + } + + sizeok = 0; + sc2 = sc.push(this); + sc2.stc &= storage_class & STC.STC_TYPECTOR; + sc2.parent = this; + if (isUnionDeclaration()) + sc2.inunion = 1; + sc2.protection = PROT.PROTpublic; + sc2.explicitProtection = 0; + + int members_dim = members.dim; + for (i = 0; i < members_dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + s.semantic(sc2); + if (isUnionDeclaration()) + sc2.offset = 0; +static if (false) { + if (sizeok == 2) + { //printf("forward reference\n"); + break; + } +} + Type t; + if (s.isDeclaration() && + (t = s.isDeclaration().type) !is null && + t.toBasetype().ty == TY.Tstruct) + { StructDeclaration sd = cast(StructDeclaration)t.toDsymbol(sc); + if (sd.isnested) + error("inner struct %s cannot be a field", sd.toChars()); + } + } + + /* The TypeInfo_Struct is expecting an opEquals and opCmp with + * a parameter that is a pointer to the struct. But if there + * isn't one, but is an opEquals or opCmp with a value, write + * another that is a shell around the value: + * int opCmp(struct *p) { return opCmp(*p); } + */ + + TypeFunction tfeqptr; + { + Arguments arguments = new Arguments; + Argument arg = new Argument(STC.STCin, handle, Id.p, null); + + arguments.push(cast(void*)arg); + tfeqptr = new TypeFunction(arguments, Type.tint32, 0, LINK.LINKd); + tfeqptr = cast(TypeFunction)tfeqptr.semantic(Loc(0), sc); + } + + TypeFunction tfeq; + { + Arguments arguments = new Arguments; + Argument arg = new Argument(STC.STCin, type, null, null); + + arguments.push(cast(void*)arg); + tfeq = new TypeFunction(arguments, Type.tint32, 0, LINK.LINKd); + tfeq = cast(TypeFunction)tfeq.semantic(Loc(0), sc); + } + + Identifier id = Id.eq; + for (int j = 0; j < 2; j++) + { + Dsymbol s = search_function(this, id); + FuncDeclaration fdx = s ? s.isFuncDeclaration() : null; + if (fdx) + { FuncDeclaration fd = fdx.overloadExactMatch(tfeqptr); + if (!fd) + { fd = fdx.overloadExactMatch(tfeq); + if (fd) + { // Create the thunk, fdptr + FuncDeclaration fdptr = new FuncDeclaration(loc, loc, fdx.ident, STC.STCundefined, tfeqptr); + Expression e = new IdentifierExp(loc, Id.p); + e = new PtrExp(loc, e); + Expressions args = new Expressions(); + args.push(cast(void*)e); + e = new IdentifierExp(loc, id); + e = new CallExp(loc, e, args); + fdptr.fbody = new ReturnStatement(loc, e); + ScopeDsymbol ss = fdx.parent.isScopeDsymbol(); + assert(ss); + ss.members.push(cast(void*)fdptr); + fdptr.addMember(sc, ss, 1); + fdptr.semantic(sc2); + } + } + } + + id = Id.cmp; + } +version (DMDV2) { + dtor = buildDtor(sc2); + postblit = buildPostBlit(sc2); + cpctor = buildCpCtor(sc2); + buildOpAssign(sc2); +} + + sc2.pop(); + + if (sizeok == 2) + { // semantic() failed because of forward references. + // Unwind what we did, and defer it for later + fields.setDim(0); + structsize = 0; + alignsize = 0; + structalign = 0; + + scope_ = scx ? scx : new Scope(sc); + scope_.setNoFree(); + scope_.module_.addDeferredSemantic(this); + //printf("\tdeferring %s\n", toChars()); + return; + } + + // 0 sized struct's are set to 1 byte + if (structsize == 0) + { + structsize = 1; + alignsize = 1; + } + + // Round struct size up to next alignsize boundary. + // This will ensure that arrays of structs will get their internals + // aligned properly. + structsize = (structsize + alignsize - 1) & ~(alignsize - 1); + + sizeok = 1; + Module.dprogress++; + + //printf("-StructDeclaration.semantic(this=%p, '%s')\n", this, toChars()); + + // Determine if struct is all zeros or not + zeroInit = true; + for (i = 0; i < fields.dim; i++) + { + Dsymbol s = cast(Dsymbol)fields.data[i]; + VarDeclaration vd = s.isVarDeclaration(); + if (vd && !vd.isDataseg()) + { + if (vd.init) + { + // Should examine init to see if it is really all 0's + zeroInit = false; + break; + } + else + { + if (!vd.type.isZeroInit(loc)) + { + zeroInit = false; + break; + } + } + } + } + + /* Look for special member functions. + */ +version (DMDV2) { + ctor = search(Loc(0), Id.ctor, 0); +} + inv = cast(InvariantDeclaration)search(Loc(0), Id.classInvariant, 0); + aggNew = cast(NewDeclaration)search(Loc(0), Id.classNew, 0); + aggDelete = cast(DeleteDeclaration)search(Loc(0), Id.classDelete, 0); + + if (sc.func) + { + semantic2(sc); + semantic3(sc); + } + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + string mangle() + { + //printf("StructDeclaration.mangle() '%s'\n", toChars()); + return Dsymbol.mangle(); + } + + string kind() + { + assert(false); + } + + /******************************************* + * We need an opAssign for the struct if + * it has a destructor or a postblit. + * We need to generate one if a user-specified one does not exist. + */ + bool needOpAssign() + { +static if (false) { + printf("StructDeclaration.needOpAssign() %s\n", toChars()); +} + if (hasIdentityAssign) + goto Ldontneed; + + if (dtor || postblit) + goto Lneed; + + /* If any of the fields need an opAssign, then we + * need it too. + */ + for (size_t i = 0; i < fields.dim; i++) + { + Dsymbol s = cast(Dsymbol)fields.data[i]; + VarDeclaration v = s.isVarDeclaration(); + assert(v && v.storage_class & STC.STCfield); + if (v.storage_class & STC.STCref) + continue; + Type tv = v.type.toBasetype(); + while (tv.ty == TY.Tsarray) + { TypeSArray ta = cast(TypeSArray)tv; + tv = tv.nextOf().toBasetype(); + } + if (tv.ty == TY.Tstruct) + { TypeStruct ts = cast(TypeStruct)tv; + StructDeclaration sd = ts.sym; + if (sd.needOpAssign()) + goto Lneed; + } + } + Ldontneed: +static if (false) { + printf("\tdontneed\n"); +} + return false; + + Lneed: +static if (false) { + printf("\tneed\n"); +} + return true; + } + + /****************************************** + * Build opAssign for struct. + * S* opAssign(S s) { ... } + */ + FuncDeclaration buildOpAssign(Scope sc) + { + if (!needOpAssign()) + return null; + + //printf("StructDeclaration.buildOpAssign() %s\n", toChars()); + + FuncDeclaration fop = null; + + Argument param = new Argument(STC.STCnodtor, type, Id.p, null); + Arguments fparams = new Arguments; + fparams.push(cast(void*)param); + Type ftype = new TypeFunction(fparams, handle, false, LINK.LINKd); +version (STRUCTTHISREF) { + (cast(TypeFunction)ftype).isref = 1; +} + + fop = new FuncDeclaration(Loc(0), Loc(0), Id.assign, STC.STCundefined, ftype); + + Expression e = null; + if (postblit) + { /* Swap: + * tmp = *this; *this = s; tmp.dtor(); + */ + //printf("\tswap copy\n"); + Identifier idtmp = Lexer.uniqueId("__tmp"); + VarDeclaration tmp; + AssignExp ec = null; + if (dtor) + { + tmp = new VarDeclaration(Loc(0), type, idtmp, new VoidInitializer(Loc(0))); + tmp.noauto = true; + e = new DeclarationExp(Loc(0), tmp); + + Expression e2; +version (STRUCTTHISREF) { + e2 = new ThisExp(Loc(0)); +} else { + e2 = new PtrExp(Loc(0), new ThisExp(Loc(0))); +} + ec = new AssignExp(Loc(0), new VarExp(Loc(0), tmp), e2); + ec.op = TOK.TOKblit; + e = Expression.combine(e, ec); + } + Expression e2; +version (STRUCTTHISREF) { + e2 = new ThisExp(Loc(0)); +} else { + e2 = new PtrExp(Loc(0), new ThisExp(Loc(0))); +} + + ec = new AssignExp(Loc(0), e2, new IdentifierExp(Loc(0), Id.p)); + ec.op = TOK.TOKblit; + e = Expression.combine(e, ec); + if (dtor) + { + /* Instead of running the destructor on s, run it + * on tmp. This avoids needing to copy tmp back in to s. + */ + Expression ecc = new DotVarExp(Loc(0), new VarExp(Loc(0), tmp), dtor, 0); + ecc = new CallExp(Loc(0), ecc); + e = Expression.combine(e, ecc); + } + } + else + { /* Do memberwise copy + */ + //printf("\tmemberwise copy\n"); + for (size_t i = 0; i < fields.dim; i++) + { + Dsymbol s = cast(Dsymbol)fields.data[i]; + VarDeclaration v = s.isVarDeclaration(); + assert(v && v.storage_class & STC.STCfield); + // this.v = s.v; + AssignExp ec = new AssignExp(Loc(0), new DotVarExp(Loc(0), new ThisExp(Loc(0)), v, 0), new DotVarExp(Loc(0), new IdentifierExp(Loc(0), Id.p), v, 0)); + ec.op = TOK.TOKblit; + e = Expression.combine(e, ec); + } + } + Statement s1 = new ExpStatement(Loc(0), e); + + /* Add: + * return this; + */ + e = new ThisExp(Loc(0)); + Statement s2 = new ReturnStatement(Loc(0), e); + + fop.fbody = new CompoundStatement(Loc(0), s1, s2); + + members.push(cast(void*)fop); + fop.addMember(sc, this, 1); + + sc = sc.push(); + sc.stc = STC.STCundefined; + sc.linkage = LINK.LINKd; + + fop.semantic(sc); + + sc.pop(); + + //printf("-StructDeclaration.buildOpAssign() %s\n", toChars()); + + return fop; + } + + /***************************************** + * Create inclusive postblit for struct by aggregating + * all the postblits in postblits[] with the postblits for + * all the members. + * Note the close similarity with AggregateDeclaration.buildDtor(), + * and the ordering changes (runs forward instead of backwards). + */ + +version (DMDV2) { + FuncDeclaration buildPostBlit(Scope sc) + { + //printf("StructDeclaration.buildPostBlit() %s\n", toChars()); + Expression e = null; + + for (size_t i = 0; i < fields.dim; i++) + { + Dsymbol s = cast(Dsymbol)fields.data[i]; + VarDeclaration v = s.isVarDeclaration(); + assert(v && v.storage_class & STC.STCfield); + if (v.storage_class & STC.STCref) + continue; + Type tv = v.type.toBasetype(); + size_t dim = 1; + while (tv.ty == TY.Tsarray) + { TypeSArray ta = cast(TypeSArray)tv; + dim *= (cast(TypeSArray)tv).dim.toInteger(); + tv = tv.nextOf().toBasetype(); + } + if (tv.ty == TY.Tstruct) + { TypeStruct ts = cast(TypeStruct)tv; + StructDeclaration sd = ts.sym; + if (sd.postblit) + { Expression ex; + + // this.v + ex = new ThisExp(Loc(0)); + ex = new DotVarExp(Loc(0), ex, v, 0); + + if (dim == 1) + { // this.v.postblit() + ex = new DotVarExp(Loc(0), ex, sd.postblit, 0); + ex = new CallExp(Loc(0), ex); + } + else + { + // Typeinfo.postblit(cast(void*)&this.v); + Expression ea = new AddrExp(Loc(0), ex); + ea = new CastExp(Loc(0), ea, Type.tvoid.pointerTo()); + + Expression et = v.type.getTypeInfo(sc); + et = new DotIdExp(Loc(0), et, Id.postblit); + + ex = new CallExp(Loc(0), et, ea); + } + e = Expression.combine(e, ex); // combine in forward order + } + } + } + + /* Build our own "postblit" which executes e + */ + if (e) + { //printf("Building __fieldPostBlit()\n"); + PostBlitDeclaration dd = new PostBlitDeclaration(Loc(0), Loc(0), Lexer.idPool("__fieldPostBlit")); + dd.fbody = new ExpStatement(Loc(0), e); + postblits.shift(cast(void*)dd); + members.push(cast(void*)dd); + dd.semantic(sc); + } + + switch (postblits.dim) + { + case 0: + return null; + + case 1: + return cast(FuncDeclaration)postblits.data[0]; + + default: + e = null; + for (size_t i = 0; i < postblits.dim; i++) + { FuncDeclaration fd = cast(FuncDeclaration)postblits.data[i]; + Expression ex = new ThisExp(Loc(0)); + ex = new DotVarExp(Loc(0), ex, fd, 0); + ex = new CallExp(Loc(0), ex); + e = Expression.combine(e, ex); + } + PostBlitDeclaration dd = new PostBlitDeclaration(Loc(0), Loc(0), Lexer.idPool("__aggrPostBlit")); + dd.fbody = new ExpStatement(Loc(0), e); + members.push(cast(void*)dd); + dd.semantic(sc); + return dd; + } + } +} + + /******************************************* + * Build copy constructor for struct. + * Copy constructors are compiler generated only, and are only + * callable from the compiler. They are not user accessible. + * A copy constructor is: + * void cpctpr(ref S s) + * { + * *this = s; + * this.postBlit(); + * } + * This is done so: + * - postBlit() never sees uninitialized data + * - memcpy can be much more efficient than memberwise copy + * - no fields are overlooked + */ + FuncDeclaration buildCpCtor(Scope sc) + { + //printf("StructDeclaration.buildCpCtor() %s\n", toChars()); + FuncDeclaration fcp = null; + + /* Copy constructor is only necessary if there is a postblit function, + * otherwise the code generator will just do a bit copy. + */ + if (postblit) + { + //printf("generating cpctor\n"); + + Argument param = new Argument(STC.STCref, type, Id.p, null); + Arguments fparams = new Arguments; + fparams.push(cast(void*)param); + Type ftype = new TypeFunction(fparams, Type.tvoid, false, LINK.LINKd); + + fcp = new FuncDeclaration(Loc(0), Loc(0), Id.cpctor, STC.STCundefined, ftype); + + // Build *this = p; + Expression e = new ThisExp(Loc(0)); +version (STRUCTTHISREF) { +} else { + e = new PtrExp(Loc(0), e); +} + AssignExp ea = new AssignExp(Loc(0), e, new IdentifierExp(Loc(0), Id.p)); + ea.op = TOK.TOKblit; + Statement s = new ExpStatement(Loc(0), ea); + + // Build postBlit(); + e = new VarExp(Loc(0), postblit, 0); + e = new CallExp(Loc(0), e); + + s = new CompoundStatement(Loc(0), s, new ExpStatement(Loc(0), e)); + fcp.fbody = s; + + members.push(cast(void*)fcp); + + sc = sc.push(); + sc.stc = STC.STCundefined; + sc.linkage = LINK.LINKd; + + fcp.semantic(sc); + + sc.pop(); + } + + return fcp; + } + + void toDocBuffer(OutBuffer buf) + { + assert(false); + } + + PROT getAccess(Dsymbol smember) // determine access to smember + { + assert(false); + } + + void toObjFile(int multiobj) // compile to .obj file + { + //printf("StructDeclaration.toObjFile('%s')\n", toChars()); + + if (multiobj) + { + obj_append(this); + return; + } + + // Anonymous structs/unions only exist as part of others, + // do not output forward referenced structs's + if (!isAnonymous() && members) + { + if (global.params.symdebug) { + toDebug(); + } + + type.getTypeInfo(null); // generate TypeInfo + + if (true) + { + // Generate static initializer + toInitializer(); + +static if (false) { + sinit.Sclass = SC.SCcomdat; +} else { + if (inTemplateInstance()) + { + sinit.Sclass = SC.SCcomdat; + } + else + { + sinit.Sclass = SC.SCglobal; + } +} + sinit.Sfl = FL.FLdata; + + toDt(&sinit.Sdt); + +version (OMFOBJ) { + /* For OMF, common blocks aren't pulled in from the library. + */ + /* ELF comdef's generate multiple + * definition errors for them from the gnu linker. + * Need to figure out how to generate proper comdef's for ELF. + */ + // See if we can convert a comdat to a comdef, + // which saves on exe file space. + if (sinit.Sclass == SCcomdat && + sinit.Sdt && + sinit.Sdt.dt == DT.DT_azeros && + sinit.Sdt.DTnext == null && + !global.params.multiobj) + { + sinit.Sclass = SC.SCglobal; + sinit.Sdt.dt = DT.DT_common; + } +} + +version (ELFOBJ) { + sinit.Sseg = Segment.CDATA; +} +version (MACHOBJ) { + sinit.Sseg = Segment.DATA; +} + outdata(sinit); + } + + // Put out the members + for (uint i = 0; i < members.dim; i++) + { + Dsymbol member = cast(Dsymbol)members.data[i]; + member.toObjFile(0); + } + } + } + + void toDt(dt_t** pdt) + { + uint offset; + uint i; + dt_t* dt; + + //printf("StructDeclaration.toDt(), this='%s'\n", toChars()); + offset = 0; + + // Note equivalence of this loop to class's + for (i = 0; i < fields.dim; i++) + { + VarDeclaration v = cast(VarDeclaration)fields.data[i]; + //printf("\tfield '%s' voffset %d, offset = %d\n", v.toChars(), v.offset, offset); + dt = null; + int sz; + + if (v.storage_class & STC.STCref) + { + sz = PTRSIZE; + if (v.offset >= offset) + dtnzeros(&dt, sz); + } + else + { + sz = cast(uint)v.type.size(); + Initializer init = v.init; + if (init) + { + //printf("\t\thas initializer %s\n", init.toChars()); + ExpInitializer ei = init.isExpInitializer(); + Type tb = v.type.toBasetype(); + if (ei && tb.ty == TY.Tsarray) + (cast(TypeSArray)tb).toDtElem(&dt, ei.exp); + else + dt = init.toDt(); + } + else if (v.offset >= offset) + v.type.toDt(&dt); + } + if (dt) + { + if (v.offset < offset) + error("overlapping initialization for struct %s.%s", toChars(), v.toChars()); + else + { + if (offset < v.offset) + dtnzeros(pdt, v.offset - offset); + dtcat(pdt, dt); + offset = v.offset + sz; + } + } + } + + if (offset < structsize) + dtnzeros(pdt, structsize - offset); + + dt_optimize(*pdt); + } + + void toDebug() // to symbolic debug info + { + assert(false); + } + + StructDeclaration isStructDeclaration() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/StructInitializer.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/StructInitializer.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,62 @@ +module dmd.StructInitializer; + +import dmd.Initializer; +import dmd.ArrayTypes; +import dmd.Array; +import dmd.Loc; +import dmd.Type; +import dmd.Scope; +import dmd.Identifier; +import dmd.AggregateDeclaration; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Expression; + +import dmd.backend.dt_t; + +class StructInitializer : Initializer +{ + Identifiers field; // of Identifier *'s + Initializers value; // parallel array of Initializer *'s + + Array vars; // parallel array of VarDeclaration *'s + AggregateDeclaration ad; // which aggregate this is for + + this(Loc loc) + { + assert(false); + super(loc); + } + + Initializer syntaxCopy() + { + assert(false); + } + + void addInit(Identifier field, Initializer value) + { + assert(false); + } + + Initializer semantic(Scope sc, Type t) + { + assert(false); + } + + Expression toExpression() + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + dt_t* toDt() + { + assert(false); + } + + StructInitializer isStructInitializer() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/StructLiteralExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/StructLiteralExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,134 @@ +module dmd.StructLiteralExp; + +import dmd.Expression; +import dmd.StructDeclaration; +import dmd.backend.elem; +import dmd.InterState; +import dmd.MATCH; +import dmd.Type; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.InlineCostState; +import dmd.IRState; +import dmd.InlineDoState; +import dmd.backend.Symbol; +import dmd.HdrGenState; +import dmd.backend.dt_t; +import dmd.InlineScanState; +import dmd.ArrayTypes; +import dmd.TOK; + + +class StructLiteralExp : Expression +{ + StructDeclaration sd; // which aggregate this is for + Expressions elements; // parallels sd->fields[] with + // NULL entries for fields to skip + + Symbol* sym; // back end symbol to initialize with literal + size_t soffset; // offset from start of s + int fillHoles; // fill alignment 'holes' with zero + + this(Loc loc, StructDeclaration sd, Expressions elements) + { + assert(false); + super(loc, TOK.init, 0); + } + + Expression syntaxCopy() + { + assert(false); + } + + Expression semantic(Scope sc) + { + assert(false); + } + + Expression getField(Type type, uint offset) + { + assert(false); + } + + int getFieldIndex(Type type, uint offset) + { + assert(false); + } + + elem* toElem(IRState* irs) + { + assert(false); + } + + bool checkSideEffect(int flag) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + void toMangleBuffer(OutBuffer buf) + { + assert(false); + } + + void scanForNestedRef(Scope sc) + { + assert(false); + } + + Expression optimize(int result) + { + assert(false); + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + dt_t** toDt(dt_t** pdt) + { + assert(false); + } + + int isLvalue() + { + assert(false); + } + + Expression toLvalue(Scope sc, Expression e) + { + assert(false); + } + + bool canThrow() + { + assert(false); + } + + MATCH implicitConvTo(Type t) + { + assert(false); + } + + int inlineCost(InlineCostState* ics) + { + assert(false); + } + + Expression doInline(InlineDoState ids) + { + assert(false); + } + + Expression inlineScan(InlineScanState* iss) + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/SuperExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/SuperExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,125 @@ +module dmd.SuperExp; + +import dmd.Expression; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.InlineCostState; +import dmd.InlineDoState; +import dmd.FuncDeclaration; +import dmd.ClassDeclaration; +import dmd.Dsymbol; +import dmd.HdrGenState; +import dmd.ThisExp; +import dmd.TOK; +import dmd.CSX; +import dmd.Type; + +class SuperExp : ThisExp +{ + this(Loc loc) + { + super(loc); + op = TOK.TOKsuper; + } + + Expression semantic(Scope sc) + { + FuncDeclaration fd; + FuncDeclaration fdthis; + + version (LOGSEMANTIC) { + printf("SuperExp.semantic('%s')\n", toChars()); + } + if (type) + return this; + + /* Special case for typeof(this) and typeof(super) since both + * should work even if they are not inside a non-static member function + */ + if (sc.intypeof) + { + // Find enclosing class + for (Dsymbol s = sc.parent; 1; s = s.parent) + { + ClassDeclaration cd; + + if (!s) + { + error("%s is not in a class scope", toChars()); + goto Lerr; + } + cd = s.isClassDeclaration(); + if (cd) + { + cd = cd.baseClass; + if (!cd) + { + error("class %s has no 'super'", s.toChars()); + goto Lerr; + } + type = cd.type; + return this; + } + } + } + + fdthis = sc.parent.isFuncDeclaration(); + fd = hasThis(sc); + if (!fd) + goto Lerr; + assert(fd.vthis); + var = fd.vthis; + assert(var.parent); + + Dsymbol s = fd.toParent(); + while (s && s.isTemplateInstance()) + s = s.toParent(); + assert(s); + ClassDeclaration cd = s.isClassDeclaration(); + //printf("parent is %s %s\n", fd.toParent().kind(), fd.toParent().toChars()); + if (!cd) + goto Lerr; + if (!cd.baseClass) + { + error("no base class for %s", cd.toChars()); + type = fd.vthis.type; + } + else + { + type = cd.baseClass.type; + } + + var.isVarDeclaration().checkNestedReference(sc, loc); + + if (!sc.intypeof) + sc.callSuper |= CSXsuper; + return this; + + Lerr: + error("'super' is only allowed in non-static class member functions"); + type = Type.tint32; + return this; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + void scanForNestedRef(Scope sc) + { + assert(false); + } + + int inlineCost(InlineCostState* ics) + { + assert(false); + } + + Expression doInline(InlineDoState ids) + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/SwitchErrorStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/SwitchErrorStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,33 @@ +module dmd.SwitchErrorStatement; + +import dmd.Statement; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.IRState; +import dmd.HdrGenState; +import dmd.BE; + +class SwitchErrorStatement : Statement +{ + this(Loc loc) + { + assert(false); + super(loc); + } + + BE blockExit() + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + void toIR(IRState* irs) + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/SwitchStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/SwitchStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,440 @@ +module dmd.SwitchStatement; + +import dmd.Statement; +import dmd.Expression; +import dmd.DefaultStatement; +import dmd.TryFinallyStatement; +import dmd.Array; +import dmd.Loc; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.InlineScanState; +import dmd.IRState; +import dmd.InterState; +import dmd.BE; +import dmd.TY; +import dmd.WANT; +import dmd.GotoCaseStatement; +import dmd.CaseStatement; +import dmd.ArrayTypes; +import dmd.CompoundStatement; +import dmd.Global; +import dmd.SwitchErrorStatement; +import dmd.Type; +import dmd.HaltExp; +import dmd.ExpStatement; +import dmd.BreakStatement; +import dmd.EnumDeclaration; +import dmd.TypeEnum; +import dmd.Dsymbol; +import dmd.EnumMember; +import dmd.TypeTypedef; +import dmd.TOK; +import dmd.StringExp; + +import dmd.backend.Util; +import dmd.backend.block; +import dmd.backend.Blockx; +import dmd.backend.elem; +import dmd.backend.OPER; +import dmd.backend.TYM; +import dmd.backend.BC; +import dmd.backend.dt_t; +import dmd.backend.Symbol; +import dmd.backend.SC; +import dmd.backend.FL; +import dmd.backend.RTLSYM; +import dmd.backend.targ_types; + +class SwitchStatement : Statement +{ + Expression condition; + Statement body_; + bool isFinal; + + DefaultStatement sdefault = null; + TryFinallyStatement tf = null; + Array gotoCases; // array of unresolved GotoCaseStatement's + Array cases; // array of CaseStatement's + int hasNoDefault = 0; // !=0 if no default statement + int hasVars = 0; // !=0 if has variable case values + + this(Loc loc, Expression c, Statement b, bool isFinal) + { + super(loc); + + this.condition = c; + this.body_ = b; + this.isFinal = isFinal; + + gotoCases = new Array(); + } + + Statement syntaxCopy() + { + assert(false); + } + + Statement semantic(Scope sc) + { + //printf("SwitchStatement.semantic(%p)\n", this); + tf = sc.tf; + assert(!cases); // ensure semantic() is only run once + condition = condition.semantic(sc); + condition = resolveProperties(sc, condition); + if (condition.type.isString()) + { + // If it's not an array, cast it to one + if (condition.type.ty != Tarray) + { + condition = condition.implicitCastTo(sc, condition.type.nextOf().arrayOf()); + } + condition.type = condition.type.constOf(); + } + else + { + condition = condition.integralPromotions(sc); + condition.checkIntegral(); + } + condition = condition.optimize(WANTvalue); + + sc = sc.push(); + sc.sbreak = this; + sc.sw = this; + + cases = new Array(); + sc.noctor++; // BUG: should use Scope.mergeCallSuper() for each case instead + body_ = body_.semantic(sc); + sc.noctor--; + + // Resolve any goto case's with exp + for (int i = 0; i < gotoCases.dim; i++) + { + GotoCaseStatement gcs = cast(GotoCaseStatement)gotoCases.data[i]; + + if (!gcs.exp) + { + gcs.error("no case statement following goto case;"); + break; + } + + for (Scope scx = sc; scx; scx = scx.enclosing) + { + if (!scx.sw) + continue; + for (int j = 0; j < scx.sw.cases.dim; j++) + { + CaseStatement cs = cast(CaseStatement)scx.sw.cases.data[j]; + + if (cs.exp.equals(gcs.exp)) + { + gcs.cs = cs; + goto Lfoundcase; + } + } + } + gcs.error("case %s not found", gcs.exp.toChars()); + + Lfoundcase: + ; + } + + if (!sc.sw.sdefault && !isFinal) + { + hasNoDefault = 1; + + warning("switch statement has no default"); + + // Generate runtime error if the default is hit + Statements a = new Statements(); + CompoundStatement cs; + Statement s; + + if (global.params.useSwitchError) + s = new SwitchErrorStatement(loc); + else + { + Expression e = new HaltExp(loc); + s = new ExpStatement(loc, e); + } + + a.reserve(4); + a.push(cast(void*)body_); + a.push(cast(void*)new BreakStatement(loc, null)); + sc.sw.sdefault = new DefaultStatement(loc, s); + a.push(cast(void*)sc.sw.sdefault); + cs = new CompoundStatement(loc, a); + body_ = cs; + } + + version (DMDV2) { + if (isFinal) + { + Type t = condition.type; + while (t.ty == Ttypedef) + { + // Don't use toBasetype() because that will skip past enums + t = (cast(TypeTypedef)t).sym.basetype; + } + if (condition.type.ty == Tenum) + { + TypeEnum te = cast(TypeEnum)condition.type; + EnumDeclaration ed = te.toDsymbol(sc).isEnumDeclaration(); + assert(ed); + size_t dim = ed.members.dim; + for (size_t i = 0; i < dim; i++) + { + EnumMember em = (cast(Dsymbol)ed.members.data[i]).isEnumMember(); + if (em) + { + for (size_t j = 0; j < cases.dim; j++) + { + CaseStatement cs = cast(CaseStatement)cases.data[j]; + if (cs.exp.equals(em.value)) + goto L1; + } + error("enum member %s not represented in final switch", em.toChars()); + } + L1: + ; + } + } + } + } + + sc.pop(); + return this; + } + + bool hasBreak() + { + assert(false); + } + + bool usesEH() + { + assert(false); + } + + BE blockExit() + { + BE result = BE.BEnone; + if (condition.canThrow()) + result |= BE.BEthrow; + + if (body_) + { result |= body_.blockExit(); + if (result & BE.BEbreak) + { + result |= BE.BEfallthru; + result &= ~BE.BEbreak; + } + } + else + result |= BE.BEfallthru; + + return result; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + Statement inlineScan(InlineScanState* iss) + { + //printf("SwitchStatement.inlineScan()\n"); + condition = condition.inlineScan(iss); + body_ = body_ ? body_.inlineScan(iss) : null; + if (sdefault) + sdefault = cast(DefaultStatement)sdefault.inlineScan(iss); + if (cases) + { + for (int i = 0; i < cases.dim; i++) + { + Statement s = cast(Statement)cases.data[i]; + cases.data[i] = cast(void*)s.inlineScan(iss); + } + } + return this; + } + + void toIR(IRState* irs) + { + int string; + Blockx* blx = irs.blx; + + //printf("SwitchStatement.toIR()\n"); + IRState mystate = IRState(irs,this); + + mystate.switchBlock = blx.curblock; + + /* Block for where "break" goes to + */ + mystate.breakBlock = block_calloc(blx); + + /* Block for where "default" goes to. + * If there is a default statement, then that is where default goes. + * If not, then do: + * default: break; + * by making the default block the same as the break block. + */ + mystate.defaultBlock = sdefault ? block_calloc(blx) : mystate.breakBlock; + + int numcases = 0; + if (cases) + numcases = cases.dim; + + incUsage(irs, loc); + elem* econd = condition.toElem(&mystate); + + version (DMDV2) { + if (hasVars) + { + /* Generate a sequence of if-then-else blocks for the cases. + */ + if (econd.Eoper != OPvar) + { + elem* e = exp2_copytotemp(econd); + block_appendexp(mystate.switchBlock, e); + econd = e.E2; + } + + for (int i = 0; i < numcases; i++) + { + CaseStatement cs = cast(CaseStatement)cases.data[i]; + + elem* ecase = cs.exp.toElem(&mystate); + elem* e = el_bin(OPeqeq, TYbool, el_copytree(econd), ecase); + block* b = blx.curblock; + block_appendexp(b, e); + block* bcase = block_calloc(blx); + cs.cblock = bcase; + block_next(blx, BCiftrue, null); + list_append(&b.Bsucc, bcase); + list_append(&b.Bsucc, blx.curblock); + } + + /* The final 'else' clause goes to the default + */ + block* b = blx.curblock; + block_next(blx, BCgoto, null); + list_append(&b.Bsucc, mystate.defaultBlock); + + body_.toIR(&mystate); + + /* Have the end of the switch body fall through to the block + * following the switch statement. + */ + block_goto(blx, BCgoto, mystate.breakBlock); + return; + } + } + + if (condition.type.isString()) + { + // Number the cases so we can unscramble things after the sort() + for (int i = 0; i < numcases; i++) + { + CaseStatement cs = cast(CaseStatement)cases.data[i]; + cs.index = i; + } + + cases.sort(); + + /* Create a sorted array of the case strings, and si + * will be the symbol for it. + */ + dt_t* dt = null; + Symbol* si = symbol_generate(SCstatic,type_fake(TYullong)); + version (MACHOBJ) { + si.Sseg = Segment.DATA; + } + dtdword(&dt, numcases); + dtxoff(&dt, si, 8, TYnptr); + + for (int i = 0; i < numcases; i++) + { + CaseStatement cs = cast(CaseStatement)cases.data[i]; + + if (cs.exp.op != TOKstring) + { + error("case '%s' is not a string", cs.exp.toChars()); // BUG: this should be an assert + } + else + { + StringExp se = cast(StringExp)(cs.exp); + uint len = se.len; + dtdword(&dt, len); + dtabytes(&dt, TYnptr, 0, se.len * se.sz, cast(char*)se.string_); + } + } + + si.Sdt = dt; + si.Sfl = FLdata; + outdata(si); + + /* Call: + * _d_switch_string(string[] si, string econd) + */ + elem* eparam = el_param(econd, el_var(si)); + switch (condition.type.nextOf().ty) + { + case Tchar: + econd = el_bin(OPcall, TYint, el_var(rtlsym[RTLSYM_SWITCH_STRING]), eparam); + break; + case Twchar: + econd = el_bin(OPcall, TYint, el_var(rtlsym[RTLSYM_SWITCH_USTRING]), eparam); + break; + case Tdchar: // BUG: implement + econd = el_bin(OPcall, TYint, el_var(rtlsym[RTLSYM_SWITCH_DSTRING]), eparam); + break; + default: + assert(0); + } + elem_setLoc(econd, loc); + string = 1; + } + else + string = 0; + block_appendexp(mystate.switchBlock, econd); + block_next(blx,BCswitch,null); + + targ_llong* pu = cast(targ_llong*) malloc(targ_llong.sizeof * (numcases + 1)); + mystate.switchBlock.Bswitch = pu; + /* First pair is the number of cases, and the default block + */ + *pu++ = numcases; + list_append(&mystate.switchBlock.Bsucc, mystate.defaultBlock); + + /* Fill in the first entry in each pair, which is the case value. + * CaseStatement.toIR() will fill in + * the second entry for each pair with the block. + */ + for (int i = 0; i < numcases; i++) + { + CaseStatement cs = cast(CaseStatement)cases.data[i]; + if (string) + { + pu[cs.index] = i; + } + else + { + pu[i] = cs.exp.toInteger(); + } + } + + body_.toIR(&mystate); + + /* Have the end of the switch body fall through to the block + * following the switch statement. + */ + block_goto(blx, BCgoto, mystate.breakBlock); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/SymOffExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/SymOffExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,230 @@ +module dmd.SymOffExp; + +import dmd.Expression; +import dmd.Declaration; +import dmd.MATCH; +import dmd.Type; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.InlineDoState; +import dmd.HdrGenState; +import dmd.backend.dt_t; +import dmd.SymbolExp; +import dmd.VarDeclaration; +import dmd.DelegateExp; +import dmd.ThisExp; +import dmd.FuncDeclaration; +import dmd.IntegerExp; +import dmd.ErrorExp; +import dmd.TY; +import dmd.TOK; + +import dmd.backend.Symbol; +import dmd.backend.Util; +import dmd.backend.TYM; + +class SymOffExp : SymbolExp +{ + uint offset; + + this(Loc loc, Declaration var, uint offset, int hasOverloads = 0) + { + super(loc, TOK.TOKsymoff, SymOffExp.sizeof, var, hasOverloads); + + this.offset = offset; + VarDeclaration v = var.isVarDeclaration(); + if (v && v.needThis()) + error("need 'this' for address of %s", v.toChars()); + } + + Expression semantic(Scope sc) + { + version(LOGSEMANTIC) { + printf("SymOffExp::semantic('%s')\n", toChars()); + } + //var.semantic(sc); + if (!type) + type = var.type.pointerTo(); + VarDeclaration v = var.isVarDeclaration(); + if (v) + v.checkNestedReference(sc, loc); + return this; + } + + void checkEscape() + { + VarDeclaration v = var.isVarDeclaration(); + if (v) + { + if (!v.isDataseg()) + error("escaping reference to local variable %s", v.toChars()); + } + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + int isConst() + { + return 2; + } + + bool isBool(bool result) + { + assert(false); + } + + Expression doInline(InlineDoState ids) + { + int i; + + //printf("SymOffExp.doInline(%s)\n", toChars()); + for (i = 0; i < ids.from.dim; i++) + { + if (var is cast(Declaration)ids.from.data[i]) + { + SymOffExp se = cast(SymOffExp)copy(); + + se.var = cast(Declaration)ids.to.data[i]; + return se; + } + } + return this; + } + + MATCH implicitConvTo(Type t) + { + static if (false) { + printf("SymOffExp::implicitConvTo(this=%s, type=%s, t=%s)\n", toChars(), type.toChars(), t.toChars()); + } + MATCH result = type.implicitConvTo(t); + //printf("\tresult = %d\n", result); + + if (result == MATCHnomatch) + { + // Look for pointers to functions where the functions are overloaded. + FuncDeclaration f; + + t = t.toBasetype(); + if (type.ty == Tpointer && type.nextOf().ty == Tfunction && + (t.ty == Tpointer || t.ty == Tdelegate) && t.nextOf().ty == Tfunction) + { + f = var.isFuncDeclaration(); + if (f) + { + f = f.overloadExactMatch(t.nextOf()); + if (f) + { + if ((t.ty == Tdelegate && (f.needThis() || f.isNested())) || + (t.ty == Tpointer && !(f.needThis() || f.isNested()))) + { + result = MATCHexact; + } + } + } + } + } + //printf("\tresult = %d\n", result); + return result; + } + + Expression castTo(Scope sc, Type t) + { + static if (false) { + printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n", toChars(), type.toChars(), t.toChars()); + } + if (type == t && hasOverloads == 0) + return this; + + Expression e; + Type tb = t.toBasetype(); + Type typeb = type.toBasetype(); + + if (tb != typeb) + { + // Look for pointers to functions where the functions are overloaded. + FuncDeclaration f; + + if (hasOverloads && + typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction && + (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction) + { + f = var.isFuncDeclaration(); + if (f) + { + f = f.overloadExactMatch(tb.nextOf()); + if (f) + { + if (tb.ty == Tdelegate) + { + if (f.needThis() && hasThis(sc)) + { + e = new DelegateExp(loc, new ThisExp(loc), f); + e = e.semantic(sc); + } + else if (f.isNested()) + { + e = new DelegateExp(loc, new IntegerExp(0), f); + e = e.semantic(sc); + } + else if (f.needThis()) + { + error("no 'this' to create delegate for %s", f.toChars()); + e = new ErrorExp(); + } + else + { + error("cannot cast from function pointer to delegate"); + e = new ErrorExp(); + } + } + else + { + e = new SymOffExp(loc, f, 0); + e.type = t; + } + version (DMDV2) { + f.tookAddressOf++; + } + return e; + } + } + } + e = Expression.castTo(sc, t); + } + else + { + e = copy(); + e.type = t; + (cast(SymOffExp)e).hasOverloads = 0; + } + return e; + } + + void scanForNestedRef(Scope sc) + { + assert(false); + } + + dt_t** toDt(dt_t** pdt) + { + //printf("SymOffExp.toDt('%s')\n", var.toChars()); + assert(var); + if (!(var.isDataseg() || var.isCodeseg()) || + var.needThis() || + var.isThreadlocal() + ) + { + debug writef("SymOffExp.toDt()\n"); + error("non-constant expression %s", toChars()); + return pdt; + } + + Symbol* s = var.toSymbol(); + return dtxoff(pdt, s, offset, TYnptr); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/SymbolDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/SymbolDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,42 @@ +module dmd.SymbolDeclaration; + +import dmd.Declaration; +import dmd.StructDeclaration; +import dmd.Loc; +import dmd.TOK; +import dmd.STC; +import dmd.Identifier; + +import dmd.backend.Symbol; + +import core.stdc.string; +import std.stdio; + +// This is a shell around a back end symbol + +class SymbolDeclaration : Declaration +{ + Symbol* sym; + StructDeclaration dsym; + + this(Loc loc, Symbol* s, StructDeclaration dsym) + { + int len = strlen(s.Sident.ptr); + string name = s.Sident.ptr[0..len].idup; + + super(new Identifier(name, TOK.TOKidentifier)); + + this.loc = loc; + sym = s; + this.dsym = dsym; + storage_class |= STCconst; + } + + Symbol* toSymbol() + { + return sym; + } + + // Eliminate need for dynamic_cast + SymbolDeclaration isSymbolDeclaration() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/SymbolExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/SymbolExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,202 @@ +module dmd.SymbolExp; + +import dmd.Expression; +import dmd.Declaration; +import dmd.Loc; +import dmd.IRState; +import dmd.TOK; +import dmd.TY; +import dmd.Type; +import dmd.SymOffExp; +import dmd.FuncDeclaration; +import dmd.VarDeclaration; +import dmd.backend.OPER; +import dmd.backend.TYM; +import dmd.backend.mTY; +import dmd.backend.SC; +import dmd.backend.elem; +import dmd.backend.Symbol; +import dmd.backend.Util; +import dmd.codegen.Util; + +class SymbolExp : Expression +{ + Declaration var; + + int hasOverloads; + + this(Loc loc, TOK op, int size, Declaration var, int hasOverloads) + { + super(loc, op, size); + assert(var); + this.var = var; + this.hasOverloads = hasOverloads; + } + + elem* toElem(IRState* irs) + { + Symbol* s; + elem* e; + tym_t tym; + Type tb = (op == TOK.TOKsymoff) ? var.type.toBasetype() : type.toBasetype(); + int offset = (op == TOK.TOKsymoff) ? (cast(SymOffExp)this).offset : 0; + FuncDeclaration fd; + VarDeclaration v = var.isVarDeclaration(); + + //printf("SymbolExp::toElem('%s') %p\n", toChars(), this); + //printf("\tparent = '%s'\n", var.parent ? var.parent.toChars() : "null"); + if (op == TOK.TOKvar && var.needThis()) + { + error("need 'this' to access member %s", toChars()); + return el_long(TYM.TYint, 0); + } + s = var.toSymbol(); + fd = null; + if (var.toParent2()) + fd = var.toParent2().isFuncDeclaration(); + + int nrvo = 0; + if (fd && fd.nrvo_can && fd.nrvo_var == var) + { + s = fd.shidden; + nrvo = 1; + } + + if (s.Sclass == SC.SCauto || s.Sclass == SC.SCparameter) + { + if (fd && fd != irs.getFunc()) + { + // 'var' is a variable in an enclosing function. + elem* ethis; + int soffset; + + ethis = getEthis(loc, irs, fd); + ethis = el_una(OPER.OPaddr, TYM.TYnptr, ethis); + + if (v && v.offset) + soffset = v.offset; + else + { + soffset = s.Soffset; + /* If fd is a non-static member function of a class or struct, + * then ethis isn't the frame pointer. + * ethis is the 'this' pointer to the class/struct instance. + * We must offset it. + */ + if (fd.vthis) + { + soffset -= fd.vthis.toSymbol().Soffset; + } + //printf("\tSoffset = x%x, sthis.Soffset = x%x\n", s.Soffset, irs.sthis.Soffset); + } + + if (!nrvo) + soffset += offset; + + e = el_bin(OPER.OPadd, TYM.TYnptr, ethis, el_long(TYM.TYnptr, soffset)); + + if (op == TOK.TOKvar) + e = el_una(OPER.OPind, TYM.TYnptr, e); + if ((var.isParameter() && tb.ty == TY.Tsarray) || var.isOut() || var.isRef()) + e = el_una(OPER.OPind, s.ty(), e); + else if (op == TOK.TOKsymoff && nrvo) + { + e = el_una(OPER.OPind, TYM.TYnptr, e); + e = el_bin(OPER.OPadd, e.Ety, e, el_long(TYM.TYint, offset)); + } + goto L1; + } + } + + /* If var is a member of a closure + */ + if (v && v.offset) + { + assert(irs.sclosure); + e = el_var(irs.sclosure); + e = el_bin(OPER.OPadd, TYM.TYnptr, e, el_long(TYM.TYint, v.offset)); + if (op == TOK.TOKvar) + { + e = el_una(OPER.OPind, type.totym(), e); + if (tybasic(e.Ety) == TYM.TYstruct) + e.Enumbytes = cast(uint)type.size(); + el_setLoc(e, loc); + } + if ((var.isParameter() && tb.ty == TY.Tsarray) || var.isOut() || var.isRef()) + { + e.Ety = TYM.TYnptr; + e = el_una(OPER.OPind, s.ty(), e); + } + else if (op == TOK.TOKsymoff && nrvo) + { e = el_una(OPER.OPind, TYM.TYnptr, e); + e = el_bin(OPER.OPadd, e.Ety, e, el_long(TYM.TYint, offset)); + } + else if (op == TOK.TOKsymoff) + { + e = el_bin(OPER.OPadd, e.Ety, e, el_long(TYM.TYint, offset)); + } + goto L1; + } + + if (s.Sclass == SC.SCauto && s.Ssymnum == -1) + { + //printf("\tadding symbol\n"); + symbol_add(s); + } + + if (var.isImportedSymbol()) + { + assert(op == TOK.TOKvar); + e = el_var(var.toImport()); + e = el_una(OPER.OPind,s.ty(),e); + } + else if ((var.isParameter() && tb.ty == TY.Tsarray) || var.isOut() || var.isRef()) + { + // Static arrays are really passed as pointers to the array + // Out parameters are really references + e = el_var(s); + e.Ety = TYM.TYnptr; + if (op == TOK.TOKvar) + e = el_una(OPER.OPind, s.ty(), e); + else if (offset) + e = el_bin(OPER.OPadd, TYM.TYnptr, e, el_long(TYM.TYint, offset)); + } + else if (op == TOK.TOKvar) + e = el_var(s); + else + { + e = nrvo ? el_var(s) : el_ptr(s); + e = el_bin(OPER.OPadd, e.Ety, e, el_long(TYM.TYint, offset)); + } + L1: + if (op == TOK.TOKvar) + { + if (nrvo) + { + e.Ety = TYM.TYnptr; + e = el_una(OPER.OPind, 0, e); + } + if (tb.ty == TY.Tfunction) + { + tym = s.Stype.Tty; + } + else + tym = type.totym(); + e.Ejty = cast(ubyte)tym; + e.Ety = e.Ejty; + if (tybasic(tym) == TYM.TYstruct) + { + e.Enumbytes = cast(uint)type.size(); + } + else if (tybasic(tym) == TYM.TYarray) + { + e.Ejty = TYM.TYstruct; + e.Ety = e.Ejty; + e.Enumbytes = cast(uint)type.size(); + } + } + el_setLoc(e,loc); + return e; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/SynchronizedStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/SynchronizedStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,193 @@ +module dmd.SynchronizedStatement; + +import dmd.Statement; +import dmd.IntegerExp; +import dmd.TypeSArray; +import dmd.CompoundStatement; +import dmd.Loc; +import dmd.Scope; +import dmd.Expression; +import dmd.ClassDeclaration; +import dmd.Id; +import dmd.TypeIdentifier; +import dmd.Type; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.InlineScanState; +import dmd.IRState; +import dmd.CastExp; +import dmd.TryFinallyStatement; +import dmd.ExpStatement; +import dmd.CallExp; +import dmd.DeclarationExp; +import dmd.VarExp; +import dmd.DeclarationStatement; +import dmd.ArrayTypes; +import dmd.Statement; +import dmd.VarDeclaration; +import dmd.ExpInitializer; +import dmd.Lexer; +import dmd.Identifier; +import dmd.FuncDeclaration; +import dmd.BE; +import dmd.STC; +import dmd.DotIdExp; + +import dmd.backend.elem; +import dmd.backend.Util; + +class SynchronizedStatement : Statement +{ + Expression exp; + Statement body_; + + this(Loc loc, Expression exp, Statement body_) + { + super(loc); + + this.exp = exp; + this.body_ = body_; + this.esync = null; + } + + Statement syntaxCopy() + { + assert(false); + } + + Statement semantic(Scope sc) + { + if (exp) + { + exp = exp.semantic(sc); + exp = resolveProperties(sc, exp); + ClassDeclaration cd = exp.type.isClassHandle(); + if (!cd) + error("can only synchronize on class objects, not '%s'", exp.type.toChars()); + else if (cd.isInterfaceDeclaration()) + { + /* Cast the interface to an object, as the object has the monitor, + * not the interface. + */ + Type t = new TypeIdentifier(Loc(0), Id.Object_); + + t = t.semantic(Loc(0), sc); + exp = new CastExp(loc, exp, t); + exp = exp.semantic(sc); + } + +static if (true) { + /* Rewrite as: + * auto tmp = exp; + * _d_monitorenter(tmp); + * try { body } finally { _d_monitorexit(tmp); } + */ + Identifier id = Lexer.uniqueId("__sync"); + ExpInitializer ie = new ExpInitializer(loc, exp); + VarDeclaration tmp = new VarDeclaration(loc, exp.type, id, ie); + + Statements cs = new Statements(); + cs.push(cast(void*)new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); + + FuncDeclaration fdenter = FuncDeclaration.genCfunc(Type.tvoid, Id.monitorenter); + Expression e = new CallExp(loc, new VarExp(loc, fdenter), new VarExp(loc, tmp)); + e.type = Type.tvoid; // do not run semantic on e + cs.push(cast(void*)new ExpStatement(loc, e)); + + FuncDeclaration fdexit = FuncDeclaration.genCfunc(Type.tvoid, Id.monitorexit); + e = new CallExp(loc, new VarExp(loc, fdexit), new VarExp(loc, tmp)); + e.type = Type.tvoid; // do not run semantic on e + Statement s = new ExpStatement(loc, e); + s = new TryFinallyStatement(loc, body_, s); + cs.push(cast(void*)s); + + s = new CompoundStatement(loc, cs); + return s.semantic(sc); +} + } +/// static if (true) { + else + { + /* Generate our own critical section, then rewrite as: + * __gshared byte[CriticalSection.sizeof] critsec; + * _d_criticalenter(critsec.ptr); + * try { body } finally { _d_criticalexit(critsec.ptr); } + */ + Identifier id = Lexer.uniqueId("__critsec"); + Type t = new TypeSArray(Type.tint8, new IntegerExp(PTRSIZE + os_critsecsize())); + VarDeclaration tmp = new VarDeclaration(loc, t, id, null); + tmp.storage_class |= STCgshared | STCstatic; + + Statements cs = new Statements(); + cs.push(cast(void*)new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); + + FuncDeclaration fdenter = FuncDeclaration.genCfunc(Type.tvoid, Id.criticalenter); + Expression e = new DotIdExp(loc, new VarExp(loc, tmp), Id.ptr); + e = e.semantic(sc); + e = new CallExp(loc, new VarExp(loc, fdenter), e); + e.type = Type.tvoid; // do not run semantic on e + cs.push(cast(void*)new ExpStatement(loc, e)); + + FuncDeclaration fdexit = FuncDeclaration.genCfunc(Type.tvoid, Id.criticalexit); + e = new DotIdExp(loc, new VarExp(loc, tmp), Id.ptr); + e = e.semantic(sc); + e = new CallExp(loc, new VarExp(loc, fdexit), e); + e.type = Type.tvoid; // do not run semantic on e + Statement s = new ExpStatement(loc, e); + s = new TryFinallyStatement(loc, body_, s); + cs.push(cast(void*)s); + + s = new CompoundStatement(loc, cs); + return s.semantic(sc); + } +/// } + if (body_) + body_ = body_.semantic(sc); + + return this; + } + + bool hasBreak() + { + assert(false); + } + + bool hasContinue() + { + assert(false); + } + + bool usesEH() + { + assert(false); + } + + BE blockExit() + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + Statement inlineScan(InlineScanState* iss) + { + assert(false); + } + +// Back end + elem* esync; + + this(Loc loc, elem *esync, Statement body_) + { + assert(false); + super(loc); + } + + void toIR(IRState* irs) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TFLAGS.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TFLAGS.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,11 @@ +module dmd.TFLAGS; + +enum TFLAGS +{ + TFLAGSintegral = 1, + TFLAGSfloating = 2, + TFLAGSunsigned = 4, + TFLAGSreal = 8, + TFLAGSimaginary = 0x10, + TFLAGScomplex = 0x20, +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TOK.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TOK.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,251 @@ +module dmd.TOK; + +version (DMDV2) { + enum TOK + { + TOKreserved, + + // Other + TOKlparen, TOKrparen, + TOKlbracket, TOKrbracket, + TOKlcurly, TOKrcurly, + TOKcolon, TOKneg, + TOKsemicolon, TOKdotdotdot, + TOKeof, TOKcast, + TOKnull, TOKassert, + TOKtrue, TOKfalse, + TOKarray, TOKcall, + TOKaddress, + TOKtype, TOKthrow, + TOKnew, TOKdelete, + TOKstar, TOKsymoff, + TOKvar, TOKdotvar, + TOKdotti, TOKdotexp, + TOKdottype, TOKslice, + TOKarraylength, TOKversion, + TOKmodule, TOKdollar, + TOKtemplate, TOKdottd, + TOKdeclaration, TOKtypeof, + TOKpragma, TOKdsymbol, + TOKtypeid, TOKuadd, + TOKremove, + TOKnewanonclass, TOKcomment, + TOKarrayliteral, TOKassocarrayliteral, + TOKstructliteral, + + // Operators + TOKlt, TOKgt, + TOKle, TOKge, + TOKequal, TOKnotequal, + TOKidentity, TOKnotidentity, + TOKindex, TOKis, + TOKtobool, + + // 60 + // NCEG floating point compares + // !<>= <> <>= !> !>= !< !<= !<> + TOKunord,TOKlg,TOKleg,TOKule,TOKul,TOKuge,TOKug,TOKue, + + TOKshl, TOKshr, + TOKshlass, TOKshrass, + TOKushr, TOKushrass, + TOKcat, TOKcatass, // ~ ~= + TOKadd, TOKmin, TOKaddass, TOKminass, + TOKmul, TOKdiv, TOKmod, + TOKmulass, TOKdivass, TOKmodass, + TOKand, TOKor, TOKxor, + TOKandass, TOKorass, TOKxorass, + TOKassign, TOKnot, TOKtilde, + TOKplusplus, TOKminusminus, TOKconstruct, TOKblit, + TOKdot, TOKarrow, TOKcomma, + TOKquestion, TOKandand, TOKoror, + + // 104 + // Numeric literals + TOKint32v, TOKuns32v, + TOKint64v, TOKuns64v, + TOKfloat32v, TOKfloat64v, TOKfloat80v, + TOKimaginary32v, TOKimaginary64v, TOKimaginary80v, + + // Char constants + TOKcharv, TOKwcharv, TOKdcharv, + + // Leaf operators + TOKidentifier, TOKstring, + TOKthis, TOKsuper, + TOKhalt, TOKtuple, + + // Basic types + TOKvoid, + TOKint8, TOKuns8, + TOKint16, TOKuns16, + TOKint32, TOKuns32, + TOKint64, TOKuns64, + TOKfloat32, TOKfloat64, TOKfloat80, + TOKimaginary32, TOKimaginary64, TOKimaginary80, + TOKcomplex32, TOKcomplex64, TOKcomplex80, + TOKchar, TOKwchar, TOKdchar, TOKbit, TOKbool, + TOKcent, TOKucent, + + // Aggregates + TOKstruct, TOKclass, TOKinterface, TOKunion, TOKenum, TOKimport, + TOKtypedef, TOKalias, TOKoverride, TOKdelegate, TOKfunction, + TOKmixin, + + TOKalign, TOKextern, TOKprivate, TOKprotected, TOKpublic, TOKexport, + TOKstatic, /*TOKvirtual,*/ TOKfinal, TOKconst, TOKabstract, TOKvolatile, + TOKdebug, TOKdeprecated, TOKin, TOKout, TOKinout, TOKlazy, + TOKauto, TOKpackage, TOKmanifest, TOKimmutable, + + // Statements + TOKif, TOKelse, TOKwhile, TOKfor, TOKdo, TOKswitch, + TOKcase, TOKdefault, TOKbreak, TOKcontinue, TOKwith, + TOKsynchronized, TOKreturn, TOKgoto, TOKtry, TOKcatch, TOKfinally, + TOKasm, TOKforeach, TOKforeach_reverse, + TOKscope, + TOKon_scope_exit, TOKon_scope_failure, TOKon_scope_success, + + // Contracts + TOKbody, TOKinvariant, + + // Testing + TOKunittest, + + // Added after 1.0 + TOKref, + TOKmacro, + + TOKtraits, + TOKoverloadset, + TOKpure, + TOKnothrow, + TOKtls, + TOKgshared, + TOKline, + TOKfile, + TOKshared, + TOKat, + + TOKMAX + } +} else { + enum TOK + { + TOKreserved, + + // Other + TOKlparen, TOKrparen, + TOKlbracket, TOKrbracket, + TOKlcurly, TOKrcurly, + TOKcolon, TOKneg, + TOKsemicolon, TOKdotdotdot, + TOKeof, TOKcast, + TOKnull, TOKassert, + TOKtrue, TOKfalse, + TOKarray, TOKcall, + TOKaddress, + TOKtype, TOKthrow, + TOKnew, TOKdelete, + TOKstar, TOKsymoff, + TOKvar, TOKdotvar, + TOKdotti, TOKdotexp, + TOKdottype, TOKslice, + TOKarraylength, TOKversion, + TOKmodule, TOKdollar, + TOKtemplate, TOKdottd, + TOKdeclaration, TOKtypeof, + TOKpragma, TOKdsymbol, + TOKtypeid, TOKuadd, + TOKremove, + TOKnewanonclass, TOKcomment, + TOKarrayliteral, TOKassocarrayliteral, + TOKstructliteral, + + // Operators + TOKlt, TOKgt, + TOKle, TOKge, + TOKequal, TOKnotequal, + TOKidentity, TOKnotidentity, + TOKindex, TOKis, + TOKtobool, + + // 60 + // NCEG floating point compares + // !<>= <> <>= !> !>= !< !<= !<> + TOKunord,TOKlg,TOKleg,TOKule,TOKul,TOKuge,TOKug,TOKue, + + TOKshl, TOKshr, + TOKshlass, TOKshrass, + TOKushr, TOKushrass, + TOKcat, TOKcatass, // ~ ~= + TOKadd, TOKmin, TOKaddass, TOKminass, + TOKmul, TOKdiv, TOKmod, + TOKmulass, TOKdivass, TOKmodass, + TOKand, TOKor, TOKxor, + TOKandass, TOKorass, TOKxorass, + TOKassign, TOKnot, TOKtilde, + TOKplusplus, TOKminusminus, TOKconstruct, TOKblit, + TOKdot, TOKarrow, TOKcomma, + TOKquestion, TOKandand, TOKoror, + + // 104 + // Numeric literals + TOKint32v, TOKuns32v, + TOKint64v, TOKuns64v, + TOKfloat32v, TOKfloat64v, TOKfloat80v, + TOKimaginary32v, TOKimaginary64v, TOKimaginary80v, + + // Char constants + TOKcharv, TOKwcharv, TOKdcharv, + + // Leaf operators + TOKidentifier, TOKstring, + TOKthis, TOKsuper, + TOKhalt, TOKtuple, + + // Basic types + TOKvoid, + TOKint8, TOKuns8, + TOKint16, TOKuns16, + TOKint32, TOKuns32, + TOKint64, TOKuns64, + TOKfloat32, TOKfloat64, TOKfloat80, + TOKimaginary32, TOKimaginary64, TOKimaginary80, + TOKcomplex32, TOKcomplex64, TOKcomplex80, + TOKchar, TOKwchar, TOKdchar, TOKbit, TOKbool, + TOKcent, TOKucent, + + // Aggregates + TOKstruct, TOKclass, TOKinterface, TOKunion, TOKenum, TOKimport, + TOKtypedef, TOKalias, TOKoverride, TOKdelegate, TOKfunction, + TOKmixin, + + TOKalign, TOKextern, TOKprivate, TOKprotected, TOKpublic, TOKexport, + TOKstatic, /*TOKvirtual,*/ TOKfinal, TOKconst, TOKabstract, TOKvolatile, + TOKdebug, TOKdeprecated, TOKin, TOKout, TOKinout, TOKlazy, + TOKauto, TOKpackage, TOKmanifest, TOKimmutable, + + // Statements + TOKif, TOKelse, TOKwhile, TOKfor, TOKdo, TOKswitch, + TOKcase, TOKdefault, TOKbreak, TOKcontinue, TOKwith, + TOKsynchronized, TOKreturn, TOKgoto, TOKtry, TOKcatch, TOKfinally, + TOKasm, TOKforeach, TOKforeach_reverse, + TOKscope, + TOKon_scope_exit, TOKon_scope_failure, TOKon_scope_success, + + // Contracts + TOKbody, TOKinvariant, + + // Testing + TOKunittest, + + // Added after 1.0 + TOKref, + TOKmacro, + + TOKMAX + } +} + +import dmd.EnumUtils; +mixin(BringToCurrentScope!(TOK)); \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TY.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TY.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,58 @@ +module dmd.TY; + +enum TY +{ + Tarray, // slice array, aka T[] + Tsarray, // static array, aka T[dimension] + Tnarray, // resizable array, aka T[new] + Taarray, // associative array, aka T[type] + Tpointer, + Treference, + Tfunction, + Tident, + Tclass, + Tstruct, + Tenum, + Ttypedef, + Tdelegate, + + Tnone, + Tvoid, + Tint8, + Tuns8, + Tint16, + Tuns16, + Tint32, + Tuns32, + Tint64, + Tuns64, + Tfloat32, + Tfloat64, + Tfloat80, + + Timaginary32, + Timaginary64, + Timaginary80, + + Tcomplex32, + Tcomplex64, + Tcomplex80, + + Tbit, + Tbool, + Tchar, + Tascii = Tchar, + Twchar, + Tdchar, + + Terror, + Tinstance, + Ttypeof, + Ttuple, + Tslice, + Treturn, + TMAX +} + +import dmd.EnumUtils; +mixin(BringToCurrentScope!(TY)); \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TemplateAliasParameter.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TemplateAliasParameter.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,87 @@ +module dmd.TemplateAliasParameter; + +import dmd.TemplateParameter; +import dmd.Loc; +import dmd.Identifier; +import dmd.Type; +import dmd.ArrayTypes; +import dmd.Scope; +import dmd.Declaration; +import dmd.MATCH; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Dsymbol; + +class TemplateAliasParameter : TemplateParameter +{ + /* Syntax: + * specType ident : specAlias = defaultAlias + */ + + Type specType; + Object specAlias; + Object defaultAlias; + + static Dsymbol sdummy; + + this(Loc loc, Identifier ident, Type specType, Object specAlias, Object defaultAlias) + { + assert(false); + super(loc, ident); + } + + TemplateAliasParameter isTemplateAliasParameter() + { + assert(false); + } + + TemplateParameter syntaxCopy() + { + assert(false); + } + + void declareParameter(Scope sc) + { + assert(false); + } + + void semantic(Scope) + { + assert(false); + } + + void print(Object oarg, Object oded) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + Object specialization() + { + assert(false); + } + + Object defaultArg(Loc loc, Scope sc) + { + assert(false); + } + + bool overloadMatch(TemplateParameter) + { + assert(false); + } + + MATCH matchArg(Scope sc, Objects tiargs, int i, TemplateParameters parameters, Objects dedtypes, Declaration* psparam, int flags) + { + assert(false); + } + + void* dummyArg() + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TemplateDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TemplateDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,1143 @@ +module dmd.TemplateDeclaration; + +import dmd.Loc; +import dmd.ScopeDsymbol; +import dmd.ArrayTypes; +import dmd.Dsymbol; +import dmd.STC; +import dmd.TemplateThisParameter; +import dmd.Global; +import dmd.Array; +import dmd.Identifier; +import dmd.TypeArray; +import dmd.Expression; +import dmd.Scope; +import dmd.TypeIdentifier; +import dmd.TypeDelegate; +import dmd.IntegerExp; +import dmd.TypeSArray; +import dmd.StringExp; +import dmd.TOK; +import dmd.Argument; +import dmd.CtorDeclaration; +import dmd.TypeFunction; +import dmd.TY; +import dmd.OutBuffer; +import dmd.Declaration; +import dmd.HdrGenState; +import dmd.TemplateInstance; +import dmd.WANT; +import dmd.FuncDeclaration; +import dmd.TemplateTupleParameter; +import dmd.MATCH; +import dmd.Type; +import dmd.Tuple; +import dmd.TupleDeclaration; +import dmd.Initializer; +import dmd.ExpInitializer; +import dmd.TemplateValueParameter; +import dmd.AliasDeclaration; +import dmd.VarDeclaration; +import dmd.TemplateParameter; +import dmd.TemplateTypeParameter; + +import dmd.expression.Util; + +import std.stdio; + +/************************************** + * Determine if TemplateDeclaration is variadic. + */ + +TemplateTupleParameter isVariadic(TemplateParameters parameters) +{ + size_t dim = parameters.dim; + TemplateTupleParameter tp = null; + + if (dim) + tp = (cast(TemplateParameter)parameters.data[dim - 1]).isTemplateTupleParameter(); + + return tp; +} + +void ObjectToCBuffer(OutBuffer buf, HdrGenState* hgs, Object oarg) +{ + //printf("ObjectToCBuffer()\n"); + Type t = isType(oarg); + Expression e = isExpression(oarg); + Dsymbol s = isDsymbol(oarg); + Tuple v = isTuple(oarg); + if (t) + { + //printf("\tt: %s ty = %d\n", t.toChars(), t.ty); + t.toCBuffer(buf, null, hgs); + } + else if (e) + e.toCBuffer(buf, hgs); + else if (s) + { + string p = s.ident ? s.ident.toChars() : s.toChars(); + buf.writestring(p); + } + else if (v) + { + Objects args = v.objects; + for (size_t i = 0; i < args.dim; i++) + { + if (i) + buf.writeByte(','); + Object o = cast(Object)args.data[i]; + ObjectToCBuffer(buf, hgs, o); + } + } + else if (!oarg) + { + buf.writestring("null"); + } + else + { + debug writef("bad Object = %p\n", oarg); + assert(0); + } +} + +class TemplateDeclaration : ScopeDsymbol +{ + TemplateParameters parameters; // array of TemplateParameter's + + TemplateParameters origParameters; // originals for Ddoc + Expression constraint; + Array instances; // array of TemplateInstance's + + TemplateDeclaration overnext; // next overloaded TemplateDeclaration + TemplateDeclaration overroot; // first in overnext list + + int semanticRun; // 1 semantic() run + + Dsymbol onemember; // if !=NULL then one member of this template + + int literal; // this template declaration is a literal + + this(Loc loc, Identifier id, TemplateParameters parameters, Expression constraint, Array decldefs) + { + super(id); + + version (LOG) { + printf("TemplateDeclaration(this = %p, id = '%s')\n", this, id.toChars()); + } + static if (false) { + if (parameters) + for (int i = 0; i < parameters.dim; i++) + { + TemplateParameter tp = cast(TemplateParameter)parameters.data[i]; + //printf("\tparameter[%d] = %p\n", i, tp); + TemplateTypeParameter ttp = tp.isTemplateTypeParameter(); + + if (ttp) + { + printf("\tparameter[%d] = %s : %s\n", i, tp.ident.toChars(), ttp.specType ? ttp.specType.toChars() : ""); + } + } + } + + this.loc = loc; + this.parameters = parameters; + this.origParameters = parameters; + this.constraint = constraint; + this.members = decldefs; + + instances = new Array(); + } + + Dsymbol syntaxCopy(Dsymbol) + { + assert(false); + } + + void semantic(Scope sc) + { + version (LOG) { + printf("TemplateDeclaration.semantic(this = %p, id = '%s')\n", this, ident.toChars()); + } + if (semanticRun) + return; // semantic() already run + semanticRun = 1; + + if (sc.func) + { + version (DMDV1) { + error("cannot declare template at function scope %s", sc.func.toChars()); + } + } + + if (/*global.params.useArrayBounds &&*/ sc.module_) + { + // Generate this function as it may be used + // when template is instantiated in other modules + sc.module_.toModuleArray(); + } + + if (/*global.params.useAssert &&*/ sc.module_) + { + // Generate this function as it may be used + // when template is instantiated in other modules + sc.module_.toModuleAssert(); + } + + /* Remember Scope for later instantiations, but make + * a copy since attributes can change. + */ + this.scope_ = new Scope(sc); /// A light copy + this.scope_.setNoFree(); + + // Set up scope for parameters + ScopeDsymbol paramsym = new ScopeDsymbol(); + paramsym.parent = sc.parent; + Scope paramscope = sc.push(paramsym); + paramscope.parameterSpecialization = 1; + paramscope.stc = STCundefined; + + if (!parent) + parent = sc.parent; + + if (global.params.doDocComments) + { + origParameters = new TemplateParameters(); + origParameters.setDim(parameters.dim); + for (int i = 0; i < parameters.dim; i++) + { + TemplateParameter tp = cast(TemplateParameter)parameters.data[i]; + origParameters.data[i] = cast(void*)tp.syntaxCopy(); + } + } + + for (int i = 0; i < parameters.dim; i++) + { + TemplateParameter tp = cast(TemplateParameter)parameters.data[i]; + tp.declareParameter(paramscope); + } + + for (int i = 0; i < parameters.dim; i++) + { + TemplateParameter tp = cast(TemplateParameter)parameters.data[i]; + + tp.semantic(paramscope); + if (i + 1 != parameters.dim && tp.isTemplateTupleParameter()) + error("template tuple parameter must be last one"); + } + + paramscope.pop(); + + if (members) + { + Dsymbol s; + if (Dsymbol.oneMembers(members, &s)) + { + if (s && s.ident && s.ident.equals(ident)) + { + onemember = s; + s.parent = this; + } + } + } + + /* BUG: should check: + * o no virtual functions or non-static data members of classes + */ + } + + bool overloadInsert(Dsymbol s) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + string kind() + { + assert(false); + } + + string toChars() + { + assert(false); + } + + void emitComment(Scope sc) + { + assert(false); + } + +// void toDocBuffer(OutBuffer *buf); + + /*************************************** + * Given that ti is an instance of this TemplateDeclaration, + * deduce the types of the parameters to this, and store + * those deduced types in dedtypes[]. + * Input: + * flag 1: don't do semantic() because of dummy types + * 2: don't change types in matchArg() + * Output: + * dedtypes deduced arguments + * Return match level. + */ + MATCH matchWithInstance(TemplateInstance ti, Objects dedtypes, int flag) + { + MATCH m; + int dedtypes_dim = dedtypes.dim; + + version (LOGM) { + printf("\n+TemplateDeclaration.matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti.toChars(), flag); + } + + static if (false) { + printf("dedtypes.dim = %d, parameters.dim = %d\n", dedtypes_dim, parameters.dim); + if (ti.tiargs.dim) + printf("ti.tiargs.dim = %d, [0] = %p\n", ti.tiargs.dim, ti.tiargs.data[0]); + } + dedtypes.zero(); + + int parameters_dim = parameters.dim; + int variadic = isVariadic() !is null; + + // If more arguments than parameters, no match + if (ti.tiargs.dim > parameters_dim && !variadic) + { + version (LOGM) { + printf(" no match: more arguments than parameters\n"); + } + return MATCHnomatch; + } + + assert(dedtypes_dim == parameters_dim); + assert(dedtypes_dim >= ti.tiargs.dim || variadic); + + // Set up scope for parameters + assert(cast(size_t)cast(void*)scope_ > 0x10000); + ScopeDsymbol paramsym = new ScopeDsymbol(); + paramsym.parent = scope_.parent; + Scope paramscope = scope_.push(paramsym); + paramscope.stc = STCundefined; + + // Attempt type deduction + m = MATCHexact; + for (int i = 0; i < dedtypes_dim; i++) + { + MATCH m2; + TemplateParameter tp = cast(TemplateParameter)parameters.data[i]; + Declaration sparam; + + //printf("\targument [%d]\n", i); + version (LOGM) { + //printf("\targument [%d] is %s\n", i, oarg ? oarg.toChars() : "null"); + TemplateTypeParameter *ttp = tp.isTemplateTypeParameter(); + if (ttp) + printf("\tparameter[%d] is %s : %s\n", i, tp.ident.toChars(), ttp.specType ? ttp.specType.toChars() : ""); + } + + version (DMDV1) { + m2 = tp.matchArg(paramscope, ti.tiargs, i, parameters, dedtypes, &sparam); + } else { + m2 = tp.matchArg(paramscope, ti.tiargs, i, parameters, dedtypes, &sparam, (flag & 2) ? 1 : 0); + } + //printf("\tm2 = %d\n", m2); + + if (m2 == MATCHnomatch) + { + static if (false) { + printf("\tmatchArg() for parameter %i failed\n", i); + } + goto Lnomatch; + } + + if (m2 < m) + m = m2; + + if (!flag) + sparam.semantic(paramscope); + if (!paramscope.insert(sparam)) + goto Lnomatch; + } + + if (!flag) + { + /* Any parameter left without a type gets the type of + * its corresponding arg + */ + for (int i = 0; i < dedtypes_dim; i++) + { + if (!dedtypes.data[i]) + { + assert(i < ti.tiargs.dim); + dedtypes.data[i] = ti.tiargs.data[i]; + } + } + } + + version (DMDV2) { + if (m && constraint && !(flag & 1)) + { /* Check to see if constraint is satisfied. + */ + Expression e = constraint.syntaxCopy(); + paramscope.flags |= SCOPE.SCOPEstaticif; + e = e.semantic(paramscope); + e = e.optimize(WANTvalue | WANTinterpret); + if (e.isBool(true)) { + ; + } else if (e.isBool(false)) + goto Lnomatch; + else + { + e.error("constraint %s is not constant or does not evaluate to a bool", e.toChars()); + } + } + } + + version (LOGM) { + // Print out the results + printf("--------------------------\n"); + printf("template %s\n", toChars()); + printf("instance %s\n", ti.toChars()); + if (m) + { + for (int i = 0; i < dedtypes_dim; i++) + { + TemplateParameter tp = cast(TemplateParameter)parameters.data[i]; + Object oarg; + + printf(" [%d]", i); + + if (i < ti.tiargs.dim) + oarg = cast(Object)ti.tiargs.data[i]; + else + oarg = null; + tp.print(oarg, cast(Object)dedtypes.data[i]); + } + } + else + goto Lnomatch; + } + + version (LOGM) { + printf(" match = %d\n", m); + } + goto Lret; + + Lnomatch: + version (LOGM) { + printf(" no match\n"); + } + m = MATCHnomatch; + + Lret: + paramscope.pop(); + version (LOGM) { + printf("-TemplateDeclaration.matchWithInstance(this = %p, ti = %p) = %d\n", this, ti, m); + } + return m; + } + + MATCH leastAsSpecialized(TemplateDeclaration td2) + { + assert(false); + } + + /************************************************* + * Match function arguments against a specific template function. + * Input: + * loc instantiation location + * targsi Expression/Type initial list of template arguments + * ethis 'this' argument if !null + * fargs arguments to function + * Output: + * dedargs Expression/Type deduced template arguments + * Returns: + * match level + */ + MATCH deduceFunctionTemplateMatch(Loc loc, Objects targsi, Expression ethis, Expressions fargs, Objects dedargs) + { + size_t nfparams; + size_t nfargs; + size_t nargsi; // array size of targsi + int fptupindex = -1; + int tuple_dim = 0; + MATCH match = MATCHexact; + FuncDeclaration fd = onemember.toAlias().isFuncDeclaration(); + Arguments fparameters; // function parameter list + int fvarargs; // function varargs + scope Objects dedtypes = new Objects(); // for T:T*, the dedargs is the T*, dedtypes is the T + + static if (false) { + printf("\nTemplateDeclaration.deduceFunctionTemplateMatch() %s\n", toChars()); + for (i = 0; i < fargs.dim; i++) + { + Expression e = cast(Expression)fargs.data[i]; + printf("\tfarg[%d] is %s, type is %s\n", i, e.toChars(), e.type.toChars()); + } + printf("fd = %s\n", fd.toChars()); + printf("fd.type = %p\n", fd.type); + } + + assert(cast(size_t)cast(void*)scope_ > 0x10000); + + dedargs.setDim(parameters.dim); + dedargs.zero(); + + dedtypes.setDim(parameters.dim); + dedtypes.zero(); + + // Set up scope for parameters + ScopeDsymbol paramsym = new ScopeDsymbol(); + paramsym.parent = scope_.parent; + Scope paramscope = scope_.push(paramsym); + + TemplateTupleParameter tp = isVariadic(); + + static if (false) { + for (i = 0; i < dedargs.dim; i++) + { + printf("\tdedarg[%d] = ", i); + Object oarg = cast(Object)dedargs.data[i]; + if (oarg) printf("%s", oarg.toChars()); + printf("\n"); + } + } + + + nargsi = 0; + if (targsi) + { // Set initial template arguments + size_t n; + + nargsi = targsi.dim; + n = parameters.dim; + if (tp) + n--; + if (nargsi > n) + { + if (!tp) + goto Lnomatch; + + /* The extra initial template arguments + * now form the tuple argument. + */ + Tuple t = new Tuple(); + assert(parameters.dim); + dedargs.data[parameters.dim - 1] = cast(void*)t; + + tuple_dim = nargsi - n; + t.objects.setDim(tuple_dim); + for (size_t i = 0; i < tuple_dim; i++) + { + t.objects.data[i] = cast(void*)targsi.data[n + i]; + } + declareParameter(paramscope, tp, t); + } + else + n = nargsi; + + memcpy(dedargs.data, targsi.data, n * (*dedargs.data).sizeof); + + for (size_t i = 0; i < n; i++) + { + assert(i < parameters.dim); + TemplateParameter tp2 = cast(TemplateParameter)parameters.data[i]; + MATCH m; + Declaration sparam = null; + + m = tp2.matchArg(paramscope, dedargs, i, parameters, dedtypes, &sparam); + //printf("\tdeduceType m = %d\n", m); + if (m == MATCHnomatch) + goto Lnomatch; + if (m < match) + match = m; + + sparam.semantic(paramscope); + if (!paramscope.insert(sparam)) + goto Lnomatch; + } + } + static if (false) { + for (i = 0; i < dedargs.dim; i++) + { + printf("\tdedarg[%d] = ", i); + Object oarg = cast(Object)dedargs.data[i]; + if (oarg) printf("%s", oarg.toChars()); + printf("\n"); + } + } + + if (fd.type) + { + assert(fd.type.ty == Tfunction); + TypeFunction fdtype = cast(TypeFunction)fd.type; + fparameters = fdtype.parameters; + fvarargs = fdtype.varargs; + } + else + { + CtorDeclaration fctor = fd.isCtorDeclaration(); + assert(fctor); + fparameters = fctor.arguments; + fvarargs = fctor.varargs; + } + + nfparams = Argument.dim(fparameters); // number of function parameters + nfargs = fargs ? fargs.dim : 0; // number of function arguments + + /* Check for match of function arguments with variadic template + * parameter, such as: + * + * template Foo(T, A...) { void Foo(T t, A a); } + * void main() { Foo(1,2,3); } + */ + if (tp) // if variadic + { + if (nfparams == 0) // if no function parameters + { + Tuple t = new Tuple(); + //printf("t = %p\n", t); + dedargs.data[parameters.dim - 1] = cast(void*)t; + declareParameter(paramscope, tp, t); + goto L2; + } + else if (nfargs < nfparams - 1) + goto L1; + else + { + /* Figure out which of the function parameters matches + * the tuple template parameter. Do this by matching + * type identifiers. + * Set the index of this function parameter to fptupindex. + */ + for (fptupindex = 0; fptupindex < nfparams; fptupindex++) + { + Argument fparam = cast(Argument)fparameters.data[fptupindex]; + if (fparam.type.ty != Tident) + continue; + TypeIdentifier tid = cast(TypeIdentifier)fparam.type; + if (!tp.ident.equals(tid.ident) || tid.idents.dim) + continue; + + if (fvarargs) // variadic function doesn't + goto Lnomatch; // go with variadic template + + /* The types of the function arguments + * now form the tuple argument. + */ + Tuple t = new Tuple(); + dedargs.data[parameters.dim - 1] = cast(void*)t; + + tuple_dim = nfargs - (nfparams - 1); + t.objects.setDim(tuple_dim); + for (size_t i = 0; i < tuple_dim; i++) + { + Expression farg = cast(Expression)fargs.data[fptupindex + i]; + t.objects.data[i] = cast(void*)farg.type; + } + declareParameter(paramscope, tp, t); + goto L2; + } + fptupindex = -1; + } + } + + L1: + if (nfparams == nfargs) { + ; + } else if (nfargs > nfparams) { + if (fvarargs == 0) + goto Lnomatch; // too many args, no match + match = MATCHconvert; // match ... with a conversion + } + + L2: + version (DMDV2) { + // Match 'ethis' to any TemplateThisParameter's + if (ethis) + { + for (size_t i = 0; i < parameters.dim; i++) + { + TemplateParameter tp2 = cast(TemplateParameter)parameters.data[i]; + TemplateThisParameter ttp = tp2.isTemplateThisParameter(); + if (ttp) + { + MATCH m; + + Type t = new TypeIdentifier(Loc(0), ttp.ident); + m = ethis.type.deduceType(paramscope, t, parameters, dedtypes); + if (!m) + goto Lnomatch; + if (m < match) + match = m; // pick worst match + } + } + } + } + + // Loop through the function parameters + for (size_t i = 0; i < nfparams; i++) + { + /* Skip over function parameters which wound up + * as part of a template tuple parameter. + */ + if (i == fptupindex) + { + if (fptupindex == nfparams - 1) + break; + i += tuple_dim - 1; + continue; + } + + Argument fparam = Argument.getNth(fparameters, i); + + if (i >= nfargs) // if not enough arguments + { + if (fparam.defaultArg) + { + /* Default arguments do not participate in template argument + * deduction. + */ + goto Lmatch; + } + } + else + { + Expression farg = cast(Expression)fargs.data[i]; + static if (false) { + printf("\tfarg.type = %s\n", farg.type.toChars()); + printf("\tfparam.type = %s\n", fparam.type.toChars()); + } + Type argtype = farg.type; + + version (DMDV2) { + /* Allow string literals which are type [] to match with [dim] + */ + if (farg.op == TOKstring) + { + StringExp se = cast(StringExp)farg; + if (!se.committed && argtype.ty == Tarray && + fparam.type.toBasetype().ty == Tsarray) + { + argtype = new TypeSArray(argtype.nextOf(), new IntegerExp(se.loc, se.len, Type.tindex)); + argtype = argtype.semantic(se.loc, null); + argtype = argtype.invariantOf(); + } + } + } + + MATCH m; + m = argtype.deduceType(paramscope, fparam.type, parameters, dedtypes); + //printf("\tdeduceType m = %d\n", m); + + /* If no match, see if there's a conversion to a delegate + */ + if (!m && fparam.type.toBasetype().ty == Tdelegate) + { + TypeDelegate td = cast(TypeDelegate)fparam.type.toBasetype(); + TypeFunction tf = cast(TypeFunction)td.next; + + if (!tf.varargs && Argument.dim(tf.parameters) == 0) + { + m = farg.type.deduceType(paramscope, tf.next, parameters, dedtypes); + if (!m && tf.next.toBasetype().ty == Tvoid) + m = MATCHconvert; + } + //printf("\tm2 = %d\n", m); + } + + if (m) + { + if (m < match) + match = m; // pick worst match + continue; + } + } + + /* The following code for variadic arguments closely + * matches TypeFunction.callMatch() + */ + if (!(fvarargs == 2 && i + 1 == nfparams)) + goto Lnomatch; + + /* Check for match with function parameter T... + */ + Type tb = fparam.type.toBasetype(); + switch (tb.ty) + { + // Perhaps we can do better with this, see TypeFunction.callMatch() + case Tsarray: + { + TypeSArray tsa = cast(TypeSArray)tb; + ulong sz = tsa.dim.toInteger(); + if (sz != nfargs - i) + goto Lnomatch; + } + case Tarray: + { + TypeArray ta = cast(TypeArray)tb; + for (; i < nfargs; i++) + { + Expression arg = cast(Expression)fargs.data[i]; + assert(arg); + MATCH m; + /* If lazy array of delegates, + * convert arg(s) to delegate(s) + */ + Type tret = fparam.isLazyArray(); + if (tret) + { + if (ta.next.equals(arg.type)) + { + m = MATCHexact; + } + else + { + m = arg.implicitConvTo(tret); + if (m == MATCHnomatch) + { + if (tret.toBasetype().ty == Tvoid) + m = MATCHconvert; + } + } + } + else + { + m = arg.type.deduceType(paramscope, ta.next, parameters, dedtypes); + //m = arg.implicitConvTo(ta.next); + } + if (m == MATCHnomatch) + goto Lnomatch; + if (m < match) + match = m; + } + goto Lmatch; + } + case Tclass: + case Tident: + goto Lmatch; + + default: + goto Lnomatch; + } + } + + Lmatch: + + /* Fill in any missing arguments with their defaults. + */ + for (size_t i = nargsi; i < dedargs.dim; i++) + { + TemplateParameter tp2 = cast(TemplateParameter)parameters.data[i]; + //printf("tp2[%d] = %s\n", i, tp2.ident.toChars()); + /* For T:T*, the dedargs is the T*, dedtypes is the T + * But for function templates, we really need them to match + */ + Object oarg = cast(Object)dedargs.data[i]; + Object oded = cast(Object)dedtypes.data[i]; + //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded); + //if (oarg) printf("oarg: %s\n", oarg.toChars()); + //if (oded) printf("oded: %s\n", oded.toChars()); + if (!oarg) + { + if (oded) + { + if (tp2.specialization()) + { + /* The specialization can work as long as afterwards + * the oded == oarg + */ + Declaration sparam; + dedargs.data[i] = cast(void*)oded; + MATCH m2 = tp2.matchArg(paramscope, dedargs, i, parameters, dedtypes, &sparam, 0); + //printf("m2 = %d\n", m2); + if (!m2) + goto Lnomatch; + if (m2 < match) + match = m2; // pick worst match + if (dedtypes.data[i] !is cast(void*)oded) + error("specialization not allowed for deduced parameter %s", tp2.ident.toChars()); + } + } + else + { + oded = tp2.defaultArg(loc, paramscope); + if (!oded) + goto Lnomatch; + } + declareParameter(paramscope, tp2, oded); + dedargs.data[i] = cast(void*)oded; + } + } + + version (DMDV2) { + if (constraint) + { /* Check to see if constraint is satisfied. + */ + Expression e = constraint.syntaxCopy(); + paramscope.flags |= SCOPE.SCOPEstaticif; + e = e.semantic(paramscope); + e = e.optimize(WANTvalue | WANTinterpret); + if (e.isBool(true)) { + ; + } else if (e.isBool(false)) + goto Lnomatch; + else + { + e.error("constraint %s is not constant or does not evaluate to a bool", e.toChars()); + } + } + } + + static if (false) { + for (i = 0; i < dedargs.dim; i++) + { + Type t = cast(Type)dedargs.data[i]; + printf("\tdedargs[%d] = %d, %s\n", i, t.dyncast(), t.toChars()); + } + } + + paramscope.pop(); + //printf("\tmatch %d\n", match); + return match; + + Lnomatch: + paramscope.pop(); + //printf("\tnomatch\n"); + return MATCHnomatch; + } + + /************************************************* + * Given function arguments, figure out which template function + * to expand, and return that function. + * If no match, give error message and return null. + * Input: + * sc instantiation scope + * loc instantiation location + * targsi initial list of template arguments + * ethis if !null, the 'this' pointer argument + * fargs arguments to function + * flags 1: do not issue error message on no match, just return null + */ + FuncDeclaration deduceFunctionTemplate(Scope sc, Loc loc, Objects targsi, Expression ethis, Expressions fargs, int flags = 0) + { + MATCH m_best = MATCHnomatch; + TemplateDeclaration td_ambig = null; + TemplateDeclaration td_best = null; + Objects tdargs = new Objects(); + TemplateInstance ti; + FuncDeclaration fd; + + static if (false) { + printf("TemplateDeclaration.deduceFunctionTemplate() %s\n", toChars()); + printf(" targsi:\n"); + if (targsi) + { + for (int i = 0; i < targsi.dim; i++) + { + Object arg = cast(Object)targsi.data[i]; + printf("\t%s\n", arg.toChars()); + } + } + printf(" fargs:\n"); + for (int i = 0; i < fargs.dim; i++) + { + Expression arg = cast(Expression)fargs.data[i]; + printf("\t%s %s\n", arg.type.toChars(), arg.toChars()); + //printf("\tty = %d\n", arg.type.ty); + } + } + + for (TemplateDeclaration td = this; td; td = td.overnext) + { + if (!td.semanticRun) + { + error("forward reference to template %s", td.toChars()); + goto Lerror; + } + if (!td.onemember || !td.onemember.toAlias().isFuncDeclaration()) + { + error("is not a function template"); + goto Lerror; + } + + MATCH m; + scope Objects dedargs = new Objects(); + + m = td.deduceFunctionTemplateMatch(loc, targsi, ethis, fargs, dedargs); + //printf("deduceFunctionTemplateMatch = %d\n", m); + if (!m) // if no match + continue; + + if (m < m_best) + goto Ltd_best; + if (m > m_best) + goto Ltd; + + { + // Disambiguate by picking the most specialized TemplateDeclaration + MATCH c1 = td.leastAsSpecialized(td_best); + MATCH c2 = td_best.leastAsSpecialized(td); + //printf("c1 = %d, c2 = %d\n", c1, c2); + + if (c1 > c2) + goto Ltd; + else if (c1 < c2) + goto Ltd_best; + else + goto Lambig; + } + + Lambig: // td_best and td are ambiguous + td_ambig = td; + continue; + + Ltd_best: // td_best is the best match so far + td_ambig = null; + continue; + + Ltd: // td is the new best match + td_ambig = null; + assert(cast(size_t)cast(void*)td.scope_ > 0x10000); + td_best = td; + m_best = m; + tdargs.setDim(dedargs.dim); + memcpy(tdargs.data, dedargs.data, tdargs.dim * (void*).sizeof); + continue; + } + if (!td_best) + { + if (!(flags & 1)) + error(loc, "does not match any function template declaration"); + goto Lerror; + } + if (td_ambig) + { + error(loc, "matches more than one function template declaration:\n %s\nand:\n %s", + td_best.toChars(), td_ambig.toChars()); + } + + /* The best match is td_best with arguments tdargs. + * Now instantiate the template. + */ + assert(cast(size_t)cast(void*)td_best.scope_ > 0x10000); + ti = new TemplateInstance(loc, td_best, tdargs); + ti.semantic(sc); + fd = ti.toAlias().isFuncDeclaration(); + if (!fd) + goto Lerror; + return fd; + + Lerror: +/// version (DMDV2) { + if (!(flags & 1)) +/// } + { + HdrGenState hgs; + + scope OutBuffer bufa = new OutBuffer(); + Objects args = targsi; + if (args) + { + for (int i = 0; i < args.dim; i++) + { + if (i) + bufa.writeByte(','); + Object oarg = cast(Object)args.data[i]; + ObjectToCBuffer(bufa, &hgs, oarg); + } + } + + scope OutBuffer buf = new OutBuffer(); + argExpTypesToCBuffer(buf, fargs, &hgs); + error(loc, "cannot deduce template function from argument types !(%s)(%s)", bufa.toChars(), buf.toChars()); + } + return null; + } + + /************************************************** + * Declare template parameter tp with value o, and install it in the scope sc. + */ + void declareParameter(Scope sc, TemplateParameter tp, Object o) + { + //printf("TemplateDeclaration.declareParameter('%s', o = %p)\n", tp.ident.toChars(), o); + + Type targ = isType(o); + Expression ea = isExpression(o); + Dsymbol sa = isDsymbol(o); + Tuple va = isTuple(o); + + Dsymbol s; + + // See if tp.ident already exists with a matching definition + Dsymbol scopesym; + s = sc.search(loc, tp.ident, &scopesym); + if (s && scopesym == sc.scopesym) + { + TupleDeclaration td = s.isTupleDeclaration(); + if (va && td) + { + Tuple tup = new Tuple(); + assert(false); // < not implemented + ///tup.objects = *td.objects; + if (match(va, tup, this, sc)) + { + return; + } + } + } + + if (targ) + { + //printf("type %s\n", targ.toChars()); + s = new AliasDeclaration(Loc(0), tp.ident, targ); + } + else if (sa) + { + //printf("Alias %s %s;\n", sa.ident.toChars(), tp.ident.toChars()); + s = new AliasDeclaration(Loc(0), tp.ident, sa); + } + else if (ea) + { + // tdtypes.data[i] always matches ea here + Initializer init = new ExpInitializer(loc, ea); + TemplateValueParameter tvp = tp.isTemplateValueParameter(); + + Type t = tvp ? tvp.valType : null; + + VarDeclaration v = new VarDeclaration(loc, t, tp.ident, init); + v.storage_class = STCmanifest; + s = v; + } + else if (va) + { + //printf("\ttuple\n"); + s = new TupleDeclaration(loc, tp.ident, va.objects); + } + else + { + debug writefln(o.toString()); + assert(0); + } + + if (!sc.insert(s)) + error("declaration %s is already defined", tp.ident.toChars()); + + s.semantic(sc); + } + + TemplateDeclaration isTemplateDeclaration() { return this; } + + TemplateTupleParameter isVariadic() + { + return .isVariadic(parameters); + } + + bool isOverloadable() + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TemplateExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TemplateExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,31 @@ +module dmd.TemplateExp; + +import dmd.Expression; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.HdrGenState; +import dmd.TemplateDeclaration; +import dmd.TOK; + +class TemplateExp : Expression +{ + TemplateDeclaration td; + + this(Loc loc, TemplateDeclaration td) + { + super(loc, TOK.TOKtemplate, TemplateExp.sizeof); + //printf("TemplateExp(): %s\n", td.toChars()); + this.td = td; + } + + void rvalue() + { + error("template %s has no value", toChars()); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + buf.writestring(td.toChars()); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/TemplateInstance.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TemplateInstance.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,1386 @@ +module dmd.TemplateInstance; + +import dmd.ScopeDsymbol; +import dmd.IntegerExp; +import dmd.Identifier; +import dmd.ArrayTypes; +import dmd.TupleDeclaration; +import dmd.TemplateParameter; +import dmd.AliasDeclaration; +import dmd.TemplateDeclaration; +import dmd.TupleExp; +import dmd.WithScopeSymbol; +import dmd.Dsymbol; +import dmd.Module; +import dmd.ArrayTypes; +import dmd.Loc; +import dmd.Global; +import dmd.Util; +import dmd.Type; +import dmd.Expression; +import dmd.Tuple; +import dmd.STC; +import dmd.TOK; +import dmd.TY; +import dmd.TypeTuple; +import dmd.Argument; +import dmd.WANT; +import dmd.ExpInitializer; +import dmd.Array; +import dmd.DsymbolTable; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.VarDeclaration; +import dmd.VarExp; +import dmd.FuncExp; +import dmd.Declaration; +import dmd.MATCH; + +import dmd.backend.glue; + +Tuple isTuple(Object o) +{ + //return dynamic_cast(o); + ///if (!o || o.dyncast() != DYNCAST_TUPLE) + /// return null; + return cast(Tuple)o; +} + +/****************************** + * If o1 matches o2, return 1. + * Else, return 0. + */ + +bool match(Object o1, Object o2, TemplateDeclaration tempdecl, Scope sc) +{ + Type t1 = isType(o1); + Type t2 = isType(o2); + Expression e1 = isExpression(o1); + Expression e2 = isExpression(o2); + Dsymbol s1 = isDsymbol(o1); + Dsymbol s2 = isDsymbol(o2); + Tuple v1 = isTuple(o1); + Tuple v2 = isTuple(o2); + + //printf("\t match t1 %p t2 %p, e1 %p e2 %p, s1 %p s2 %p, v1 %p v2 %p\n", t1,t2,e1,e2,s1,s2,v1,v2); + + /* A proper implementation of the various equals() overrides + * should make it possible to just do o1.equals(o2), but + * we'll do that another day. + */ + + if (t1) + { + /* if t1 is an instance of ti, then give error + * about recursive expansions. + */ + Dsymbol s = t1.toDsymbol(sc); + if (s && s.parent) + { + TemplateInstance ti1 = s.parent.isTemplateInstance(); + if (ti1 && ti1.tempdecl == tempdecl) + { + for (Scope sc1 = sc; sc1; sc1 = sc1.enclosing) + { + if (sc1.scopesym == ti1) + { + error("recursive template expansion for template argument %s", t1.toChars()); + return true; // fake a match + } + } + } + } + + //printf("t1 = %s\n", t1.toChars()); + //printf("t2 = %s\n", t2.toChars()); + if (!t2 || !t1.equals(t2)) + goto Lnomatch; + } + else if (e1) + { +static if (false) { + if (e1 && e2) + { + printf("match %d\n", e1.equals(e2)); + e1.print(); + e2.print(); + e1.type.print(); + e2.type.print(); + } +} + if (!e2) + goto Lnomatch; + if (!e1.equals(e2)) + goto Lnomatch; + } + else if (s1) + { + //printf("%p %s, %p %s\n", s1, s1.toChars(), s2, s2.toChars()); + if (!s2 || !s1.equals(s2) || s1.parent != s2.parent) + { + goto Lnomatch; + } + version (DMDV2) { + VarDeclaration vv1 = s1.isVarDeclaration(); + VarDeclaration vv2 = s2.isVarDeclaration(); + if (vv1 && vv2 && vv1.storage_class & vv2.storage_class & STCmanifest) + { + ExpInitializer ei1 = vv1.init.isExpInitializer(); + ExpInitializer ei2 = vv2.init.isExpInitializer(); + if (ei1 && ei2 && !ei1.exp.equals(ei2.exp)) + goto Lnomatch; + } + } + } + else if (v1) + { + if (!v2) + goto Lnomatch; + + if (v1.objects.dim != v2.objects.dim) + goto Lnomatch; + + for (size_t i = 0; i < v1.objects.dim; i++) + { + if (!match(cast(Object)v1.objects.data[i], cast(Object)v2.objects.data[i], tempdecl, sc)) + goto Lnomatch; + } + } + //printf("match\n"); + return true; // match + +Lnomatch: + //printf("nomatch\n"); + return false; // nomatch; +} + +class TemplateInstance : ScopeDsymbol +{ + /* Given: + * foo!(args) => + * name = foo + * tiargs = args + */ + Identifier name; + //Array idents; + Objects tiargs; // Array of Types/Expressions of template + // instance arguments [int*, char, 10*10] + + Objects tdtypes; // Array of Types/Expressions corresponding + // to TemplateDeclaration.parameters + // [int, char, 100] + + TemplateDeclaration tempdecl; // referenced by foo.bar.abc + TemplateInstance inst; // refer to existing instance + TemplateInstance tinst; // enclosing template instance + ScopeDsymbol argsym; // argument symbol table + AliasDeclaration aliasdecl; // !=null if instance is an alias for its + // sole member + WithScopeSymbol withsym; // if a member of a with statement + int semanticRun; // has semantic() been done? + int semantictiargsdone; // has semanticTiargs() been done? + int nest; // for recursion detection + int havetempdecl; // 1 if used second constructor + Dsymbol isnested; // if referencing local symbols, this is the context + int errors; // 1 if compiled with errors +version (IN_GCC) { + /* On some targets, it is necessary to know whether a symbol + will be emitted in the output or not before the symbol + is used. This can be different from getModule(). */ + Module objFileModule; +} + + this(Loc loc, Identifier ident) + { + super(null); + + version (LOG) { + printf("TemplateInstance(this = %p, ident = '%s')\n", this, ident ? ident.toChars() : "null"); + } + this.loc = loc; + this.name = ident; + + tdtypes = new Objects(); + } + + /***************** + * This constructor is only called when we figured out which function + * template to instantiate. + */ + this(Loc loc, TemplateDeclaration td, Objects tiargs) + { + super(null); + + version (LOG) { + printf("TemplateInstance(this = %p, tempdecl = '%s')\n", this, td.toChars()); + } + this.loc = loc; + this.name = td.ident; + this.tiargs = tiargs; + this.tempdecl = td; + this.semantictiargsdone = 1; + this.havetempdecl = 1; + + assert(cast(size_t)cast(void*)tempdecl.scope_ > 0x10000); + + tdtypes = new Objects(); + } + + static Objects arraySyntaxCopy(Objects objs) + { + assert(false); + } + + Dsymbol syntaxCopy(Dsymbol) + { + assert(false); + } + + void semantic(Scope sc) + { + if (global.errors) + { + if (!global.gag) + { + /* Trying to soldier on rarely generates useful messages + * at this point. + */ + fatal(); + } + return; + } + + version (LOG) { + printf("\n+TemplateInstance.semantic('%s', this=%p)\n", toChars(), this); + } + + if (inst) // if semantic() was already run + { +version (LOG) { + printf("-TemplateInstance.semantic('%s', this=%p) already run\n", inst.toChars(), inst); +} + return; + } + + // get the enclosing template instance from the scope tinst + tinst = sc.tinst; + + if (semanticRun != 0) + { + error(loc, "recursive template expansion"); + // inst = this; + return; + } + + semanticRun = 1; + + version (LOG) { + printf("\tdo semantic\n"); + } + if (havetempdecl) + { + assert(cast(size_t)cast(void*)tempdecl.scope_ > 0x10000); + + // Deduce tdtypes + tdtypes.setDim(tempdecl.parameters.dim); + if (!tempdecl.matchWithInstance(this, tdtypes, 2)) + { + error("incompatible arguments for template instantiation"); + inst = this; + return; + } + } + else + { + /* Run semantic on each argument, place results in tiargs[] + * (if we havetempdecl, then tiargs is already evaluated) + */ + semanticTiargs(sc); + + tempdecl = findTemplateDeclaration(sc); + if (tempdecl) + tempdecl = findBestMatch(sc); + + if (!tempdecl || global.errors) + { + inst = this; + //printf("error return %p, %d\n", tempdecl, global.errors); + return; // error recovery + } + } + + hasNestedArgs(tiargs); + + /* See if there is an existing TemplateInstantiation that already + * implements the typeargs. If so, just refer to that one instead. + */ + + for (size_t i = 0; i < tempdecl.instances.dim; i++) + { + TemplateInstance ti = cast(TemplateInstance)tempdecl.instances.data[i]; + version (LOG) { + printf("\t%s: checking for match with instance %d (%p): '%s'\n", toChars(), i, ti, ti.toChars()); + } + assert(tdtypes.dim == ti.tdtypes.dim); + + // Nesting must match + if (isnested !is ti.isnested) + { + //printf("test2 isnested %s ti.isnested %s\n", isnested ? isnested.toChars() : "", ti.isnested ? ti.isnested.toChars() : ""); + continue; + } + static if (false) { + if (isnested && sc.parent != ti.parent) + continue; + } + for (size_t j = 0; j < tdtypes.dim; j++) + { + Object o1 = cast(Object)tdtypes.data[j]; + Object o2 = cast(Object)ti.tdtypes.data[j]; + if (!match(o1, o2, tempdecl, sc)) + { + goto L1; + } + } + + // It's a match + inst = ti; + parent = ti.parent; + version (LOG) { + printf("\tit's a match with instance %p\n", inst); + } + return; + + L1: + ; + } + + /* So, we need to implement 'this' instance. + */ + version (LOG) { + printf("\timplement template instance '%s'\n", toChars()); + } + uint errorsave = global.errors; + inst = this; + int tempdecl_instance_idx = tempdecl.instances.dim; + tempdecl.instances.push(cast(void*)this); + parent = tempdecl.parent; + //printf("parent = '%s'\n", parent.kind()); + + ident = genIdent(); // need an identifier for name mangling purposes. + + static if (true) { + if (isnested) + parent = isnested; + } + //printf("parent = '%s'\n", parent.kind()); + + // Add 'this' to the enclosing scope's members[] so the semantic routines + // will get called on the instance members + static if (true) { + int dosemantic3 = 0; + { + Array a; + + Scope scx = sc; + static if (false) { + for (scx = sc; scx; scx = scx.enclosing) + if (scx.scopesym) + break; + } + + //if (scx && scx.scopesym) printf("3: scx is %s %s\n", scx.scopesym.kind(), scx.scopesym.toChars()); + if (scx && scx.scopesym && + scx.scopesym.members && !scx.scopesym.isTemplateMixin() + +/// static if (false) { // removed because it bloated compile times +/// /* The problem is if A imports B, and B imports A, and both A +/// * and B instantiate the same template, does the compilation of A +/// * or the compilation of B do the actual instantiation? +/// * +/// * see bugzilla 2500. +/// */ +/// && !scx.module.selfImports() +/// } + ) + { + //printf("\t1: adding to %s %s\n", scx.scopesym.kind(), scx.scopesym.toChars()); + a = scx.scopesym.members; + } + else + { Module m = sc.module_.importedFrom; + //printf("\t2: adding to module %s instead of module %s\n", m.toChars(), sc.module.toChars()); + a = m.members; + if (m.semanticRun >= 3) + dosemantic3 = 1; + } + + for (int i = 0; 1; i++) + { + if (i == a.dim) + { + a.push(cast(void*)this); + break; + } + + if (this is cast(Dsymbol)a.data[i]) // if already in Array + break; + } + } + } + + // Copy the syntax trees from the TemplateDeclaration + members = Dsymbol.arraySyntaxCopy(tempdecl.members); + + // Create our own scope for the template parameters + Scope scope_ = tempdecl.scope_; + if (!tempdecl.semanticRun) + { + error("template instantiation %s forward references template declaration %s\n", toChars(), tempdecl.toChars()); + return; + } + + version (LOG) { + printf("\tcreate scope for template parameters '%s'\n", toChars()); + } + argsym = new ScopeDsymbol(); + argsym.parent = scope_.parent; + scope_ = scope_.push(argsym); + // scope.stc = 0; + + // Declare each template parameter as an alias for the argument type + Scope paramscope = scope_.push(); + paramscope.stc = STCundefined; + declareParameters(paramscope); + paramscope.pop(); + + // Add members of template instance to template instance symbol table + // parent = scope.scopesym; + symtab = new DsymbolTable(); + int memnum = 0; + for (int i = 0; i < members.dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + version (LOG) { + printf("\t[%d] adding member '%s' %p kind %s to '%s', memnum = %d\n", i, s.toChars(), s, s.kind(), this.toChars(), memnum); + } + memnum |= s.addMember(scope_, this, memnum); + } + + version (LOG) { + printf("adding members done\n"); + } + + /* See if there is only one member of template instance, and that + * member has the same name as the template instance. + * If so, this template instance becomes an alias for that member. + */ + //printf("members.dim = %d\n", members.dim); + if (members.dim) + { + Dsymbol s; + if (Dsymbol.oneMembers(members, &s) && s) + { + //printf("s.kind = '%s'\n", s.kind()); + //s.print(); + //printf("'%s', '%s'\n", s.ident.toChars(), tempdecl.ident.toChars()); + if (s.ident && s.ident.equals(tempdecl.ident)) + { + //printf("setting aliasdecl\n"); + aliasdecl = new AliasDeclaration(loc, s.ident, s); + } + } + } + + // Do semantic() analysis on template instance members + version (LOG) { + printf("\tdo semantic() on template instance members '%s'\n", toChars()); + } + Scope sc2; + sc2 = scope_.push(this); + //printf("isnested = %d, sc.parent = %s\n", isnested, sc.parent.toChars()); + sc2.parent = /*isnested ? sc.parent :*/ this; + sc2.tinst = this; + + try + { + static int nest; + //printf("%d\n", nest); + if (++nest > 500) + { + global.gag = 0; // ensure error message gets printed + error("recursive expansion"); + fatal(); + } + for (int i = 0; i < members.dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + //printf("\t[%d] semantic on '%s' %p kind %s in '%s'\n", i, s.toChars(), s, s.kind(), this.toChars()); + //printf("test: isnested = %d, sc2.parent = %s\n", isnested, sc2.parent.toChars()); + // if (isnested) + // s.parent = sc.parent; + //printf("test3: isnested = %d, s.parent = %s\n", isnested, s.parent.toChars()); + s.semantic(sc2); + //printf("test4: isnested = %d, s.parent = %s\n", isnested, s.parent.toChars()); + sc2.module_.runDeferredSemantic(); + } + --nest; + } + catch + { + global.gag = 0; // ensure error message gets printed + error("recursive expansion"); + fatal(); + } + + /* If any of the instantiation members didn't get semantic() run + * on them due to forward references, we cannot run semantic2() + * or semantic3() yet. + */ + for (size_t i = 0; i < Module.deferred.dim; i++) + { + Dsymbol sd = cast(Dsymbol)Module.deferred.data[i]; + + if (sd.parent is this) + goto Laftersemantic; + } + + /* The problem is when to parse the initializer for a variable. + * Perhaps VarDeclaration.semantic() should do it like it does + * for initializers inside a function. + */ + // if (sc.parent.isFuncDeclaration()) + + /* BUG 782: this has problems if the classes this depends on + * are forward referenced. Find a way to defer semantic() + * on this template. + */ + semantic2(sc2); + + if (sc.func || dosemantic3) + { + semantic3(sc2); + } + + Laftersemantic: + sc2.pop(); + + scope_.pop(); + + // Give additional context info if error occurred during instantiation + if (global.errors != errorsave) + { + error("error instantiating"); + if (tinst && !global.gag) + { + tinst.printInstantiationTrace(); + fatal(); + } + errors = 1; + if (global.gag) + tempdecl.instances.remove(tempdecl_instance_idx); + } + + version (LOG) { + printf("-TemplateInstance.semantic('%s', this=%p)\n", toChars(), this); + } + } + + void semantic2(Scope sc) + { + int i; + + if (semanticRun >= 2) + return; + + semanticRun = 2; + version (LOG) { + printf("+TemplateInstance::semantic2('%s')\n", toChars()); + } + + if (!errors && members) + { + sc = tempdecl.scope_; + assert(sc); + sc = sc.push(argsym); + sc = sc.push(this); + sc.tinst = this; + + for (i = 0; i < members.dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + version (LOG) { + printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind()); + } + s.semantic2(sc); + } + + sc = sc.pop(); + sc.pop(); + } + + version (LOG) { + printf("-TemplateInstance::semantic2('%s')\n", toChars()); + } + } + + void semantic3(Scope sc) + { + version (LOG) { + printf("TemplateInstance.semantic3('%s'), semanticRun = %d\n", toChars(), semanticRun); + } + //if (toChars()[0] == 'D') *(char*)0=0; + if (semanticRun >= 3) + return; + semanticRun = 3; + if (!errors && members) + { + sc = tempdecl.scope_; + sc = sc.push(argsym); + sc = sc.push(this); + sc.tinst = this; + for (int i = 0; i < members.dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + s.semantic3(sc); + } + sc = sc.pop(); + sc.pop(); + } + } + + void inlineScan() + { + version (LOG) { + printf("TemplateInstance.inlineScan('%s')\n", toChars()); + } + if (!errors && members) + { + for (int i = 0; i < members.dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + s.inlineScan(); + } + } + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + int i; + + Identifier id = name; + buf.writestring(id.toChars()); + buf.writestring("!("); + if (nest) + buf.writestring("..."); + else + { + nest++; + Objects args = tiargs; + for (i = 0; i < args.dim; i++) + { + if (i) + buf.writeByte(','); + Object oarg = cast(Object)args.data[i]; + ObjectToCBuffer(buf, hgs, oarg); + } + nest--; + } + buf.writeByte(')'); + } + + Dsymbol toAlias() // resolve real symbol + { + version (LOG) { + printf("TemplateInstance::toAlias()\n"); + } + if (!inst) + { + error("cannot resolve forward reference"); + return this; + } + + if (inst !is this) + return inst.toAlias(); + + if (aliasdecl) + { + return aliasdecl.toAlias(); + } + + return inst; + } + + string kind() + { + assert(false); + } + + bool oneMember(Dsymbol* ps) + { + assert(false); + } + + string toChars() + { + scope OutBuffer buf = new OutBuffer(); + HdrGenState hgs; + + toCBuffer(buf, &hgs); + return buf.extractString(); + } + + string mangle() + { + assert(false); + } + + void printInstantiationTrace() + { + assert(false); + } + + void toObjFile(int multiobj) // compile to .obj file + { + version (LOG) { + printf("TemplateInstance.toObjFile('%s', this = %p)\n", toChars(), this); + } + if (!errors && members) + { + if (multiobj) + // Append to list of object files to be written later + obj_append(this); + else + { + for (int i = 0; i < members.dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + s.toObjFile(multiobj); + } + } + } + } + + // Internal + /********************************** + * Input: + * flags 1: replace const variables with their initializers + */ + static void semanticTiargs(Loc loc, Scope sc, Objects tiargs, int flags) + { + // Run semantic on each argument, place results in tiargs[] + //printf("+TemplateInstance.semanticTiargs() %s\n", toChars()); + if (!tiargs) + return; + for (size_t j = 0; j < tiargs.dim; j++) + { + Object o = cast(Object)tiargs.data[j]; + Type ta = isType(o); + Expression ea = isExpression(o); + Dsymbol sa = isDsymbol(o); + + //printf("1: tiargs.data[%d] = %p, %p, %p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta); + if (ta) + { + //printf("type %s\n", ta.toChars()); + // It might really be an Expression or an Alias + ta.resolve(loc, sc, &ea, &ta, &sa); + if (ea) + { + ea = ea.semantic(sc); + /* This test is to skip substituting a const var with + * its initializer. The problem is the initializer won't + * match with an 'alias' parameter. Instead, do the + * const substitution in TemplateValueParameter.matchArg(). + */ + if (ea.op != TOKvar || flags & 1) + ea = ea.optimize(WANTvalue | WANTinterpret); + + tiargs.data[j] = cast(void*)ea; + } + else if (sa) + { + tiargs.data[j] = cast(void*)sa; + TupleDeclaration d = sa.toAlias().isTupleDeclaration(); + if (d) + { + size_t dim = d.objects.dim; + tiargs.remove(j); + tiargs.insert(j, d.objects); + j--; + } + } + else if (ta) + { + Ltype: + if (ta.ty == Ttuple) + { + // Expand tuple + TypeTuple tt = cast(TypeTuple)ta; + size_t dim = tt.arguments.dim; + tiargs.remove(j); + if (dim) + { + tiargs.reserve(dim); + for (size_t i = 0; i < dim; i++) + { + Argument arg = cast(Argument)tt.arguments.data[i]; + tiargs.insert(j + i, cast(void*)arg.type); + } + } + j--; + } + else + tiargs.data[j] = cast(void*)ta; + } + else + { + assert(global.errors); + tiargs.data[j] = cast(void*)Type.terror; + } + } + else if (ea) + { + if (!ea) + { + assert(global.errors); + ea = new IntegerExp(0); + } + assert(ea); + ea = ea.semantic(sc); + if (ea.op != TOKvar || flags & 1) + ea = ea.optimize(WANTvalue | WANTinterpret); + tiargs.data[j] = cast(void*)ea; + if (ea.op == TOKtype) + { + ta = ea.type; + goto Ltype; + } + if (ea.op == TOKtuple) + { + // Expand tuple + TupleExp te = cast(TupleExp)ea; + size_t dim = te.exps.dim; + tiargs.remove(j); + if (dim) + { + tiargs.reserve(dim); + for (size_t i = 0; i < dim; i++) + tiargs.insert(j + i, te.exps.data[i]); + } + j--; + } + } + else if (sa) + { + TemplateDeclaration td = sa.isTemplateDeclaration(); + if (td && !td.semanticRun && td.literal) + td.semantic(sc); + } + else + { + assert(0); + } + //printf("1: tiargs.data[%d] = %p\n", j, tiargs.data[j]); + } + +static if (false) { + printf("-TemplateInstance.semanticTiargs('%s', this=%p)\n", toChars(), this); + for (size_t j = 0; j < tiargs.dim; j++) + { + Object o = cast(Object)tiargs.data[j]; + Type ta = isType(o); + Expression ea = isExpression(o); + Dsymbol sa = isDsymbol(o); + Tuple va = isTuple(o); + + printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j, ta, ea, sa, va); + } +} + } + + void semanticTiargs(Scope sc) + { + //printf("+TemplateInstance.semanticTiargs() %s\n", toChars()); + if (semantictiargsdone) + return; + + semantictiargsdone = 1; + semanticTiargs(loc, sc, tiargs, 0); + } + + /********************************************** + * Find template declaration corresponding to template instance. + */ + TemplateDeclaration findTemplateDeclaration(Scope sc) + { + //printf("TemplateInstance.findTemplateDeclaration() %s\n", toChars()); + if (!tempdecl) + { + /* Given: + * foo!( ... ) + * figure out which TemplateDeclaration foo refers to. + */ + Dsymbol s; + Dsymbol scopesym; + int i; + + Identifier id = name; + s = sc.search(loc, id, &scopesym); + if (!s) + { + error("identifier '%s' is not defined", id.toChars()); + return null; + } + version (LOG) { + printf("It's an instance of '%s' kind '%s'\n", s.toChars(), s.kind()); + if (s.parent) + printf("s.parent = '%s'\n", s.parent.toChars()); + } + withsym = scopesym.isWithScopeSymbol(); + + /* We might have found an alias within a template when + * we really want the template. + */ + TemplateInstance ti; + if (s.parent && + (ti = s.parent.isTemplateInstance()) !is null) + { + if ( + (ti.name == id || + ti.toAlias().ident == id) + && + ti.tempdecl + ) + { + /* This is so that one can refer to the enclosing + * template, even if it has the same name as a member + * of the template, if it has a !(arguments) + */ + tempdecl = ti.tempdecl; + if (tempdecl.overroot) // if not start of overloaded list of TemplateDeclaration's + tempdecl = tempdecl.overroot; // then get the start + + s = tempdecl; + } + } + + s = s.toAlias(); + + /* It should be a TemplateDeclaration, not some other symbol + */ + tempdecl = s.isTemplateDeclaration(); + if (!tempdecl) + { + if (!s.parent && global.errors) + return null; + if (!s.parent && s.getType()) + { + Dsymbol s2 = s.getType().toDsymbol(sc); + if (!s2) + { + error("%s is not a template declaration, it is a %s", id.toChars(), s.kind()); + return null; + } + s = s2; + } + debug { + //if (!s.parent) printf("s = %s %s\n", s.kind(), s.toChars()); + } + //assert(s.parent); + TemplateInstance ti2 = s.parent ? s.parent.isTemplateInstance() : null; + if (ti2 && + (ti2.name == id || + ti2.toAlias().ident == id) + && + ti2.tempdecl + ) + { + /* This is so that one can refer to the enclosing + * template, even if it has the same name as a member + * of the template, if it has a !(arguments) + */ + tempdecl = ti2.tempdecl; + if (tempdecl.overroot) // if not start of overloaded list of TemplateDeclaration's + tempdecl = tempdecl.overroot; // then get the start + } + else + { + error("%s is not a template declaration, it is a %s", id.toChars(), s.kind()); + return null; + } + } + } + else + assert(tempdecl.isTemplateDeclaration()); + + return tempdecl; + } + + TemplateDeclaration findBestMatch(Scope sc) + { + /* Since there can be multiple TemplateDeclaration's with the same + * name, look for the best match. + */ + TemplateDeclaration td_ambig = null; + TemplateDeclaration td_best = null; + MATCH m_best = MATCHnomatch; + scope Objects dedtypes = new Objects(); + + version (LOG) { + printf("TemplateInstance.findBestMatch()\n"); + } + // First look for forward references + for (TemplateDeclaration td = tempdecl; td; td = td.overnext) + { + if (!td.semanticRun) + { + if (td.scope_) + { + // Try to fix forward reference + td.semantic(td.scope_); + } + if (!td.semanticRun) + { + error("%s forward references template declaration %s\n", toChars(), td.toChars()); + return null; + } + } + } + + for (TemplateDeclaration td = tempdecl; td; td = td.overnext) + { + MATCH m; + + //if (tiargs.dim) printf("2: tiargs.dim = %d, data[0] = %p\n", tiargs.dim, tiargs.data[0]); + + // If more arguments than parameters, + // then this is no match. + if (td.parameters.dim < tiargs.dim) + { + if (!td.isVariadic()) + continue; + } + + dedtypes.setDim(td.parameters.dim); + dedtypes.zero(); + assert(td.semanticRun); + m = td.matchWithInstance(this, dedtypes, 0); + //printf("matchWithInstance = %d\n", m); + if (!m) // no match at all + continue; + + if (m < m_best) + goto Ltd_best; + if (m > m_best) + goto Ltd; + + { + // Disambiguate by picking the most specialized TemplateDeclaration + MATCH c1 = td.leastAsSpecialized(td_best); + MATCH c2 = td_best.leastAsSpecialized(td); + //printf("c1 = %d, c2 = %d\n", c1, c2); + + if (c1 > c2) + goto Ltd; + else if (c1 < c2) + goto Ltd_best; + else + goto Lambig; + } + + Lambig: // td_best and td are ambiguous + td_ambig = td; + continue; + + Ltd_best: // td_best is the best match so far + td_ambig = null; + continue; + + Ltd: // td is the new best match + td_ambig = null; + td_best = td; + m_best = m; + tdtypes.setDim(dedtypes.dim); + memcpy(tdtypes.data, dedtypes.data, tdtypes.dim * (void*).sizeof); + continue; + } + + if (!td_best) + { + if (tempdecl && !tempdecl.overnext) + // Only one template, so we can give better error message + error("%s does not match template declaration %s", toChars(), tempdecl.toChars()); + else + error("%s does not match any template declaration", toChars()); + return null; + } + + if (td_ambig) + { + error("%s matches more than one template declaration, %s and %s", + toChars(), td_best.toChars(), td_ambig.toChars()); + } + + /* The best match is td_best + */ + tempdecl = td_best; + + static if (false) { + /* Cast any value arguments to be same type as value parameter + */ + for (size_t i = 0; i < tiargs.dim; i++) + { + Object o = cast(Object)tiargs.data[i]; + Expression ea = isExpression(o); // value argument + TemplateParameter tp = cast(TemplateParameter)tempdecl.parameters.data[i]; + assert(tp); + TemplateValueParameter tvp = tp.isTemplateValueParameter(); + if (tvp) + { + assert(ea); + ea = ea.castTo(tvp.valType); + ea = ea.optimize(WANTvalue | WANTinterpret); + tiargs.data[i] = cast(Object)ea; + } + } + } + + version (LOG) { + printf("\tIt's a match with template declaration '%s'\n", tempdecl.toChars()); + } + return tempdecl; + } + + /**************************************************** + * Declare parameters of template instance, initialize them with the + * template instance arguments. + */ + void declareParameters(Scope sc) + { + //printf("TemplateInstance::declareParameters()\n"); + for (int i = 0; i < tdtypes.dim; i++) + { + TemplateParameter tp = cast(TemplateParameter)tempdecl.parameters.data[i]; + //Object o = cast(Object)tiargs.data[i]; + Object o = cast(Object)tdtypes.data[i]; // initializer for tp + + //printf("\ttdtypes[%d] = %p\n", i, o); + tempdecl.declareParameter(sc, tp, o); + } + } + + /***************************************** + * Determines if a TemplateInstance will need a nested + * generation of the TemplateDeclaration. + */ + bool hasNestedArgs(Objects args) + { + bool nested = false; + //printf("TemplateInstance::hasNestedArgs('%s')\n", tempdecl.ident.toChars()); + + /* A nested instance happens when an argument references a local + * symbol that is on the stack. + */ + for (size_t i = 0; i < args.dim; i++) + { + Object o = cast(Object)args.data[i]; + Expression ea = isExpression(o); + Dsymbol sa = isDsymbol(o); + Tuple va = isTuple(o); + if (ea) + { + if (ea.op == TOKvar) + { + sa = (cast(VarExp)ea).var; + goto Lsa; + } + if (ea.op == TOKfunction) + { + sa = (cast(FuncExp)ea).fd; + goto Lsa; + } + } + else if (sa) + { + Lsa: + Declaration d = null; + TemplateDeclaration td = sa.isTemplateDeclaration(); + if (td && td.literal) + { + goto L2; + } + d = sa.isDeclaration(); + if (d && !d.isDataseg() && +/// version (DMDV2) { + !(d.storage_class & STCmanifest) && +/// } + (!d.isFuncDeclaration() || d.isFuncDeclaration().isNested()) && + !isTemplateMixin()) + { + L2: + // if module level template + if (tempdecl.toParent().isModule()) + { + Dsymbol dparent = sa.toParent(); + if (!isnested) + isnested = dparent; + else if (isnested != dparent) + { + /* Select the more deeply nested of the two. + * Error if one is not nested inside the other. + */ + for (Dsymbol p = isnested; p; p = p.parent) + { + if (p == dparent) + goto L1; // isnested is most nested + } + for (Dsymbol p = dparent; p; p = p.parent) + { + if (p == isnested) + { + isnested = dparent; + goto L1; // dparent is most nested + } + } + error("%s is nested in both %s and %s", + toChars(), isnested.toChars(), dparent.toChars()); + } + L1: + //printf("\tnested inside %s\n", isnested.toChars()); + nested |= 1; + } + else + error("cannot use local '%s' as parameter to non-global template %s", d.toChars(), tempdecl.toChars()); + } + } + else if (va) + { + nested |= hasNestedArgs(va.objects); + } + } + return nested; + } + + /**************************************** + * This instance needs an identifier for name mangling purposes. + * Create one by taking the template declaration name and adding + * the type signature for it. + */ + Identifier genIdent() + { + scope OutBuffer buf = new OutBuffer(); + string id; + Objects args; + + //printf("TemplateInstance::genIdent('%s')\n", tempdecl.ident.toChars()); + id = tempdecl.ident.toChars(); + buf.printf("__T%d%s", id.length, id); ///! + args = tiargs; + for (int i = 0; i < args.dim; i++) + { + Object o = cast(Object)args.data[i]; + Type ta = isType(o); + Expression ea = isExpression(o); + Dsymbol sa = isDsymbol(o); + Tuple va = isTuple(o); + //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va); + if (ta) + { + buf.writeByte('T'); + if (ta.deco) + buf.writestring(ta.deco); + else + { + debug writef("ta = %d, %s\n", ta.ty, ta.toChars()); + assert(global.errors); + } + } + else if (ea) + { + Lea: + long v; + real r; + + ea = ea.optimize(WANTvalue | WANTinterpret); + if (ea.op == TOKvar) + { + sa = (cast(VarExp)ea).var; + ea = null; + goto Lsa; + } + if (ea.op == TOKfunction) + { + sa = (cast(FuncExp)ea).fd; + ea = null; + goto Lsa; + } + buf.writeByte('V'); + if (ea.op == TOKtuple) + { + ea.error("tuple is not a valid template value argument"); + continue; + } + static if (true) { + /* Use deco that matches what it would be for a function parameter + */ + buf.writestring(ea.type.deco); + } else { + // Use type of parameter, not type of argument + TemplateParameter tp = cast(TemplateParameter)tempdecl.parameters.data[i]; + assert(tp); + TemplateValueParameter tvp = tp.isTemplateValueParameter(); + assert(tvp); + buf.writestring(tvp.valType.deco); + } + ea.toMangleBuffer(buf); + } + else if (sa) + { + Lsa: + buf.writeByte('S'); + Declaration d = sa.isDeclaration(); + if (d && (!d.type || !d.type.deco)) + { + error("forward reference of %s", d.toChars()); + continue; + } + static if (false) { + VarDeclaration v = sa.isVarDeclaration(); + if (v && v.storage_class & STCmanifest) + { + ExpInitializer ei = v.init.isExpInitializer(); + if (ei) + { + ea = ei.exp; + goto Lea; + } + } + } + string p = sa.mangle(); + buf.printf("%zu%s", p.length, p); + } + else if (va) + { + assert(i + 1 == args.dim); // must be last one + args = va.objects; + i = -1; + } + else + assert(0); + } + buf.writeByte('Z'); + id = buf.toChars(); + buf.data = null; + //printf("\tgenIdent = %s\n", id); + return new Identifier(id, TOKidentifier); + } + + TemplateInstance isTemplateInstance() { return this; } + + AliasDeclaration isAliasDeclaration() + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TemplateMixin.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TemplateMixin.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,81 @@ +module dmd.TemplateMixin; + +import dmd.TemplateInstance; +import dmd.Array; +import dmd.Type; +import dmd.ArrayTypes; +import dmd.Loc; +import dmd.Identifier; +import dmd.Dsymbol; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; + +class TemplateMixin : TemplateInstance +{ + Array idents; + Type tqual; + + this(Loc loc, Identifier ident, Type tqual, Array idents, Objects tiargs) + { + assert(false); + super(loc, ident); + } + + Dsymbol syntaxCopy(Dsymbol s) + { + assert(false); + } + + void semantic(Scope sc) + { + assert(false); + } + + void semantic2(Scope sc) + { + assert(false); + } + + void semantic3(Scope sc) + { + assert(false); + } + + void inlineScan() + { + assert(false); + } + + string kind() + { + assert(false); + } + + bool oneMember(Dsymbol* ps) + { + assert(false); + } + + bool hasPointers() + { + assert(false); + } + + string toChars() + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + void toObjFile(int multiobj) // compile to .obj file + { + assert(false); + } + + TemplateMixin isTemplateMixin() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TemplateParameter.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TemplateParameter.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,87 @@ +module dmd.TemplateParameter; + +import dmd.Loc; +import dmd.Identifier; +import dmd.Declaration; +import dmd.TemplateTypeParameter; +import dmd.TemplateValueParameter; +import dmd.TemplateAliasParameter; +import dmd.TemplateThisParameter; +import dmd.TemplateTupleParameter; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.MATCH; +import dmd.ArrayTypes; + +class TemplateParameter +{ + /* For type-parameter: + * template Foo(ident) // specType is set to NULL + * template Foo(ident : specType) + * For value-parameter: + * template Foo(valType ident) // specValue is set to NULL + * template Foo(valType ident : specValue) + * For alias-parameter: + * template Foo(alias ident) + * For this-parameter: + * template Foo(this ident) + */ + + Loc loc; + Identifier ident; + + Declaration sparam; + + this(Loc loc, Identifier ident) + { + this.loc = loc; + this.ident = ident; + } + + TemplateTypeParameter isTemplateTypeParameter() + { + assert(false); + } + + TemplateValueParameter isTemplateValueParameter() + { + assert(false); + } + + TemplateAliasParameter isTemplateAliasParameter() + { + assert(false); + } + +version (DMDV2) { + TemplateThisParameter isTemplateThisParameter() + { + assert(false); + } +} + TemplateTupleParameter isTemplateTupleParameter() + { + return null; + } + + abstract TemplateParameter syntaxCopy(); + abstract void declareParameter(Scope sc); + abstract void semantic(Scope); + abstract void print(Object oarg, Object oded); + abstract void toCBuffer(OutBuffer buf, HdrGenState* hgs); + abstract Object specialization(); + abstract Object defaultArg(Loc loc, Scope sc); + + /* If TemplateParameter's match as far as overloading goes. + */ + abstract bool overloadMatch(TemplateParameter); + + /* Match actual argument against parameter. + */ + abstract MATCH matchArg(Scope sc, Objects tiargs, int i, TemplateParameters parameters, Objects dedtypes, Declaration* psparam, int flags = 0); + + /* Create dummy argument based on parameter. + */ + abstract void* dummyArg(); +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TemplateThisParameter.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TemplateThisParameter.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,39 @@ +module dmd.TemplateThisParameter; + +import dmd.TemplateTypeParameter; +import dmd.Type; +import dmd.Loc; +import dmd.Identifier; +import dmd.TemplateParameter; +import dmd.OutBuffer; +import dmd.HdrGenState; + +class TemplateThisParameter : TemplateTypeParameter +{ + /* Syntax: + * this ident : specType = defaultType + */ + Type specType; // type parameter: if !=NULL, this is the type specialization + Type defaultType; + + this(Loc loc, Identifier ident, Type specType, Type defaultType) + { + assert(false); + super(loc, ident, specType, defaultType); + } + + TemplateThisParameter isTemplateThisParameter() + { + assert(false); + } + + TemplateParameter syntaxCopy() + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TemplateTupleParameter.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TemplateTupleParameter.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,149 @@ +module dmd.TemplateTupleParameter; + +import dmd.TemplateParameter; +import dmd.Loc; +import dmd.Identifier; +import dmd.TypeIdentifier; +import dmd.AliasDeclaration; +import dmd.Scope; +import dmd.ArrayTypes; +import dmd.MATCH; +import dmd.Declaration; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Util; +import dmd.Tuple; +import dmd.Dsymbol; +import dmd.TemplateInstance; +import dmd.Type; +import dmd.Expression; +import dmd.TupleDeclaration; + +class TemplateTupleParameter : TemplateParameter +{ + /* Syntax: + * ident ... + */ + + this(Loc loc, Identifier ident) + { + super(loc, ident); + this.ident = ident; + } + + TemplateTupleParameter isTemplateTupleParameter() + { + return this; + } + + TemplateParameter syntaxCopy() + { + TemplateTupleParameter tp = new TemplateTupleParameter(loc, ident); + return tp; + } + + void declareParameter(Scope sc) + { + TypeIdentifier ti = new TypeIdentifier(loc, ident); + sparam = new AliasDeclaration(loc, ident, ti); + if (!sc.insert(sparam)) + error(loc, "parameter '%s' multiply defined", ident.toChars()); + } + + void semantic(Scope) + { + } + + void print(Object oarg, Object oded) + { + writef(" %s... [", ident.toChars()); + Tuple v = isTuple(oded); + assert(v); + + //printf("|%d| ", v.objects.dim); + for (int i = 0; i < v.objects.dim; i++) + { + if (i) + writef(", "); + + Object o = cast(Object)v.objects.data[i]; + + Dsymbol sa = isDsymbol(o); + if (sa) + writef("alias: %s", sa.toChars()); + + Type ta = isType(o); + if (ta) + writef("type: %s", ta.toChars()); + + Expression ea = isExpression(o); + if (ea) + writef("exp: %s", ea.toChars()); + + assert(!isTuple(o)); // no nested Tuple arguments + } + + writef("]\n"); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + buf.writestring(ident.toChars()); + buf.writestring("..."); + } + + Object specialization() + { + return null; + } + + Object defaultArg(Loc loc, Scope sc) + { + return null; + } + + bool overloadMatch(TemplateParameter tp) + { + TemplateTupleParameter tvp = tp.isTemplateTupleParameter(); + if (tvp) { + return true; // match + } + + Lnomatch: + return false; + } + + MATCH matchArg(Scope sc, Objects tiargs, int i, TemplateParameters parameters, Objects dedtypes, Declaration* psparam, int flags) + { + //printf("TemplateTupleParameter.matchArg()\n"); + + /* The rest of the actual arguments (tiargs[]) form the match + * for the variadic parameter. + */ + assert(i + 1 == dedtypes.dim); // must be the last one + Tuple ovar; + if (i + 1 == tiargs.dim && isTuple(cast(Object)tiargs.data[i])) + ovar = isTuple(cast(Object)tiargs.data[i]); + else + { + ovar = new Tuple(); + //printf("ovar = %p\n", ovar); + if (i < tiargs.dim) + { + //printf("i = %d, tiargs.dim = %d\n", i, tiargs.dim); + ovar.objects.setDim(tiargs.dim - i); + for (size_t j = 0; j < ovar.objects.dim; j++) + ovar.objects.data[j] = tiargs.data[i + j]; + } + } + *psparam = new TupleDeclaration(loc, ident, ovar.objects); + dedtypes.data[i] = cast(void*)ovar; + + return MATCH.MATCHexact; + } + + void* dummyArg() + { + return null; + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TemplateTypeParameter.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TemplateTypeParameter.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,215 @@ +module dmd.TemplateTypeParameter; + +import dmd.TemplateParameter; +import dmd.Type; +import dmd.Loc; +import dmd.Identifier; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Declaration; +import dmd.ArrayTypes; +import dmd.TypeIdentifier; +import dmd.AliasDeclaration; +import dmd.Util; +import dmd.MATCH; +import dmd.Dsymbol; + +class TemplateTypeParameter : TemplateParameter +{ + /* Syntax: + * ident : specType = defaultType + */ + Type specType; // type parameter: if !=null, this is the type specialization + Type defaultType; + + this(Loc loc, Identifier ident, Type specType, Type defaultType) + { + super(loc, ident); + this.ident = ident; + this.specType = specType; + this.defaultType = defaultType; + } + + TemplateTypeParameter isTemplateTypeParameter() + { + return this; + } + + TemplateParameter syntaxCopy() + { + assert(false); + } + + void declareParameter(Scope sc) + { + //printf("TemplateTypeParameter.declareParameter('%s')\n", ident.toChars()); + TypeIdentifier ti = new TypeIdentifier(loc, ident); + sparam = new AliasDeclaration(loc, ident, ti); + if (!sc.insert(sparam)) + error(loc, "parameter '%s' multiply defined", ident.toChars()); + } + + void semantic(Scope sc) + { + //printf("TemplateTypeParameter.semantic('%s')\n", ident.toChars()); + if (specType) + { + specType = specType.semantic(loc, sc); + } + static if (false) { // Don't do semantic() until instantiation + if (defaultType) + { + defaultType = defaultType.semantic(loc, sc); + } + } + } + + void print(Object oarg, Object oded) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + buf.writestring(ident.toChars()); + if (specType) + { + buf.writestring(" : "); + specType.toCBuffer(buf, null, hgs); + } + if (defaultType) + { + buf.writestring(" = "); + defaultType.toCBuffer(buf, null, hgs); + } + } + + Object specialization() + { + return specType; + } + + Object defaultArg(Loc loc, Scope sc) + { + Type t; + + t = defaultType; + if (t) + { + t = t.syntaxCopy(); + t = t.semantic(loc, sc); + } + return t; + } + + bool overloadMatch(TemplateParameter) + { + assert(false); + } + + /******************************************* + * Match to a particular TemplateParameter. + * Input: + * i i'th argument + * tiargs[] actual arguments to template instance + * parameters[] template parameters + * dedtypes[] deduced arguments to template instance + * *psparam set to symbol declared and initialized to dedtypes[i] + * flags 1: don't do 'toHeadMutable()' + */ + MATCH matchArg(Scope sc, Objects tiargs, int i, TemplateParameters parameters, Objects dedtypes, Declaration* psparam, int flags) + { + //printf("TemplateTypeParameter.matchArg()\n"); + Type t; + Object oarg; + MATCH m = MATCHexact; + Type ta; + + if (i < tiargs.dim) + oarg = cast(Object)tiargs.data[i]; + else + { + // Get default argument instead + oarg = defaultArg(loc, sc); + if (!oarg) + { + assert(i < dedtypes.dim); + // It might have already been deduced + oarg = cast(Object)dedtypes.data[i]; + if (!oarg) + { + goto Lnomatch; + } + flags |= 1; // already deduced, so don't to toHeadMutable() + } + } + + ta = isType(oarg); + if (!ta) + { + //printf("%s %p %p %p\n", oarg.toChars(), isExpression(oarg), isDsymbol(oarg), isTuple(oarg)); + goto Lnomatch; + } + //printf("ta is %s\n", ta.toChars()); + + t = cast(Type)dedtypes.data[i]; + + if (specType) + { + //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta.toChars(), specType.toChars()); + MATCH m2 = ta.deduceType(sc, specType, parameters, dedtypes); + if (m2 == MATCHnomatch) + { + //printf("\tfailed deduceType\n"); + goto Lnomatch; + } + + if (m2 < m) + m = m2; + t = cast(Type)dedtypes.data[i]; + } + else + { + // So that matches with specializations are better + m = MATCHconvert; + + /* This is so that: + * template Foo(T), Foo!(const int), => ta == int + */ + // if (!(flags & 1)) + // ta = ta.toHeadMutable(); + + if (t) + { // Must match already deduced type + + m = MATCHexact; + if (!t.equals(ta)) + { + //printf("t = %s ta = %s\n", t.toChars(), ta.toChars()); + goto Lnomatch; + } + } + } + + if (!t) + { + dedtypes.data[i] = cast(void*)ta; + t = ta; + } + + *psparam = new AliasDeclaration(loc, ident, t); + //printf("\tm = %d\n", m); + return m; + + Lnomatch: + *psparam = null; + //printf("\tm = %d\n", MATCHnomatch); + return MATCHnomatch; + } + + void* dummyArg() + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TemplateValueParameter.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TemplateValueParameter.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,87 @@ +module dmd.TemplateValueParameter; + +import dmd.TemplateParameter; +import dmd.Scope; +import dmd.Declaration; +import dmd.ArrayTypes; +import dmd.Type; +import dmd.Expression; +import dmd.Loc; +import dmd.Identifier; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.MATCH; + +class TemplateValueParameter : TemplateParameter +{ + /* Syntax: + * valType ident : specValue = defaultValue + */ + + Type valType; + Expression specValue; + Expression defaultValue; + + static Expression edummy; + + this(Loc loc, Identifier ident, Type valType, Expression specValue, Expression defaultValue) + { + assert(false); + super(loc, ident); + } + + TemplateValueParameter isTemplateValueParameter() + { + assert(false); + } + + TemplateParameter syntaxCopy() + { + assert(false); + } + + void declareParameter(Scope sc) + { + assert(false); + } + + void semantic(Scope) + { + assert(false); + } + + void print(Object oarg, Object oded) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + Object specialization() + { + assert(false); + } + + Object defaultArg(Loc loc, Scope sc) + { + assert(false); + } + + bool overloadMatch(TemplateParameter) + { + assert(false); + } + + MATCH matchArg(Scope sc, Objects tiargs, int i, TemplateParameters parameters, Objects dedtypes, Declaration* psparam, int flags) + { + assert(false); + } + + void* dummyArg() + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ThisDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ThisDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,25 @@ +module dmd.ThisDeclaration; + +import dmd.VarDeclaration; +import dmd.Dsymbol; +import dmd.Loc; +import dmd.Type; +import dmd.Id; + +// For the "this" parameter to member functions + +class ThisDeclaration : VarDeclaration +{ + this(Loc loc, Type t) + { + super(loc, t, Id.This, null); + noauto = true; + } + + Dsymbol syntaxCopy(Dsymbol) + { + assert(false); + } + + ThisDeclaration isThisDeclaration() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/ThisExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ThisExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,189 @@ +module dmd.ThisExp; + +import dmd.Expression; +import dmd.Declaration; +import dmd.StructDeclaration; +import dmd.ClassDeclaration; +import dmd.Dsymbol; +import dmd.FuncDeclaration; +import dmd.backend.elem; +import dmd.CSX; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.Type; +import dmd.TOK; +import dmd.InlineCostState; +import dmd.InlineDoState; +import dmd.IRState; +import dmd.HdrGenState; +import dmd.VarExp; +import dmd.TY; + +import dmd.codegen.Util; +import dmd.backend.TYM; +import dmd.backend.Util; +import dmd.backend.OPER; + +class ThisExp : Expression +{ + Declaration var; + + this(Loc loc) + { + super(loc, TOK.TOKthis, ThisExp.sizeof); + //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum); + } + + Expression semantic(Scope sc) + { + FuncDeclaration fd; + FuncDeclaration fdthis; + + version (LOGSEMANTIC) { + printf("ThisExp::semantic()\n"); + } + if (type) + { + //assert(global.errors || var); + return this; + } + + /* Special case for typeof(this) and typeof(super) since both + * should work even if they are not inside a non-static member function + */ + if (sc.intypeof) + { + // Find enclosing struct or class + for (Dsymbol s = sc.parent; 1; s = s.parent) + { + if (!s) + { + error("%s is not in a class or struct scope", toChars()); + goto Lerr; + } + ClassDeclaration cd = s.isClassDeclaration(); + if (cd) + { + type = cd.type; + return this; + } + StructDeclaration sd = s.isStructDeclaration(); + if (sd) + { + version (STRUCTTHISREF) { + type = sd.type; + } else { + type = sd.type.pointerTo(); + } + return this; + } + } + } + + fdthis = sc.parent.isFuncDeclaration(); + fd = hasThis(sc); // fd is the uplevel function with the 'this' variable + if (!fd) + goto Lerr; + + assert(fd.vthis); + var = fd.vthis; + assert(var.parent); + type = var.type; + var.isVarDeclaration().checkNestedReference(sc, loc); + if (!sc.intypeof) + sc.callSuper |= CSXthis; + return this; + + Lerr: + error("'this' is only defined in non-static member functions, not %s", sc.parent.toChars()); + type = Type.terror; + return this; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + bool isBool(bool result) + { + return result ? true : false; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + buf.writestring("this"); + } + +version (DMDV2) { + int isLvalue() + { + return 1; + } +} + Expression toLvalue(Scope sc, Expression e) + { + return this; + } + + void scanForNestedRef(Scope sc) + { + assert(false); + } + + int inlineCost(InlineCostState* ics) + { + FuncDeclaration fd = ics.fd; + if (!ics.hdrscan) + if (fd.isNested() || !ics.hasthis) + return COST_MAX; + + return 1; + } + + Expression doInline(InlineDoState ids) + { + //if (!ids.vthis) + //error("no 'this' when inlining %s", ids.parent.toChars()); + if (!ids.vthis) + { + return this; + } + + VarExp ve = new VarExp(loc, ids.vthis); + ve.type = type; + return ve; + } + + elem* toElem(IRState* irs) + { + elem* ethis; + FuncDeclaration fd; + + //printf("ThisExp::toElem()\n"); + assert(irs.sthis); + + if (var) + { + assert(var.parent); + fd = var.toParent2().isFuncDeclaration(); + assert(fd); + ethis = getEthis(loc, irs, fd); + } + else + ethis = el_var(irs.sthis); + + version (STRUCTTHISREF) { + if (type.ty == Tstruct) + { + ethis = el_una(OPind, TYstruct, ethis); + ethis.Enumbytes = cast(uint)type.size(); + } + } + el_setLoc(ethis,loc); + return ethis; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/ThrowStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/ThrowStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,85 @@ +module dmd.ThrowStatement; + +import dmd.Statement; +import dmd.Expression; +import dmd.Loc; +import dmd.IRState; +import dmd.InlineScanState; +import dmd.HdrGenState; +import dmd.OutBuffer; +import dmd.Scope; +import dmd.Expression; +import dmd.FuncDeclaration; +import dmd.BE; + +import dmd.backend.Util; +import dmd.backend.Blockx; +import dmd.backend.elem; +import dmd.backend.RTLSYM; +import dmd.backend.OPER; +import dmd.backend.TYM; + +class ThrowStatement : Statement +{ + Expression exp; + + this(Loc loc, Expression exp) + { + super(loc); + this.exp = exp; + } + + Statement syntaxCopy() + { + assert(false); + } + + Statement semantic(Scope sc) + { + //printf("ThrowStatement::semantic()\n"); + + FuncDeclaration fd = sc.parent.isFuncDeclaration(); + fd.hasReturnExp |= 2; + + if (sc.incontract) + error("Throw statements cannot be in contracts"); + exp = exp.semantic(sc); + exp = resolveProperties(sc, exp); + if (!exp.type.toBasetype().isClassHandle()) + error("can only throw class objects, not type %s", exp.type.toChars()); + return this; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + BE blockExit() + { + return BE.BEthrow; // obviously + } + + Statement inlineScan(InlineScanState* iss) + { + if (exp) + exp = exp.inlineScan(iss); + return this; + } + + void toIR(IRState* irs) + { + // throw(exp) + + Blockx *blx = irs.blx; + + incUsage(irs, loc); + elem *e = exp.toElem(irs); + static if (false) { + e = el_bin(OPcall, TYvoid, el_var(rtlsym[RTLSYM_LTHROW]),e); + } else { + e = el_bin(OPcall, TYvoid, el_var(rtlsym[RTLSYM_THROW]),e); + } + block_appendexp(blx.curblock, e); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/Token.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Token.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,215 @@ +module dmd.Token; + +import dmd.TOK; +import dmd.Identifier; +import dmd.OutBuffer; +import dmd.Utf; + +import core.stdc.stdio; +import core.stdc.ctype; + +struct Token +{ + Token* next; + ubyte* ptr; // pointer to first character of this token within buffer + TOK value; + ubyte* blockComment; // doc comment string prior to this token + ubyte* lineComment; // doc comment for previous token + + union + { + // Integers + int int32value; + uint uns32value; + long int64value; + ulong uns64value; + + // Floats +version (IN_GCC) { + // real_t float80value; // can't use this in a union! +} else { + real float80value; +} + + struct + { + const(char)* ustring; // UTF8 string + uint len; + ubyte postfix; // 'c', 'w', 'd' + }; + + Identifier ident; + } + +version (IN_GCC) { + real float80value; // can't use this in a union! +} + + static string tochars[TOK.TOKMAX]; +/// static void *operator new(size_t sz); + + int isKeyword() + { + assert(false); + } + + void print() + { + assert(false); + } + + string toChars() + { + static char buffer[3 + 3 * value.sizeof + 1]; + + string p; + + switch (value) + { + case TOK.TOKint32v: +version (IN_GCC) { + sprintf(buffer.ptr,"%d",cast(int)int64value); +} else { + sprintf(buffer.ptr,"%d",int32value); +} + break; + + case TOK.TOKuns32v: + case TOK.TOKcharv: + case TOK.TOKwcharv: + case TOK.TOKdcharv: +version (IN_GCC) { + sprintf(buffer.ptr,"%uU",cast(uint)uns64value); +} else { + sprintf(buffer.ptr,"%uU",uns32value); +} + break; + + case TOK.TOKint64v: + sprintf(buffer.ptr,"%jdL",int64value); + break; + + case TOK.TOKuns64v: + sprintf(buffer.ptr,"%juUL",uns64value); + break; + +version (IN_GCC) { + case TOK.TOKfloat32v: + case TOK.TOKfloat64v: + case TOK.TOKfloat80v: + float80value.format(buffer, sizeof(buffer)); + break; + case TOK.TOKimaginary32v: + case TOK.TOKimaginary64v: + case TOK.TOKimaginary80v: + float80value.format(buffer, sizeof(buffer)); + // %% buffer + strcat(buffer, "i"); + break; +} else { + case TOK.TOKfloat32v: + sprintf(buffer.ptr,"%Lgf", float80value); + break; + + case TOK.TOKfloat64v: + sprintf(buffer.ptr,"%Lg", float80value); + break; + + case TOK.TOKfloat80v: + sprintf(buffer.ptr,"%LgL", float80value); + break; + + case TOK.TOKimaginary32v: + sprintf(buffer.ptr,"%Lgfi", float80value); + break; + + case TOK.TOKimaginary64v: + sprintf(buffer.ptr,"%Lgi", float80value); + break; + + case TOK.TOKimaginary80v: + sprintf(buffer.ptr,"%LgLi", float80value); + break; +} + + case TOK.TOKstring: +version (CSTRINGS) { + p = string; +} else { + { OutBuffer buf; + + buf.writeByte('"'); + for (size_t i = 0; i < len; ) + { + dchar c; ///! + + utf_decodeChar(ustring[0..len], &i, &c); + switch (c) + { + case 0: + break; + + case '"': + case '\\': + buf.writeByte('\\'); + default: + if (isprint(c)) + buf.writeByte(c); + else if (c <= 0x7F) + buf.printf("\\x%02x", c); + else if (c <= 0xFFFF) + buf.printf("\\u%04x", c); + else + buf.printf("\\U%08x", c); + continue; + } + break; + } + buf.writeByte('"'); + if (postfix) + buf.writeByte('"'); + buf.writeByte(0); + p = buf.extractString(); + } +} + break; + + case TOK.TOKidentifier: + case TOK.TOKenum: + case TOK.TOKstruct: + case TOK.TOKimport: + case TOK.TOKwchar: case TOK.TOKdchar: + case TOK.TOKbit: case TOK.TOKbool: case TOK.TOKchar: + case TOK.TOKint8: case TOK.TOKuns8: + case TOK.TOKint16: case TOK.TOKuns16: + case TOK.TOKint32: case TOK.TOKuns32: + case TOK.TOKint64: case TOK.TOKuns64: + case TOK.TOKfloat32: case TOK.TOKfloat64: case TOK.TOKfloat80: + case TOK.TOKimaginary32: case TOK.TOKimaginary64: case TOK.TOKimaginary80: + case TOK.TOKcomplex32: case TOK.TOKcomplex64: case TOK.TOKcomplex80: + case TOK.TOKvoid: + p = ident.toChars(); + break; + + default: + p = toChars(value); + break; + } + return p; + } + + static string toChars(TOK value) + { + string p; + static char buffer[3 + 3 * value.sizeof + 1]; + + p = tochars[value]; + if (!p) + { + int len = sprintf(buffer.ptr, "TOK%d".ptr, value); + p = buffer[0..len].idup; + } + + return p; + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TraitsExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TraitsExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,39 @@ +module dmd.TraitsExp; + +import dmd.Expression; +import dmd.Identifier; +import dmd.ArrayTypes; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.HdrGenState; +import dmd.TOK; + +class TraitsExp : Expression +{ + Identifier ident; + + Objects args; + + this(Loc loc, Identifier ident, Objects args) + { + assert(false); + super(loc, TOK.init, 0); + } + + Expression syntaxCopy() + { + assert(false); + } + + Expression semantic(Scope sc) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/TryCatchStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TryCatchStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,201 @@ +module dmd.TryCatchStatement; + +import dmd.Statement; +import dmd.Array; +import dmd.Loc; +import dmd.Id; +import dmd.Identifier; +import dmd.Scope; +import dmd.InlineScanState; +import dmd.IRState; +import dmd.OutBuffer; +import dmd.Catch; +import dmd.HdrGenState; +import dmd.BE; + +import dmd.backend.BC; +import dmd.codegen.Util; +import dmd.backend.Util; +import dmd.backend.Blockx; +import dmd.backend.block; +import dmd.backend.mTY; +import dmd.backend.TYM; + +class TryCatchStatement : Statement +{ + Statement body_; + Array catches; + + this(Loc loc, Statement body_, Array catches) + { + super(loc); + this.body_ = body_; + this.catches = catches; + } + + Statement syntaxCopy() + { + assert(false); + } + + Statement semantic(Scope sc) + { + body_ = body_.semanticScope(sc, null /*this*/, null); + + /* Even if body is null, still do semantic analysis on catches + */ + for (size_t i = 0; i < catches.dim; i++) + { + Catch c = cast(Catch)catches.data[i]; + c.semantic(sc); + + // Determine if current catch 'hides' any previous catches + for (size_t j = 0; j < i; j++) + { + Catch cj = cast(Catch)catches.data[j]; + string si = c.loc.toChars(); + string sj = cj.loc.toChars(); + + if (c.type.toBasetype().implicitConvTo(cj.type.toBasetype())) + error("catch at %s hides catch at %s", sj, si); + } + } + + if (!body_ || body_.isEmpty()) + { + return null; + } + return this; + } + + bool hasBreak() + { + assert(false); + } + + bool usesEH() + { + assert(false); + } + + BE blockExit() + { + assert(body_); + BE result = body_.blockExit(); + + BE catchresult = BE.BEnone; + for (size_t i = 0; i < catches.dim; i++) + { + Catch c = cast(Catch)catches.data[i]; + catchresult |= c.blockExit(); + + /* If we're catching Object, then there is no throwing + */ + Identifier id = c.type.toBasetype().isClassHandle().ident; + if (i == 0 && + (id is Id.Object_ || id is Id.Throwable || id is Id.Exception)) + { + result &= ~BE.BEthrow; + } + } + return result | catchresult; + } + + Statement inlineScan(InlineScanState* iss) + { + if (body_) + body_ = body_.inlineScan(iss); + if (catches) + { + for (int i = 0; i < catches.dim; i++) + { + Catch c = cast(Catch)catches.data[i]; + + if (c.handler) + c.handler = c.handler.inlineScan(iss); + } + } + return this; + } + + /*************************************** + * Builds the following: + * _try + * block + * jcatch + * handler + * A try-catch statement. + */ + void toIR(IRState *irs) + { + Blockx *blx = irs.blx; + + version (SEH) { + nteh_declarvars(blx); + } + + IRState mystate = IRState(irs, this); + + block* tryblock = block_goto(blx,BCgoto,null); + + int previndex = blx.scope_index; + tryblock.Blast_index = previndex; + blx.scope_index = tryblock.Bscope_index = blx.next_index++; + + // Set the current scope index + setScopeIndex(blx,tryblock,tryblock.Bscope_index); + + // This is the catch variable + tryblock.jcatchvar = symbol_genauto(type_fake(mTYvolatile | TYnptr)); + + blx.tryblock = tryblock; + block *breakblock = block_calloc(blx); + block_goto(blx,BC_try,null); + if (body_) + { + body_.toIR(&mystate); + } + blx.tryblock = tryblock.Btry; + + // break block goes here + block_goto(blx, BCgoto, breakblock); + + setScopeIndex(blx,blx.curblock, previndex); + blx.scope_index = previndex; + + // create new break block that follows all the catches + breakblock = block_calloc(blx); + + list_append(&blx.curblock.Bsucc, breakblock); + block_next(blx,BCgoto,null); + + assert(catches); + for (int i = 0 ; i < catches.dim; i++) + { + Catch cs = cast(Catch)(catches.data[i]); + if (cs.var) + cs.var.csym = tryblock.jcatchvar; + block* bcatch = blx.curblock; + if (cs.type) + bcatch.Bcatchtype = cs.type.toBasetype().toSymbol(); + list_append(&tryblock.Bsucc,bcatch); + block_goto(blx,BCjcatch,null); + if (cs.handler !is null) + { + IRState catchState = IRState(irs, this); + cs.handler.toIR(&catchState); + } + list_append(&blx.curblock.Bsucc, breakblock); + block_next(blx, BCgoto, null); + } + + block_next(blx,cast(BC)blx.curblock.BC, breakblock); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + TryCatchStatement isTryCatchStatement() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TryFinallyStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TryFinallyStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,160 @@ +module dmd.TryFinallyStatement; + +import dmd.Statement; +import dmd.Loc; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Scope; +import dmd.InlineScanState; +import dmd.CompoundStatement; +import dmd.IRState; +import dmd.BE; + +import dmd.backend.block; +import dmd.backend.Blockx; +import dmd.backend.BC; +import dmd.backend.Util; + +import dmd.codegen.Util; + +class TryFinallyStatement : Statement +{ + Statement body_; + Statement finalbody; + + this(Loc loc, Statement body_, Statement finalbody) + { + super(loc); + this.body_ = body_; + this.finalbody = finalbody; + } + + Statement syntaxCopy() + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + Statement semantic(Scope sc) + { + //printf("TryFinallyStatement::semantic()\n"); + body_ = body_.semantic(sc); + sc = sc.push(); + sc.tf = this; + sc.sbreak = null; + sc.scontinue = null; // no break or continue out of finally block + finalbody = finalbody.semantic(sc); + sc.pop(); + if (!body_) + return finalbody; + if (!finalbody) + return body_; + if (body_.blockExit() == BE.BEfallthru) + { + Statement s = new CompoundStatement(loc, body_, finalbody); + return s; + } + return this; + } + + bool hasBreak() + { + assert(false); + } + + bool hasContinue() + { + assert(false); + } + + bool usesEH() + { + assert(false); + } + + BE blockExit() + { + if (body_) + return body_.blockExit(); + return BE.BEfallthru; + } + + Statement inlineScan(InlineScanState* iss) + { + if (body_) + body_ = body_.inlineScan(iss); + if (finalbody) + finalbody = finalbody.inlineScan(iss); + return this; + } + + /**************************************** + * A try-finally statement. + * Builds the following: + * _try + * block + * _finally + * finalbody + * _ret + */ + void toIR(IRState* irs) + { + //printf("TryFinallyStatement.toIR()\n"); + Blockx* blx = irs.blx; + + version (SEH) { + nteh_declarvars(blx); + } + + block* tryblock = block_goto(blx, BCgoto, null); + + int previndex = blx.scope_index; + tryblock.Blast_index = previndex; + tryblock.Bscope_index = blx.next_index++; + blx.scope_index = tryblock.Bscope_index; + + // Current scope index + setScopeIndex(blx,tryblock,tryblock.Bscope_index); + + blx.tryblock = tryblock; + block_goto(blx,BC_try,null); + + IRState bodyirs = IRState(irs, this); + block* breakblock = block_calloc(blx); + block* contblock = block_calloc(blx); + + if (body_) + body_.toIR(&bodyirs); + blx.tryblock = tryblock.Btry; // back to previous tryblock + + setScopeIndex(blx,blx.curblock,previndex); + blx.scope_index = previndex; + + block_goto(blx,BCgoto, breakblock); + block* finallyblock = block_goto(blx,BCgoto,contblock); + + list_append(&tryblock.Bsucc,finallyblock); + + block_goto(blx,BC_finally,null); + + IRState finallyState = IRState(irs, this); + breakblock = block_calloc(blx); + contblock = block_calloc(blx); + + setScopeIndex(blx, blx.curblock, previndex); + if (finalbody) + finalbody.toIR(&finallyState); + block_goto(blx, BCgoto, contblock); + block_goto(blx, BCgoto, breakblock); + + block* retblock = blx.curblock; + block_next(blx,BC_ret,null); + + list_append(&finallyblock.Bsucc, blx.curblock); + list_append(&retblock.Bsucc, blx.curblock); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/Tuple.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Tuple.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,14 @@ +module dmd.Tuple; + +import dmd.ArrayTypes; + +class Tuple +{ + Objects objects; + + int dyncast() + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/TupleDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TupleDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,45 @@ +module dmd.TupleDeclaration; + +import dmd.Declaration; +import dmd.ArrayTypes; +import dmd.TypeTuple; +import dmd.Loc; +import dmd.Identifier; +import dmd.Dsymbol; +import dmd.Type; + +class TupleDeclaration : Declaration +{ + Objects objects; + int isexp; // 1: expression tuple + + TypeTuple tupletype; // !=NULL if this is a type tuple + + this(Loc loc, Identifier ident, Objects objects) + { + assert(false); + super(ident); + } + + Dsymbol syntaxCopy(Dsymbol) + { + assert(false); + } + + string kind() + { + assert(false); + } + + Type getType() + { + assert(false); + } + + bool needThis() + { + assert(false); + } + + TupleDeclaration isTupleDeclaration() { return this; } +}; \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TupleExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TupleExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,110 @@ +module dmd.TupleExp; + +import dmd.Expression; +import dmd.TupleDeclaration; +import dmd.backend.elem; +import dmd.InterState; +import dmd.Type; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.InlineCostState; +import dmd.IRState; +import dmd.InlineDoState; +import dmd.HdrGenState; +import dmd.InlineScanState; +import dmd.ArrayTypes; +import dmd.TOK; + +class TupleExp : Expression +{ + Expressions exps; + + this(Loc loc, Expressions exps) + { + assert(false); + super(Loc(0), TOK.init, 0); + } + + this(Loc loc, TupleDeclaration tup) + { + assert(false); + super(Loc(0), TOK.init, 0); + } + + Expression syntaxCopy() + { + assert(false); + } + + int equals(Object o) + { + assert(false); + } + + Expression semantic(Scope sc) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + void scanForNestedRef(Scope sc) + { + assert(false); + } + + void checkEscape() + { + assert(false); + } + + bool checkSideEffect(int flag) + { + assert(false); + } + + Expression optimize(int result) + { + assert(false); + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + Expression castTo(Scope sc, Type t) + { + assert(false); + } + + elem* toElem(IRState* irs) + { + assert(false); + } + + bool canThrow() + { + assert(false); + } + + int inlineCost(InlineCostState* ics) + { + assert(false); + } + + Expression doInline(InlineDoState ids) + { + assert(false); + } + + Expression inlineScan(InlineScanState* iss) + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/Type.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Type.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,2445 @@ +module dmd.Type; + +import dmd.TY; +import dmd.Argument; +import dmd.TOK; +import dmd.STC; +import dmd.TypeArray; +import dmd.DotVarExp; +import dmd.ErrorExp; +import dmd.StringExp; +import dmd.IntegerExp; +import dmd.VarExp; +import dmd.TemplateParameter; +import dmd.TypeInfoSharedDeclaration; +import dmd.TypeInfoConstDeclaration; +import dmd.TypeInfoInvariantDeclaration; +import dmd.Module; +import dmd.Id; +import dmd.Util; +import dmd.VarDeclaration; +import dmd.Loc; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.Identifier; +import dmd.HdrGenState; +import dmd.Expression; +import dmd.Dsymbol; +import dmd.MATCH; +import dmd.TypeInfoDeclaration; +import dmd.ClassDeclaration; +import dmd.StringTable; +import dmd.ArrayTypes; +import dmd.TypeBasic; +import dmd.DYNCAST; +import dmd.MOD; +import dmd.Lexer; +import dmd.TypeSArray; +import dmd.TypeDArray; +import dmd.TypeAArray; +import dmd.TypePointer; +import dmd.TypeReference; +import dmd.TypeFunction; +import dmd.TypeDelegate; +import dmd.TypeIdentifier; +import dmd.TypeInstance; +import dmd.TypeTypeof; +import dmd.TypeReturn; +import dmd.TypeStruct; +import dmd.TypeEnum; +import dmd.TypeTypedef; +import dmd.TypeClass; +import dmd.TypeTuple; +import dmd.TypeSlice; +import dmd.Global; +import dmd.StringValue; + +import dmd.backend.Symbol; +import dmd.backend.TYPE; +import dmd.backend.dt_t; +import dmd.backend.Util; +import dmd.backend.TYM; +import dmd.backend.mTY; + +import core.stdc.stdio; + +/* These have default values for 32 bit code, they get + * adjusted for 64 bit code. + */ + +int PTRSIZE = 4; + +int Tsize_t; +int Tptrdiff_t; + +/* REALSIZE = size a real consumes in memory + * REALPAD = 'padding' added to the CPU real size to bring it up to REALSIZE + * REALALIGNSIZE = alignment for reals + */ +version (TARGET_OSX) { + int REALSIZE = 16; + int REALPAD = 6; + int REALALIGNSIZE = 16; +} else version (XXX) { /// TARGET_LINUX || TARGET_FREEBSD || TARGET_SOLARIS + int REALSIZE = 12; + int REALPAD = 2; + int REALALIGNSIZE = 4; +} else { + int REALSIZE = 10; + int REALPAD = 0; + int REALALIGNSIZE = 2; +} + +/**** + * Given an identifier, figure out which TemplateParameter it is. + * Return -1 if not found. + */ + +int templateIdentifierLookup(Identifier id, TemplateParameters parameters) +{ + for (size_t i = 0; i < parameters.dim; i++) + { + TemplateParameter tp = cast(TemplateParameter)parameters.data[i]; + + if (tp.ident.equals(id)) + return i; + } + return -1; +} + +int templateParameterLookup(Type tparam, TemplateParameters parameters) +{ + assert(tparam.ty == Tident); + TypeIdentifier tident = cast(TypeIdentifier)tparam; + //printf("\ttident = '%s'\n", tident.toChars()); + if (tident.idents.dim == 0) + { + return templateIdentifierLookup(tident.ident, parameters); + } + return -1; +} + +class Type +{ + TY ty; + MOD mod; // modifiers MODxxxx + /* pick this order of numbers so switch statements work better + */ +/// #define MODconst 1 // type is const +/// #define MODinvariant 4 // type is invariant +/// #define MODshared 2 // type is shared + string deco; + + /* These are cached values that are lazily evaluated by constOf(), invariantOf(), etc. + * They should not be referenced by anybody but mtype.c. + * They can be null if not lazily evaluated yet. + * Note that there is no "shared immutable", because that is just immutable + */ + + Type cto; // MODconst ? mutable version of this type : const version + Type ito; // MODinvariant ? mutable version of this type : invariant version + Type sto; // MODshared ? mutable version of this type : shared mutable version + Type scto; // MODshared|MODconst ? mutable version of this type : shared const version + + Type pto; // merged pointer to this type + Type rto; // reference to this type + Type arrayof; // array of this type + TypeInfoDeclaration vtinfo; // TypeInfo object for this Type + + type* ctype; // for back end + + static ClassDeclaration typeinfo; + static ClassDeclaration typeinfoclass; + static ClassDeclaration typeinfointerface; + static ClassDeclaration typeinfostruct; + static ClassDeclaration typeinfotypedef; + static ClassDeclaration typeinfopointer; + static ClassDeclaration typeinfoarray; + static ClassDeclaration typeinfostaticarray; + static ClassDeclaration typeinfoassociativearray; + static ClassDeclaration typeinfoenum; + static ClassDeclaration typeinfofunction; + static ClassDeclaration typeinfodelegate; + static ClassDeclaration typeinfotypelist; + static ClassDeclaration typeinfoconst; + static ClassDeclaration typeinfoinvariant; + static ClassDeclaration typeinfoshared; + + static Type basic[TY.TMAX]; + static ubyte mangleChar[TY.TMAX]; + static ubyte sizeTy[TY.TMAX]; + static StringTable stringtable; + + // These tables are for implicit conversion of binary ops; + // the indices are the type of operand one, followed by operand two. + static ubyte impcnvResult[TY.TMAX][TY.TMAX] = [ + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,19,19,19,19,20,21,22,23,24,25,23,24,25,29,30,31,37,19,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,19,19,19,19,20,21,22,23,24,25,23,24,25,29,30,31,37,19,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,19,19,19,19,20,21,22,23,24,25,23,24,25,29,30,31,37,19,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,19,19,19,19,20,21,22,23,24,25,23,24,25,29,30,31,37,19,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,19,19,19,19,20,21,22,23,24,25,23,24,25,29,30,31,37,19,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,20,20,20,20,20,20,21,22,23,24,25,23,24,25,29,30,31,37,20,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,21,21,21,21,21,21,21,22,23,24,25,23,24,25,29,30,31,37,21,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,22,22,22,22,22,22,22,22,23,24,25,23,24,25,29,30,31,37,22,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,23,23,23,23,23,23,23,23,23,24,25,23,24,25,29,30,31,37,23,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,24,24,24,24,24,24,24,24,24,24,25,24,24,25,30,30,31,37,24,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,25,25,25,25,25,25,25,25,25,25,25,25,25,25,31,31,31,37,25,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,23,23,23,23,23,23,23,23,23,24,25,26,27,28,29,30,31,37,23,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,24,24,24,24,24,24,24,24,24,24,25,27,27,28,30,30,31,37,24,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,25,25,25,25,25,25,25,25,25,25,25,28,28,28,31,31,31,37,25,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,29,29,29,29,29,29,29,29,29,30,31,29,30,31,29,30,31,37,29,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,30,30,30,30,30,30,30,30,30,30,31,30,30,31,30,30,31,37,30,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,37,31,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,19,19,19,19,20,21,22,23,24,25,23,24,25,29,30,31,37,33,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + ]; + + static ubyte impcnvType1[TY.TMAX][TY.TMAX] = [ + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,19,19,19,19,20,21,22,23,24,25,23,24,25,23,24,25,37,19,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,19,19,19,19,20,21,22,23,24,25,23,24,25,23,24,25,37,19,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,19,19,19,19,20,21,22,23,24,25,23,24,25,23,24,25,37,19,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,19,19,19,19,20,21,22,23,24,25,23,24,25,23,24,25,37,19,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,19,19,19,19,20,21,22,23,24,25,23,24,25,23,24,25,37,19,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,20,20,20,20,20,20,21,22,23,24,25,23,24,25,23,24,25,37,20,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,21,21,21,21,21,21,21,22,23,24,25,23,24,25,23,24,25,37,21,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,22,22,22,22,22,22,22,22,23,24,25,23,24,25,23,24,25,37,22,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,23,23,23,23,23,23,23,23,23,24,25,23,24,25,23,24,25,37,23,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,24,24,24,24,24,24,24,24,24,24,25,24,24,25,24,24,25,37,24,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,37,25,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,26,26,26,26,26,26,26,26,26,27,28,26,27,28,26,27,28,37,26,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,27,27,27,27,27,27,27,27,27,27,28,27,27,28,27,27,28,37,27,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,37,28,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,29,29,29,29,29,29,29,29,29,30,31,29,30,31,29,30,31,37,29,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,30,30,30,30,30,30,30,30,30,30,31,30,30,31,30,30,31,37,30,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,37,31,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,19,19,19,19,20,21,22,23,24,25,23,24,25,23,24,25,37,33,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + ]; + + static ubyte impcnvType2[TY.TMAX][TY.TMAX] = [ + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,19,19,19,19,20,21,22,23,24,25,26,27,28,29,30,31,37,19,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,19,19,19,19,20,21,22,23,24,25,26,27,28,29,30,31,37,19,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,19,19,19,19,20,21,22,23,24,25,26,27,28,29,30,31,37,19,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,19,19,19,19,20,21,22,23,24,25,26,27,28,29,30,31,37,19,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,19,19,19,19,20,21,22,23,24,25,26,27,28,29,30,31,37,19,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,20,20,20,20,20,20,21,22,23,24,25,26,27,28,29,30,31,37,20,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,21,21,21,21,21,21,21,22,23,24,25,26,27,28,29,30,31,37,21,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,22,22,22,22,22,22,22,22,23,24,25,26,27,28,29,30,31,37,22,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,23,23,23,23,23,23,23,23,23,24,25,26,27,28,29,30,31,37,23,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,24,24,24,24,24,24,24,24,24,24,25,27,27,28,30,30,31,37,24,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,25,25,25,25,25,25,25,25,25,25,25,28,28,28,31,31,31,37,25,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,23,23,23,23,23,23,23,23,23,24,25,26,27,28,29,30,31,37,23,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,24,24,24,24,24,24,24,24,24,24,25,27,27,28,30,30,31,37,24,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,25,25,25,25,25,25,25,25,25,25,25,28,28,28,31,31,31,37,25,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,23,23,23,23,23,23,23,23,23,24,25,26,27,28,29,30,31,37,23,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,24,24,24,24,24,24,24,24,24,24,25,27,27,28,30,30,31,37,24,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,25,25,25,25,25,25,25,25,25,25,25,28,28,28,31,31,31,37,25,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,19,19,19,19,20,21,22,23,24,25,26,27,28,29,30,31,37,33,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + [37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37], + ]; + + // If !=0, give warning on implicit conversion + static const(bool) impcnvWarn[TY.TMAX][TY.TMAX] = [ + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + ]; + + static this() + { + stringtable = new StringTable(); + } + + static ~this() + { + delete stringtable; + } + + this(TY ty) + { + this.ty = ty; + } + + Type syntaxCopy() + { + assert(false); + } + + int equals(Object o) + { + Type t = cast(Type)o; + //printf("Type.equals(%s, %s)\n", toChars(), t.toChars()); + if (this is o || (t && deco == t.deco) && // deco strings are unique + deco !is null) // and semantic() has been run + { + //printf("deco = '%s', t.deco = '%s'\n", deco, t.deco); + return 1; + } + //if (deco && t && t.deco) printf("deco = '%s', t.deco = '%s'\n", deco, t.deco); + return 0; + } + + DYNCAST dyncast() { return DYNCAST.DYNCAST_TYPE; } // kludge for template.isType() + + /******************************* + * Returns: + * 0 types are distinct + * 1 this is covariant with t + * 2 arguments match as far as overloading goes, + * but types are not covariant + * 3 cannot determine covariance because of forward references + */ + int covariant(Type t) + { +static if (false) { + printf("Type.covariant(t = %s) %s\n", t.toChars(), toChars()); + printf("deco = %p, %p\n", deco, t.deco); + // printf("ty = %d\n", next.ty); + printf("mod = %x, %x\n", mod, t.mod); +} + + int inoutmismatch = 0; + + TypeFunction t1; + TypeFunction t2; + + if (equals(t)) + return 1; // covariant + + if (ty != TY.Tfunction || t.ty != TY.Tfunction) + goto Ldistinct; + + t1 = cast(TypeFunction)this; + t2 = cast(TypeFunction)t; + + if (t1.varargs != t2.varargs) + goto Ldistinct; + + if (t1.parameters && t2.parameters) + { + size_t dim = Argument.dim(t1.parameters); + if (dim != Argument.dim(t2.parameters)) + goto Ldistinct; + + for (size_t i = 0; i < dim; i++) + { + Argument arg1 = Argument.getNth(t1.parameters, i); + Argument arg2 = Argument.getNth(t2.parameters, i); + + if (!arg1.type.equals(arg2.type)) + { +///static if (false) { +/// // turn on this for contravariant argument types, see bugzilla 3075 +/// // We can add const, but not subtract it +/// if (arg2.type.implicitConvTo(arg1.type) < MATCH.MATCHconst) +///} + goto Ldistinct; + } + if ((arg1.storageClass & ~STC.STCscope) != (arg2.storageClass & ~STC.STCscope)) + inoutmismatch = 1; + // We can add scope, but not subtract it + if (!(arg1.storageClass & STC.STCscope) && (arg2.storageClass & STC.STCscope)) + inoutmismatch = 1; + } + } + else if (t1.parameters != t2.parameters) + goto Ldistinct; + + // The argument lists match + if (inoutmismatch) + goto Lnotcovariant; + if (t1.linkage != t2.linkage) + goto Lnotcovariant; + + { + // Return types + Type t1n = t1.next; + Type t2n = t2.next; + + if (t1n.equals(t2n)) + goto Lcovariant; + if (t1n.ty == TY.Tclass && t2n.ty == TY.Tclass) + { + /* If same class type, but t2n is const, then it's + * covariant. Do this test first because it can work on + * forward references. + */ + if ((cast(TypeClass)t1n).sym == (cast(TypeClass)t2n).sym && + t2n.mod == MOD.MODconst) + goto Lcovariant; + + // If t1n is forward referenced: + ClassDeclaration cd = (cast(TypeClass)t1n).sym; + if (!cd.baseClass && cd.baseclasses.dim && !cd.isInterfaceDeclaration()) + { + return 3; + } + } + if (t1n.implicitConvTo(t2n)) + goto Lcovariant; + } + + goto Lnotcovariant; + + Lcovariant: + /* Can convert mutable to const + */ + if (t1.mod != t2.mod) + { + if (!(t1.mod & MOD.MODconst) && (t2.mod & MOD.MODconst)) + goto Lnotcovariant; + if (!(t1.mod & MOD.MODshared) && (t2.mod & MOD.MODshared)) + goto Lnotcovariant; + } + + /* Can convert pure to impure, and nothrow to throw + */ + if (!t1.ispure && t2.ispure) + goto Lnotcovariant; + + if (!t1.isnothrow && t2.isnothrow) + goto Lnotcovariant; + + if (t1.isref != t2.isref) + goto Lnotcovariant; + + //printf("\tcovaraint: 1\n"); + return 1; + + Ldistinct: + //printf("\tcovaraint: 0\n"); + return 0; + + Lnotcovariant: + //printf("\tcovaraint: 2\n"); + return 2; + } + + string toChars() + { + scope OutBuffer buf = new OutBuffer(); + + HdrGenState hgs; + toCBuffer(buf, null, &hgs); + return buf.toChars(); + } + + static char needThisPrefix() + { + return 'M'; // name mangling prefix for functions needing 'this' + } + + static void init() + { + Lexer.initKeywords(); + + for (int i = 0; i < TY.TMAX; i++) + sizeTy[i] = TypeBasic.sizeof; + + sizeTy[TY.Tsarray] = TypeSArray.sizeof; + sizeTy[TY.Tarray] = TypeDArray.sizeof; + //sizeTy[TY.Tnarray] = TypeNArray.sizeof; + sizeTy[TY.Taarray] = TypeAArray.sizeof; + sizeTy[TY.Tpointer] = TypePointer.sizeof; + sizeTy[TY.Treference] = TypeReference.sizeof; + sizeTy[TY.Tfunction] = TypeFunction.sizeof; + sizeTy[TY.Tdelegate] = TypeDelegate.sizeof; + sizeTy[TY.Tident] = TypeIdentifier.sizeof; + sizeTy[TY.Tinstance] = TypeInstance.sizeof; + sizeTy[TY.Ttypeof] = TypeTypeof.sizeof; + sizeTy[TY.Tenum] = TypeEnum.sizeof; + sizeTy[TY.Ttypedef] = TypeTypedef.sizeof; + sizeTy[TY.Tstruct] = TypeStruct.sizeof; + sizeTy[TY.Tclass] = TypeClass.sizeof; + sizeTy[TY.Ttuple] = TypeTuple.sizeof; + sizeTy[TY.Tslice] = TypeSlice.sizeof; + sizeTy[TY.Treturn] = TypeReturn.sizeof; + + mangleChar[TY.Tarray] = 'A'; + mangleChar[TY.Tsarray] = 'G'; + mangleChar[TY.Tnarray] = '@'; + mangleChar[TY.Taarray] = 'H'; + mangleChar[TY.Tpointer] = 'P'; + mangleChar[TY.Treference] = 'R'; + mangleChar[TY.Tfunction] = 'F'; + mangleChar[TY.Tident] = 'I'; + mangleChar[TY.Tclass] = 'C'; + mangleChar[TY.Tstruct] = 'S'; + mangleChar[TY.Tenum] = 'E'; + mangleChar[TY.Ttypedef] = 'T'; + mangleChar[TY.Tdelegate] = 'D'; + + mangleChar[TY.Tnone] = 'n'; + mangleChar[TY.Tvoid] = 'v'; + mangleChar[TY.Tint8] = 'g'; + mangleChar[TY.Tuns8] = 'h'; + mangleChar[TY.Tint16] = 's'; + mangleChar[TY.Tuns16] = 't'; + mangleChar[TY.Tint32] = 'i'; + mangleChar[TY.Tuns32] = 'k'; + mangleChar[TY.Tint64] = 'l'; + mangleChar[TY.Tuns64] = 'm'; + mangleChar[TY.Tfloat32] = 'f'; + mangleChar[TY.Tfloat64] = 'd'; + mangleChar[TY.Tfloat80] = 'e'; + + mangleChar[TY.Timaginary32] = 'o'; + mangleChar[TY.Timaginary64] = 'p'; + mangleChar[TY.Timaginary80] = 'j'; + mangleChar[TY.Tcomplex32] = 'q'; + mangleChar[TY.Tcomplex64] = 'r'; + mangleChar[TY.Tcomplex80] = 'c'; + + mangleChar[TY.Tbool] = 'b'; + mangleChar[TY.Tascii] = 'a'; + mangleChar[TY.Twchar] = 'u'; + mangleChar[TY.Tdchar] = 'w'; + + mangleChar[TY.Tbit] = '@'; + mangleChar[TY.Tinstance] = '@'; + mangleChar[TY.Terror] = '@'; + mangleChar[TY.Ttypeof] = '@'; + mangleChar[TY.Ttuple] = 'B'; + mangleChar[TY.Tslice] = '@'; + mangleChar[TY.Treturn] = '@'; + +debug { + for (int i = 0; i < TY.TMAX; i++) { + if (!mangleChar[i]) { + writef("ty = %d\n", i); + } + assert(mangleChar[i]); + } +} + // Set basic types + static TY[] basetab = [ + TY.Tvoid, TY.Tint8, TY.Tuns8, TY.Tint16, TY.Tuns16, TY.Tint32, TY.Tuns32, TY.Tint64, TY.Tuns64, + TY.Tfloat32, TY.Tfloat64, TY.Tfloat80, + TY.Timaginary32, TY.Timaginary64, TY.Timaginary80, + TY.Tcomplex32, TY.Tcomplex64, TY.Tcomplex80, + TY.Tbool, + TY.Tascii, TY.Twchar, TY.Tdchar + ]; + + foreach (bt; basetab) { + Type t = new TypeBasic(bt); + t = t.merge(); + basic[bt] = t; + } + + basic[TY.Terror] = basic[TY.Tint32]; + + tvoidptr = tvoid.pointerTo(); + + if (global.params.isX86_64) { + PTRSIZE = 8; + if (global.params.isLinux || global.params.isFreeBSD || global.params.isSolaris) + REALSIZE = 10; + else + REALSIZE = 8; + Tsize_t = TY.Tuns64; + Tptrdiff_t = TY.Tint64; + } + else + { + PTRSIZE = 4; +version (TARGET_OSX) { + REALSIZE = 16; + REALPAD = 6; +} else version (XXX) { //#elif TARGET_LINUX || TARGET_FREEBSD || TARGET_SOLARIS + REALSIZE = 12; + REALPAD = 2; +} else { + REALSIZE = 10; + REALPAD = 0; +} + Tsize_t = TY.Tuns32; + Tptrdiff_t = TY.Tint32; + } + } + + ulong size() + { + return size(Loc(0)); + } + + ulong size(Loc loc) + { + error(loc, "no size for type %s", toChars()); + return 1; + } + + uint alignsize() + { + return cast(uint)size(Loc(0)); /// + } + + Type semantic(Loc loc, Scope sc) + { + return merge(); + } + + Type trySemantic(Loc loc, Scope sc) + { + uint errors = global.errors; + global.gag++; // suppress printing of error messages + Type t = semantic(loc, sc); + global.gag--; + if (errors != global.errors) // if any errors happened + { + global.errors = errors; + t = null; + } + return t; + } + + /******************************** + * Name mangling. + * Input: + * flag 0x100 do not do const/invariant + */ + void toDecoBuffer(OutBuffer buf, int flag = 0) + { + if (flag != mod && flag != 0x100) + { + if (mod & MOD.MODshared) + buf.writeByte('O'); + + if (mod & MOD.MODconst) + buf.writeByte('x'); + else if (mod & MOD.MODinvariant) + buf.writeByte('y'); + + // Cannot be both const and invariant + assert((mod & (MOD.MODconst | MOD.MODinvariant)) != (MOD.MODconst | MOD.MODinvariant)); + } + buf.writeByte(mangleChar[ty]); + } + + Type merge() + { + Type t = this; + assert(t); + + //printf("merge(%s)\n", toChars()); + if (deco is null) + { + OutBuffer buf = new OutBuffer(); + + //if (next) + //next = next.merge(); + toDecoBuffer(buf); + StringValue* sv = stringtable.update(buf.extractString()); + if (sv.ptrvalue) + { + t = cast(Type) sv.ptrvalue; +debug { + if (!t.deco) + writef("t = %s\n", t.toChars()); +} + assert(t.deco); + //printf("old value, deco = '%s' %p\n", t.deco, t.deco); + } + else + { + sv.ptrvalue = cast(void*)this; + deco = sv.lstring.string_; + //printf("new value, deco = '%s' %p\n", t.deco, t.deco); + } + } + return t; + } + + /************************************* + * This version does a merge even if the deco is already computed. + * Necessary for types that have a deco, but are not merged. + */ + Type merge2() + { + //printf("merge2(%s)\n", toChars()); + Type t = this; + assert(t); + if (!t.deco) + return t.merge(); + + StringValue* sv = stringtable.lookup(t.deco); + if (sv && sv.ptrvalue) + { + t = cast(Type)sv.ptrvalue; + assert(t.deco); + } + else + assert(0); + + return t; + } + + void toCBuffer(OutBuffer buf, Identifier ident, HdrGenState* hgs) + { + toCBuffer2(buf, hgs, MOD.MODundefined); + if (ident) + { + buf.writeByte(' '); + buf.writestring(ident.toChars()); + } + } + + void toCBuffer2(OutBuffer buf, HdrGenState* hgs, MOD mod) + { + if (mod != this.mod) + { + toCBuffer3(buf, hgs, mod); + return; + } + buf.writestring(toChars()); + } + + void toCBuffer3(OutBuffer buf, HdrGenState* hgs, MOD mod) + { + if (mod != this.mod) + { + string p; + + if (this.mod & MOD.MODshared) + buf.writestring("shared("); + + switch (this.mod & (MOD.MODconst | MOD.MODinvariant)) + { + case MOD.MODundefined: + toCBuffer2(buf, hgs, this.mod); + break; + case MOD.MODconst: + p = "const("; + goto L1; + case MOD.MODinvariant: + p = "immutable("; + L1: buf.writestring(p); + toCBuffer2(buf, hgs, this.mod); + buf.writeByte(')'); + break; + } + + if (this.mod & MOD.MODshared) + buf.writeByte(')'); + } + } + + void modToBuffer(OutBuffer buf) + { + if (mod & MOD.MODshared) + buf.writestring(" shared"); + if (mod & MOD.MODconst) + buf.writestring(" const"); + if (mod & MOD.MODinvariant) + buf.writestring(" immutable"); + } + +version (CPP_MANGLE) { + void toCppMangle(OutBuffer buf, CppMangleState* cms) + { + assert(false); + } +} + bool isintegral() + { + return false; + } + + bool isfloating() // real, imaginary, or complex + { + return false; + } + + bool isreal() + { + return false; + } + + bool isimaginary() + { + return false; + } + + bool iscomplex() + { + return false; + } + + bool isscalar() + { + return false; + } + + bool isunsigned() + { + return false; + } + + bool isauto() + { + return false; + } + + int isString() + { + return false; + } + + /************************** + * Given: + * T a, b; + * Can we assign: + * a = b; + * ? + */ + int isAssignable() + { + return true; + } + + bool checkBoolean() // if can be converted to boolean value + { + return isscalar(); + } + + /********************************* + * Check type to see if it is based on a deprecated symbol. + */ + void checkDeprecated(Loc loc, Scope sc) + { + Dsymbol s = toDsymbol(sc); + if (s) + s.checkDeprecated(loc, sc); + } + + bool isConst() { return (mod & MOD.MODconst) != 0; } + + int isInvariant() { return mod & MOD.MODinvariant; } + + int isMutable() { return !(mod & (MOD.MODconst | MOD.MODinvariant)); } + + int isShared() { return mod & MOD.MODshared; } + + int isSharedConst() { return mod == (MOD.MODshared | MOD.MODconst); } + + /******************************** + * Convert to 'const'. + */ + Type constOf() + { +static if (false) { + //printf("Type.constOf() %p %s\n", this, toChars()); + if (isConst()) + return this; + if (cto) + return cto; + Type t = makeConst(); + t = t.merge(); + cto = t; + if (ito) + ito.cto = t; + //if (t.nextOf()) assert(t.nextOf().isConst()); + //printf("-Type.constOf() %p %s\n", t, toChars()); + return t; +} else { + //printf("Type.constOf() %p %s\n", this, toChars()); + if (mod == MOD.MODconst) + return this; + if (cto) + { + assert(cto.mod == MOD.MODconst); + return cto; + } + Type t = makeConst(); + t = t.merge(); + t.fixTo(this); + //printf("-Type.constOf() %p %s\n", t, toChars()); + return t; +} + } + + /******************************** + * Convert to 'immutable'. + */ + Type invariantOf() + { +static if (false) { + //printf("Type.invariantOf() %p %s\n", this, toChars()); + if (isInvariant()) + { + return this; + } + if (ito) + { + //if (!ito.isInvariant()) printf("\tito is %p %s\n", ito, ito.toChars()); + assert(ito.isInvariant()); + return ito; + } + Type t = makeInvariant(); + t = t.merge(); + ito = t; + if (cto) + cto.ito = t; +static if (false) {// fails for function types + if (t.nextOf() && !t.nextOf().isInvariant()) + { + assert(0); + } +} + //printf("\t%p\n", t); + return t; +} else { + //printf("Type.invariantOf() %p %s\n", this, toChars()); + if (isInvariant()) + { + return this; + } + if (ito) + { + assert(ito.isInvariant()); + return ito; + } + Type t = makeInvariant(); + t = t.merge(); + t.fixTo(this); + //printf("\t%p\n", t); + return t; +} + } + + Type mutableOf() + { + static if (false) { + //printf("Type.mutableOf() %p, %s\n", this, toChars()); + Type t = this; + if (isConst()) + { + t = cto; + assert(!t || t.isMutable()); + } + else if (isInvariant()) + { + t = ito; + assert(!t || t.isMutable()); + } + if (!t) + { + uint sz = this.classinfo.init.length; + t = cast(Type)malloc(sz); + memcpy(cast(void*)t, cast(void*)this, sz); + t.mod = 0; + t.deco = null; + t.arrayof = null; + t.pto = null; + t.rto = null; + t.cto = null; + t.ito = null; + t.sto = null; + t.scto = null; + t.vtinfo = null; + if (ty == Tsarray) + { + TypeSArray ta = cast(TypeSArray)t; + //ta.next = ta.next.mutableOf(); + } + t = t.merge(); + if (isConst()) + { cto = t; + t.cto = this; + if (ito) + ito.cto = this; + } + else if (isInvariant()) + { ito = t; + t.ito = this; + if (cto) + cto.ito = this; + } + } + return t; + } else { + //printf("Type.mutableOf() %p, %s\n", this, toChars()); + Type t = this; + if (isConst()) + { + if (isShared()) + t = sto; // shared const => shared + else + t = cto; + assert(!t || t.isMutable()); + } + else if (isInvariant()) + { + t = ito; + assert(!t || (t.isMutable() && !t.isShared())); + } + if (!t) + { + uint sz = this.classinfo.init.length; + t = cast(Type)malloc(sz); + memcpy(cast(void*)t, cast(void*)this, sz); + t.mod = MODundefined; + t.deco = null; + t.arrayof = null; + t.pto = null; + t.rto = null; + t.cto = null; + t.ito = null; + t.sto = null; + t.scto = null; + t.vtinfo = null; + t = t.merge(); + + t.fixTo(this); + + switch (mod) + { + case MODconst: + t.cto = this; + break; + + case MODinvariant: + t.ito = this; + break; + + case MODshared: + t.sto = this; + break; + + case MODshared | MODconst: + t.scto = this; + break; + + default: + assert(0); + } + } + return t; + } + } + + Type sharedOf() + { + //printf("Type.sharedOf() %p, %s\n", this, toChars()); + if (mod == MOD.MODshared) + { + return this; + } + if (sto) + { + assert(sto.isShared()); + return sto; + } + + Type t = makeShared(); + t = t.merge(); + t.fixTo(this); + + //printf("\t%p\n", t); + return t; + } + + Type sharedConstOf() + { + //printf("Type.sharedConstOf() %p, %s\n", this, toChars()); + if (mod == (MODshared | MODconst)) + { + return this; + } + if (scto) + { + assert(scto.mod == (MODshared | MODconst)); + return scto; + } + + Type t = makeSharedConst(); + t = t.merge(); + t.fixTo(this); + //printf("\t%p\n", t); + + return t; + } + + static uint X(MOD m, MOD n) + { + return (((m) << 3) | (n)); + } + + /********************************** + * For our new type 'this', which is type-constructed from t, + * fill in the cto, ito, sto, scto shortcuts. + */ + void fixTo(Type t) + { + ito = t.ito; +static if (false) { + /* Cannot do these because these are not fully transitive: + * there can be a shared ptr to immutable, for example. + * Immutable subtypes are always immutable, though. + */ + cto = t.cto; + sto = t.sto; + scto = t.scto; +} + + assert(mod != t.mod); + + switch (X(mod, t.mod)) + { + case X(MOD.MODundefined, MOD.MODconst): + cto = t; + break; + + case X(MOD.MODundefined, MOD.MODinvariant): + ito = t; + break; + + case X(MOD.MODundefined, MOD.MODshared): + sto = t; + break; + + case X(MOD.MODundefined, MOD.MODshared | MOD.MODconst): + scto = t; + break; + + + case X(MOD.MODconst, MOD.MODundefined): + cto = null; + goto L2; + + case X(MOD.MODconst, MOD.MODinvariant): + ito = t; + goto L2; + + case X(MOD.MODconst, MOD.MODshared): + sto = t; + goto L2; + + case X(MOD.MODconst, MOD.MODshared | MOD.MODconst): + scto = t; + L2: + t.cto = this; + break; + + + case X(MOD.MODinvariant, MOD.MODundefined): + ito = null; + goto L3; + + case X(MOD.MODinvariant, MOD.MODconst): + cto = t; + goto L3; + + case X(MOD.MODinvariant, MOD.MODshared): + sto = t; + goto L3; + + case X(MOD.MODinvariant, MOD.MODshared | MOD.MODconst): + scto = t; + L3: + t.ito = this; + if (t.cto) t.cto.ito = this; + if (t.sto) t.sto.ito = this; + if (t.scto) t.scto.ito = this; + break; + + + case X(MOD.MODshared, MOD.MODundefined): + sto = null; + goto L4; + + case X(MOD.MODshared, MOD.MODconst): + cto = t; + goto L4; + + case X(MOD.MODshared, MOD.MODinvariant): + ito = t; + goto L4; + + case X(MOD.MODshared, MOD.MODshared | MOD.MODconst): + scto = t; + L4: + t.sto = this; + break; + + + case X(MOD.MODshared | MOD.MODconst, MOD.MODundefined): + scto = null; + break; + + case X(MOD.MODshared | MOD.MODconst, MOD.MODconst): + cto = t; + break; + + case X(MOD.MODshared | MOD.MODconst, MOD.MODinvariant): + ito = t; + break; + + case X(MOD.MODshared | MOD.MODconst, MOD.MODshared): + sto = t; + L5: + t.scto = this; + break; + } + + check(); + t.check(); + //printf("fixTo: %s, %s\n", toChars(), t.toChars()); + } + + /*************************** + * Look for bugs in constructing types. + */ + void check() + { + switch (mod) + { + case MOD.MODundefined: + if (cto) assert(cto.mod == MOD.MODconst); + if (ito) assert(ito.mod == MOD.MODinvariant); + if (sto) assert(sto.mod == MOD.MODshared); + if (scto) assert(scto.mod == (MOD.MODshared | MOD.MODconst)); + break; + + case MOD.MODconst: + if (cto) assert(cto.mod == MOD.MODundefined); + if (ito) assert(ito.mod == MOD.MODinvariant); + if (sto) assert(sto.mod == MOD.MODshared); + if (scto) assert(scto.mod == (MOD.MODshared | MOD.MODconst)); + break; + + case MOD.MODinvariant: + if (cto) assert(cto.mod == MOD.MODconst); + if (ito) assert(ito.mod == MOD.MODundefined); + if (sto) assert(sto.mod == MOD.MODshared); + if (scto) assert(scto.mod == (MOD.MODshared | MOD.MODconst)); + break; + + case MOD.MODshared: + if (cto) assert(cto.mod == MOD.MODconst); + if (ito) assert(ito.mod == MOD.MODinvariant); + if (sto) assert(sto.mod == MOD.MODundefined); + if (scto) assert(scto.mod == (MOD.MODshared | MOD.MODconst)); + break; + + case MOD.MODshared | MOD.MODconst: + if (cto) assert(cto.mod == MOD.MODconst); + if (ito) assert(ito.mod == MOD.MODinvariant); + if (sto) assert(sto.mod == MOD.MODshared); + if (scto) assert(scto.mod == MOD.MODundefined); + break; + } + + Type tn = nextOf(); + if (tn && ty != TY.Tfunction && ty != TY.Tdelegate) + { + // Verify transitivity + switch (mod) + { + case MOD.MODundefined: + break; + + case MOD.MODconst: + assert(tn.mod & MOD.MODinvariant || tn.mod & MOD.MODconst); + break; + + case MOD.MODinvariant: + assert(tn.mod == MOD.MODinvariant); + break; + + case MOD.MODshared: + assert(tn.mod & MOD.MODinvariant || tn.mod & MOD.MODshared); + break; + + case MOD.MODshared | MOD.MODconst: + assert(tn.mod & MOD.MODinvariant || tn.mod & (MOD.MODshared | MOD.MODconst)); + break; + } + tn.check(); + } + } + + Type castMod(uint mod) + { + assert(false); + } + + /************************************ + * Add MODxxxx bits to existing type. + * We're adding, not replacing, so adding const to + * a shared type => "shared const" + */ + Type addMod(MOD mod) + { + Type t = this; + + /* Add anything to immutable, and it remains immutable + */ + if (!t.isInvariant()) + { + switch (mod) + { + case MOD.MODundefined: + break; + + case MOD.MODconst: + if (isShared()) + t = sharedConstOf(); + else + t = constOf(); + break; + + case MOD.MODinvariant: + t = invariantOf(); + break; + + case MOD.MODshared: + if (isConst()) + t = sharedConstOf(); + else + t = sharedOf(); + break; + + case MOD.MODshared | MOD.MODconst: + t = sharedConstOf(); + break; + } + } + return t; + } + + Type addStorageClass(STC stc) + { + /* Just translate to MOD bits and let addMod() do the work + */ + MOD mod = MOD.MODundefined; + + if (stc & STC.STCimmutable) + mod = MOD.MODinvariant; + else + { + if (stc & (STC.STCconst | STC.STCin)) + mod = MOD.MODconst; + if (stc & STC.STCshared) + mod |= MOD.MODshared; + } + + return addMod(mod); + } + + Type pointerTo() + { + if (pto is null) + { + Type t = new TypePointer(this); + pto = t.merge(); + } + + return pto; + } + + Type referenceTo() + { + assert(false); + } + +version (DumbClone) { + final Type clone() + { + auto size = this.classinfo.init.length; + auto ptr = malloc(size); + memcpy(ptr, cast(void*)this, size); + + return cast(Type)ptr; + } +} else { + final Type cloneTo(Type t) + { + t.ctype = ctype; + return t; + } + + Type clone() + { + assert(this.classinfo is Type.classinfo); + return cloneTo(new Type(ty)); + } +} + + Type arrayOf() + { + if (!arrayof) + { + Type t = new TypeDArray(this); + arrayof = t.merge(); + } + return arrayof; + } + + Type makeConst() + { + //printf("Type.makeConst() %p, %s\n", this, toChars()); + if (cto) + return cto; + + Type t = clone(); + t.mod = MOD.MODconst; + + t.deco = null; + t.arrayof = null; + t.pto = null; + t.rto = null; + t.cto = null; + t.ito = null; + t.sto = null; + t.scto = null; + t.vtinfo = null; + + //printf("-Type.makeConst() %p, %s\n", t, toChars()); + return t; + } + + Type makeInvariant() + { + if (ito) { + return ito; + } + + Type t = clone(); + t.mod = MOD.MODinvariant; + + t.deco = null; + t.arrayof = null; + t.pto = null; + t.rto = null; + t.cto = null; + t.ito = null; + t.sto = null; + t.scto = null; + t.vtinfo = null; + + return t; + } + + Type makeShared() + { + if (sto) + return sto; + + Type t = clone(); + t.mod = MOD.MODshared; + + t.deco = null; + t.arrayof = null; + t.pto = null; + t.rto = null; + t.cto = null; + t.ito = null; + t.sto = null; + t.scto = null; + t.vtinfo = null; + + return t; + } + + Type makeSharedConst() + { + if (scto) + return scto; + + Type t = clone(); + t.mod = MODshared | MODconst; + + t.deco = null; + t.arrayof = null; + t.pto = null; + t.rto = null; + t.cto = null; + t.ito = null; + t.sto = null; + t.scto = null; + t.vtinfo = null; + + return t; + } + + Dsymbol toDsymbol(Scope sc) + { + return null; + } + + /******************************* + * If this is a shell around another type, + * get that other type. + */ + + Type toBasetype() + { + return this; + } + + /************************** + * Return type with the top level of it being mutable. + */ + Type toHeadMutable() + { + if (!mod) + return this; + + return mutableOf(); + } + + bool isBaseOf(Type t, int* poffset) + { + return false; // assume not + } + + /******************************* + * Determine if converting 'this' to 'to' is an identity operation, + * a conversion to const operation, or the types aren't the same. + * Returns: + * MATCHequal 'this' == 'to' + * MATCHconst 'to' is const + * MATCHnomatch conversion to mutable or invariant + */ + MATCH constConv(Type to) + { + if (equals(to)) + return MATCH.MATCHexact; + if (ty == to.ty && to.mod == MOD.MODconst) + return MATCH.MATCHconst; + return MATCH.MATCHnomatch; + } + + /******************************** + * Determine if 'this' can be implicitly converted + * to type 'to'. + * Returns: + * MATCHnomatch, MATCHconvert, MATCHconst, MATCHexact + */ + MATCH implicitConvTo(Type to) + { + //printf("Type.implicitConvTo(this=%p, to=%p)\n", this, to); + //printf("from: %s\n", toChars()); + //printf("to : %s\n", to.toChars()); + if (this is to) + return MATCHexact; + + return MATCHnomatch; + } + + ClassDeclaration isClassHandle() + { + return null; + } + + Expression getProperty(Loc loc, Identifier ident) + { + Expression e; + +version (LOGDOTEXP) { + printf("Type.getProperty(type = '%s', ident = '%s')\n", toChars(), ident.toChars()); +} + if (ident == Id.__sizeof) + { + e = new IntegerExp(loc, size(loc), Type.tsize_t); + } + else if (ident == Id.size) + { + error(loc, ".size property should be replaced with .sizeof"); + e = new ErrorExp(); + } + else if (ident is Id.alignof_) + { + e = new IntegerExp(loc, alignsize(), Type.tsize_t); + } + else if (ident == Id.typeinfo_) + { + if (!global.params.useDeprecated) + error(loc, ".typeinfo deprecated, use typeid(type)"); + e = getTypeInfo(null); + } + else if (ident == Id.init_) + { + if (ty == TY.Tvoid) + error(loc, "void does not have an initializer"); + e = defaultInit(loc); + } + else if (ident is Id.mangleof_) + { + string s; + if (!deco) { + s = toChars(); + error(loc, "forward reference of type %s.mangleof", s); + } else { + s = deco; + } + + e = new StringExp(loc, s, 'c'); + Scope sc = new Scope(); + e = e.semantic(sc); + } + else if (ident is Id.stringof_) + { + string s = toChars(); + e = new StringExp(loc, s, 'c'); + Scope sc = new Scope(); + e = e.semantic(sc); + } + else + { + error(loc, "no property '%s' for type '%s'", ident.toChars(), toChars()); + e = new ErrorExp(); + } + return e; + } + + Expression dotExp(Scope sc, Expression e, Identifier ident) + { + VarDeclaration v = null; + +version (LOGDOTEXP) { + printf("Type.dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars()); +} + if (e.op == TOK.TOKdotvar) + { + DotVarExp dv = cast(DotVarExp)e; + v = dv.var.isVarDeclaration(); + } + else if (e.op == TOK.TOKvar) + { + VarExp ve = cast(VarExp)e; + v = ve.var.isVarDeclaration(); + } + if (v) + { + if (ident is Id.offset) + { + if (!global.params.useDeprecated) + error(e.loc, ".offset deprecated, use .offsetof"); + goto Loffset; + } + else if (ident is Id.offsetof) + { + Loffset: + if (v.storage_class & STC.STCfield) + { + e = new IntegerExp(e.loc, v.offset, Type.tsize_t); + return e; + } + } + else if (ident is Id.init_) + { +static if (false) { + if (v.init) + { + if (v.init.isVoidInitializer()) + error(e.loc, "%s.init is void", v.toChars()); + else + { Loc loc = e.loc; + e = v.init.toExpression(); + if (e.op == TOK.TOKassign || e.op == TOK.TOKconstruct || e.op == TOK.TOKblit) + { + e = (cast(AssignExp)e).e2; + + /* Take care of case where we used a 0 + * to initialize the struct. + */ + if (e.type == Type.tint32 && + e.isBool(0) && + v.type.toBasetype().ty == TY.Tstruct) + { + e = v.type.defaultInit(e.loc); + } + } + e = e.optimize(WANTvalue | WANTinterpret); + // if (!e.isConst()) + // error(loc, ".init cannot be evaluated at compile time"); + } + return e; + } +} + Expression ex = defaultInit(e.loc); + return ex; + } + } + if (ident is Id.typeinfo_) + { + if (!global.params.useDeprecated) + error(e.loc, ".typeinfo deprecated, use typeid(type)"); + e = getTypeInfo(sc); + return e; + } + if (ident is Id.stringof_) + { + string s = e.toChars(); + e = new StringExp(e.loc, s, 'c'); + Scope sc2 = new Scope(); /// + e = e.semantic(sc2); + return e; + } + return getProperty(e.loc, ident); + } + + uint memalign(uint salign) + { + return salign; + } + + ///Expression defaultInit(Loc loc = Loc(0)) + Expression defaultInit(Loc loc) + { + assert(false); + } + + ///bool isZeroInit(Loc loc = Loc(0)) // if initializer is 0 + bool isZeroInit(Loc loc) // if initializer is 0 + { + assert(false); + } + + dt_t** toDt(dt_t** pdt) + { + //printf("Type.toDt()\n"); + Expression e = defaultInit(Loc(0)); + return e.toDt(pdt); + } + + Identifier getTypeInfoIdent(int internal) + { + // _init_10TypeInfo_%s + scope OutBuffer buf = new OutBuffer(); + Identifier id; + char* name; + int len; + + if (internal) + { + buf.writeByte(mangleChar[ty]); + if (ty == TY.Tarray) + buf.writeByte(mangleChar[(cast(TypeArray)this).next.ty]); + } + else + toDecoBuffer(buf); + + len = buf.offset; + name = cast(char*)alloca(19 + len.sizeof * 3 + len + 1); + buf.writeByte(0); + version (TARGET_OSX) { + // The LINKc will prepend the _ + len = sprintf(name, "D%dTypeInfo_%s6__initZ".ptr, 9 + len, buf.data); + } else { + len = sprintf(name, "_D%dTypeInfo_%s6__initZ".ptr, 9 + len, buf.data); + } + if (global.params.isWindows) + name++; // C mangling will add it back in + //printf("name = %s\n", name); + id = Lexer.idPool(name[0..len-1].idup); + return id; + } + + /* These form the heart of template argument deduction. + * Given 'this' being the type argument to the template instance, + * it is matched against the template declaration parameter specialization + * 'tparam' to determine the type to be used for the parameter. + * Example: + * template Foo(T:T*) // template declaration + * Foo!(int*) // template instantiation + * Input: + * this = int* + * tparam = T + * parameters = [ T:T* ] // Array of TemplateParameter's + * Output: + * dedtypes = [ int ] // Array of Expression/Type's + */ + MATCH deduceType(Scope sc, Type tparam, TemplateParameters parameters, Objects dedtypes) + { + static if (false) { + printf("Type.deduceType()\n"); + printf("\tthis = %d, ", ty); print(); + printf("\ttparam = %d, ", tparam.ty); tparam.print(); + } + if (!tparam) + goto Lnomatch; + + if (this == tparam) + goto Lexact; + + if (tparam.ty == Tident) + { + // Determine which parameter tparam is + int i = templateParameterLookup(tparam, parameters); + if (i == -1) + { + if (!sc) + goto Lnomatch; + + /* Need a loc to go with the semantic routine. + */ + Loc loc; + if (parameters.dim) + { + TemplateParameter tp = cast(TemplateParameter)parameters.data[0]; + loc = tp.loc; + } + + /* BUG: what if tparam is a template instance, that + * has as an argument another Tident? + */ + tparam = tparam.semantic(loc, sc); + assert(tparam.ty != Tident); + return deduceType(sc, tparam, parameters, dedtypes); + } + + TemplateParameter tp = cast(TemplateParameter)parameters.data[i]; + + // Found the corresponding parameter tp + if (!tp.isTemplateTypeParameter()) + goto Lnomatch; + Type tt = this; + Type at = cast(Type)dedtypes.data[i]; + + // 3*3 == 9 cases + if (tparam.isMutable()) + { // foo(U:U) T => T + // foo(U:U) const(T) => const(T) + // foo(U:U) invariant(T) => invariant(T) + if (!at) + { + dedtypes.data[i] = cast(void*)this; + goto Lexact; + } + } + else if (mod == tparam.mod) + { // foo(U:const(U)) const(T) => T + // foo(U:invariant(U)) invariant(T) => T + tt = mutableOf(); + if (!at) + { + dedtypes.data[i] = cast(void*)tt; + goto Lexact; + } + } + else if (tparam.isConst()) + { // foo(U:const(U)) T => T + // foo(U:const(U)) invariant(T) => T + tt = mutableOf(); + if (!at) + { + dedtypes.data[i] = cast(void*)tt; + goto Lconst; + } + } + else + { // foo(U:invariant(U)) T => nomatch + // foo(U:invariant(U)) const(T) => nomatch + if (!at) + goto Lnomatch; + } + + if (tt.equals(at)) + goto Lexact; + else if (tt.ty == Tclass && at.ty == Tclass) + { + return tt.implicitConvTo(at); + } + else if (tt.ty == Tsarray && at.ty == Tarray && + tt.nextOf().implicitConvTo(at.nextOf()) >= MATCHconst) + { + goto Lexact; + } + else + goto Lnomatch; + } + + if (ty != tparam.ty) + return implicitConvTo(tparam); + // goto Lnomatch; + + if (nextOf()) + return nextOf().deduceType(sc, tparam.nextOf(), parameters, dedtypes); + + Lexact: + return MATCHexact; + + Lnomatch: + return MATCHnomatch; + + version (DMDV2) { + Lconst: + return MATCHconst; + } + } + + void resolve(Loc loc, Scope sc, Expression* pe, Type* pt, Dsymbol* ps) + { + //printf("Type.resolve() %s, %d\n", toChars(), ty); + Type t = semantic(loc, sc); + *pt = t; + *pe = null; + *ps = null; + } + + /******************************************* + * Get a canonicalized form of the TypeInfo for use with the internal + * runtime library routines. Canonicalized in that static arrays are + * represented as dynamic arrays, enums are represented by their + * underlying type, etc. This reduces the number of TypeInfo's needed, + * so we can use the custom internal ones more. + */ + Expression getInternalTypeInfo(Scope sc) + { + TypeInfoDeclaration tid; + Expression e; + Type t; + static TypeInfoDeclaration internalTI[TMAX]; + + //printf("Type.getInternalTypeInfo() %s\n", toChars()); + t = toBasetype(); + switch (t.ty) + { + case Tsarray: + static if (false) { + // convert to corresponding dynamic array type + t = t.nextOf().mutableOf().arrayOf(); + } + break; + + case Tclass: + if ((cast(TypeClass)t).sym.isInterfaceDeclaration()) + break; + goto Linternal; + + case Tarray: + // convert to corresponding dynamic array type + t = t.nextOf().mutableOf().arrayOf(); + if (t.nextOf().ty != Tclass) + break; + goto Linternal; + + case Tfunction: + case Tdelegate: + case Tpointer: + Linternal: + tid = internalTI[t.ty]; + if (!tid) + { + tid = new TypeInfoDeclaration(t, 1); + internalTI[t.ty] = tid; + } + e = new VarExp(Loc(0), tid); + e = e.addressOf(sc); + e.type = tid.type; // do this so we don't get redundant dereference + return e; + + default: + break; + } + //printf("\tcalling getTypeInfo() %s\n", t.toChars()); + return t.getTypeInfo(sc); + } + + /**************************************************** + * Get the exact TypeInfo. + */ + Expression getTypeInfo(Scope sc) + { + Expression e; + Type t; + + //printf("Type.getTypeInfo() %p, %s\n", this, toChars()); + t = merge2(); // do this since not all Type's are merge'd + if (!t.vtinfo) + { +version (DMDV2) { + if (t.isShared()) // does both 'shared' and 'shared const' + t.vtinfo = new TypeInfoSharedDeclaration(t); + else if (t.isConst()) + t.vtinfo = new TypeInfoConstDeclaration(t); + else if (t.isInvariant()) + t.vtinfo = new TypeInfoInvariantDeclaration(t); + else + t.vtinfo = t.getTypeInfoDeclaration(); +} else { + t.vtinfo = t.getTypeInfoDeclaration(); +} + assert(t.vtinfo); + vtinfo = t.vtinfo; + + /* If this has a custom implementation in std/typeinfo, then + * do not generate a COMDAT for it. + */ + if (!t.builtinTypeInfo()) + { + // Generate COMDAT + if (sc) // if in semantic() pass + { + // Find module that will go all the way to an object file + Module m = sc.module_.importedFrom; + m.members.push(cast(void*)t.vtinfo); + } + else // if in obj generation pass + { + t.vtinfo.toObjFile(global.params.multiobj); + } + } + } + e = new VarExp(Loc(0), t.vtinfo); + e = e.addressOf(sc); + e.type = t.vtinfo.type; // do this so we don't get redundant dereference + return e; + } + + TypeInfoDeclaration getTypeInfoDeclaration() + { + //printf("Type.getTypeInfoDeclaration() %s\n", toChars()); + return new TypeInfoDeclaration(this, 0); + } + + /* These decide if there's an instance for them already in std.typeinfo, + * because then the compiler doesn't need to build one. + */ + bool builtinTypeInfo() + { + return false; + } + + /******************************* + * If one of the subtypes of this type is a TypeIdentifier, + * i.e. it's an unresolved type, return that type. + */ + Type reliesOnTident() + { + return null; + } + + Expression toExpression() + { + assert(false); + } + + /*************************************** + * Return true if type has pointers that need to + * be scanned by the GC during a collection cycle. + */ + bool hasPointers() + { + return false; + } + + /************************************* + * If this is a type of something, return that something. + */ + Type nextOf() + { + return null; + } + + ulong sizemask() + { + assert(false); + } + + static void error(T...)(Loc loc, string format, T t) + { + .error(loc, format, t); + } + + static void warning(T...)(Loc loc, string format, T t) + { + assert(false); + } + + // For backend + /***************************** + * Return back end type corresponding to D front end type. + */ + TYM totym() + { + TYM t; + + switch (ty) + { + case TY.Tvoid: t = TYM.TYvoid; break; + case TY.Tint8: t = TYM.TYschar; break; + case TY.Tuns8: t = TYM.TYuchar; break; + case TY.Tint16: t = TYM.TYshort; break; + case TY.Tuns16: t = TYM.TYushort; break; + case TY.Tint32: t = TYM.TYint; break; + case TY.Tuns32: t = TYM.TYuint; break; + case TY.Tint64: t = TYM.TYllong; break; + case TY.Tuns64: t = TYM.TYullong; break; + case TY.Tfloat32: t = TYM.TYfloat; break; + case TY.Tfloat64: t = TYM.TYdouble; break; + case TY.Tfloat80: t = TYM.TYldouble; break; + case TY.Timaginary32: t = TYM.TYifloat; break; + case TY.Timaginary64: t = TYM.TYidouble; break; + case TY.Timaginary80: t = TYM.TYildouble; break; + case TY.Tcomplex32: t = TYM.TYcfloat; break; + case TY.Tcomplex64: t = TYM.TYcdouble; break; + case TY.Tcomplex80: t = TYM.TYcldouble; break; + //case Tbit: t = TYM.TYuchar; break; + case TY.Tbool: t = TYM.TYbool; break; + case TY.Tchar: t = TYM.TYchar; break; + version (XXX) { ///TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS + case TY.Twchar: t = TYM.TYwchar_t; break; + case TY.Tdchar: t = TYM.TYdchar; break; + } else { + case TY.Twchar: t = TYM.TYwchar_t; break; + case TY.Tdchar: + t = (global.params.symdebug == 1) ? TYM.TYdchar : TYM.TYulong; + break; + } + + case TY.Taarray: t = TYM.TYaarray; break; + case TY.Tclass: + case TY.Treference: + case TY.Tpointer: t = TYM.TYnptr; break; + case TY.Tdelegate: t = TYM.TYdelegate; break; + case TY.Tarray: t = TYM.TYdarray; break; + case TY.Tsarray: t = TYM.TYarray; break; + case TY.Tstruct: t = TYM.TYstruct; break; + + case TY.Tenum: + case TY.Ttypedef: + t = toBasetype().totym(); + break; + + case TY.Tident: + case TY.Ttypeof: + debug { + writef("ty = %d, '%s'\n", ty, toChars()); + } + error (Loc(0), "forward reference of %s", toChars()); + t = TYM.TYint; + break; + + default: + debug { + writef("ty = %d, '%s'\n", ty, toChars()); + } + assert(0); + } + + version (DMDV2) { + // Add modifiers + switch (mod) + { + case MOD.MODundefined: + break; + case MOD.MODconst: + t |= mTY.mTYconst; + break; + case MOD.MODinvariant: + t |= mTY.mTYimmutable; + break; + case MOD.MODshared: + t |= mTY.mTYshared; + break; + case MOD.MODshared | MOD.MODconst: + t |= mTY.mTYshared | mTY.mTYconst; + break; + default: + assert(0); + } + } + + return t; + } + + /*************************************** + * Convert from D type to C type. + * This is done so C debug info can be generated. + */ + type* toCtype() + { + if (!ctype) + { + ctype = type_fake(totym()); + ctype.Tcount++; + } + return ctype; + } + + type* toCParamtype() + { + return toCtype(); + } + + Symbol* toSymbol() + { + assert(false); + } + + // For eliminating dynamic_cast + TypeBasic isTypeBasic() + { + return null; + } + + static Type tvoid() + { + return basic[TY.Tvoid]; + } + + static Type tint8() + { + return basic[TY.Tint8]; + } + + static Type tuns8() + { + return basic[TY.Tuns8]; + } + + static Type tint16() + { + return basic[TY.Tint16]; + } + + static Type tuns16() + { + return basic[TY.Tuns16]; + } + + static Type tint32() + { + return basic[TY.Tint32]; + } + + static Type tuns32() + { + return basic[TY.Tuns32]; + } + + static Type tint64() + { + return basic[TY.Tint64]; + } + + static Type tuns64() + { + return basic[TY.Tuns64]; + } + + static Type tfloat32() + { + return basic[TY.Tfloat32]; + } + + static Type tfloat64() + { + return basic[TY.Tfloat64]; + } + + static Type tfloat80() + { + return basic[TY.Tfloat80]; + } + + static Type timaginary32() + { + return basic[TY.Timaginary32]; + } + + static Type timaginary64() + { + return basic[TY.Timaginary64]; + } + + static Type timaginary80() + { + return basic[TY.Timaginary80]; + } + + static Type tcomplex32() + { + return basic[TY.Tcomplex32]; + } + + static Type tcomplex64() + { + return basic[TY.Tcomplex64]; + } + + static Type tcomplex80() + { + return basic[TY.Tcomplex80]; + } + + static Type tbit() + { + return basic[TY.Tbit]; + } + + static Type tbool() + { + return basic[TY.Tbool]; + } + + static Type tchar() + { + return basic[TY.Tchar]; + } + + static Type twchar() + { + return basic[TY.Twchar]; + } + + static Type tdchar() + { + return basic[TY.Tdchar]; + } + + // Some special types + static Type tshiftcnt() + { + return tint32; // right side of shift expression + } + +// #define tboolean tint32 // result of boolean expression + static Type tboolean() + { + return tbool; // result of boolean expression + } + + static Type tindex() + { + return tint32; // array/ptr index + } + + static Type tvoidptr; // void* + + static Type terror() + { + return basic[TY.Terror]; // for error recovery + } + + static Type tsize_t() + { + return basic[Tsize_t]; // matches size_t alias + } + + static Type tptrdiff_t() + { + return basic[Tptrdiff_t]; // matches ptrdiff_t alias + } + + static Type thash_t() + { + return tsize_t; // matches hash_t alias + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TypeAArray.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeAArray.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,360 @@ +module dmd.TypeAArray; + +import dmd.TypeArray; +import dmd.MOD; +import dmd.ArrayTypes; +import dmd.TypeInfoDeclaration; +import dmd.Expression; +import dmd.Scope; +import dmd.Loc; +import dmd.Dsymbol; +import dmd.Type; +import dmd.TypeSArray; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Identifier; +import dmd.MATCH; +import dmd.TY; +import dmd.Id; +import dmd.CallExp; +import dmd.IntegerExp; +import dmd.FuncDeclaration; +import dmd.VarExp; +import dmd.TypeFunction; +import dmd.NullExp; +import dmd.Array; + +import dmd.backend.Symbol; +import dmd.backend.TYPE; +import dmd.backend.Util; +import dmd.backend.SC; +import dmd.backend.LIST; +import dmd.backend.TYM; +import dmd.backend.TF; +import dmd.backend.mTYman; + +import core.stdc.stdio; +import core.stdc.stdlib; + +class TypeAArray : TypeArray +{ + Type index; // key type + + this(Type t, Type index) + { + super(Taarray, t); + this.index = index; + } + + Type syntaxCopy() + { + assert(false); + } + +version (DumbClone) { +} else { + Type clone() + { + assert(false); + } +} + ulong size(Loc loc) + { + return PTRSIZE /* * 2*/; + } + + Type semantic(Loc loc, Scope sc) + { + //printf("TypeAArray::semantic() %s index.ty = %d\n", toChars(), index.ty); + + // Deal with the case where we thought the index was a type, but + // in reality it was an expression. + if (index.ty == Tident || index.ty == Tinstance || index.ty == Tsarray) + { + Expression e; + Type t; + Dsymbol s; + + index.resolve(loc, sc, &e, &t, &s); + if (e) + { // It was an expression - + // Rewrite as a static array + TypeSArray tsa = new TypeSArray(next, e); + return tsa.semantic(loc,sc); + } + else if (t) + index = t; + else + index.error(loc, "index is not a type or an expression"); + } + else + index = index.semantic(loc,sc); + + if (index.nextOf() && !index.nextOf().isInvariant()) + { + index = index.constOf().mutableOf(); +static if (false) { + printf("index is %p %s\n", index, index.toChars()); + index.check(); + printf("index.mod = x%x\n", index.mod); + printf("index.ito = x%x\n", index.ito); + if (index.ito) { + printf("index.ito.mod = x%x\n", index.ito.mod); + printf("index.ito.ito = x%x\n", index.ito.ito); + } +} + } + + switch (index.toBasetype().ty) + { + case Tbool: + case Tfunction: + case Tvoid: + case Tnone: + error(loc, "can't have associative array key of %s", index.toBasetype().toChars()); + break; + default: + break; /// + } + next = next.semantic(loc,sc); + transitive(); + + switch (next.toBasetype().ty) + { + case Tfunction: + case Tnone: + error(loc, "can't have associative array of %s", next.toChars()); + break; + default: + break; /// + } + if (next.isauto()) + error(loc, "cannot have array of auto %s", next.toChars()); + + return merge(); + } + + void resolve(Loc loc, Scope sc, Expression* pe, Type* pt, Dsymbol* ps) + { + assert(false); + } + + void toDecoBuffer(OutBuffer buf, int flag) + { + Type.toDecoBuffer(buf, flag); + index.toDecoBuffer(buf); + next.toDecoBuffer(buf, (flag & 0x100) ? MOD.MODundefined : mod); + } + + void toCBuffer2(OutBuffer buf, HdrGenState* hgs, MOD mod) + { + assert(false); + } + + Expression dotExp(Scope sc, Expression e, Identifier ident) + { + version (LOGDOTEXP) { + printf("TypeAArray.dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars()); + } + if (ident == Id.length) + { + Expression ec; + FuncDeclaration fd; + Expressions arguments; + + fd = FuncDeclaration.genCfunc(Type.tsize_t, Id.aaLen); + ec = new VarExp(Loc(0), fd); + arguments = new Expressions(); + arguments.push(cast(void*)e); + e = new CallExp(e.loc, ec, arguments); + e.type = (cast(TypeFunction)fd.type).next; + } + else if (ident == Id.keys) + { + Expression ec; + FuncDeclaration fd; + Expressions arguments; + int size = cast(int)index.size(e.loc); + + assert(size); + fd = FuncDeclaration.genCfunc(Type.tindex, Id.aaKeys); + ec = new VarExp(Loc(0), fd); + arguments = new Expressions(); + arguments.push(cast(void*)e); + arguments.push(cast(void*)new IntegerExp(Loc(0), size, Type.tsize_t)); + e = new CallExp(e.loc, ec, arguments); + e.type = index.arrayOf(); + } + else if (ident == Id.values) + { + Expression ec; + FuncDeclaration fd; + Expressions arguments; + + fd = FuncDeclaration.genCfunc(Type.tindex, Id.aaValues); + ec = new VarExp(Loc(0), fd); + arguments = new Expressions(); + arguments.push(cast(void*)e); + size_t keysize = cast(size_t)index.size(e.loc); + keysize = (keysize + PTRSIZE - 1) & ~(PTRSIZE - 1); + arguments.push(cast(void*)new IntegerExp(Loc(0), keysize, Type.tsize_t)); + arguments.push(cast(void*)new IntegerExp(Loc(0), next.size(e.loc), Type.tsize_t)); + e = new CallExp(e.loc, ec, arguments); + e.type = next.arrayOf(); + } + else if (ident == Id.rehash) + { + Expression ec; + FuncDeclaration fd; + Expressions arguments; + + fd = FuncDeclaration.genCfunc(Type.tint64, Id.aaRehash); + ec = new VarExp(Loc(0), fd); + arguments = new Expressions(); + arguments.push(cast(void*)e.addressOf(sc)); + arguments.push(cast(void*)index.getInternalTypeInfo(sc)); + e = new CallExp(e.loc, ec, arguments); + e.type = this; + } + else + { + e = Type.dotExp(sc, e, ident); + } + return e; + } + + Expression defaultInit(Loc loc) + { + version (LOGDEFAULTINIT) { + printf("TypeAArray.defaultInit() '%s'\n", toChars()); + } + Expression e = new NullExp(loc); + e.type = this; + return e; + } + + MATCH deduceType(Scope sc, Type tparam, TemplateParameters parameters, Objects dedtypes) + { + assert(false); + } + + bool isZeroInit(Loc loc) + { + assert(false); + } + + bool checkBoolean() + { + assert(false); + } + + TypeInfoDeclaration getTypeInfoDeclaration() + { + assert(false); + } + + bool hasPointers() + { + return true; + } + + MATCH implicitConvTo(Type to) + { + assert(false); + } + + MATCH constConv(Type to) + { + assert(false); + } + +version (CPP_MANGLE) { + void toCppMangle(OutBuffer buf, CppMangleState* cms) + { + assert(false); + } +} + + // Back end + /******************************************** + * Determine the right symbol to look up + * an associative array element. + * Input: + * flags 0 don't add value signature + * 1 add value signature + */ + Symbol* aaGetSymbol(const(char)* func, int flags) + in + { + assert(func); + assert((flags & ~1) == 0); + } + out (result) + { + assert(result); + } + body + { + int sz; + char* id; + type* t; + Symbol* s; + int i; + + // Dumb linear symbol table - should use associative array! + static Array sarray = null; + + //printf("aaGetSymbol(func = '%s', flags = %d, key = %p)\n", func, flags, key); + static if (false) { + scope OutBuffer buf = new OutBuffer(); + key.toKeyBuffer(buf); + + sz = next.size(); // it's just data, so we only care about the size + sz = (sz + 3) & ~3; // reduce proliferation of library routines + id = cast(char*)alloca(3 + strlen(func) + buf.offset + sizeof(sz) * 3 + 1); + buf.writeByte(0); + if (flags & 1) + sprintf(id, "_aa%s%s%d", func, buf.data, sz); + else + sprintf(id, "_aa%s%s", func, buf.data); + } else { + id = cast(char*)alloca(3 + strlen(func) + 1); + sprintf(id, "_aa%s", func); + } + if (!sarray) + sarray = new Array(); + + // See if symbol is already in sarray + for (i = 0; i < sarray.dim; i++) + { + s = cast(Symbol*)sarray.data[i]; + if (strcmp(id, s.Sident.ptr) == 0) + return s; // use existing Symbol + } + + // Create new Symbol + + s = symbol_calloc(id); + slist_add(s); + s.Sclass = SCextern; + s.Ssymnum = -1; + symbol_func(s); + + t = type_alloc(TYnfunc); + t.Tflags = TFprototype | TFfixed; + t.Tmangle = mTYman_c; + t.Tparamtypes = null; + t.Tnext = next.toCtype(); + t.Tnext.Tcount++; + t.Tcount++; + s.Stype = t; + + sarray.push(s); // remember it + return s; + } + + type* toCtype() + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TypeArray.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeArray.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,134 @@ +module dmd.TypeArray; + +import dmd.Type; +import dmd.TypeNext; +import dmd.Id; +import dmd.Loc; +import dmd.ArrayTypes; +import dmd.CallExp; +import dmd.FuncDeclaration; +import dmd.VarExp; +import dmd.Expression; +import dmd.MATCH; +import dmd.Scope; +import dmd.Identifier; +import dmd.TY; +import dmd.IntegerExp; +import dmd.Global; + +// Allow implicit conversion of T[] to T* +bool IMPLICIT_ARRAY_TO_PTR() +{ + return global.params.useDeprecated; +} + +class TypeArray : TypeNext +{ + this(TY ty, Type next) + { + super(ty, next); + } + + Expression dotExp(Scope sc, Expression e, Identifier ident) + { + Type n = this.next.toBasetype(); // uncover any typedef's + + version (LOGDOTEXP) { + printf("TypeArray.dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars()); + } + if (ident == Id.reverse && (n.ty == Tchar || n.ty == Twchar)) + { + Expression ec; + FuncDeclaration fd; + Expressions arguments; + string nm; + static string name[2] = [ "_adReverseChar", "_adReverseWchar" ]; + + nm = name[n.ty == Twchar]; + fd = FuncDeclaration.genCfunc(Type.tindex, nm); + ec = new VarExp(Loc(0), fd); + e = e.castTo(sc, n.arrayOf()); // convert to dynamic array + arguments = new Expressions(); + arguments.push(cast(void*)e); + e = new CallExp(e.loc, ec, arguments); + e.type = next.arrayOf(); + } + else if (ident == Id.sort && (n.ty == Tchar || n.ty == Twchar)) + { + Expression ec; + FuncDeclaration fd; + Expressions arguments; + string nm; + static string name2[2] = [ "_adSortChar", "_adSortWchar" ]; + + nm = name2[n.ty == Twchar]; + fd = FuncDeclaration.genCfunc(Type.tindex, nm); + ec = new VarExp(Loc(0), fd); + e = e.castTo(sc, n.arrayOf()); // convert to dynamic array + arguments = new Expressions(); + arguments.push(cast(void*)e); + e = new CallExp(e.loc, ec, arguments); + e.type = next.arrayOf(); + } + else if (ident == Id.reverse || ident == Id.dup || ident == Id.idup) + { + Expression ec; + FuncDeclaration fd; + Expressions arguments; + int size = cast(int)next.size(e.loc); + int dup; + + assert(size); + dup = (ident == Id.dup || ident == Id.idup); + fd = FuncDeclaration.genCfunc(Type.tindex, dup ? Id.adDup : Id.adReverse); + ec = new VarExp(Loc(0), fd); + e = e.castTo(sc, n.arrayOf()); // convert to dynamic array + arguments = new Expressions(); + if (dup) + arguments.push(cast(void*)getTypeInfo(sc)); + arguments.push(cast(void*)e); + if (!dup) + arguments.push(cast(void*)new IntegerExp(Loc(0), size, Type.tsize_t)); + e = new CallExp(e.loc, ec, arguments); + if (ident == Id.idup) + { + Type einv = next.invariantOf(); + if (next.implicitConvTo(einv) < MATCHconst) + error(e.loc, "cannot implicitly convert element type %s to immutable", next.toChars()); + e.type = einv.arrayOf(); + } + else + e.type = next.mutableOf().arrayOf(); + } + else if (ident == Id.sort) + { + Expression ec; + FuncDeclaration fd; + Expressions arguments; + + fd = FuncDeclaration.genCfunc(tint32.arrayOf(), "_adSort"); + ec = new VarExp(Loc(0), fd); + e = e.castTo(sc, n.arrayOf()); // convert to dynamic array + arguments = new Expressions(); + arguments.push(cast(void*)e); + arguments.push(n.ty == Tsarray + ? cast(void*)n.getTypeInfo(sc) // don't convert to dynamic array + : cast(void*)n.getInternalTypeInfo(sc)); + e = new CallExp(e.loc, ec, arguments); + e.type = next.arrayOf(); + } + else + { + e = Type.dotExp(sc, e, ident); + } + return e; + } + +version (DumbClone) { +} else { + Type clone() + { + assert(false); + } +} +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TypeBasic.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeBasic.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,779 @@ +module dmd.TypeBasic; + +import dmd.Type; +import dmd.Id; +import dmd.MOD; +import dmd.TOK; +import dmd.Token; +import dmd.TFLAGS; +import dmd.TY; +import dmd.Loc; +import dmd.Scope; +import dmd.Expression; +import dmd.IntegerExp; +import dmd.Identifier; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.CppMangleState; +import dmd.MATCH; +import dmd.RealExp; +import dmd.ComplexExp; +import dmd.Util; +import dmd.Port; +import dmd.Complex; + +class TypeBasic : Type +{ + string dstring; + uint flags; + + this(TY ty) + { + super(ty); + + enum TFLAGSintegral = 1; + enum TFLAGSfloating = 2; + enum TFLAGSunsigned = 4; + enum TFLAGSreal = 8; + enum TFLAGSimaginary = 0x10; + enum TFLAGScomplex = 0x20; + + string d; + + uint flags = 0; + switch (ty) + { + case TY.Tvoid: d = Token.toChars(TOK.TOKvoid); + break; + + case TY.Tint8: d = Token.toChars(TOK.TOKint8); + flags |= TFLAGSintegral; + break; + + case TY.Tuns8: d = Token.toChars(TOK.TOKuns8); + flags |= TFLAGSintegral | TFLAGSunsigned; + break; + + case TY.Tint16: d = Token.toChars(TOK.TOKint16); + flags |= TFLAGSintegral; + break; + + case TY.Tuns16: d = Token.toChars(TOK.TOKuns16); + flags |= TFLAGSintegral | TFLAGSunsigned; + break; + + case TY.Tint32: d = Token.toChars(TOK.TOKint32); + flags |= TFLAGSintegral; + break; + + case TY.Tuns32: d = Token.toChars(TOK.TOKuns32); + flags |= TFLAGSintegral | TFLAGSunsigned; + break; + + case TY.Tfloat32: d = Token.toChars(TOK.TOKfloat32); + flags |= TFLAGSfloating | TFLAGSreal; + break; + + case TY.Tint64: d = Token.toChars(TOK.TOKint64); + flags |= TFLAGSintegral; + break; + + case TY.Tuns64: d = Token.toChars(TOK.TOKuns64); + flags |= TFLAGSintegral | TFLAGSunsigned; + break; + + case TY.Tfloat64: d = Token.toChars(TOK.TOKfloat64); + flags |= TFLAGSfloating | TFLAGSreal; + break; + + case TY.Tfloat80: d = Token.toChars(TOK.TOKfloat80); + flags |= TFLAGSfloating | TFLAGSreal; + break; + + case TY.Timaginary32: d = Token.toChars(TOK.TOKimaginary32); + flags |= TFLAGSfloating | TFLAGSimaginary; + break; + + case TY.Timaginary64: d = Token.toChars(TOK.TOKimaginary64); + flags |= TFLAGSfloating | TFLAGSimaginary; + break; + + case TY.Timaginary80: d = Token.toChars(TOK.TOKimaginary80); + flags |= TFLAGSfloating | TFLAGSimaginary; + break; + + case TY.Tcomplex32: d = Token.toChars(TOK.TOKcomplex32); + flags |= TFLAGSfloating | TFLAGScomplex; + break; + + case TY.Tcomplex64: d = Token.toChars(TOK.TOKcomplex64); + flags |= TFLAGSfloating | TFLAGScomplex; + break; + + case TY.Tcomplex80: d = Token.toChars(TOK.TOKcomplex80); + flags |= TFLAGSfloating | TFLAGScomplex; + break; + + case TY.Tbool: d = "bool"; + flags |= TFLAGSintegral | TFLAGSunsigned; + break; + + case TY.Tascii: d = Token.toChars(TOK.TOKchar); + flags |= TFLAGSintegral | TFLAGSunsigned; + break; + + case TY.Twchar: d = Token.toChars(TOK.TOKwchar); + flags |= TFLAGSintegral | TFLAGSunsigned; + break; + + case TY.Tdchar: d = Token.toChars(TOK.TOKdchar); + flags |= TFLAGSintegral | TFLAGSunsigned; + break; + } + + this.dstring = d; + this.flags = flags; + merge(); + } + +version (DumbClone) { +} else { + Type clone() + { + assert(false); + } +} + Type syntaxCopy() + { + // No semantic analysis done on basic types, no need to copy + return this; + } + + ulong size(Loc loc) + { + uint size; + + //printf("TypeBasic.size()\n"); + switch (ty) + { + case TY.Tint8: + case TY.Tuns8: size = 1; break; + case TY.Tint16: + case TY.Tuns16: size = 2; break; + case TY.Tint32: + case TY.Tuns32: + case TY.Tfloat32: + case TY.Timaginary32: + size = 4; break; + case TY.Tint64: + case TY.Tuns64: + case TY.Tfloat64: + case TY.Timaginary64: + size = 8; break; + case TY.Tfloat80: + case TY.Timaginary80: + size = REALSIZE; break; + case TY.Tcomplex32: + size = 8; break; + case TY.Tcomplex64: + size = 16; break; + case TY.Tcomplex80: + size = REALSIZE * 2; break; + + case TY.Tvoid: + //size = Type.size(); // error message + size = 1; + break; + + case TY.Tbool: size = 1; break; + case TY.Tascii: size = 1; break; + case TY.Twchar: size = 2; break; + case TY.Tdchar: size = 4; break; + + default: + assert(0); + break; + } + + //printf("TypeBasic.size() = %d\n", size); + return size; + } + + uint alignsize() + { + uint sz; + + switch (ty) + { + case TY.Tfloat80: + case TY.Timaginary80: + case TY.Tcomplex80: + sz = REALALIGNSIZE; + break; + +version (XXX) { ///TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS + case TY.Tint64: + case TY.Tuns64: + case TY.Tfloat64: + case TY.Timaginary64: + case TY.Tcomplex32: + case TY.Tcomplex64: + sz = 4; + break; +} + + default: + sz = cast(uint)size(Loc(0)); /// + break; + } + + return sz; + } + + Expression getProperty(Loc loc, Identifier ident) + { + Expression e; + long ivalue; + real fvalue; + + //printf("TypeBasic.getProperty('%s')\n", ident.toChars()); + if (ident is Id.max) + { + switch (ty) + { + case TY.Tint8: ivalue = byte.max; goto Livalue; + case TY.Tuns8: ivalue = ubyte.max; goto Livalue; + case TY.Tint16: ivalue = short.max; goto Livalue; + case TY.Tuns16: ivalue = ushort.max; goto Livalue; + case TY.Tint32: ivalue = int.max; goto Livalue; + case TY.Tuns32: ivalue = uint.max; goto Livalue; + case TY.Tint64: ivalue = long.max; goto Livalue; + case TY.Tuns64: ivalue = ulong.max; goto Livalue; + case TY.Tbool: ivalue = bool.max; goto Livalue; + case TY.Tchar: ivalue = char.max; goto Livalue; + case TY.Twchar: ivalue = wchar.max; goto Livalue; + case TY.Tdchar: ivalue = 0x10FFFF; goto Livalue; + case TY.Tcomplex32: + case TY.Timaginary32: + case TY.Tfloat32: fvalue = float.max; goto Lfvalue; + case TY.Tcomplex64: + case TY.Timaginary64: + case TY.Tfloat64: fvalue = double.max;goto Lfvalue; + case TY.Tcomplex80: + case TY.Timaginary80: + case TY.Tfloat80: fvalue = real.max; goto Lfvalue; + } + } + else if (ident is Id.min) + { + switch (ty) + { + case TY.Tint8: ivalue = byte.min; goto Livalue; + case TY.Tuns8: ivalue = ubyte.min; goto Livalue; + case TY.Tint16: ivalue = short.min; goto Livalue; + case TY.Tuns16: ivalue = ushort.min; goto Livalue; + case TY.Tint32: ivalue = int.min; goto Livalue; + case TY.Tuns32: ivalue = uint.min; goto Livalue; + case TY.Tint64: ivalue = long.min; goto Livalue; + case TY.Tuns64: ivalue = ulong.min; goto Livalue; + case TY.Tbool: ivalue = bool.min; goto Livalue; + case TY.Tchar: ivalue = char.min; goto Livalue; + case TY.Twchar: ivalue = wchar.min; goto Livalue; + case TY.Tdchar: ivalue = dchar.min; goto Livalue; + case TY.Tcomplex32: + case TY.Timaginary32: + case TY.Tfloat32: fvalue = float.min; goto Lfvalue; + case TY.Tcomplex64: + case TY.Timaginary64: + case TY.Tfloat64: fvalue = double.min; goto Lfvalue; + case TY.Tcomplex80: + case TY.Timaginary80: + case TY.Tfloat80: fvalue = real.min; goto Lfvalue; + } + } + else if (ident is Id.nan) + { + switch (ty) + { + case TY.Tcomplex32: + case TY.Tcomplex64: + case TY.Tcomplex80: + case TY.Timaginary32: + case TY.Timaginary64: + case TY.Timaginary80: + case TY.Tfloat32: + case TY.Tfloat64: + case TY.Tfloat80: + { + fvalue = real.nan; + goto Lfvalue; + } + } + } + else if (ident is Id.infinity) + { + switch (ty) + { + case TY.Tcomplex32: + case TY.Tcomplex64: + case TY.Tcomplex80: + case TY.Timaginary32: + case TY.Timaginary64: + case TY.Timaginary80: + case TY.Tfloat32: + case TY.Tfloat64: + case TY.Tfloat80: + fvalue = real.infinity; + goto Lfvalue; + } + } + else if (ident is Id.dig) + { + switch (ty) + { + case TY.Tcomplex32: + case TY.Timaginary32: + case TY.Tfloat32: ivalue = float.dig; goto Lint; + case TY.Tcomplex64: + case TY.Timaginary64: + case TY.Tfloat64: ivalue = double.dig; goto Lint; + case TY.Tcomplex80: + case TY.Timaginary80: + case TY.Tfloat80: ivalue = real.dig; goto Lint; + } + } + else if (ident is Id.epsilon) + { + switch (ty) + { + case TY.Tcomplex32: + case TY.Timaginary32: + case TY.Tfloat32: fvalue = float.epsilon; goto Lfvalue; + case TY.Tcomplex64: + case TY.Timaginary64: + case TY.Tfloat64: fvalue = double.epsilon; goto Lfvalue; + case TY.Tcomplex80: + case TY.Timaginary80: + case TY.Tfloat80: fvalue = real.epsilon; goto Lfvalue; + } + } + else if (ident is Id.mant_dig) + { + switch (ty) + { + case TY.Tcomplex32: + case TY.Timaginary32: + case TY.Tfloat32: ivalue = float.mant_dig; goto Lint; + case TY.Tcomplex64: + case TY.Timaginary64: + case TY.Tfloat64: ivalue = double.mant_dig; goto Lint; + case TY.Tcomplex80: + case TY.Timaginary80: + case TY.Tfloat80: ivalue = real.mant_dig; goto Lint; + } + } + else if (ident is Id.max_10_exp) + { + switch (ty) + { + case TY.Tcomplex32: + case TY.Timaginary32: + case TY.Tfloat32: ivalue = float.max_10_exp; goto Lint; + case TY.Tcomplex64: + case TY.Timaginary64: + case TY.Tfloat64: ivalue = double.max_10_exp; goto Lint; + case TY.Tcomplex80: + case TY.Timaginary80: + case TY.Tfloat80: ivalue = real.max_10_exp; goto Lint; + } + } + else if (ident is Id.max_exp) + { + switch (ty) + { + case TY.Tcomplex32: + case TY.Timaginary32: + case TY.Tfloat32: ivalue = float.max_exp; goto Lint; + case TY.Tcomplex64: + case TY.Timaginary64: + case TY.Tfloat64: ivalue = double.max_exp; goto Lint; + case TY.Tcomplex80: + case TY.Timaginary80: + case TY.Tfloat80: ivalue = real.max_exp; goto Lint; + } + } + else if (ident is Id.min_10_exp) + { + switch (ty) + { + case TY.Tcomplex32: + case TY.Timaginary32: + case TY.Tfloat32: ivalue = float.min_10_exp; goto Lint; + case TY.Tcomplex64: + case TY.Timaginary64: + case TY.Tfloat64: ivalue = double.min_10_exp; goto Lint; + case TY.Tcomplex80: + case TY.Timaginary80: + case TY.Tfloat80: ivalue = real.min_10_exp; goto Lint; + } + } + else if (ident is Id.min_exp) + { + switch (ty) + { + case TY.Tcomplex32: + case TY.Timaginary32: + case TY.Tfloat32: ivalue = float.min_exp; goto Lint; + case TY.Tcomplex64: + case TY.Timaginary64: + case TY.Tfloat64: ivalue = double.min_exp; goto Lint; + case TY.Tcomplex80: + case TY.Timaginary80: + case TY.Tfloat80: ivalue = real.min_exp; goto Lint; + } + } + + Ldefault: + return Type.getProperty(loc, ident); + + Livalue: + e = new IntegerExp(loc, ivalue, this); + return e; + + Lfvalue: + if (isreal() || isimaginary()) + e = new RealExp(loc, fvalue, this); + else + { + Complex!(real) cvalue; + cvalue.re = fvalue; + cvalue.im = fvalue; + + //for (int i = 0; i < 20; i++) + // printf("%02x ", ((unsigned char *)&cvalue)[i]); + //printf("\n"); + e = new ComplexExp(loc, cvalue, this); + } + return e; + + Lint: + e = new IntegerExp(loc, ivalue, Type.tint32); + return e; + } + + Expression dotExp(Scope sc, Expression e, Identifier ident) + { +version (LOGDOTEXP) { + printf("TypeBasic.dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars()); +} + Type t; + + if (ident is Id.re) + { + switch (ty) + { + case TY.Tcomplex32: t = tfloat32; goto L1; + case TY.Tcomplex64: t = tfloat64; goto L1; + case TY.Tcomplex80: t = tfloat80; goto L1; + L1: + e = e.castTo(sc, t); + break; + + case TY.Tfloat32: + case TY.Tfloat64: + case TY.Tfloat80: + break; + + case TY.Timaginary32: t = tfloat32; goto L2; + case TY.Timaginary64: t = tfloat64; goto L2; + case TY.Timaginary80: t = tfloat80; goto L2; + L2: + e = new RealExp(Loc(0), 0.0, t); + break; + + default: + return Type.getProperty(e.loc, ident); + } + } + else if (ident is Id.im) + { + Type t2; + + switch (ty) + { + case TY.Tcomplex32: t = timaginary32; t2 = tfloat32; goto L3; + case TY.Tcomplex64: t = timaginary64; t2 = tfloat64; goto L3; + case TY.Tcomplex80: t = timaginary80; t2 = tfloat80; goto L3; + L3: + e = e.castTo(sc, t); + e.type = t2; + break; + + case TY.Timaginary32: t = tfloat32; goto L4; + case TY.Timaginary64: t = tfloat64; goto L4; + case TY.Timaginary80: t = tfloat80; goto L4; + L4: + e = e.copy(); + e.type = t; + break; + + case TY.Tfloat32: + case TY.Tfloat64: + case TY.Tfloat80: + e = new RealExp(Loc(0), 0.0, this); + break; + + default: + return Type.getProperty(e.loc, ident); + } + } + else + { + return Type.dotExp(sc, e, ident); + } + return e; + } + + string toChars() + { + return Type.toChars(); + } + + void toCBuffer2(OutBuffer buf, HdrGenState* hgs, MOD mod) + { + //printf("TypeBasic.toCBuffer2(mod = %d, this.mod = %d)\n", mod, this.mod); + if (mod != this.mod) + { + toCBuffer3(buf, hgs, mod); + return; + } + buf.writestring(dstring); + } + +version (CPP_MANGLE) { + void toCppMangle(OutBuffer buf, CppMangleState* cms) + { + assert(false); + } +} + bool isintegral() + { + //printf("TypeBasic.isintegral('%s') x%x\n", toChars(), flags); + return (flags & TFLAGS.TFLAGSintegral) != 0; + } + + bool isbit() + { + assert(false); + } + + bool isfloating() + { + return (flags & TFLAGS.TFLAGSfloating) != 0; + } + + bool isreal() + { + return (flags & TFLAGS.TFLAGSreal) != 0; + } + + bool isimaginary() + { + return (flags & TFLAGS.TFLAGSimaginary) != 0; + } + + bool iscomplex() + { + return (flags & TFLAGS.TFLAGScomplex) != 0; + } + + bool isscalar() + { + return (flags & (TFLAGS.TFLAGSintegral | TFLAGS.TFLAGSfloating)) != 0; + } + + bool isunsigned() + { + return (flags & TFLAGS.TFLAGSunsigned) != 0; + } + + MATCH implicitConvTo(Type to) + { + //printf("TypeBasic.implicitConvTo(%s) from %s\n", to.toChars(), toChars()); + if (this is to) + return MATCH.MATCHexact; + +version (DMDV2) { + if (ty is to.ty) + { + return (mod == to.mod) ? MATCH.MATCHexact : MATCH.MATCHconst; + } +} + + if (ty == TY.Tvoid || to.ty == TY.Tvoid) + return MATCH.MATCHnomatch; + if (to.ty == TY.Tbool) + return MATCH.MATCHnomatch; + if (!to.isTypeBasic()) + return MATCH.MATCHnomatch; + + TypeBasic tob = cast(TypeBasic)to; + if (flags & TFLAGS.TFLAGSintegral) + { + // Disallow implicit conversion of integers to imaginary or complex + if (tob.flags & (TFLAGS.TFLAGSimaginary | TFLAGS.TFLAGScomplex)) + return MATCH.MATCHnomatch; + +version (DMDV2) { + // If converting from integral to integral + if (1 && tob.flags & TFLAGS.TFLAGSintegral) + { ulong sz = size(Loc(0)); + ulong tosz = tob.size(Loc(0)); + + /* Can't convert to smaller size + */ + if (sz > tosz) + return MATCH.MATCHnomatch; + + /* Can't change sign if same size + */ + /*if (sz == tosz && (flags ^ tob.flags) & TFLAGSunsigned) + return MATCH.MATCHnomatch;*/ + } +} + } + else if (flags & TFLAGS.TFLAGSfloating) + { + // Disallow implicit conversion of floating point to integer + if (tob.flags & TFLAGS.TFLAGSintegral) + return MATCH.MATCHnomatch; + + assert(tob.flags & TFLAGS.TFLAGSfloating); + + // Disallow implicit conversion from complex to non-complex + if (flags & TFLAGS.TFLAGScomplex && !(tob.flags & TFLAGS.TFLAGScomplex)) + return MATCH.MATCHnomatch; + + // Disallow implicit conversion of real or imaginary to complex + if (flags & (TFLAGS.TFLAGSreal | TFLAGS.TFLAGSimaginary) && + tob.flags & TFLAGS.TFLAGScomplex) + return MATCH.MATCHnomatch; + + // Disallow implicit conversion to-from real and imaginary + if ((flags & (TFLAGS.TFLAGSreal | TFLAGS.TFLAGSimaginary)) != + (tob.flags & (TFLAGS.TFLAGSreal | TFLAGS.TFLAGSimaginary))) + return MATCH.MATCHnomatch; + } + return MATCH.MATCHconvert; + } + + Expression defaultInit(Loc loc) + { + long value = 0; + +version (SNAN_DEFAULT_INIT) { + /* + * Use a payload which is different from the machine NaN, + * so that uninitialised variables can be + * detected even if exceptions are disabled. + */ + ushort[8] snan = [ 0, 0, 0, 0xA000, 0x7FFF, 0, 0, 0 ]; + /* + * Although long doubles are 10 bytes long, some + * C ABIs pad them out to 12 or even 16 bytes, so + * leave enough space in the snan array. + */ + assert(REALSIZE <= snan.sizeof); + real fvalue = *cast(real*)snan.ptr; +} + + version (LOGDEFAULTINIT) { + printf("TypeBasic.defaultInit() '%s'\n", toChars()); + } + switch (ty) + { + case TY.Tchar: + value = 0xFF; + break; + + case TY.Twchar: + case TY.Tdchar: + value = 0xFFFF; + break; + + case TY.Timaginary32: + case TY.Timaginary64: + case TY.Timaginary80: + case TY.Tfloat32: + case TY.Tfloat64: + case TY.Tfloat80: + version (SNAN_DEFAULT_INIT) { + return new RealExp(loc, fvalue, this); + } else { + return getProperty(loc, Id.nan); + } + + case TY.Tcomplex32: + case TY.Tcomplex64: + case TY.Tcomplex80: + version (SNAN_DEFAULT_INIT) { + { + // Can't use fvalue + I*fvalue (the im part becomes a quiet NaN). + Complex!(real) cvalue; + cvalue.re = fvalue; + cvalue.im = fvalue; + + return new ComplexExp(loc, cvalue, this); + } + } else { + return getProperty(loc, Id.nan); + } + + case TY.Tvoid: + error(loc, "void does not have a default initializer"); + + default: + break; /// + } + return new IntegerExp(loc, value, this); + } + + bool isZeroInit(Loc loc) + { + switch (ty) + { + case TY.Tchar: + case TY.Twchar: + case TY.Tdchar: + case TY.Timaginary32: + case TY.Timaginary64: + case TY.Timaginary80: + case TY.Tfloat32: + case TY.Tfloat64: + case TY.Tfloat80: + case TY.Tcomplex32: + case TY.Tcomplex64: + case TY.Tcomplex80: + return false; // no + default: + break; + } + + return true; // yes + } + + bool builtinTypeInfo() + { + version (DMDV2) { + return mod ? false : true; + } else { + return true; + } + } + + // For eliminating dynamic_cast + TypeBasic isTypeBasic() + { + return this; + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TypeClass.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeClass.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,637 @@ +module dmd.TypeClass; + +import dmd.Type; +import dmd.ClassDeclaration; +import dmd.Loc; +import dmd.Dsymbol; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Expression; +import dmd.Identifier; +import dmd.MATCH; +import dmd.CppMangleState; +import dmd.ArrayTypes; +import dmd.TypeInfoDeclaration; +import dmd.TY; +import dmd.MOD; +import dmd.Global; +import dmd.TypePointer; +import dmd.Declaration; +import dmd.VarDeclaration; +import dmd.TOK; +import dmd.DotExp; +import dmd.Id; +import dmd.ScopeExp; +import dmd.DotVarExp; +import dmd.VarExp; +import dmd.PtrExp; +import dmd.AddExp; +import dmd.IntegerExp; +import dmd.DotIdExp; +import dmd.EnumMember; +import dmd.TemplateMixin; +import dmd.TemplateDeclaration; +import dmd.TemplateInstance; +import dmd.OverloadSet; +import dmd.DotTypeExp; +import dmd.TupleExp; +import dmd.ClassInfoDeclaration; +import dmd.TypeInfoInterfaceDeclaration; +import dmd.TypeInfoClassDeclaration; +import dmd.Util; +import dmd.NullExp; +import dmd.TypeExp; +import dmd.DotTemplateExp; +import dmd.ErrorExp; +import dmd.ThisExp; +import dmd.CommaExp; + +import dmd.expression.Util; +import dmd.backend.Symbol; +import dmd.backend.TYPE; +import dmd.backend.Util; +import dmd.backend.SC; +import dmd.backend.STR; +import dmd.backend.TYM; +import dmd.backend.LIST; +import dmd.backend.Classsym; + +import std.string : toStringz; + +class TypeClass : Type +{ + ClassDeclaration sym; + + this(ClassDeclaration sym) + { + super(TY.Tclass); + this.sym = sym; + } + +version (DumbClone) { +} else { + Type clone() + { + assert(false); + } +} + ulong size(Loc loc) + { + return PTRSIZE; + } + + string toChars() + { + if (mod) + return Type.toChars(); + return sym.toPrettyChars(); + } + + Type syntaxCopy() + { + assert(false); + } + + Type semantic(Loc loc, Scope sc) + { + //printf("TypeClass.semantic(%s)\n", sym.toChars()); + if (deco) + return this; + //printf("\t%s\n", merge().deco); + return merge(); + } + + Dsymbol toDsymbol(Scope sc) + { + return sym; + } + + void toDecoBuffer(OutBuffer buf, int flag) + { + string name = sym.mangle(); + //printf("TypeClass.toDecoBuffer('%s' flag=%d mod=%x) = '%s'\n", toChars(), flag, mod, name); + Type.toDecoBuffer(buf, flag); + buf.printf("%s", name); + } + + void toCBuffer2(OutBuffer buf, HdrGenState* hgs, MOD mod) + { + if (mod != this.mod) + { + toCBuffer3(buf, hgs, mod); + return; + } + buf.writestring(sym.toChars()); + } + + Expression dotExp(Scope sc, Expression e, Identifier ident) + { + uint offset; + + Expression b; + VarDeclaration v; + Dsymbol s; + +version (LOGDOTEXP) { + printf("TypeClass.dotExp(e='%s', ident='%s')\n", e.toChars(), ident.toChars()); +} + + if (e.op == TOK.TOKdotexp) + { + DotExp de = cast(DotExp)e; + + if (de.e1.op == TOK.TOKimport) + { + ScopeExp se = cast(ScopeExp)de.e1; + + s = se.sds.search(e.loc, ident, 0); + e = de.e1; + goto L1; + } + } + + if (ident is Id.tupleof_) + { + /* Create a TupleExp + */ + e = e.semantic(sc); // do this before turning on noaccesscheck + Expressions exps = new Expressions; + exps.reserve(sym.fields.dim); + for (size_t i = 0; i < sym.fields.dim; i++) + { + VarDeclaration v2 = cast(VarDeclaration)sym.fields.data[i]; + Expression fe = new DotVarExp(e.loc, e, v2); + exps.push(cast(void*)fe); + } + e = new TupleExp(e.loc, exps); + sc = sc.push(); + sc.noaccesscheck = 1; + e = e.semantic(sc); + sc.pop(); + return e; + } + + s = sym.search(e.loc, ident, 0); + L1: + if (!s) + { + // See if it's a base class + ClassDeclaration cbase; + for (cbase = sym.baseClass; cbase; cbase = cbase.baseClass) + { + if (cbase.ident.equals(ident)) + { + e = new DotTypeExp(Loc(0), e, cbase); + return e; + } + } + + if (ident is Id.classinfo_) + { + assert(ClassDeclaration.classinfo); + Type t = ClassDeclaration.classinfo.type; + if (e.op == TOK.TOKtype || e.op == TOK.TOKdottype) + { + /* For type.classinfo, we know the classinfo + * at compile time. + */ + if (!sym.vclassinfo) + sym.vclassinfo = new ClassInfoDeclaration(sym); + + e = new VarExp(e.loc, sym.vclassinfo); + e = e.addressOf(sc); + e.type = t; // do this so we don't get redundant dereference + } + else + { + /* For class objects, the classinfo reference is the first + * entry in the vtbl[] + */ + e = new PtrExp(e.loc, e); + e.type = t.pointerTo(); + if (sym.isInterfaceDeclaration()) + { + if (sym.isCPPinterface()) + { + /* C++ interface vtbl[]s are different in that the + * first entry is always pointer to the first virtual + * function, not classinfo. + * We can't get a .classinfo for it. + */ + error(e.loc, "no .classinfo for C++ interface objects"); + } + /* For an interface, the first entry in the vtbl[] + * is actually a pointer to an instance of struct Interface. + * The first member of Interface is the .classinfo, + * so add an extra pointer indirection. + */ + e.type = e.type.pointerTo(); + e = new PtrExp(e.loc, e); + e.type = t.pointerTo(); + } + e = new PtrExp(e.loc, e, t); + } + return e; + } + + if (ident is Id.__vptr) + { + /* The pointer to the vtbl[] + * *cast(invariant(void*)**)e + */ + e = e.castTo(sc, tvoidptr.invariantOf().pointerTo().pointerTo()); + e = new PtrExp(e.loc, e); + e = e.semantic(sc); + return e; + } + + if (ident is Id.__monitor) + { /* The handle to the monitor (call it a void*) + * *(cast(void**)e + 1) + */ + e = e.castTo(sc, tvoidptr.pointerTo()); + e = new AddExp(e.loc, e, new IntegerExp(1)); + e = new PtrExp(e.loc, e); + e = e.semantic(sc); + return e; + } + + if (ident is Id.typeinfo_) + { + if (!global.params.useDeprecated) + error(e.loc, ".typeinfo deprecated, use typeid(type)"); + + return getTypeInfo(sc); + } + if (ident is Id.outer && sym.vthis) + { + s = sym.vthis; + } + else + { + if (ident !is Id.__sizeof && + ident !is Id.alignof_ && + ident !is Id.init_ && + ident !is Id.mangleof_ && + ident !is Id.stringof_ && + ident !is Id.offsetof) + { + /* See if we should forward to the alias this. + */ + if (sym.aliasthis) + { + /* Rewrite e.ident as: + * e.aliasthis.ident + */ + e = new DotIdExp(e.loc, e, sym.aliasthis.ident); + e = new DotIdExp(e.loc, e, ident); + return e.semantic(sc); + } + + /* Look for overloaded opDot() to see if we should forward request + * to it. + */ + Dsymbol fd = search_function(sym, Id.opDot); + if (fd) + { + /* Rewrite e.ident as: + * e.opId().ident + */ + e = build_overload(e.loc, sc, e, null, fd.ident); + e = new DotIdExp(e.loc, e, ident); + return e.semantic(sc); + } + } + + return Type.dotExp(sc, e, ident); + } + } + + if (!s.isFuncDeclaration()) // because of overloading + s.checkDeprecated(e.loc, sc); + + s = s.toAlias(); + v = s.isVarDeclaration(); + + if (v && !v.isDataseg()) + { + Expression ei = v.getConstInitializer(); + + if (ei) + { + e = ei.copy(); // need to copy it if it's a StringExp + e = e.semantic(sc); + return e; + } + } + + if (s.getType()) + { + // if (e.op == TOKtype) + return new TypeExp(e.loc, s.getType()); + // return new DotTypeExp(e.loc, e, s); + } + + EnumMember em = s.isEnumMember(); + if (em) + { + assert(em.value); + return em.value.copy(); + } + + TemplateMixin tm = s.isTemplateMixin(); + if (tm) + { + Expression de = new DotExp(e.loc, e, new ScopeExp(e.loc, tm)); + de.type = e.type; + return de; + } + + TemplateDeclaration td = s.isTemplateDeclaration(); + if (td) + { + e = new DotTemplateExp(e.loc, e, td); + e.semantic(sc); + return e; + } + + TemplateInstance ti = s.isTemplateInstance(); + if (ti) + { + if (!ti.semanticRun) + ti.semantic(sc); + s = ti.inst.toAlias(); + if (!s.isTemplateInstance()) + goto L1; + Expression de = new DotExp(e.loc, e, new ScopeExp(e.loc, ti)); + de.type = e.type; + return de; + } + + OverloadSet o = s.isOverloadSet(); + if (o) + { + /* We really should allow this + */ + error(e.loc, "overload set for %s.%s not allowed in struct declaration", e.toChars(), ident.toChars()); + return new ErrorExp(); + } + + Declaration d = s.isDeclaration(); + if (!d) + { + e.error("%s.%s is not a declaration", e.toChars(), ident.toChars()); + return new ErrorExp(); + } + + if (e.op == TOK.TOKtype) + { + /* It's: + * Class.d + */ + if (d.isTupleDeclaration()) + { + e = new TupleExp(e.loc, d.isTupleDeclaration()); + e = e.semantic(sc); + return e; + } + else if (d.needThis() && (hasThis(sc) || !d.isFuncDeclaration())) + { + if (sc.func) + { + ClassDeclaration thiscd; + thiscd = sc.func.toParent().isClassDeclaration(); + + if (thiscd) + { + ClassDeclaration cd = e.type.isClassHandle(); + + if (cd is thiscd) + { + e = new ThisExp(e.loc); + e = new DotTypeExp(e.loc, e, cd); + DotVarExp de = new DotVarExp(e.loc, e, d); + e = de.semantic(sc); + return e; + } + else if ((!cd || !cd.isBaseOf(thiscd, null)) && !d.isFuncDeclaration()) + e.error("'this' is required, but %s is not a base class of %s", e.type.toChars(), thiscd.toChars()); + } + } + + /* Rewrite as: + * this.d + */ + DotVarExp de = new DotVarExp(e.loc, new ThisExp(e.loc), d); + e = de.semantic(sc); + return e; + } + else + { + VarExp ve = new VarExp(e.loc, d, 1); + return ve; + } + } + + if (d.isDataseg()) + { + // (e, d) + accessCheck(e.loc, sc, e, d); + VarExp ve = new VarExp(e.loc, d); + e = new CommaExp(e.loc, e, ve); + e.type = d.type; + return e; + } + + if (d.parent && d.toParent().isModule()) + { + // (e, d) + VarExp ve = new VarExp(e.loc, d, 1); + e = new CommaExp(e.loc, e, ve); + e.type = d.type; + return e; + } + + DotVarExp de = new DotVarExp(e.loc, e, d); + return de.semantic(sc); + } + + ClassDeclaration isClassHandle() + { + return sym; + } + + bool isBaseOf(Type t, int* poffset) + { + assert(false); + } + + MATCH implicitConvTo(Type to) + { + //printf("TypeClass.implicitConvTo(to = '%s') %s\n", to.toChars(), toChars()); + MATCH m = constConv(to); + if (m != MATCH.MATCHnomatch) + return m; + + ClassDeclaration cdto = to.isClassHandle(); + if (cdto && cdto.isBaseOf(sym, null)) + { + //printf("'to' is base\n"); + return MATCH.MATCHconvert; + } + + if (global.params.Dversion == 1) + { + // Allow conversion to (void *) + if (to.ty == TY.Tpointer && (cast(TypePointer)to).next.ty == TY.Tvoid) + return MATCH.MATCHconvert; + } + + m = MATCH.MATCHnomatch; + if (sym.aliasthis) + { + Declaration d = sym.aliasthis.isDeclaration(); + if (d) + { + assert(d.type); + Type t = d.type.addMod(mod); + m = t.implicitConvTo(to); + } + } + + return m; + } + + Expression defaultInit(Loc loc) + { +version (LOGDEFAULTINIT) { + printf("TypeClass::defaultInit() '%s'\n", toChars()); +} + Expression e = new NullExp(loc); + e.type = this; + return e; + } + + bool isZeroInit(Loc loc) + { + return true; + } + + MATCH deduceType(Scope sc, Type tparam, TemplateParameters parameters, Objects dedtypes) + { + assert(false); + } + + bool isauto() + { + return sym.isauto; + } + + bool checkBoolean() + { + return true; + } + + TypeInfoDeclaration getTypeInfoDeclaration() + { + if (sym.isInterfaceDeclaration()) + return new TypeInfoInterfaceDeclaration(this); + else + return new TypeInfoClassDeclaration(this); + } + + bool hasPointers() + { + return true; + } + + bool builtinTypeInfo() + { + /* This is statically put out with the ClassInfo, so + * claim it is built in so it isn't regenerated by each module. + */ + version (DMDV2) { + return mod ? false : true; + } else { + return true; + } + } + +version (DMDV2) { + Type toHeadMutable() + { + assert(false); + } + + MATCH constConv(Type to) + { + if (equals(to)) + return MATCH.MATCHexact; + + if (ty == to.ty && sym == (cast(TypeClass)to).sym && to.mod == MOD.MODconst) + return MATCH.MATCHconst; + + return MATCH.MATCHnomatch; + } + +version (CPP_MANGLE) { + void toCppMangle(OutBuffer buf, CppMangleState* cms) + { + assert(false); + } +} +} + + type* toCtype() + { + type* t; + Symbol* s; + + //printf("TypeClass.toCtype() %s\n", toChars()); + if (ctype) + return ctype; + + /* Need this symbol to do C++ name mangling + */ + string name = sym.isCPPinterface() ? sym.ident.toChars() : sym.toPrettyChars(); + s = symbol_calloc(toStringz(name)); + s.Sclass = SC.SCstruct; + s.Sstruct = struct_calloc(); + s.Sstruct.Sflags |= STR.STRclass; + s.Sstruct.Salignsize = sym.alignsize; + s.Sstruct.Sstructalign = cast(ubyte)sym.structalign; + s.Sstruct.Sstructsize = sym.structsize; + + t = type_alloc(TYM.TYstruct); + t.Ttag = cast(Classsym*)s; // structure tag name + t.Tcount++; + s.Stype = t; + slist_add(s); + + t = type_allocn(TYM.TYnptr, t); + + t.Tcount++; + ctype = t; + + /* Add in fields of the class + * (after setting ctype to avoid infinite recursion) + */ + if (global.params.symdebug) + for (int i = 0; i < sym.fields.dim; i++) + { + VarDeclaration v = cast(VarDeclaration)sym.fields.data[i]; + + Symbol* s2 = symbol_name(toStringz(v.ident.toChars()), SC.SCmember, v.type.toCtype()); + s2.Smemoff = v.offset; + list_append(&s.Sstruct.Sfldlst, s2); + } + + return t; + } + + Symbol* toSymbol() + { + return sym.toSymbol(); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TypeDArray.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeDArray.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,339 @@ +module dmd.TypeDArray; + +import dmd.TypeArray; +import dmd.MOD; +import dmd.Id; +import dmd.TOK; +import dmd.StringExp; +import dmd.IntegerExp; +import dmd.ArrayLengthExp; +import dmd.Type; +import dmd.Loc; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Expression; +import dmd.Identifier; +import dmd.MATCH; +import dmd.ArrayTypes; +import dmd.TypeInfoDeclaration; +import dmd.TypeInfoArrayDeclaration; +import dmd.NullExp; +import dmd.TY; +import dmd.TypeStruct; +import dmd.Util; +import dmd.TypePointer; +import dmd.Global; + +import dmd.backend.TYPE; +import dmd.backend.Symbol; +import dmd.backend.Classsym; +import dmd.backend.Util; +import dmd.backend.SC; +import dmd.backend.TYM; +import dmd.backend.LIST; + +import core.stdc.stdlib; +import core.stdc.stdio; + +// Dynamic array, no dimension +class TypeDArray : TypeArray +{ + this(Type t) + { + super(TY.Tarray, t); + //printf("TypeDArray(t = %p)\n", t); + } + +version (DumbClone) { +} else { + Type clone() + { + assert(false); + } +} + Type syntaxCopy() + { + Type t = next.syntaxCopy(); + if (t == next) + t = this; + else + { + t = new TypeDArray(t); + t.mod = mod; + } + return t; + } + + ulong size(Loc loc) + { + //printf("TypeDArray.size()\n"); + return PTRSIZE * 2; + } + + uint alignsize() + { + // A DArray consists of two ptr-sized values, so align it on pointer size + // boundary + return PTRSIZE; + } + + Type semantic(Loc loc, Scope sc) + { + Type tn = next; + + tn = next.semantic(loc,sc); + Type tbn = tn.toBasetype(); + switch (tbn.ty) + { + case TY.Tfunction: + case TY.Tnone: + case TY.Ttuple: + error(loc, "can't have array of %s", tbn.toChars()); + tn = next = tint32; + break; + case TY.Tstruct: + { + TypeStruct ts = cast(TypeStruct)tbn; + if (ts.sym.isnested) + error(loc, "cannot have array of inner structs %s", ts.toChars()); + break; + } + + default: + break; /// + } + if (tn.isauto()) + error(loc, "cannot have array of auto %s", tn.toChars()); + + next = tn; + transitive(); + return merge(); + } + + void toDecoBuffer(OutBuffer buf, int flag) + { + Type.toDecoBuffer(buf, flag); + if (next) + next.toDecoBuffer(buf, (flag & 0x100) ? 0 : mod); + } + + void toCBuffer2(OutBuffer buf, HdrGenState* hgs, MOD mod) + { + if (mod != this.mod) + { + toCBuffer3(buf, hgs, mod); + return; + } + next.toCBuffer2(buf, hgs, this.mod); + buf.writestring("[]"); + } + + Expression dotExp(Scope sc, Expression e, Identifier ident) + { +version (LOGDOTEXP) { + printf("TypeDArray.dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars()); +} + if (ident is Id.length) + { + if (e.op == TOK.TOKstring) + { + StringExp se = cast(StringExp)e; + + return new IntegerExp(se.loc, se.len, Type.tindex); + } + e = new ArrayLengthExp(e.loc, e); + e.type = Type.tsize_t; + return e; + } + else if (ident is Id.ptr) + { + e = e.castTo(sc, next.pointerTo()); + return e; + } + else + { + e = TypeArray.dotExp(sc, e, ident); + } + return e; + } + + int isString() + { + assert(false); + } + + bool isZeroInit(Loc loc) + { + return true; + } + + bool checkBoolean() + { + return true; + } + + MATCH implicitConvTo(Type to) + { + //printf("TypeDArray.implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars()); + if (equals(to)) + return MATCHexact; + + // Allow implicit conversion of array to pointer + if (IMPLICIT_ARRAY_TO_PTR && to.ty == Tpointer) + { + TypePointer tp = cast(TypePointer)to; + + /* Allow conversion to void* + */ + if (tp.next.ty == Tvoid && + (next.mod == tp.next.mod || tp.next.mod == MODconst)) + { + return MATCHconvert; + } + + return next.constConv(to); + } + + if (to.ty == Tarray) + { + int offset = 0; + TypeDArray ta = cast(TypeDArray)to; + + if (!(next.mod == ta.next.mod || ta.next.mod == MODconst)) + return MATCHnomatch; // not const-compatible + + /* Allow conversion to void[] + */ + if (next.ty != Tvoid && ta.next.ty == Tvoid) + { + return MATCHconvert; + } + + MATCH m = next.constConv(ta.next); + if (m != MATCHnomatch) + { + if (m == MATCHexact && mod != to.mod) + m = MATCHconst; + return m; + } + + /* Allow conversions of T[][] to const(T)[][] + */ + if (mod == ta.mod && next.ty == Tarray && ta.next.ty == Tarray) + { + m = next.implicitConvTo(ta.next); + if (m == MATCHconst) + return m; + } + + /* Conversion of array of derived to array of base + */ + if (ta.next.isBaseOf(next, &offset) && offset == 0) + return MATCHconvert; + } + return Type.implicitConvTo(to); + } + + Expression defaultInit(Loc loc) + { + version (LOGDEFAULTINIT) { + printf("TypeDArray.defaultInit() '%s'\n", toChars()); + } + Expression e = new NullExp(loc); + e.type = this; + return e; + } + + bool builtinTypeInfo() + { + version (DMDV2) { + return !mod && (next.isTypeBasic() !is null && !next.mod || + // strings are so common, make them builtin + next.ty == Tchar && next.mod == MODinvariant); + } else { + return next.isTypeBasic() !is null; + } + } +version (DMDV2) { + MATCH deduceType(Scope sc, Type tparam, TemplateParameters parameters, Objects dedtypes) + { + static if (false) { + printf("TypeDArray.deduceType()\n"); + printf("\tthis = %d, ", ty); print(); + printf("\ttparam = %d, ", tparam.ty); tparam.print(); + } + return Type.deduceType(sc, tparam, parameters, dedtypes); + + Lnomatch: + return MATCHnomatch; + } +} + TypeInfoDeclaration getTypeInfoDeclaration() + { + return new TypeInfoArrayDeclaration(this); + } + + bool hasPointers() + { + return true; + } + +version (CPP_MANGLE) { + void toCppMangle(OutBuffer buf, CppMangleState* cms); +} + + type* toCtype() + { + type *t; + + if (ctype) + return ctype; + + if (0 && global.params.symdebug) + { + /* Create a C type out of: + * struct _Array_T { size_t length; T* data; } + */ + Symbol* s; + char *id; + + assert(next.deco); + id = cast(char*) alloca(7 + next.deco.length + 1); + sprintf(id, "_Array_%.*s", next.deco); + s = symbol_calloc(id); + s.Sclass = SC.SCstruct; + s.Sstruct = struct_calloc(); + s.Sstruct.Sflags |= 0; + s.Sstruct.Salignsize = alignsize(); + s.Sstruct.Sstructalign = cast(ubyte)global.structalign; + s.Sstruct.Sstructsize = cast(uint)size(Loc(0)); + slist_add(s); + + Symbol* s1 = symbol_name("length", SC.SCmember, Type.tsize_t.toCtype()); + list_append(&s.Sstruct.Sfldlst, s1); + + Symbol* s2 = symbol_name("data", SC.SCmember, next.pointerTo().toCtype()); + s2.Smemoff = cast(uint)Type.tsize_t.size(); + list_append(&s.Sstruct.Sfldlst, s2); + + t = type_alloc(TYM.TYstruct); + t.Ttag = cast(Classsym*)s; // structure tag name + t.Tcount++; + s.Stype = t; + } + else + { + if (global.params.symdebug == 1) + { + // Generate D symbolic debug info, rather than C + t = type_allocn(TYM.TYdarray, next.toCtype()); + } + else + t = type_fake(TYM.TYdarray); + } + t.Tcount++; + ctype = t; + return t; + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TypeDelegate.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeDelegate.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,213 @@ +module dmd.TypeDelegate; + +import dmd.Type; +import dmd.TypeNext; +import dmd.MOD; +import dmd.OutBuffer; +import dmd.Id; +import dmd.AddExp; +import dmd.PtrExp; +import dmd.IntegerExp; +import dmd.NullExp; +import dmd.TypeFunction; +import dmd.HdrGenState; +import dmd.Expression; +import dmd.Identifier; +import dmd.CppMangleState; +import dmd.Argument; +import dmd.Loc; +import dmd.Scope; +import dmd.TypeInfoDeclaration; +import dmd.TypeInfoDelegateDeclaration; +import dmd.TY; +import dmd.Global; + +import dmd.backend.TYPE; +import dmd.backend.Symbol; +import dmd.backend.Classsym; +import dmd.backend.TYM; +import dmd.backend.SC; +import dmd.backend.Util; +import dmd.backend.LIST; + +class TypeDelegate : TypeNext +{ + // .next is a TypeFunction + + this(Type t) + { + super(TY.Tfunction, t); + ty = TY.Tdelegate; + } + +version (DumbClone) { +} else { + Type clone() + { + assert(false); + } +} + Type syntaxCopy() + { + Type t = next.syntaxCopy(); + if (t == next) + t = this; + else + { + t = new TypeDelegate(t); + t.mod = mod; + } + return t; + } + + Type semantic(Loc loc, Scope sc) + { + if (deco) // if semantic() already run + { + //printf("already done\n"); + return this; + } + + next = next.semantic(loc, sc); + return merge(); + } + + ulong size(Loc loc) + { + return PTRSIZE * 2; + } + + void toCBuffer2(OutBuffer buf, HdrGenState* hgs, MOD mod) + { + if (mod != this.mod) + { + toCBuffer3(buf, hgs, mod); + return; + } + TypeFunction tf = cast(TypeFunction)next; + + tf.next.toCBuffer2(buf, hgs, MODundefined); + buf.writestring(" delegate"); + Argument.argsToCBuffer(buf, hgs, tf.parameters, tf.varargs); + } + + Expression defaultInit(Loc loc) + { + version (LOGDEFAULTINIT) { + printf("TypeDelegate.defaultInit() '%s'\n", toChars()); + } + Expression e; + e = new NullExp(loc); + e.type = this; + return e; + } + + bool isZeroInit(Loc loc) + { + return true; + } + + bool checkBoolean() + { + return true; + } + + TypeInfoDeclaration getTypeInfoDeclaration() + { + return new TypeInfoDelegateDeclaration(this); + } + + Expression dotExp(Scope sc, Expression e, Identifier ident) + { + version (LOGDOTEXP) { + printf("TypeDelegate.dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars()); + } + if (ident == Id.ptr) + { + e.type = tvoidptr; + return e; + } + else if (ident == Id.funcptr) + { + e = e.addressOf(sc); + e.type = tvoidptr; + e = new AddExp(e.loc, e, new IntegerExp(PTRSIZE)); + e.type = tvoidptr; + e = new PtrExp(e.loc, e); + e.type = next.pointerTo(); + return e; + } + else + { + e = Type.dotExp(sc, e, ident); + } + return e; + } + + bool hasPointers() + { + return true; + } + +version (CPP_MANGLE) { + void toCppMangle(OutBuffer buf, CppMangleState* cms) + { + assert(false); + } +} + + type* toCtype() + { + type* t; + + if (ctype) + return ctype; + + if (0 && global.params.symdebug) + { + /* A delegate consists of: + * _Delegate { void* frameptr; Function *funcptr; } + */ + + static Symbol* s; + + if (!s) + { + s = symbol_calloc("_Delegate"); + s.Sclass = SC.SCstruct; + s.Sstruct = struct_calloc(); + s.Sstruct.Sflags |= 0; /// huh? + s.Sstruct.Salignsize = alignsize(); + s.Sstruct.Sstructalign = cast(ubyte)global.structalign; + s.Sstruct.Sstructsize = cast(uint)size(Loc(0)); + slist_add(s); + + Symbol* s1 = symbol_name("frameptr", SC.SCmember, Type.tvoidptr.toCtype()); + list_append(&s.Sstruct.Sfldlst, s1); + + Symbol* s2 = symbol_name("funcptr", SC.SCmember, Type.tvoidptr.toCtype()); + s2.Smemoff = cast(uint)Type.tvoidptr.size(); + list_append(&s.Sstruct.Sfldlst, s2); + } + + t = type_alloc(TYM.TYstruct); + t.Ttag = cast(Classsym*)s; // structure tag name + t.Tcount++; + s.Stype = t; + } + else + { + if (global.params.symdebug == 1) + { + // Generate D symbolic debug info, rather than C + t = type_allocn(TYM.TYdelegate, next.toCtype()); + } + else + t = type_fake(TYM.TYdelegate); + } + + t.Tcount++; + ctype = t; + return t; + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TypeEnum.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeEnum.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,228 @@ +module dmd.TypeEnum; + +import dmd.Type; +import dmd.EnumDeclaration; +import dmd.Scope; +import dmd.Loc; +import dmd.Id; +import dmd.ErrorExp; +import dmd.Dsymbol; +import dmd.EnumMember; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Expression; +import dmd.Identifier; +import dmd.MATCH; +import dmd.OutBuffer; +import dmd.CppMangleState; +import dmd.TypeInfoDeclaration; +import dmd.TypeInfoEnumDeclaration; +import dmd.ArrayTypes; +import dmd.TY; +import dmd.Util; + +import dmd.backend.TYPE; + +class TypeEnum : Type +{ + EnumDeclaration sym; + + this(EnumDeclaration sym) + { + super(TY.Tenum); + this.sym = sym; + } + +version (DumbClone) { +} else { + Type clone() + { + assert(false); + } +} + Type syntaxCopy() + { + assert(false); + } + + ulong size(Loc loc) + { + if (!sym.memtype) + { + error(loc, "enum %s is forward referenced", sym.toChars()); + return 4; + } + return sym.memtype.size(loc); + } + + uint alignsize() + { + assert(false); + } + + string toChars() + { + assert(false); + } + + Type semantic(Loc loc, Scope sc) + { + //printf("TypeEnum::semantic() %s\n", toChars()); + //sym.semantic(sc); + return merge(); + } + + Dsymbol toDsymbol(Scope sc) + { + return sym; + } + + void toDecoBuffer(OutBuffer buf, int flag) + { + string name = sym.mangle(); + Type.toDecoBuffer(buf, flag); + buf.printf("%s", name); + } + + void toCBuffer2(OutBuffer buf, HdrGenState* hgs, int mod) + { + assert(false); + } + + Expression dotExp(Scope sc, Expression e, Identifier ident) + { + version (LOGDOTEXP) { + printf("TypeEnum::dotExp(e = '%s', ident = '%s') '%s'\n", e.toChars(), ident.toChars(), toChars()); + } + Dsymbol s = sym.search(e.loc, ident, 0); + if (!s) + { + if (ident is Id.max || + ident is Id.min || + ident is Id.init_ || + ident is Id.stringof_ || + !sym.memtype + ) + { + return getProperty(e.loc, ident); + } + + return sym.memtype.dotExp(sc, e, ident); + } + + EnumMember m = s.isEnumMember(); + Expression em = m.value.copy(); + em.loc = e.loc; + return em; + } + + Expression getProperty(Loc loc, Identifier ident) + { + assert(false); + } + + bool isintegral() + { + return true; + } + + bool isfloating() + { + return false; + } + + bool isscalar() + { + return true; + //return sym.memtype.isscalar(); + } + + bool isunsigned() + { + return sym.memtype.isunsigned(); + } + + MATCH implicitConvTo(Type to) + { + MATCH m; + + //printf("TypeEnum::implicitConvTo()\n"); + if (ty == to.ty && sym == (cast(TypeEnum)to).sym) + m = (mod == to.mod) ? MATCHexact : MATCHconst; + else if (sym.memtype.implicitConvTo(to)) + m = MATCHconvert; // match with conversions + else + m = MATCHnomatch; // no match + return m; + } + + MATCH constConv(Type to) + { + assert(false); + } + + Type toBasetype() + { + if (!sym.memtype) + { + debug writef("2: "); + error(sym.loc, "enum %s is forward referenced", sym.toChars()); + return tint32; + } + + return sym.memtype.toBasetype(); + } + + Expression defaultInit(Loc loc) + { + version (LOGDEFAULTINIT) { + printf("TypeEnum::defaultInit() '%s'\n", toChars()); + } + // Initialize to first member of enum + //printf("%s\n", sym.defaultval.type.toChars()); + if (!sym.defaultval) + { + error(loc, "forward reference of %s.init", toChars()); + return new ErrorExp(); + } + return sym.defaultval; + } + + bool isZeroInit(Loc loc) + { + if (!sym.defaultval) + { + debug writef("3: "); + error(loc, "enum %s is forward referenced", sym.toChars()); + return 0; + } + return sym.defaultval.isBool(false); + } + + MATCH deduceType(Scope sc, Type tparam, TemplateParameters parameters, Objects dedtypes) + { + assert(false); + } + + TypeInfoDeclaration getTypeInfoDeclaration() + { + return new TypeInfoEnumDeclaration(this); + } + + bool hasPointers() + { + return toBasetype().hasPointers(); + } + +version (CPP_MANGLE) { + void toCppMangle(OutBuffer buf, CppMangleState* cms) + { + assert(false); + } +} + + type* toCtype() + { + return sym.memtype.toCtype(); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TypeExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,62 @@ +module dmd.TypeExp; + +import dmd.Expression; +import dmd.backend.elem; +import dmd.Type; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.IRState; +import dmd.HdrGenState; +import dmd.TOK; + +class TypeExp : Expression +{ + this(Loc loc, Type type) + { + super(loc, TOK.TOKtype, TypeExp.sizeof); + //printf("TypeExp::TypeExp(%s)\n", type->toChars()); + this.type = type; + } + +version (DumbClone) { +} else { + Type clone() + { + assert(false); + } +} + Expression syntaxCopy() + { + //printf("TypeExp.syntaxCopy()\n"); + return new TypeExp(loc, type.syntaxCopy()); + } + + Expression semantic(Scope sc) + { + //printf("TypeExp::semantic(%s)\n", type->toChars()); + type = type.semantic(loc, sc); + return this; + } + + void rvalue() + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + Expression optimize(int result) + { + return this; + } + + elem* toElem(IRState* irs) + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/TypeFunction.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeFunction.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,734 @@ +module dmd.TypeFunction; + +import dmd.TypeNext; +import dmd.TypeSArray; +import dmd.TypeArray; +import dmd.ArrayTypes; +import dmd.LINK; +import dmd.StructDeclaration; +import dmd.TypeStruct; +import dmd.Global; +import dmd.STC; +import dmd.MOD; +import dmd.Type; +import dmd.Loc; +import dmd.Scope; +import dmd.Identifier; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.CppMangleState; +import dmd.TypeInfoDeclaration; +import dmd.MATCH; +import dmd.Argument; +import dmd.Expression; +import dmd.RET; +import dmd.TY; +import dmd.Util; + +import dmd.backend.TYPE; +import dmd.backend.PARAM; +import dmd.backend.Util; +import dmd.backend.TYM; +import dmd.backend.TF; +import dmd.backend.mTY; + +import core.stdc.stdlib; +import core.stdc.string; + +class TypeFunction : TypeNext +{ + // .next is the return type + + Arguments parameters; // function parameters + int varargs; // 1: T t, ...) style for variable number of arguments + // 2: T t ...) style for variable number of arguments + bool isnothrow; // true: nothrow + bool ispure; // true: pure + bool isproperty; // can be called without parentheses + bool isref; // true: returns a reference + LINK linkage; // calling convention + + int inuse; + + this(Arguments parameters, Type treturn, int varargs, LINK linkage) + { + super(TY.Tfunction, treturn); + + //if (!treturn) *(char*)0=0; + // assert(treturn); + assert(0 <= varargs && varargs <= 2); + this.parameters = parameters; + this.varargs = varargs; + this.linkage = linkage; + } + + Type syntaxCopy() + { + Type treturn = next ? next.syntaxCopy() : null; + Arguments params = Argument.arraySyntaxCopy(parameters); + TypeFunction t = new TypeFunction(params, treturn, varargs, linkage); + t.mod = mod; + t.isnothrow = isnothrow; + t.ispure = ispure; + t.isproperty = isproperty; + t.isref = isref; + + return t; + } + +version (DumbClone) { +} else { + final TypeFunction cloneTo(TypeFunction t) + { + super.cloneTo(t); + + // these 3 should be set by ctor + assert(t.parameters is null); + assert(t.varargs == varargs); + assert(t.linkage == linkage); + + t.isnothrow = isnothrow; + t.ispure = ispure; + t.isproperty = isproperty; + t.isref = isref; + t.inuse = inuse; + + if (parameters) + { + t.parameters = parameters.copy(); + for (size_t i = 0; i < parameters.dim; i++) + { + Argument arg = cast(Argument)parameters.data[i]; + Argument cpy = arg.clone(); + t.parameters.data[i] = cast(void*)cpy; + } + } + + return t; + } + + TypeFunction clone() + { + assert(this.classinfo == TypeFunction.classinfo); + return cloneTo(new TypeFunction(null, next, varargs, linkage)); + } +} + Type semantic(Loc loc, Scope sc) + { + if (deco) // if semantic() already run + { + //printf("already done\n"); + return this; + } + //printf("TypeFunction.semantic() this = %p\n", this); + //printf("TypeFunction.semantic() %s, sc.stc = %x\n", toChars(), sc.stc); + + /* Copy in order to not mess up original. + * This can produce redundant copies if inferring return type, + * as semantic() will get called again on this. + */ + + TypeFunction tf = cast(TypeFunction)clone(); + + if (sc.stc & STC.STCpure) + tf.ispure = true; + if (sc.stc & STC.STCnothrow) + tf.isnothrow = true; + if (sc.stc & STC.STCref) + tf.isref = true; + + tf.linkage = sc.linkage; + if (tf.next) + { + tf.next = tf.next.semantic(loc,sc); + if (tf.next.toBasetype().ty == TY.Tsarray) + { error(loc, "functions cannot return static array %s", tf.next.toChars()); + tf.next = Type.terror; + } + if (tf.next.toBasetype().ty == TY.Tfunction) + { error(loc, "functions cannot return a function"); + tf.next = Type.terror; + } + if (tf.next.toBasetype().ty == TY.Ttuple) + { error(loc, "functions cannot return a tuple"); + tf.next = Type.terror; + } + if (tf.next.isauto() && !(sc.flags & SCOPE.SCOPEctor)) + error(loc, "functions cannot return scope %s", tf.next.toChars()); + } + + if (tf.parameters) + { size_t dim = Argument.dim(tf.parameters); + + for (size_t i = 0; i < dim; i++) + { Argument arg = Argument.getNth(tf.parameters, i); + + tf.inuse++; + arg.type = arg.type.semantic(loc,sc); + if (tf.inuse == 1) tf.inuse--; + + arg.type = arg.type.addStorageClass(arg.storageClass); + + if (arg.storageClass & (STC.STCauto | STC.STCalias | STC.STCstatic)) + { + if (!arg.type) + continue; + } + + Type t = arg.type.toBasetype(); + + if (arg.storageClass & (STC.STCout | STC.STCref | STC.STClazy)) + { + if (t.ty == TY.Tsarray) + error(loc, "cannot have out or ref parameter of type %s", t.toChars()); + if (arg.storageClass & STC.STCout && arg.type.mod) + error(loc, "cannot have const/invariant out parameter of type %s", t.toChars()); + } + if (!(arg.storageClass & STC.STClazy) && t.ty == TY.Tvoid) + error(loc, "cannot have parameter of type %s", arg.type.toChars()); + + if (arg.defaultArg) + { + arg.defaultArg = arg.defaultArg.semantic(sc); + arg.defaultArg = resolveProperties(sc, arg.defaultArg); + arg.defaultArg = arg.defaultArg.implicitCastTo(sc, arg.type); + } + + /* If arg turns out to be a tuple, the number of parameters may + * change. + */ + if (t.ty == TY.Ttuple) + { dim = Argument.dim(tf.parameters); + i--; + } + } + } + if (tf.next) + tf.deco = tf.merge().deco; + + if (tf.inuse) + { error(loc, "recursive type"); + tf.inuse = 0; + return terror; + } + + if (tf.varargs == 1 && tf.linkage != LINK.LINKd && Argument.dim(tf.parameters) == 0) + error(loc, "variadic functions with non-D linkage must have at least one parameter"); + + /* Don't return merge(), because arg identifiers and default args + * can be different + * even though the types match + */ + return tf; + } + + void toDecoBuffer(OutBuffer buf, int flag) + { + ubyte mc; + + //printf("TypeFunction.toDecoBuffer() this = %p %s\n", this, toChars()); + //static int nest; if (++nest == 50) *(char*)0=0; + if (inuse) + { + inuse = 2; // flag error to caller + return; + } + inuse++; +static if (true) { + if (mod & MOD.MODshared) + buf.writeByte('O'); + if (mod & MOD.MODconst) + buf.writeByte('x'); + else if (mod & MOD.MODinvariant) + buf.writeByte('y'); +} + switch (linkage) + { + case LINK.LINKd: mc = 'F'; break; + case LINK.LINKc: mc = 'U'; break; + case LINK.LINKwindows: mc = 'W'; break; + case LINK.LINKpascal: mc = 'V'; break; + case LINK.LINKcpp: mc = 'R'; break; + } + buf.writeByte(mc); + if (ispure || isnothrow || isproperty || isref) + { + if (ispure) + buf.writestring("Na"); + if (isnothrow) + buf.writestring("Nb"); + if (isref) + buf.writestring("Nc"); + if (isproperty) + buf.writestring("Nd"); + } + // Write argument types + Argument.argsToDecoBuffer(buf, parameters); + //if (buf.data[buf.offset - 1] == '@') halt(); + buf.writeByte('Z' - varargs); // mark end of arg list + next.toDecoBuffer(buf); + inuse--; + } + + void toCBuffer(OutBuffer buf, Identifier ident, HdrGenState* hgs) + { + //printf("TypeFunction.toCBuffer() this = %p\n", this); + string p = null; + + if (inuse) + { + inuse = 2; // flag error to caller + return; + } + inuse++; + + /* Use 'storage class' style for attributes + */ + if (mod & MODconst) + buf.writestring("const "); + if (mod & MODinvariant) + buf.writestring("immutable "); + if (mod & MODshared) + buf.writestring("shared "); + + if (ispure) + buf.writestring("pure "); + if (isnothrow) + buf.writestring("nothrow "); + if (isproperty) + buf.writestring("@property "); + if (isref) + buf.writestring("ref "); + + if (next && (!ident || ident.toHChars2() == ident.toChars())) + next.toCBuffer2(buf, hgs, MODundefined); + if (hgs.ddoc != 1) + { + switch (linkage) + { + case LINKd: p = null; break; + case LINKc: p = "C "; break; + case LINKwindows: p = "Windows "; break; + case LINKpascal: p = "Pascal "; break; + case LINKcpp: p = "C++ "; break; + default: + assert(0); + } + } + + if (!hgs.hdrgen && p) + buf.writestring(p); + if (ident) + { + buf.writeByte(' '); + buf.writestring(ident.toHChars2()); + } + Argument.argsToCBuffer(buf, hgs, parameters, varargs); + inuse--; + } + + void toCBuffer2(OutBuffer buf, HdrGenState* hgs, MOD mod) + { + //printf("TypeFunction::toCBuffer2() this = %p, ref = %d\n", this, isref); + string p; + + if (inuse) + { + inuse = 2; // flag error to caller + return; + } + + inuse++; + if (next) + next.toCBuffer2(buf, hgs, MODundefined); + + if (hgs.ddoc != 1) + { + switch (linkage) + { + case LINKd: p = null; break; + case LINKc: p = "C "; break; + case LINKwindows: p = "Windows "; break; + case LINKpascal: p = "Pascal "; break; + case LINKcpp: p = "C++ "; break; + default: assert(0); + } + } + + if (!hgs.hdrgen && p) + buf.writestring(p); + buf.writestring(" function"); + Argument.argsToCBuffer(buf, hgs, parameters, varargs); + + /* Use postfix style for attributes + */ + if (mod != this.mod) + { + modToBuffer(buf); + } + + if (ispure) + buf.writestring(" pure"); + if (isnothrow) + buf.writestring(" nothrow"); + if (isproperty) + buf.writestring(" @property"); + if (isref) + buf.writestring(" ref"); + + inuse--; + } + + MATCH deduceType(Scope sc, Type tparam, TemplateParameters parameters, Objects dedtypes) + { + assert(false); + } + + TypeInfoDeclaration getTypeInfoDeclaration() + { + assert(false); + } + + Type reliesOnTident() + { + if (parameters) + { + for (size_t i = 0; i < parameters.dim; i++) + { + Argument arg = cast(Argument)parameters.data[i]; + Type t = arg.type.reliesOnTident(); + if (t) + return t; + } + } + return next.reliesOnTident(); + } + +version (CPP_MANGLE) { + void toCppMangle(OutBuffer buf, CppMangleState* cms) + { + assert(false); + } +} + + /*************************** + * Examine function signature for parameter p and see if + * p can 'escape' the scope of the function. + */ + bool parameterEscapes(Argument p) + { + /* Scope parameters do not escape. + * Allow 'lazy' to imply 'scope' - + * lazy parameters can be passed along + * as lazy parameters to the next function, but that isn't + * escaping. + */ + if (p.storageClass & (STC.STCscope | STC.STClazy)) + return false; + + if (ispure) + { /* With pure functions, we need only be concerned if p escapes + * via any return statement. + */ + Type tret = nextOf().toBasetype(); + if (!isref && !tret.hasPointers()) + { /* The result has no references, so p could not be escaping + * that way. + */ + return false; + } + } + + /* Assume it escapes in the absence of better information. + */ + return true; + } + + /******************************** + * 'args' are being matched to function 'this' + * Determine match level. + * Returns: + * MATCHxxxx + */ + MATCH callMatch(Expression ethis, Expressions args) + { + //printf("TypeFunction.callMatch() %s\n", toChars()); + MATCH match = MATCH.MATCHexact; // assume exact match + + if (ethis) + { + Type t = ethis.type; + if (t.toBasetype().ty == TY.Tpointer) + t = t.toBasetype().nextOf(); // change struct* to struct + + if (t.mod != mod) + { + if (mod == MOD.MODconst) + match = MATCH.MATCHconst; + else + return MATCH.MATCHnomatch; + } + } + + size_t nparams = Argument.dim(parameters); + size_t nargs = args ? args.dim : 0; + if (nparams == nargs) { + ; + } else if (nargs > nparams) + { + if (varargs == 0) + goto Nomatch; // too many args; no match + match = MATCH.MATCHconvert; // match ... with a "conversion" match level + } + + for (size_t u = 0; u < nparams; u++) + { + MATCH m; + Expression arg; + + // BUG: what about out and ref? + + Argument p = Argument.getNth(parameters, u); + assert(p); + if (u >= nargs) + { + if (p.defaultArg) + continue; + if (varargs == 2 && u + 1 == nparams) + goto L1; + goto Nomatch; // not enough arguments + } + + arg = cast(Expression)args.data[u]; + assert(arg); + + // Non-lvalues do not match ref or out parameters + if (p.storageClass & (STC.STCref | STC.STCout) && !arg.isLvalue()) + goto Nomatch; + + if (p.storageClass & STC.STClazy && p.type.ty == TY.Tvoid && arg.type.ty != TY.Tvoid) + m = MATCH.MATCHconvert; + else + m = arg.implicitConvTo(p.type); + //printf("\tm = %d\n", m); + if (m == MATCH.MATCHnomatch) // if no match + { + L1: + if (varargs == 2 && u + 1 == nparams) // if last varargs param + { + Type tb = p.type.toBasetype(); + TypeSArray tsa; + long sz; + + switch (tb.ty) + { + case TY.Tsarray: + tsa = cast(TypeSArray)tb; + sz = tsa.dim.toInteger(); + if (sz != nargs - u) + goto Nomatch; + case TY.Tarray: + { + TypeArray ta = cast(TypeArray)tb; + for (; u < nargs; u++) + { + arg = cast(Expression)args.data[u]; + assert(arg); +static if (true) { + /* If lazy array of delegates, + * convert arg(s) to delegate(s) + */ + Type tret = p.isLazyArray(); + if (tret) + { + if (ta.next.equals(arg.type)) + { + m = MATCH.MATCHexact; + } + else + { + m = arg.implicitConvTo(tret); + if (m == MATCH.MATCHnomatch) + { + if (tret.toBasetype().ty == TY.Tvoid) + m = MATCH.MATCHconvert; + } + } + } + else + m = arg.implicitConvTo(ta.next); +} else { + m = arg.implicitConvTo(ta.next); +} + if (m == MATCH.MATCHnomatch) + goto Nomatch; + + if (m < match) + match = m; + } + goto Ldone; + } + + case TY.Tclass: + // Should see if there's a constructor match? + // Or just leave it ambiguous? + goto Ldone; + + default: + goto Nomatch; + } + } + + goto Nomatch; + } + + if (m < match) + match = m; // pick worst match + } + + Ldone: + //printf("match = %d\n", match); + return match; + + Nomatch: + //printf("no match\n"); + return MATCH.MATCHnomatch; + } + + type* toCtype() + { + if (ctype) { + return ctype; + } + + type* t; + if (true) + { + param_t* paramtypes; + tym_t tyf; + type* tp; + + paramtypes = null; + size_t nparams = Argument.dim(parameters); + for (size_t i = 0; i < nparams; i++) + { + Argument arg = Argument.getNth(parameters, i); + tp = arg.type.toCtype(); + if (arg.storageClass & (STC.STCout | STC.STCref)) + { + // C doesn't have reference types, so it's really a pointer + // to the parameter type + tp = type_allocn(TYM.TYref, tp); + } + param_append_type(¶mtypes,tp); + } + tyf = totym(); + t = type_alloc(tyf); + t.Tflags |= TF.TFprototype; + if (varargs != 1) + t.Tflags |= TF.TFfixed; + ctype = t; + t.Tnext = next.toCtype(); + t.Tnext.Tcount++; + t.Tparamtypes = paramtypes; + } + ctype = t; + return t; + } + + /*************************** + * Determine return style of function - whether in registers or + * through a hidden pointer to the caller's stack. + */ + RET retStyle() + { + //printf("TypeFunction.retStyle() %s\n", toChars()); +version (DMDV2) { + if (isref) + return RET.RETregs; // returns a pointer +} + + Type tn = next.toBasetype(); + + if (tn.ty == TY.Tstruct) + { + StructDeclaration sd = (cast(TypeStruct)tn).sym; + if (global.params.isLinux && linkage != LINK.LINKd) { + ; + } +///version (DMDV2) { + else if (sd.dtor || sd.cpctor) { + ; + } +///} + else + { + switch (cast(int)tn.size()) + { + case 1: + case 2: + case 4: + case 8: + return RET.RETregs; // return small structs in regs + // (not 3 byte structs!) + default: + break; + } + } + return RET.RETstack; + } + else if ((global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isSolaris) && + linkage == LINK.LINKc && + tn.iscomplex()) + { + if (tn.ty == TY.Tcomplex32) + return RET.RETregs; // in EDX:EAX, not ST1:ST0 + else + return RET.RETstack; + } + else + return RET.RETregs; + } + + TYM totym() + { + TYM tyf; + + //printf("TypeFunction.totym(), linkage = %d\n", linkage); + switch (linkage) + { + case LINK.LINKwindows: + tyf = (varargs == 1) ? TYM.TYnfunc : TYM.TYnsfunc; + break; + + case LINK.LINKpascal: + tyf = (varargs == 1) ? TYM.TYnfunc : TYM.TYnpfunc; + break; + + case LINK.LINKc: + tyf = TYM.TYnfunc; + version (XXX) {///TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS + if (retStyle() == RET.RETstack) + tyf = TYM.TYhfunc; + } + break; + + case LINK.LINKd: + tyf = (varargs == 1) ? TYM.TYnfunc : TYM.TYjfunc; + break; + + case LINK.LINKcpp: + tyf = TYM.TYnfunc; + break; + + default: + writef("linkage = %d\n", linkage); + assert(0); + } + version (DMDV2) { + if (isnothrow) + tyf |= mTY.mTYnothrow; + } + return tyf; + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TypeIdentifier.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeIdentifier.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,180 @@ +module dmd.TypeIdentifier; + +import dmd.TypeQualified; +import dmd.MOD; +import dmd.Identifier; +import dmd.IdentifierExp; +import dmd.DotIdExp; +import dmd.TypeTypedef; +import dmd.Loc; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Expression; +import dmd.Scope; +import dmd.Type; +import dmd.Dsymbol; +import dmd.MATCH; +import dmd.ArrayTypes; +import dmd.TY; +import dmd.Util; + +debug import dmd.Global; + +class TypeIdentifier : TypeQualified +{ + Identifier ident; + + this(Loc loc, Identifier ident) + { + super(TY.Tident, loc); + this.ident = ident; + } + +version (DumbClone) { +} else { + Type clone() + { + assert(false); + } +} + Type syntaxCopy() + { + TypeIdentifier t = new TypeIdentifier(loc, ident); + t.syntaxCopyHelper(this); + t.mod = mod; + + return t; + } + + //char *toChars(); + + void toDecoBuffer(OutBuffer buf, int flag) + { + Type.toDecoBuffer(buf, flag); + string name = ident.toChars(); + buf.printf("%d%s", name.length, name); + } + + void toCBuffer2(OutBuffer buf, HdrGenState* hgs, MOD mod) + { + if (mod != this.mod) + { + toCBuffer3(buf, hgs, mod); + return; + } + buf.writestring(this.ident.toChars()); + toCBuffer2Helper(buf, hgs); + } + + /************************************* + * Takes an array of Identifiers and figures out if + * it represents a Type or an Expression. + * Output: + * if expression, *pe is set + * if type, *pt is set + */ + void resolve(Loc loc, Scope sc, Expression* pe, Type* pt, Dsymbol* ps) + { + Dsymbol scopesym; + + //printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, toChars()); + Dsymbol s = sc.search(loc, ident, &scopesym); + resolveHelper(loc, sc, s, scopesym, pe, pt, ps); + if (*pt) + (*pt) = (*pt).addMod(mod); + } + + /***************************************** + * See if type resolves to a symbol, if so, + * return that symbol. + */ + Dsymbol toDsymbol(Scope sc) + { + //printf("TypeIdentifier::toDsymbol('%s')\n", toChars()); + if (!sc) + return null; + //printf("ident = '%s'\n", ident.toChars()); + + Dsymbol scopesym; + Dsymbol s = sc.search(loc, ident, &scopesym); + if (s) + { + for (int i = 0; i < idents.dim; i++) + { + Identifier id = cast(Identifier)idents.data[i]; + s = s.searchX(loc, sc, id); + if (!s) // failed to find a symbol + { + //printf("\tdidn't find a symbol\n"); + break; + } + } + } + + return s; + } + + Type semantic(Loc loc, Scope sc) + { + Type t; + Expression e; + Dsymbol s; + + //printf("TypeIdentifier::semantic(%s)\n", toChars()); + resolve(loc, sc, &e, &t, &s); + if (t) + { + //printf("\tit's a type %d, %s, %s\n", t.ty, t.toChars(), t.deco); + + if (t.ty == TY.Ttypedef) + { + TypeTypedef tt = cast(TypeTypedef)t; + + if (tt.sym.sem == 1) + error(loc, "circular reference of typedef %s", tt.toChars()); + } + t = t.addMod(mod); + } + else + { +debug { + if (!global.gag) { + writef("1: "); + } +} + if (s) + { + s.error(loc, "is used as a type"); + //halt(); + } + else { + error(loc, "%s is used as a type", toChars()); + } + t = tvoid; + } + //t.print(); + return t; + } + + MATCH deduceType(Scope sc, Type tparam, TemplateParameters parameters, Objects dedtypes) + { + assert(false); + } + + Type reliesOnTident() + { + return this; + } + + Expression toExpression() + { + Expression e = new IdentifierExp(loc, ident); + for (int i = 0; i < idents.dim; i++) + { + Identifier id = cast(Identifier)idents.data[i]; + e = new DotIdExp(loc, e, id); + } + + return e; + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TypeInfoArrayDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeInfoArrayDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,34 @@ +module dmd.TypeInfoArrayDeclaration; + +import dmd.Type; +import dmd.TypeInfoDeclaration; +import dmd.Type; +import dmd.TY; +import dmd.TypeDArray; + +import dmd.backend.dt_t; +import dmd.backend.Util; +import dmd.backend.TYM; + +class TypeInfoArrayDeclaration : TypeInfoDeclaration +{ + this(Type tinfo) + { + super(tinfo, 0); + } + + void toDt(dt_t** pdt) + { + //printf("TypeInfoArrayDeclaration::toDt()\n"); + dtxoff(pdt, Type.typeinfoarray.toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfo_Array + dtdword(pdt, 0); // monitor + + assert(tinfo.ty == Tarray); + + TypeDArray tc = cast(TypeDArray)tinfo; + + tc.next.getTypeInfo(null); + dtxoff(pdt, tc.next.vtinfo.toSymbol(), 0, TYnptr); // TypeInfo for array of type + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/TypeInfoClassDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeInfoClassDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,40 @@ +module dmd.TypeInfoClassDeclaration; + +import dmd.Type; +import dmd.TypeInfoDeclaration; +import dmd.ClassInfoDeclaration; +import dmd.TypeClass; +import dmd.TY; +import dmd.Util; +import dmd.backend.dt_t; +import dmd.backend.Util; +import dmd.backend.TYM; +import dmd.backend.Symbol; + +class TypeInfoClassDeclaration : TypeInfoDeclaration +{ + this(Type tinfo) + { + super(tinfo, 0); + } + + void toDt(dt_t** pdt) + { + //printf("TypeInfoClassDeclaration::toDt() %s\n", tinfo->toChars()); + dtxoff(pdt, Type.typeinfoclass.toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfoClass + dtdword(pdt, 0); // monitor + + assert(tinfo.ty == Tclass); + + TypeClass tc = cast(TypeClass)tinfo; + + if (!tc.sym.vclassinfo) + tc.sym.vclassinfo = new ClassInfoDeclaration(tc.sym); + + Symbol* s = tc.sym.vclassinfo.toSymbol(); + assert(s.Sxtrnnum == 0); + + dtxoff(pdt, s, 0, TYnptr); // ClassInfo for tinfo + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/TypeInfoConstDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeInfoConstDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,28 @@ +module dmd.TypeInfoConstDeclaration; + +import dmd.Type; +import dmd.TypeInfoDeclaration; +import dmd.Type; +import dmd.backend.dt_t; +import dmd.backend.Util; +import dmd.backend.TYM; + +class TypeInfoConstDeclaration : TypeInfoDeclaration +{ + this(Type tinfo) + { + super(tinfo, 0); + } + + void toDt(dt_t** pdt) + { + //printf("TypeInfoConstDeclaration.toDt() %s\n", toChars()); + dtxoff(pdt, Type.typeinfoconst.toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfo_Const + dtdword(pdt, 0); // monitor + Type tm = tinfo.mutableOf(); + tm = tm.merge(); + tm.getTypeInfo(null); + dtxoff(pdt, tm.vtinfo.toSymbol(), 0, TYnptr); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/TypeInfoDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeInfoDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,114 @@ +module dmd.TypeInfoDeclaration; + +import dmd.VarDeclaration; +import dmd.Type; +import dmd.Dsymbol; +import dmd.Scope; +import dmd.Loc; +import dmd.STC; +import dmd.PROT; +import dmd.LINK; + +import dmd.backend.Symbol; +import dmd.backend.dt_t; +import dmd.backend.DT; +import dmd.backend.SC; +import dmd.backend.FL; +import dmd.backend.glue; +import dmd.backend.Util; +import dmd.backend.TYPE; + +import core.stdc.stdio; + +class TypeInfoDeclaration : VarDeclaration +{ + Type tinfo; + + this(Type tinfo, int internal) + { + super(Loc(0), Type.typeinfo.type, tinfo.getTypeInfoIdent(internal), null); + this.tinfo = tinfo; + storage_class = STC.STCstatic | STC.STCgshared; + protection = PROT.PROTpublic; + linkage = LINK.LINKc; + } + +version (DumbClone) { +} else { + Type clone() + { + assert(false); + } +} + Dsymbol syntaxCopy(Dsymbol) + { + assert(false); + } + + void semantic(Scope sc) + { + assert(false); + } + + void emitComment(Scope sc) + { + assert(false); + } + + Symbol* toSymbol() + { + //printf("TypeInfoDeclaration::toSymbol(%s), linkage = %d\n", toChars(), linkage); + return VarDeclaration.toSymbol(); + } + + void toObjFile(int multiobj) // compile to .obj file + { + Symbol* s; + uint sz; + Dsymbol parent; + + //printf("TypeInfoDeclaration.toObjFile(%p '%s') protection %d\n", this, toChars(), protection); + + if (multiobj) + { + obj_append(this); + return; + } + + s = toSymbol(); + sz = cast(uint)type.size(); + + parent = this.toParent(); + s.Sclass = SC.SCcomdat; + s.Sfl = FL.FLdata; + + toDt(&s.Sdt); + + dt_optimize(s.Sdt); + + // See if we can convert a comdat to a comdef, + // which saves on exe file space. + if (s.Sclass == SC.SCcomdat && + s.Sdt.dt == DT.DT_azeros && + s.Sdt.DTnext == null) + { + s.Sclass = SC.SCglobal; + s.Sdt.dt = DT.DT_common; + } + +version (XXX) { ///ELFOBJ || MACHOBJ // Burton + if (s.Sdt && s.Sdt.dt == DT_azeros && s.Sdt.DTnext == null) + s.Sseg = Segment.UDATA; + else + s.Sseg = Segment.DATA; +} + outdata(s); + if (isExport()) + obj_export(s,0); + } + + void toDt(dt_t** pdt) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TypeInfoDelegateDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeInfoDelegateDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,33 @@ +module dmd.TypeInfoDelegateDeclaration; + +import dmd.Type; +import dmd.TypeInfoDeclaration; +import dmd.TypeDelegate; +import dmd.TY; + +import dmd.backend.dt_t; +import dmd.backend.Util; +import dmd.backend.TYM; + +class TypeInfoDelegateDeclaration : TypeInfoDeclaration +{ + this(Type tinfo) + { + super(tinfo, 0); + } + + void toDt(dt_t** pdt) + { + //printf("TypeInfoDelegateDeclaration.toDt()\n"); + dtxoff(pdt, Type.typeinfodelegate.toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfo_Delegate + dtdword(pdt, 0); // monitor + + assert(tinfo.ty == Tdelegate); + + TypeDelegate tc = cast(TypeDelegate)tinfo; + + tc.next.nextOf().getTypeInfo(null); + dtxoff(pdt, tc.next.nextOf().vtinfo.toSymbol(), 0, TYnptr); // TypeInfo for delegate return value + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/TypeInfoEnumDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeInfoEnumDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,66 @@ +module dmd.TypeInfoEnumDeclaration; + +import dmd.TY; +import dmd.Type; +import dmd.Loc; +import dmd.TypeEnum; +import dmd.EnumDeclaration; +import dmd.TypeInfoDeclaration; +import dmd.backend.dt_t; +import dmd.backend.Util; +import dmd.backend.TYM; + +import std.string : toStringz; + +class TypeInfoEnumDeclaration : TypeInfoDeclaration +{ + this(Type tinfo) + { + super(tinfo, 0); + } + + void toDt(dt_t** pdt) + { + //printf("TypeInfoEnumDeclaration::toDt()\n"); + dtxoff(pdt, Type.typeinfoenum.toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfo_Enum + dtdword(pdt, 0); // monitor + + assert(tinfo.ty == Tenum); + + TypeEnum tc = cast(TypeEnum)tinfo; + EnumDeclaration sd = tc.sym; + + /* Put out: + * TypeInfo base; + * char[] name; + * void[] m_init; + */ + + if (sd.memtype) + { + sd.memtype.getTypeInfo(null); + dtxoff(pdt, sd.memtype.vtinfo.toSymbol(), 0, TYnptr); // TypeInfo for enum members + } + else + dtdword(pdt, 0); + + string name = sd.toPrettyChars(); + size_t namelen = name.length; + dtdword(pdt, namelen); + dtabytes(pdt, TYnptr, 0, namelen + 1, toStringz(name)); + + // void[] init; + if (!sd.defaultval || tinfo.isZeroInit(Loc(0))) + { + // 0 initializer, or the same as the base type + dtdword(pdt, 0); // init.length + dtdword(pdt, 0); // init.ptr + } + else + { + dtdword(pdt, cast(int)sd.type.size()); // init.length + dtxoff(pdt, sd.toInitializer(), 0, TYnptr); // init.ptr + } + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/TypeInfoInterfaceDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeInfoInterfaceDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,38 @@ +module dmd.TypeInfoInterfaceDeclaration; + +import dmd.Type; +import dmd.TypeInfoDeclaration; +import dmd.ClassInfoDeclaration; +import dmd.TypeClass; +import dmd.TY; + +import dmd.backend.dt_t; +import dmd.backend.Symbol; +import dmd.backend.Util; +import dmd.backend.TYM; + +class TypeInfoInterfaceDeclaration : TypeInfoDeclaration +{ + this(Type tinfo) + { + super(tinfo, 0); + } + + void toDt(dt_t** pdt) + { + //printf("TypeInfoInterfaceDeclaration.toDt() %s\n", tinfo.toChars()); + dtxoff(pdt, Type.typeinfointerface.toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfoInterface + dtdword(pdt, 0); // monitor + + assert(tinfo.ty == Tclass); + + TypeClass tc = cast(TypeClass)tinfo; + Symbol *s; + + if (!tc.sym.vclassinfo) + tc.sym.vclassinfo = new ClassInfoDeclaration(tc.sym); + s = tc.sym.vclassinfo.toSymbol(); + dtxoff(pdt, s, 0, TYnptr); // ClassInfo for tinfo + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/TypeInfoInvariantDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeInfoInvariantDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,27 @@ +module dmd.TypeInfoInvariantDeclaration; + +import dmd.Type; +import dmd.TypeInfoDeclaration; +import dmd.backend.dt_t; +import dmd.backend.Util; +import dmd.backend.TYM; + +class TypeInfoInvariantDeclaration : TypeInfoDeclaration +{ + this(Type tinfo) + { + super(tinfo, 0); + } + + void toDt(dt_t** pdt) + { + //printf("TypeInfoInvariantDeclaration.toDt() %s\n", toChars()); + dtxoff(pdt, Type.typeinfoinvariant.toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfo_Invariant + dtdword(pdt, 0); // monitor + Type tm = tinfo.mutableOf(); + tm = tm.merge(); + tm.getTypeInfo(null); + dtxoff(pdt, tm.vtinfo.toSymbol(), 0, TYnptr); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/TypeInfoPointerDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeInfoPointerDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,32 @@ +module dmd.TypeInfoPointerDeclaration; + +import dmd.Type; +import dmd.TypeInfoDeclaration; +import dmd.TypePointer; +import dmd.TY; +import dmd.backend.dt_t; +import dmd.backend.Util; +import dmd.backend.TYM; + +class TypeInfoPointerDeclaration : TypeInfoDeclaration +{ + this(Type tinfo) + { + super(tinfo, 0); + } + + void toDt(dt_t** pdt) + { + //printf("TypeInfoPointerDeclaration::toDt()\n"); + dtxoff(pdt, Type.typeinfopointer.toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfo_Pointer + dtdword(pdt, 0); // monitor + + assert(tinfo.ty == Tpointer); + + TypePointer tc = cast(TypePointer)tinfo; + + tc.next.getTypeInfo(null); + dtxoff(pdt, tc.next.vtinfo.toSymbol(), 0, TYnptr); // TypeInfo for type being pointed to + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/TypeInfoSharedDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeInfoSharedDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,20 @@ +module dmd.TypeInfoSharedDeclaration; + +import dmd.Type; +import dmd.TypeInfoDeclaration; +import dmd.backend.dt_t; + +class TypeInfoSharedDeclaration : TypeInfoDeclaration +{ + this(Type tinfo) + { + assert(false); + super(tinfo, 0); + } + + void toDt(dt_t** pdt) + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/TypeInfoStructDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeInfoStructDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,229 @@ +module dmd.TypeInfoStructDeclaration; + +import dmd.Type; +import dmd.TY; +import dmd.MOD; +import dmd.Loc; +import dmd.Argument; +import dmd.STC; +import dmd.TypeStruct; +import dmd.TypeFunction; +import dmd.StructDeclaration; +import dmd.FuncDeclaration; +import dmd.Dsymbol; +import dmd.ArrayTypes; +import dmd.Scope; +import dmd.LINK; +import dmd.Id; +import dmd.TypeInfoDeclaration; +import dmd.backend.dt_t; +import dmd.backend.TYM; +import dmd.backend.Util; +import dmd.expression.Util; + +import std.string : toStringz; + +class TypeInfoStructDeclaration : TypeInfoDeclaration +{ + this(Type tinfo) + { + super(tinfo, 0); + } + + void toDt(dt_t** pdt) + { + //printf("TypeInfoStructDeclaration.toDt() '%s'\n", toChars()); + + uint offset = Type.typeinfostruct.structsize; + + dtxoff(pdt, Type.typeinfostruct.toVtblSymbol(), 0, TYM.TYnptr); // vtbl for TypeInfo_Struct + dtdword(pdt, 0); // monitor + + assert(tinfo.ty == TY.Tstruct); + + TypeStruct tc = cast(TypeStruct)tinfo; + StructDeclaration sd = tc.sym; + + /* Put out: + * char[] name; + * void[] init; + * hash_t function(in void*) xtoHash; + * bool function(in void*, in void*) xopEquals; + * int function(in void*, in void*) xopCmp; + * string function(const(void)*) xtoString; + * uint m_flags; + * xgetMembers; + * xdtor; + * xpostblit; + * + * name[] + */ + + string name = sd.toPrettyChars(); + size_t namelen = name.length; + dtdword(pdt, namelen); + + //dtabytes(pdt, TYnptr, 0, namelen + 1, name); + dtxoff(pdt, toSymbol(), offset, TYM.TYnptr); + offset += namelen + 1; + + // void[] init; + dtdword(pdt, sd.structsize); // init.length + if (sd.zeroInit) + dtdword(pdt, 0); // null for 0 initialization + else + dtxoff(pdt, sd.toInitializer(), 0, TYM.TYnptr); // init.ptr + FuncDeclaration fd; + FuncDeclaration fdx; + TypeFunction tf; + Type ta; + Dsymbol s; + + static TypeFunction tftohash; + static TypeFunction tftostring; + + if (!tftohash) + { + scope Scope sc = new Scope(); + + tftohash = new TypeFunction(null, Type.thash_t, 0, LINK.LINKd); + tftohash.mod = MOD.MODconst; + tftohash = cast(TypeFunction)tftohash.semantic(Loc(0), sc); + + tftostring = new TypeFunction(null, Type.tchar.invariantOf().arrayOf(), 0, LINK.LINKd); + tftostring = cast(TypeFunction)tftostring.semantic(Loc(0), sc); + } + + TypeFunction tfeqptr; + { + // bool opEqual(const T*) const; + scope Scope sc = new Scope(); + Arguments arguments = new Arguments; + version (STRUCTTHISREF) { + // arg type is ref const T + Argument arg = new Argument(STC.STCref, tc.constOf(), null, null); + } else { + // arg type is const T* + Argument arg = new Argument(STC.STCin, tc.pointerTo(), null, null); + } + + arguments.push(cast(void*)arg); + tfeqptr = new TypeFunction(arguments, Type.tbool, 0, LINK.LINKd); + tfeqptr.mod = MOD.MODconst; + tfeqptr = cast(TypeFunction)tfeqptr.semantic(Loc(0), sc); + } + + TypeFunction tfcmpptr; + { + scope Scope sc = new Scope(); + Arguments arguments = new Arguments; + version (STRUCTTHISREF) { + // arg type is ref const T + Argument arg = new Argument(STC.STCref, tc.constOf(), null, null); + } else { + // arg type is const T* + Argument arg = new Argument(STC.STCin, tc.pointerTo(), null, null); + } + + arguments.push(cast(void*)arg); + tfcmpptr = new TypeFunction(arguments, Type.tint32, 0, LINK.LINKd); + tfcmpptr.mod = MOD.MODconst; + tfcmpptr = cast(TypeFunction)tfcmpptr.semantic(Loc(0), sc); + } + + s = search_function(sd, Id.tohash); + fdx = s ? s.isFuncDeclaration() : null; + if (fdx) + { + fd = fdx.overloadExactMatch(tftohash); + if (fd) + dtxoff(pdt, fd.toSymbol(), 0, TYM.TYnptr); + else + //fdx.error("must be declared as extern (D) uint toHash()"); + dtdword(pdt, 0); + } + else + dtdword(pdt, 0); + + s = search_function(sd, Id.eq); + fdx = s ? s.isFuncDeclaration() : null; + if (fdx) + { + //printf("test1 %s, %s, %s\n", fdx.toChars(), fdx.type.toChars(), tfeqptr.toChars()); + fd = fdx.overloadExactMatch(tfeqptr); + if (fd) + dtxoff(pdt, fd.toSymbol(), 0, TYM.TYnptr); + else + { + fd = fdx.overloadExactMatch(tfcmpptr); + if (fd) + fdx.error("must return bool, not int"); + //fdx.error("must be declared as extern (D) int %s(%s*)", fdx.toChars(), sd.toChars()); + dtdword(pdt, 0); + } + } + else + dtdword(pdt, 0); + + s = search_function(sd, Id.cmp); + fdx = s ? s.isFuncDeclaration() : null; + if (fdx) + { + //printf("test1 %s, %s, %s\n", fdx.toChars(), fdx.type.toChars(), tfeqptr.toChars()); + fd = fdx.overloadExactMatch(tfcmpptr); + if (fd) + { + dtxoff(pdt, fd.toSymbol(), 0, TYM.TYnptr); + //printf("test2\n"); + } + else + //fdx.error("must be declared as extern (D) int %s(%s*)", fdx.toChars(), sd.toChars()); + dtdword(pdt, 0); + } + else + dtdword(pdt, 0); + + s = search_function(sd, Id.tostring); + fdx = s ? s.isFuncDeclaration() : null; + if (fdx) + { + fd = fdx.overloadExactMatch(tftostring); + if (fd) + dtxoff(pdt, fd.toSymbol(), 0, TYM.TYnptr); + else + //fdx.error("must be declared as extern (D) char[] toString()"); + dtdword(pdt, 0); + } + else + dtdword(pdt, 0); + + // uint m_flags; + dtdword(pdt, tc.hasPointers()); + +version (DMDV2) { + // xgetMembers + FuncDeclaration sgetmembers = sd.findGetMembers(); + if (sgetmembers) + dtxoff(pdt, sgetmembers.toSymbol(), 0, TYM.TYnptr); + else + dtdword(pdt, 0); // xgetMembers + + // xdtor + FuncDeclaration sdtor = sd.dtor; + if (sdtor) + dtxoff(pdt, sdtor.toSymbol(), 0, TYM.TYnptr); + else + dtdword(pdt, 0); // xdtor + + // xpostblit + FuncDeclaration spostblit = sd.postblit; + if (spostblit) + dtxoff(pdt, spostblit.toSymbol(), 0, TYM.TYnptr); + else + dtdword(pdt, 0); // xpostblit +} + // name[] + dtnbytes(pdt, namelen + 1, toStringz(name)); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/TypeInfoTypedefDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeInfoTypedefDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,65 @@ +module dmd.TypeInfoTypedefDeclaration; + +import dmd.Type; +import dmd.TypeInfoDeclaration; +import dmd.TypedefDeclaration; +import dmd.TypeTypedef; +import dmd.TY; +import dmd.Loc; +import dmd.backend.dt_t; +import dmd.backend.TYM; +import dmd.backend.Util; + +import std.string; + +class TypeInfoTypedefDeclaration : TypeInfoDeclaration +{ + this(Type tinfo) + { + super(tinfo, 0); + } + + void toDt(dt_t** pdt) + { + //printf("TypeInfoTypedefDeclaration.toDt() %s\n", toChars()); + + dtxoff(pdt, Type.typeinfotypedef.toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfo_Typedef + dtdword(pdt, 0); // monitor + + assert(tinfo.ty == Ttypedef); + + TypeTypedef tc = cast(TypeTypedef)tinfo; + TypedefDeclaration sd = tc.sym; + //printf("basetype = %s\n", sd.basetype.toChars()); + + /* Put out: + * TypeInfo base; + * char[] name; + * void[] m_init; + */ + + sd.basetype = sd.basetype.merge(); + sd.basetype.getTypeInfo(null); // generate vtinfo + assert(sd.basetype.vtinfo); + dtxoff(pdt, sd.basetype.vtinfo.toSymbol(), 0, TYnptr); // TypeInfo for basetype + + string name = sd.toPrettyChars(); + size_t namelen = name.length; + dtdword(pdt, namelen); + dtabytes(pdt, TYnptr, 0, namelen + 1, toStringz(name)); + + // void[] init; + if (tinfo.isZeroInit(Loc(0)) || !sd.init) + { + // 0 initializer, or the same as the base type + dtdword(pdt, 0); // init.length + dtdword(pdt, 0); // init.ptr + } + else + { + dtdword(pdt, cast(int)sd.type.size()); // init.length + dtxoff(pdt, sd.toInitializer(), 0, TYnptr); // init.ptr + } + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/TypeInstance.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeInstance.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,118 @@ +module dmd.TypeInstance; + +import dmd.TypeQualified; +import dmd.TemplateInstance; +import dmd.MOD; +import dmd.MATCH; +import dmd.Loc; +import dmd.Global; +import dmd.Type; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Dsymbol; +import dmd.Expression; +import dmd.Scope; +import dmd.ArrayTypes; +import dmd.TY; + +/* Similar to TypeIdentifier, but with a TemplateInstance as the root + */ +class TypeInstance : TypeQualified +{ + TemplateInstance tempinst; + + this(Loc loc, TemplateInstance tempinst) + { + super(Tinstance, loc); + this.tempinst = tempinst; + } + +version (DumbClone) { +} else { + Type clone() + { + assert(false); + } +} + + Type syntaxCopy() + { + assert(false); + } + + //char *toChars(); + + //void toDecoBuffer(OutBuffer *buf, int flag); + + void toCBuffer2(OutBuffer buf, HdrGenState* hgs, MOD mod) + { + assert(false); + } + + void resolve(Loc loc, Scope sc, Expression* pe, Type* pt, Dsymbol* ps) + { + // Note close similarity to TypeIdentifier::resolve() + Dsymbol s; + + *pe = null; + *pt = null; + *ps = null; + + static if (false) { + if (!idents.dim) + { + error(loc, "template instance '%s' has no identifier", toChars()); + return; + } + } + //id = (Identifier *)idents.data[0]; + //printf("TypeInstance::resolve(sc = %p, idents = '%s')\n", sc, id->toChars()); + s = tempinst; + if (s) + s.semantic(sc); + resolveHelper(loc, sc, s, null, pe, pt, ps); + if (*pt) + *pt = (*pt).addMod(mod); + //printf("pt = '%s'\n", (*pt)->toChars()); + } + + Type semantic(Loc loc, Scope sc) + { + assert(false); + } + + Dsymbol toDsymbol(Scope sc) + { + Type t; + Expression e; + Dsymbol s; + + //printf("TypeInstance::semantic(%s)\n", toChars()); + + if (sc.parameterSpecialization) + { + uint errors = global.errors; + global.gag++; + + resolve(loc, sc, &e, &t, &s); + + global.gag--; + if (errors != global.errors) + { + if (global.gag == 0) + global.errors = errors; + + return null; + } + } + else + resolve(loc, sc, &e, &t, &s); + + return s; + } + + MATCH deduceType(Scope sc, Type tparam, TemplateParameters parameters, Objects dedtypes) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TypeNext.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeNext.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,137 @@ +module dmd.TypeNext; + +import dmd.Type; +import dmd.TY; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.MATCH; +import dmd.MOD; + +class TypeNext : Type +{ + Type next; + + this(TY ty, Type next) + { + super(ty); + this.next = next; + } +version (DumbClone) { +} else { + final TypeNext cloneTo(TypeNext t) + { + super.cloneTo(t); + return t; + } + + TypeNext clone() + { + assert(this.classinfo == TypeNext.classinfo); + return cloneTo(new TypeNext(ty, next)); + } +} + void toDecoBuffer(OutBuffer buf, int flag) + { + super.toDecoBuffer(buf, flag); + assert(next !is this); + //printf("this = %p, ty = %d, next = %p, ty = %d\n", this, this.ty, next, next.ty); + next.toDecoBuffer(buf, (flag & 0x100) ? 0 : mod); + } + + void checkDeprecated(Loc loc, Scope sc) + { + Type.checkDeprecated(loc, sc); + if (next) // next can be null if TypeFunction and auto return type + next.checkDeprecated(loc, sc); + } + + Type reliesOnTident() + { + return next.reliesOnTident(); + } + + Type nextOf() + { + return next; + } + + Type makeConst() + { + //printf("TypeNext::makeConst() %p, %s\n", this, toChars()); + if (cto) + { + assert(cto.mod == MOD.MODconst); + return cto; + } + + TypeNext t = cast(TypeNext)super.makeConst(); + if (ty != TY.Tfunction && ty != TY.Tdelegate && + (next.deco || next.ty == TY.Tfunction) && + !next.isInvariant() && !next.isConst()) + { + if (next.isShared()) + t.next = next.sharedConstOf(); + else + t.next = next.constOf(); + } + //printf("TypeNext::makeConst() returns %p, %s\n", t, t.toChars()); + return t; + } + + Type makeInvariant() + { + //printf("TypeNext::makeInvariant() %s\n", toChars()); + if (ito) + { + assert(ito.isInvariant()); + return ito; + } + TypeNext t = cast(TypeNext)Type.makeInvariant(); + if (ty != TY.Tfunction && ty != TY.Tdelegate && (next.deco || next.ty == TY.Tfunction) && !next.isInvariant()) + { + t.next = next.invariantOf(); + } + return t; + } + + Type makeShared() + { + //printf("TypeNext::makeShared() %s\n", toChars()); + if (sto) + { + assert(sto.mod == MODshared); + return sto; + } + TypeNext t = cast(TypeNext)Type.makeShared(); + if (ty != Tfunction && ty != Tdelegate && + (next.deco || next.ty == Tfunction) && + !next.isInvariant() && !next.isShared()) + { + if (next.isConst()) + t.next = next.sharedConstOf(); + else + t.next = next.sharedOf(); + } + + //printf("TypeNext::makeShared() returns %p, %s\n", t, t.toChars()); + return t; + } + + Type makeSharedConst() + { + assert(false); + } + + MATCH constConv(Type to) + { + assert(false); + } + + void transitive() + { + /* Invoke transitivity of type attributes + */ + next = next.addMod(mod); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TypePointer.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypePointer.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,200 @@ +module dmd.TypePointer; + +import dmd.Type; +import dmd.Loc; +import dmd.Scope; +import dmd.TypeNext; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.MATCH; +import dmd.Expression; +import dmd.NullExp; +import dmd.TypeInfoDeclaration; +import dmd.TypeInfoPointerDeclaration; +import dmd.CppMangleState; +import dmd.TY; +import dmd.Util; +import dmd.MOD; +import dmd.Global; + +import dmd.backend.TYPE; +import dmd.backend.Util; +import dmd.backend.TYM; + +class TypePointer : TypeNext +{ + this(Type t) + { + super(TY.Tpointer, t); + } +version (DumbClone) { +} else { + final TypePointer cloneTo(TypePointer t) + { + super.cloneTo(t); + return t; + } + + TypePointer clone() + { + assert(this.classinfo == TypePointer.classinfo); + return cloneTo(new TypePointer(next)); + } +} + Type syntaxCopy() + { + Type t = next.syntaxCopy(); + if (t == next) + t = this; + else + { + t = new TypePointer(t); + t.mod = mod; + } + return t; + } + + Type semantic(Loc loc, Scope sc) + { + //printf("TypePointer.semantic()\n"); + if (deco) + return this; + Type n = next.semantic(loc, sc); + switch (n.toBasetype().ty) + { + case TY.Ttuple: + error(loc, "can't have pointer to %s", n.toChars()); + n = tint32; + break; + default: + break; + } + if (n !is next) + { + deco = null; + } + next = n; + transitive(); + return merge(); + } + + ulong size(Loc loc) + { + return PTRSIZE; + } + + void toCBuffer2(OutBuffer buf, HdrGenState* hgs, MOD mod) + { + //printf("TypePointer::toCBuffer2() next = %d\n", next->ty); + if (mod != this.mod) + { + toCBuffer3(buf, hgs, mod); + return; + } + next.toCBuffer2(buf, hgs, this.mod); + if (next.ty != Tfunction) + buf.writeByte('*'); + } + + MATCH implicitConvTo(Type to) + { + //printf("TypePointer.implicitConvTo(to = %s) %s\n", to.toChars(), toChars()); + + if (equals(to)) + return MATCH.MATCHexact; + if (to.ty == TY.Tpointer) + { + TypePointer tp = cast(TypePointer)to; + assert(tp.next); + + if (!(next.mod == tp.next.mod || tp.next.mod == MOD.MODconst)) + return MATCH.MATCHnomatch; // not const-compatible + + /* Alloc conversion to void[] + */ + if (next.ty != TY.Tvoid && tp.next.ty == TY.Tvoid) + { + return MATCH.MATCHconvert; + } + + MATCH m = next.constConv(tp.next); + if (m != MATCH.MATCHnomatch) + { + if (m == MATCH.MATCHexact && mod != to.mod) + m = MATCH.MATCHconst; + return m; + } + + /* Conversion of ptr to derived to ptr to base + */ + int offset = 0; + if (tp.next.isBaseOf(next, &offset) && offset == 0) + return MATCH.MATCHconvert; + } + return MATCH.MATCHnomatch; + } + + bool isscalar() + { + return true; + } + + Expression defaultInit(Loc loc) + { + version (LOGDEFAULTINIT) { + printf("TypePointer::defaultInit() '%s'\n", toChars()); + } + Expression e = new NullExp(loc); + e.type = this; + return e; + } + + bool isZeroInit(Loc loc) + { + return true; + } + + TypeInfoDeclaration getTypeInfoDeclaration() + { + return new TypeInfoPointerDeclaration(this); + } + + bool hasPointers() + { + return true; + } + +version (CPP_MANGLE) { + void toCppMangle(OutBuffer buf, CppMangleState* cms) + { + assert(false); + } +} + + type* toCtype() + { + type* tn; + type* t; + + //printf("TypePointer.toCtype() %s\n", toChars()); + if (ctype) + return ctype; + + if (1 || global.params.symdebug) + { /* Need to always do this, otherwise C++ name mangling + * goes awry. + */ + t = type_alloc(TYM.TYnptr); + ctype = t; + tn = next.toCtype(); + t.Tnext = tn; + tn.Tcount++; + } + else + t = type_fake(totym()); + + t.Tcount++; + ctype = t; + return t; + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TypeQualified.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeQualified.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,271 @@ +module dmd.TypeQualified; + +import dmd.Type; +import dmd.Import; +import dmd.TypeExp; +import dmd.DotIdExp; +import dmd.VarDeclaration; +import dmd.EnumMember; +import dmd.TupleDeclaration; +import dmd.Id; +import dmd.VarExp; +import dmd.TemplateInstance; +import dmd.Loc; +import dmd.Array; +import dmd.TY; +import dmd.Identifier; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Scope; +import dmd.Dsymbol; +import dmd.DYNCAST; +import dmd.Expression; +import dmd.Util; + +class TypeQualified : Type +{ + Loc loc; + Array idents; // array of Identifier's representing ident.ident.ident etc. + + this(TY ty, Loc loc) + { + super(ty); + this.loc = loc; + + idents = new Array(); + } + +version (DumbClone) { +} else { + Type clone() + { + assert(false); + } +} + void syntaxCopyHelper(TypeQualified t) + { + //printf("TypeQualified::syntaxCopyHelper(%s) %s\n", t->toChars(), toChars()); + idents.setDim(t.idents.dim); + for (int i = 0; i < idents.dim; i++) + { + Identifier id = cast(Identifier)t.idents.data[i]; + if (id.dyncast() == DYNCAST.DYNCAST_DSYMBOL) + { + TemplateInstance ti = cast(TemplateInstance)id; + + ti = cast(TemplateInstance)ti.syntaxCopy(null); + id = cast(Identifier)ti; + } + + idents.data[i] = cast(void*)id; + } + } + + void addIdent(Identifier ident) + { + idents.push(cast(void*)ident); + } + + void toCBuffer2Helper(OutBuffer buf, HdrGenState* hgs) + { + int i; + + for (i = 0; i < idents.dim; i++) + { + Identifier id = cast(Identifier)idents.data[i]; + buf.writeByte('.'); + + if (id.dyncast() == DYNCAST.DYNCAST_DSYMBOL) + { + TemplateInstance ti = cast(TemplateInstance)id; + ti.toCBuffer(buf, hgs); + } else { + buf.writestring(id.toChars()); + } + } + } + + ulong size(Loc loc) + { + assert(false); + } + + /************************************* + * Takes an array of Identifiers and figures out if + * it represents a Type or an Expression. + * Output: + * if expression, *pe is set + * if type, *pt is set + */ + void resolveHelper(Loc loc, Scope sc, Dsymbol s, Dsymbol scopesym, Expression* pe, Type* pt, Dsymbol* ps) + { + VarDeclaration v; + EnumMember em; + TupleDeclaration td; + Expression e; + +static if (false) { + printf("TypeQualified.resolveHelper(sc = %p, idents = '%s')\n", sc, toChars()); + if (scopesym) + printf("\tscopesym = '%s'\n", scopesym.toChars()); +} + *pe = null; + *pt = null; + *ps = null; + if (s) + { + //printf("\t1: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind()); + s.checkDeprecated(loc, sc); // check for deprecated aliases + s = s.toAlias(); + //printf("\t2: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind()); + for (int i = 0; i < idents.dim; i++) + { + Identifier id = cast(Identifier)idents.data[i]; + Dsymbol sm = s.searchX(loc, sc, id); + //printf("\t3: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind()); + //printf("\tgetType = '%s'\n", s.getType().toChars()); + if (!sm) + { + Type t; + + v = s.isVarDeclaration(); + if (v && id == Id.length) + { + e = v.getConstInitializer(); + if (!e) + e = new VarExp(loc, v); + t = e.type; + if (!t) + goto Lerror; + goto L3; + } + t = s.getType(); + if (!t && s.isDeclaration()) + t = s.isDeclaration().type; + if (t) + { + sm = t.toDsymbol(sc); + if (sm) + { sm = sm.search(loc, id, 0); + if (sm) + goto L2; + } + //e = t.getProperty(loc, id); + e = new TypeExp(loc, t); + e = t.dotExp(sc, e, id); + i++; + L3: + for (; i < idents.dim; i++) + { + id = cast(Identifier)idents.data[i]; + //printf("e: '%s', id: '%s', type = %p\n", e.toChars(), id.toChars(), e.type); + if (id == Id.offsetof) + { e = new DotIdExp(e.loc, e, id); + e = e.semantic(sc); + } + else + e = e.type.dotExp(sc, e, id); + } + *pe = e; + } + else + Lerror: + error(loc, "identifier '%s' of '%s' is not defined", id.toChars(), toChars()); + return; + } + L2: + s = sm.toAlias(); + } + + v = s.isVarDeclaration(); + if (v) + { +///static if (false) { +/// // It's not a type, it's an expression +/// Expression *e = v.getConstInitializer(); +/// if (e) +/// { +/// *pe = e.copy(); // make copy so we can change loc +/// (*pe).loc = loc; +/// } +/// else +///} + { +///static if (false) { +/// WithScopeSymbol withsym; +/// if (scopesym && (withsym = scopesym.isWithScopeSymbol()) !is null) +/// { +/// // Same as wthis.ident +/// e = new VarExp(loc, withsym.withstate.wthis); +/// e = new DotIdExp(loc, e, ident); +/// //assert(0); // BUG: should handle this +/// } +/// else +///} + *pe = new VarExp(loc, v); + } + return; + } + em = s.isEnumMember(); + if (em) + { + // It's not a type, it's an expression + *pe = em.value.copy(); + return; + } + + L1: + Type t = s.getType(); + if (!t) + { + // If the symbol is an import, try looking inside the import + Import si; + + si = s.isImport(); + if (si) + { + s = si.search(loc, s.ident, 0); + if (s && s != si) + goto L1; + s = si; + } + *ps = s; + return; + } + if (t.ty == TY.Tinstance && t != this && !t.deco) + { + error(loc, "forward reference to '%s'", t.toChars()); + return; + } + + if (t != this) + { + if (t.reliesOnTident()) + { + Scope scx; + + for (scx = sc; 1; scx = scx.enclosing) + { + if (!scx) + { + error(loc, "forward reference to '%s'", t.toChars()); + return; + } + if (scx.scopesym == scopesym) + break; + } + t = t.semantic(loc, scx); + //((TypeIdentifier *)t).resolve(loc, scx, pe, &t, ps); + } + } + if (t.ty == TY.Ttuple) + *pt = t; + else + *pt = t.merge(); + } + if (!s) + { + error(loc, "identifier '%s' is not defined", toChars()); + } + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TypeReference.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeReference.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,72 @@ +module dmd.TypeReference; + +import dmd.Type; +import dmd.MOD; +import dmd.TypeNext; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.HdrGenState; +import dmd.Expression; +import dmd.Identifier; +import dmd.CppMangleState; +import dmd.TY; + +class TypeReference : TypeNext +{ + this(Type t) + { + super(TY.init, null); + assert(false); + } + +version (DumbClone) { +} else { + Type clone() + { + assert(false); + } +} + + Type syntaxCopy() + { + assert(false); + } + + Type semantic(Loc loc, Scope sc) + { + assert(false); + } + + ulong size(Loc loc) + { + assert(false); + } + + void toCBuffer2(OutBuffer buf, HdrGenState* hgs, MOD mod) + { + assert(false); + } + + Expression dotExp(Scope sc, Expression e, Identifier ident) + { + assert(false); + } + + Expression defaultInit(Loc loc) + { + assert(false); + } + + bool isZeroInit(Loc loc) + { + assert(false); + } + +version (CPP_MANGLE) { + void toCppMangle(OutBuffer buf, CppMangleState* cms) + { + assert(false); + } +} +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TypeReturn.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeReturn.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,91 @@ +module dmd.TypeReturn; + +import dmd.Loc; +import dmd.MOD; +import dmd.Type; +import dmd.TypeQualified; +import dmd.Scope; +import dmd.Dsymbol; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.TY; + +class TypeReturn : TypeQualified +{ + this(Loc loc) + { + super(TY.Treturn, loc); + } + +version (DumbClone) { +} else { + Type clone() + { + assert(false); + } +} + + Type syntaxCopy() + { + TypeReturn t = new TypeReturn(loc); + t.syntaxCopyHelper(this); + t.mod = mod; + return t; + } + + Dsymbol toDsymbol(Scope sc) + { + Type *t = semantic(0, sc); + if (t == this) + return null; + return t.toDsymbol(sc); + } + + Type semantic(Loc loc, Scope sc) + { + Type t; + if (!sc.func) + { + error(loc, "typeof(return) must be inside function"); + goto Lerr; + } + t = sc.func.type.nextOf(); + t = t.addMod(mod); + + if (idents.dim) + { + Dsymbol s = t.toDsymbol(sc); + for (size_t i = 0; i < idents.dim; i++) + { + if (!s) + break; + Identifier id = cast(Identifier)idents.data[i]; + s = s.searchX(loc, sc, id); + } + if (s) + { + t = s.getType(); + if (!t) + { + error(loc, "%s is not a type", s.toChars()); + goto Lerr; + } + } + else + { + error(loc, "cannot resolve .property for %s", toChars()); + goto Lerr; + } + } + + return t; + + Lerr: + return terror; + } + + void toCBuffer2(OutBuffer buf, HdrGenState* hgs, MOD mod) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TypeSArray.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeSArray.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,455 @@ +module dmd.TypeSArray; + +import dmd.TypeArray; +import dmd.MOD; +import dmd.Argument; +import dmd.TypeStruct; +import dmd.TypeTuple; +import dmd.VarExp; +import dmd.IntegerExp; +import dmd.Expression; +import dmd.Type; +import dmd.TupleDeclaration; +import dmd.TOK; +import dmd.Loc; +import dmd.STC; +import dmd.Scope; +import dmd.Dsymbol; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Identifier; +import dmd.MATCH; +import dmd.TypeDArray; +import dmd.TypePointer; +import dmd.ArrayTypes; +import dmd.WANT; +import dmd.TypeInfoDeclaration; +import dmd.TY; +import dmd.Util; +import dmd.Id; + +import dmd.type.Util; + +import dmd.backend.dt_t; +import dmd.backend.TYPE; +import dmd.backend.Util; +import dmd.backend.TYM; +import dmd.backend.DT; + +// Static array, one with a fixed dimension +class TypeSArray : TypeArray +{ + Expression dim; + + this(Type t, Expression dim) + { + super(TY.Tsarray, t); + //printf("TypeSArray(%s)\n", dim.toChars()); + this.dim = dim; + } + +version (DumbClone) { +} else { + Type clone() + { + assert(false); + } +} + + Type syntaxCopy() + { + assert(false); + } + + ulong size(Loc loc) + { + if (!dim) + return Type.size(loc); + + long sz = dim.toInteger(); + + { + long n, n2; + n = next.size(); + n2 = n * sz; + if (n && (n2 / n) != sz) + goto Loverflow; + + sz = n2; + } + return sz; + + Loverflow: + error(loc, "index %jd overflow for static array", sz); + return 1; + } + + uint alignsize() + { + return next.alignsize(); + } + + Type semantic(Loc loc, Scope sc) + { + //printf("TypeSArray.semantic() %s\n", toChars()); + + Type t; + Expression e; + Dsymbol s; + next.resolve(loc, sc, &e, &t, &s); + if (dim && s && s.isTupleDeclaration()) + { + TupleDeclaration sd = s.isTupleDeclaration(); + + dim = semanticLength(sc, sd, dim); + dim = dim.optimize(WANT.WANTvalue | WANT.WANTinterpret); + ulong d = dim.toUInteger(); + + if (d >= sd.objects.dim) + { error(loc, "tuple index %ju exceeds %u", d, sd.objects.dim); + return Type.terror; + } + ///Object o = cast(Object)sd.objects.data[(size_t)d]; + ///if (o.dyncast() != DYNCAST_TYPE) + ///{ + /// error(loc, "%s is not a type", toChars()); + /// return Type.terror; + ///} + ///t = cast(Type)o; + + t = cast(Type)sd.objects.data[cast(size_t)d]; + if (t is null) { + error(loc, "%s is not a type", toChars()); + return Type.terror; + } + return t; + } + + next = next.semantic(loc,sc); + transitive(); + + Type tbn = next.toBasetype(); + + if (dim) + { + long n, n2; + + dim = semanticLength(sc, tbn, dim); + + dim = dim.optimize(WANT.WANTvalue | WANT.WANTinterpret); + if (sc && sc.parameterSpecialization && dim.op == TOK.TOKvar && + (cast(VarExp)dim).var.storage_class & STC.STCtemplateparameter) + { + /* It could be a template parameter N which has no value yet: + * template Foo(T : T[N], size_t N); + */ + return this; + } + long d1 = dim.toInteger(); + dim = dim.castTo(sc, tsize_t); + dim = dim.optimize(WANT.WANTvalue); + long d2 = dim.toInteger(); + + if (d1 != d2) + goto Loverflow; + + if (tbn.isintegral() || + tbn.isfloating() || + tbn.ty == TY.Tpointer || + tbn.ty == TY.Tarray || + tbn.ty == TY.Tsarray || + tbn.ty == TY.Taarray || + tbn.ty == TY.Tclass) + { + /* Only do this for types that don't need to have semantic() + * run on them for the size, since they may be forward referenced. + */ + n = tbn.size(loc); + n2 = n * d2; + if (cast(int)n2 < 0) + goto Loverflow; + if (n2 >= 0x1000000) // put a 'reasonable' limit on it + goto Loverflow; + if (n && n2 / n != d2) + { + Loverflow: + error(loc, "index %jd overflow for static array", d1); + dim = new IntegerExp(Loc(0), 1, tsize_t); + } + } + } + switch (tbn.ty) + { + case TY.Ttuple: + { // Index the tuple to get the type + assert(dim); + TypeTuple tt = cast(TypeTuple)tbn; + ulong d = dim.toUInteger(); + + if (d >= tt.arguments.dim) + { + error(loc, "tuple index %ju exceeds %u", d, tt.arguments.dim); + return Type.terror; + } + Argument arg = cast(Argument)tt.arguments.data[cast(size_t)d]; + return arg.type; + } + case TY.Tstruct: + { TypeStruct ts = cast(TypeStruct)tbn; + if (ts.sym.isnested) + error(loc, "cannot have array of inner structs %s", ts.toChars()); + break; + } + case TY.Tfunction: + case TY.Tnone: + error(loc, "can't have array of %s", tbn.toChars()); + tbn = next = tint32; + break; + default: /// + break; + } + if (tbn.isauto()) + error(loc, "cannot have array of auto %s", tbn.toChars()); + return merge(); + } + + void resolve(Loc loc, Scope sc, Expression* pe, Type* pt, Dsymbol* ps) + { + assert(false); + } + + void toDecoBuffer(OutBuffer buf, int flag) + { + Type.toDecoBuffer(buf, flag); + if (dim) + //buf.printf("%ju", dim.toInteger()); /// + buf.printf("%s", dim.toInteger()); + if (next) + /* Note that static arrays are value types, so + * for a parameter, propagate the 0x100 to the next + * level, since for T[4][3], any const should apply to the T, + * not the [4]. + */ + next.toDecoBuffer(buf, (flag & 0x100) ? flag : mod); + } + + void toCBuffer2(OutBuffer buf, HdrGenState* hgs, MOD mod) + { + assert(false); + } + + Expression dotExp(Scope sc, Expression e, Identifier ident) + { + version (LOGDOTEXP) { + printf("TypeSArray.dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars()); + } + if (ident == Id.length) + { + e = dim; + } + else if (ident == Id.ptr) + { + e = e.castTo(sc, next.pointerTo()); + } + else + { + e = TypeArray.dotExp(sc, e, ident); + } + return e; + } + + int isString() + { + assert(false); + } + + bool isZeroInit(Loc loc) + { + return next.isZeroInit(loc); + } + + uint memalign(uint salign) + { + return next.memalign(salign); + } + + MATCH constConv(Type to) + { + assert(false); + } + + MATCH implicitConvTo(Type to) + { + //printf("TypeSArray.implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars()); + + // Allow implicit conversion of static array to pointer or dynamic array + if (IMPLICIT_ARRAY_TO_PTR && to.ty == Tpointer) + { + TypePointer tp = cast(TypePointer)to; + + if (next.mod != tp.next.mod && tp.next.mod != MODconst) + return MATCHnomatch; + + if (tp.next.ty == Tvoid || next.constConv(tp.next) != MATCHnomatch) + { + return MATCHconvert; + } + return MATCHnomatch; + } + if (to.ty == Tarray) + { + int offset = 0; + TypeDArray ta = cast(TypeDArray)to; + + if (next.mod != ta.next.mod && ta.next.mod != MODconst) + return MATCHnomatch; + + if (next.equals(ta.next) || + next.implicitConvTo(ta.next) >= MATCHconst || + (ta.next.isBaseOf(next, &offset) && offset == 0) || + ta.next.ty == Tvoid + ) + return MATCHconvert; + + return MATCHnomatch; + } + if (to.ty == Tsarray) + { + if (this == to) + return MATCHexact; + + TypeSArray tsa = cast(TypeSArray)to; + + if (dim.equals(tsa.dim)) + { + /* Since static arrays are value types, allow + * conversions from const elements to non-const + * ones, just like we allow conversion from const int + * to int. + */ + MATCH m = next.implicitConvTo(tsa.next); + if (m >= MATCHconst) + { + if (mod != to.mod) + m = MATCHconst; + return m; + } + } + } + return MATCHnomatch; + } + + Expression defaultInit(Loc loc) + { + version (LOGDEFAULTINIT) { + printf("TypeSArray.defaultInit() '%s'\n", toChars()); + } + return next.defaultInit(loc); + } + + dt_t** toDt(dt_t** pdt) + { + return toDtElem(pdt, null); + } + + dt_t** toDtElem(dt_t** pdt, Expression e) + { + int i; + + //printf("TypeSArray::toDtElem()\n"); + uint len = cast(uint)dim.toInteger(); + if (len) + { + while (*pdt) + pdt = &((*pdt).DTnext); + Type tnext = next; + Type tbn = tnext.toBasetype(); + while (tbn.ty == Tsarray) + { + TypeSArray tsa = cast(TypeSArray)tbn; + + len *= tsa.dim.toInteger(); + tnext = tbn.nextOf(); + tbn = tnext.toBasetype(); + } + if (!e) // if not already supplied + e = tnext.defaultInit(Loc(0)); // use default initializer + if (tbn.ty == Tstruct) + tnext.toDt(pdt); + else + e.toDt(pdt); + dt_optimize(*pdt); + if ((*pdt).dt == DT_azeros && !(*pdt).DTnext) + { + (*pdt).DTazeros *= len; + pdt = &((*pdt).DTnext); + } + else if ((*pdt).dt == DT_1byte && (*pdt).DTonebyte == 0 && !(*pdt).DTnext) + { + (*pdt).dt = DT_azeros; + (*pdt).DTazeros = len; + pdt = &((*pdt).DTnext); + } + else if (e.op != TOKstring) + { + for (i = 1; i < len; i++) + { + if (tbn.ty == Tstruct) + { + pdt = tnext.toDt(pdt); + while (*pdt) + pdt = &((*pdt).DTnext); + } + else + pdt = e.toDt(pdt); + } + } + } + return pdt; + } + + MATCH deduceType(Scope sc, Type tparam, TemplateParameters parameters, Objects dedtypes) + { + assert(false); + } + + TypeInfoDeclaration getTypeInfoDeclaration() + { + assert(false); + } + + Expression toExpression() + { + assert(false); + } + + bool hasPointers() + { + return next.hasPointers(); + } + +version (CPP_MANGLE) { + void toCppMangle(OutBuffer buf, CppMangleState* cms) + { + assert(false); + } +} + + type* toCtype() + { + if (!ctype) + { + type* tn = next.toCtype(); + ctype = type_allocn(TYarray, tn); + ctype.Tdim = cast(uint)dim.toInteger(); + } + + return ctype; + } + + type* toCParamtype() + { + // arrays are passed as pointers + return next.pointerTo().toCtype(); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TypeSlice.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeSlice.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,52 @@ +module dmd.TypeSlice; + +import dmd.Type; +import dmd.TypeNext; +import dmd.MOD; +import dmd.Expression; +import dmd.Loc; +import dmd.Scope; +import dmd.Dsymbol; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.TY; + +class TypeSlice : TypeNext +{ + Expression lwr; + Expression upr; + + this(Type next, Expression lwr, Expression upr) + { + super(TY.init, null); + assert(false); + } + +version (DumbClone) { +} else { + Type clone() + { + assert(false); + } +} + + Type syntaxCopy() + { + assert(false); + } + + Type semantic(Loc loc, Scope sc) + { + assert(false); + } + + void resolve(Loc loc, Scope sc, Expression* pe, Type* pt, Dsymbol* ps) + { + assert(false); + } + + void toCBuffer2(OutBuffer buf, HdrGenState* hgs, MOD mod) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TypeStruct.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeStruct.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,589 @@ +module dmd.TypeStruct; + +import dmd.Type; +import dmd.StructDeclaration; +import dmd.Declaration; +import dmd.STC; +import dmd.MOD; +import dmd.OutBuffer; +import dmd.DotVarExp; +import dmd.TemplateMixin; +import dmd.DotTemplateExp; +import dmd.DsymbolExp; +import dmd.TypeExp; +import dmd.EnumMember; +import dmd.Id; +import dmd.DotIdExp; +import dmd.ScopeExp; +import dmd.TupleExp; +import dmd.TemplateDeclaration; +import dmd.OverloadSet; +import dmd.Import; +import dmd.DotExp; +import dmd.ErrorExp; +import dmd.Loc; +import dmd.Scope; +import dmd.Dsymbol; +import dmd.HdrGenState; +import dmd.Expression; +import dmd.Identifier; +import dmd.MATCH; +import dmd.ArrayTypes; +import dmd.TemplateInstance; +import dmd.FuncDeclaration; +import dmd.VarExp; +import dmd.CommaExp; +import dmd.ThisExp; +import dmd.SymbolDeclaration; +import dmd.TypeInfoDeclaration; +import dmd.TypeInfoStructDeclaration; +import dmd.TY; +import dmd.TOK; +import dmd.Global; +import dmd.VarDeclaration; +import dmd.Util; +import dmd.expression.Util; + +import dmd.backend.TYPE; +import dmd.backend.dt_t; +import dmd.backend.Symbol; +import dmd.backend.Util; +import dmd.backend.STR; +import dmd.backend.TYM; +import dmd.backend.Classsym; +import dmd.backend.SC; +import dmd.backend.LIST; + +import std.string : toStringz; + +class TypeStruct : Type +{ + StructDeclaration sym; + + this(StructDeclaration sym) + { + super(TY.Tstruct); + this.sym = sym; + } +version (DumbClone) { +} else { + final TypeStruct cloneTo(TypeStruct t) + { + super.cloneTo(t); + assert(t.sym is sym); + return t; + } + + TypeStruct clone() + { + assert(this.classinfo == TypeStruct.classinfo); + return cloneTo(new TypeStruct(sym)); + } +} + ulong size(Loc loc) + { + return sym.size(loc); + } + + uint alignsize() + { + uint sz; + + sym.size(Loc(0)); // give error for forward references + sz = sym.alignsize; + if (sz > sym.structalign) + sz = sym.structalign; + return sz; + } + + string toChars() + { + assert(false); + } + + Type syntaxCopy() + { + assert(false); + } + + Type semantic(Loc loc, Scope sc) + { + //printf("TypeStruct.semantic('%s')\n", sym.toChars()); + + /* Cannot do semantic for sym because scope chain may not + * be right. + */ + //sym.semantic(sc); + + return merge(); + } + + Dsymbol toDsymbol(Scope sc) + { + return sym; + } + + void toDecoBuffer(OutBuffer buf, int flag) + { + string name = sym.mangle(); + //printf("TypeStruct.toDecoBuffer('%s') = '%s'\n", toChars(), name); + Type.toDecoBuffer(buf, flag); + buf.printf("%s", name); + } + + void toCBuffer2(OutBuffer buf, HdrGenState* hgs, MOD mod) + { + if (mod != this.mod) + { + toCBuffer3(buf, hgs, mod); + return; + } + TemplateInstance ti = sym.parent.isTemplateInstance(); + if (ti && ti.toAlias() == sym) + buf.writestring(ti.toChars()); + else + buf.writestring(sym.toChars()); + } + + Expression dotExp(Scope sc, Expression e, Identifier ident) + { + uint offset; + + VarDeclaration v; + Dsymbol s; + DotVarExp de; + Declaration d; + + version (LOGDOTEXP) { + printf("TypeStruct.dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars()); + } + if (!sym.members) + { + error(e.loc, "struct %s is forward referenced", sym.toChars()); + return new ErrorExp(); + } + + /* If e.tupleof + */ + if (ident is Id.tupleof_) + { + /* Create a TupleExp out of the fields of the struct e: + * (e.field0, e.field1, e.field2, ...) + */ + e = e.semantic(sc); // do this before turning on noaccesscheck + Expressions exps = new Expressions; + exps.reserve(sym.fields.dim); + for (size_t i = 0; i < sym.fields.dim; i++) + { + VarDeclaration v2 = cast(VarDeclaration)sym.fields.data[i]; + Expression fe = new DotVarExp(e.loc, e, v2); + exps.push(cast(void*)fe); + } + e = new TupleExp(e.loc, exps); + sc = sc.push(); + sc.noaccesscheck = 1; + e = e.semantic(sc); + sc.pop(); + return e; + } + + if (e.op == TOK.TOKdotexp) + { + DotExp de2 = cast(DotExp)e; + + if (de2.e1.op == TOK.TOKimport) + { + assert(0); // cannot find a case where this happens; leave + // assert in until we do + ScopeExp se = cast(ScopeExp)de2.e1; + + s = se.sds.search(e.loc, ident, 0); + e = de2.e1; + goto L1; + } + } + + s = sym.search(e.loc, ident, 0); + L1: + if (!s) + { + if (ident !is Id.__sizeof && + ident !is Id.alignof_ && + ident !is Id.init_ && + ident !is Id.mangleof_ && + ident !is Id.stringof_ && + ident !is Id.offsetof) + { + /* See if we should forward to the alias this. + */ + if (sym.aliasthis) + { + /* Rewrite e.ident as: + * e.aliasthis.ident + */ + e = new DotIdExp(e.loc, e, sym.aliasthis.ident); + e = new DotIdExp(e.loc, e, ident); + return e.semantic(sc); + } + + /* Look for overloaded opDot() to see if we should forward request + * to it. + */ + Dsymbol fd = search_function(sym, Id.opDot); + if (fd) + { + /* Rewrite e.ident as: + * e.opId().ident + */ + e = build_overload(e.loc, sc, e, null, fd.ident); + e = new DotIdExp(e.loc, e, ident); + return e.semantic(sc); + } + } + + return Type.dotExp(sc, e, ident); + } + + if (!s.isFuncDeclaration()) // because of overloading + s.checkDeprecated(e.loc, sc); + + s = s.toAlias(); + + v = s.isVarDeclaration(); + if (v && !v.isDataseg()) + { + Expression ei = v.getConstInitializer(); + if (ei) + { + e = ei.copy(); // need to copy it if it's a StringExp + e = e.semantic(sc); + return e; + } + } + + if (s.getType()) + { + //return new DotTypeExp(e.loc, e, s); + return new TypeExp(e.loc, s.getType()); + } + + EnumMember em = s.isEnumMember(); + if (em) + { + assert(em.value); + return em.value.copy(); + } + + TemplateMixin tm = s.isTemplateMixin(); + if (tm) + { + Expression de2 = new DotExp(e.loc, e, new ScopeExp(e.loc, tm)); + de2.type = e.type; + return de2; + } + + TemplateDeclaration td = s.isTemplateDeclaration(); + if (td) + { + e = new DotTemplateExp(e.loc, e, td); + e.semantic(sc); + return e; + } + + TemplateInstance ti = s.isTemplateInstance(); + if (ti) + { + if (!ti.semanticRun) + ti.semantic(sc); + s = ti.inst.toAlias(); + if (!s.isTemplateInstance()) + goto L1; + Expression de2 = new DotExp(e.loc, e, new ScopeExp(e.loc, ti)); + de2.type = e.type; + return de2; + } + + Import timp = s.isImport(); + if (timp) + { + e = new DsymbolExp(e.loc, s, 0); + e = e.semantic(sc); + return e; + } + + OverloadSet o = s.isOverloadSet(); + if (o) + { + /* We really should allow this, triggered by: + * template c() + * { + * void a(); + * void b () { this.a(); } + * } + * struct S + * { + * mixin c; + * mixin c; + * } + * alias S e; + */ + error(e.loc, "overload set for %s.%s not allowed in struct declaration", e.toChars(), ident.toChars()); + return new ErrorExp(); + } + + d = s.isDeclaration(); + + debug { + if (!d) + writef("d = %s '%s'\n", s.kind(), s.toChars()); + } + assert(d); + + if (e.op == TOK.TOKtype) + { + FuncDeclaration fd = sc.func; + + if (d.isTupleDeclaration()) + { + e = new TupleExp(e.loc, d.isTupleDeclaration()); + e = e.semantic(sc); + return e; + } + + if (d.needThis() && fd && fd.vthis) + { + e = new DotVarExp(e.loc, new ThisExp(e.loc), d); + e = e.semantic(sc); + return e; + } + + return new VarExp(e.loc, d, 1); + } + + if (d.isDataseg()) + { + // (e, d) + accessCheck(e.loc, sc, e, d); + VarExp ve = new VarExp(e.loc, d); + e = new CommaExp(e.loc, e, ve); + e.type = d.type; + return e; + } + + if (v) + { + if (v.toParent() != sym) + sym.error(e.loc, "'%s' is not a member", v.toChars()); + + // *(&e + offset) + accessCheck(e.loc, sc, e, d); +static if (false) { + Expression b = new AddrExp(e.loc, e); + b.type = e.type.pointerTo(); + b = new AddExp(e.loc, b, new IntegerExp(e.loc, v.offset, Type.tint32)); + b.type = v.type.pointerTo(); + b = new PtrExp(e.loc, b); + b.type = v.type.addMod(e.type.mod); + return b; +} + } + + de = new DotVarExp(e.loc, e, d); + return de.semantic(sc); + } + + uint memalign(uint salign) + { + sym.size(Loc(0)); // give error for forward references + return sym.structalign; + } + + Expression defaultInit(Loc loc) + { + Symbol* s; + Declaration d; + + version (LOGDEFAULTINIT) { + printf("TypeStruct::defaultInit() '%s'\n", toChars()); + } + s = sym.toInitializer(); + d = new SymbolDeclaration(sym.loc, s, sym); + assert(d); + d.type = this; + return new VarExp(sym.loc, d); + } + + bool isZeroInit(Loc loc) + { + return sym.zeroInit; + } + + int isAssignable() + { + /* If any of the fields are const or invariant, + * then one cannot assign this struct. + */ + for (size_t i = 0; i < sym.fields.dim; i++) + { + VarDeclaration v = cast(VarDeclaration)sym.fields.data[i]; + if (v.isConst() || v.isInvariant()) + return false; + } + return true; + } + + bool checkBoolean() + { + return false; + } + + dt_t** toDt(dt_t** pdt) + { + sym.toDt(pdt); + return pdt; + } + + MATCH deduceType(Scope sc, Type tparam, TemplateParameters parameters, Objects dedtypes) + { + assert(false); + } + + TypeInfoDeclaration getTypeInfoDeclaration() + { + return new TypeInfoStructDeclaration(this); + } + + bool hasPointers() + { + StructDeclaration s = sym; + + sym.size(Loc(0)); // give error for forward references + for (size_t i = 0; i < s.fields.dim; i++) + { + Dsymbol sm = cast(Dsymbol)s.fields.data[i]; + Declaration d = sm.isDeclaration(); + if (d.storage_class & STC.STCref || d.hasPointers()) + return true; + } + + return false; + } + + MATCH implicitConvTo(Type to) + { + MATCH m; + + //printf("TypeStruct.implicitConvTo(%s => %s)\n", toChars(), to.toChars()); + if (ty == to.ty && sym == (cast(TypeStruct)to).sym) + { + m = MATCHexact; // exact match + if (mod != to.mod) + { + if (to.mod == MODconst) + m = MATCHconst; + else + { /* Check all the fields. If they can all be converted, + * allow the conversion. + */ + for (int i = 0; i < sym.fields.dim; i++) + { + Dsymbol s = cast(Dsymbol)sym.fields.data[i]; + VarDeclaration v = s.isVarDeclaration(); + assert(v && v.storage_class & STCfield); + + // 'from' type + Type tvf = v.type.addMod(mod); + + // 'to' type + Type tv = v.type.castMod(to.mod); + + //printf("\t%s => %s, match = %d\n", v.type.toChars(), tv.toChars(), tvf.implicitConvTo(tv)); + if (tvf.implicitConvTo(tv) < MATCHconst) + return MATCHnomatch; + } + m = MATCHconst; + } + } + } + else if (sym.aliasthis) + { + m = MATCHnomatch; + Declaration d = sym.aliasthis.isDeclaration(); + if (d) + { + assert(d.type); + Type t = d.type.addMod(mod); + m = t.implicitConvTo(to); + } + } + else + m = MATCHnomatch; // no match + return m; + } + + MATCH constConv(Type to) + { + if (equals(to)) + return MATCHexact; + if (ty == to.ty && sym == (cast(TypeStruct)to).sym && to.mod == MODconst) + return MATCHconst; + return MATCHnomatch; + } + + Type toHeadMutable() + { + assert(false); + } + +version (CPP_MANGLE) { + void toCppMangle(OutBuffer buf, CppMangleState* cms) + { + assert(false); + } +} + + type* toCtype() + { + type* t; + Symbol* s; + + if (ctype) + return ctype; + + //printf("TypeStruct.toCtype() '%s'\n", sym.toChars()); + s = symbol_calloc(toStringz(sym.toPrettyChars())); + s.Sclass = SC.SCstruct; + s.Sstruct = struct_calloc(); + s.Sstruct.Sflags |= 0; /// huh? + s.Sstruct.Salignsize = sym.alignsize; + s.Sstruct.Sstructalign = cast(ubyte)sym.structalign; + s.Sstruct.Sstructsize = sym.structsize; + + if (sym.isUnionDeclaration()) + s.Sstruct.Sflags |= STR.STRunion; + + t = type_alloc(TYM.TYstruct); + t.Ttag = cast(Classsym*)s; // structure tag name + t.Tcount++; + s.Stype = t; + slist_add(s); + ctype = t; + + /* Add in fields of the struct + * (after setting ctype to avoid infinite recursion) + */ + if (global.params.symdebug) { + for (int i = 0; i < sym.fields.dim; i++) + { + VarDeclaration v = cast(VarDeclaration)sym.fields.data[i]; + + Symbol* s2 = symbol_name(toStringz(v.ident.toChars()), SC.SCmember, v.type.toCtype()); + s2.Smemoff = v.offset; + list_append(&s.Sstruct.Sfldlst, s2); + } + } + + //printf("t = %p, Tflags = x%x\n", t, t.Tflags); + return t; + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TypeTuple.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeTuple.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,78 @@ +module dmd.TypeTuple; + +import dmd.Type; +import dmd.ArrayTypes; +import dmd.MOD; +import dmd.TypeInfoDeclaration; +import dmd.Expression; +import dmd.Loc; +import dmd.Identifier; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Scope; +import dmd.TY; + +class TypeTuple : Type +{ + Arguments arguments; // types making up the tuple + + this(Arguments arguments) + { + assert(false); + super(TY.init); + } + +version (DumbClone) { +} else { + Type clone() + { + assert(false); + } +} + + this(Expressions exps) + { + assert(false); + super(TY.init); + } + + Type syntaxCopy() + { + assert(false); + } + + Type semantic(Loc loc, Scope sc) + { + assert(false); + } + + int equals(Object *o) + { + assert(false); + } + + Type reliesOnTident() + { + assert(false); + } + + void toCBuffer2(OutBuffer buf, HdrGenState* hgs, MOD mod) + { + assert(false); + } + + void toDecoBuffer(OutBuffer buf, int flag) + { + assert(false); + } + + Expression getProperty(Loc loc, Identifier ident) + { + assert(false); + } + + TypeInfoDeclaration getTypeInfoDeclaration() + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TypeTypedef.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeTypedef.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,296 @@ +module dmd.TypeTypedef; + +import dmd.Type; +import dmd.TypedefDeclaration; +import dmd.MOD; +import dmd.Loc; +import dmd.Id; +import dmd.Dsymbol; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Expression; +import dmd.Identifier; +import dmd.ArrayTypes; +import dmd.MATCH; +import dmd.TypeSArray; +import dmd.CppMangleState; +import dmd.TypeInfoDeclaration; +import dmd.TypeInfoTypedefDeclaration; +import dmd.TY; + +import dmd.backend.TYPE; +import dmd.backend.dt_t; + +class TypeTypedef : Type +{ + TypedefDeclaration sym; + + this(TypedefDeclaration sym) + { + super(Ttypedef); + this.sym = sym; + } + +version (DumbClone) { +} else { + Type clone() + { + assert(false); + } +} + + Type syntaxCopy() + { + assert(false); + } + + ulong size(Loc loc) + { + return sym.basetype.size(loc); + } + + uint alignsize() + { + assert(false); + } + + string toChars() + { + assert(false); + } + + Type semantic(Loc loc, Scope sc) + { + //printf("TypeTypedef::semantic(%s), sem = %d\n", toChars(), sym->sem); + sym.semantic(sc); + return merge(); + } + + Dsymbol toDsymbol(Scope sc) + { + return sym; + } + + void toDecoBuffer(OutBuffer buf, int flag) + { + Type.toDecoBuffer(buf, flag); + string name = sym.mangle(); + buf.printf("%s", name); + } + + void toCBuffer2(OutBuffer buf, HdrGenState* hgs, MOD mod) + { + assert(false); + } + + Expression dotExp(Scope sc, Expression e, Identifier ident) + { + version (LOGDOTEXP) { + printf("TypeTypedef.dotExp(e = '%s', ident = '%s') '%s'\n", e.toChars(), ident.toChars(), toChars()); + } + if (ident is Id.init_) + { + return Type.dotExp(sc, e, ident); + } + return sym.basetype.dotExp(sc, e, ident); + } + + Expression getProperty(Loc loc, Identifier ident) + { + assert(false); + } + + bool isbit() + { + assert(false); + } + + bool isintegral() + { + //printf("TypeTypedef::isintegral()\n"); + //printf("sym = '%s'\n", sym->toChars()); + //printf("basetype = '%s'\n", sym->basetype->toChars()); + return sym.basetype.isintegral(); + } + + bool isfloating() + { + return sym.basetype.isfloating(); + } + + bool isreal() + { + return sym.basetype.isreal(); + } + + bool isimaginary() + { + return sym.basetype.isimaginary(); + } + + bool iscomplex() + { + return sym.basetype.iscomplex(); + } + + bool isscalar() + { + return sym.basetype.isscalar(); + } + + bool isunsigned() + { + return sym.basetype.isunsigned(); + } + + bool checkBoolean() + { + assert(false); + } + + int isAssignable() + { + return sym.basetype.isAssignable(); + } + + Type toBasetype() + { + if (sym.inuse) + { + sym.error("circular definition"); + sym.basetype = Type.terror; + return Type.terror; + } + sym.inuse = 1; + Type t = sym.basetype.toBasetype(); + sym.inuse = 0; + t = t.addMod(mod); + return t; + } + + MATCH implicitConvTo(Type to) + { + MATCH m; + + //printf("TypeTypedef::implicitConvTo(to = %s) %s\n", to->toChars(), toChars()); + if (equals(to)) + m = MATCHexact; // exact match + else if (sym.basetype.implicitConvTo(to)) + m = MATCHconvert; // match with conversions + else if (ty == to.ty && sym == (cast(TypeTypedef)to).sym) + { + m = constConv(to); + } + else + m = MATCHnomatch; // no match + return m; + } + + MATCH constConv(Type to) + { + assert(false); + } + + Expression defaultInit(Loc loc) + { + Expression e; + Type bt; + + version (LOGDEFAULTINIT) { + printf("TypeTypedef::defaultInit() '%s'\n", toChars()); + } + if (sym.init) + { + //sym->init->toExpression()->print(); + return sym.init.toExpression(); + } + bt = sym.basetype; + e = bt.defaultInit(loc); + e.type = this; + while (bt.ty == Tsarray) + { + TypeSArray tsa = cast(TypeSArray)bt; + e.type = tsa.next; + bt = tsa.next.toBasetype(); + } + return e; + } + + bool isZeroInit(Loc loc) + { + if (sym.init) + { + if (sym.init.isVoidInitializer()) + return true; // initialize voids to 0 + Expression e = sym.init.toExpression(); + if (e && e.isBool(false)) + return true; + + return false; // assume not + } + if (sym.inuse) + { + sym.error("circular definition"); + sym.basetype = Type.terror; + } + sym.inuse = 1; + bool result = sym.basetype.isZeroInit(loc); + sym.inuse = 0; + + return result; + } + + dt_t** toDt(dt_t** pdt) + { + if (sym.init) + { + dt_t* dt = sym.init.toDt(); + + while (*pdt) + pdt = &((*pdt).DTnext); + *pdt = dt; + return pdt; + } + + sym.basetype.toDt(pdt); + return pdt; + } + + MATCH deduceType(Scope sc, Type tparam, TemplateParameters parameters, Objects dedtypes) + { + assert(false); + } + + TypeInfoDeclaration getTypeInfoDeclaration() + { + return new TypeInfoTypedefDeclaration(this); + } + + bool hasPointers() + { + return toBasetype().hasPointers(); + } + + Type toHeadMutable() + { + assert(false); + } + +version (CPP_MANGLE) { + void toCppMangle(OutBuffer buf, CppMangleState* cms) + { + assert(false); + } +} + + type* toCtype() + { + return sym.basetype.toCtype(); + } + + type* toCParamtype() + { + return sym.basetype.toCParamtype(); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TypeTypeof.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeTypeof.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,167 @@ +module dmd.TypeTypeof; + +import dmd.TypeQualified; +import dmd.Expression; +import dmd.Identifier; +import dmd.Scope; +import dmd.Loc; +import dmd.MOD; +import dmd.Type; +import dmd.Dsymbol; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.TY; +import dmd.Util; +import dmd.TOK; + +class TypeTypeof : TypeQualified +{ + Expression exp; + + this(Loc loc, Expression exp) + { + super(TY.Ttypeof, loc); + this.exp = exp; + } + +version (DumbClone) { +} else { + Type clone() + { + assert(false); + } +} + + Type syntaxCopy() + { + assert(false); + } + + Dsymbol toDsymbol(Scope sc) + { + Type t = semantic(loc, sc); + if (t is this) + return null; + + return t.toDsymbol(sc); + } + + void toCBuffer2(OutBuffer buf, HdrGenState* hgs, MOD mod) + { + assert(false); + } + + Type semantic(Loc loc, Scope sc) + { + Expression e; + Type t; + + //printf("TypeTypeof.semantic() %p\n", this); + + //static int nest; if (++nest == 50) *(char*)0=0; + +/+static if (false) { + /* Special case for typeof(this) and typeof(super) since both + * should work even if they are not inside a non-static member function + */ + if (exp.op == TOK.TOKthis || exp.op == TOK.TOKsuper) + { + / / Find enclosing struct or class + for (Dsymbol *s = sc.parent; 1; s = s.parent) + { + ClassDeclaration *cd; + StructDeclaration *sd; + + if (!s) + { + error(loc, "%s is not in a struct or class scope", exp.toChars()); + goto Lerr; + } + cd = s.isClassDeclaration(); + if (cd) + { + if (exp.op == TOK.TOKsuper) + { + cd = cd.baseClass; + if (!cd) + { error(loc, "class %s has no 'super'", s.toChars()); + goto Lerr; + } + } + t = cd.type; + break; + } + sd = s.isStructDeclaration(); + if (sd) + { + if (exp.op == TOK.TOKsuper) + { + error(loc, "struct %s has no 'super'", sd.toChars()); + goto Lerr; + } + t = sd.type.pointerTo(); + break; + } + } + } + else +}+/ + { + sc.intypeof++; + exp = exp.semantic(sc); + sc.intypeof--; + if (exp.op == TOK.TOKtype) + { + error(loc, "argument %s to typeof is not an expression", exp.toChars()); + } + t = exp.type; + if (!t) + { + error(loc, "expression (%s) has no type", exp.toChars()); + goto Lerr; + } + if (t.ty == TY.Ttypeof) + error(loc, "forward reference to %s", toChars()); + + /* typeof should reflect the true type, + * not what 'auto' would have gotten us. + */ + //t = t.toHeadMutable(); + } + if (idents.dim) + { + Dsymbol s = t.toDsymbol(sc); + for (size_t i = 0; i < idents.dim; i++) + { + if (!s) + break; + Identifier id = cast(Identifier)idents.data[i]; + s = s.searchX(loc, sc, id); + } + + if (s) + { + t = s.getType(); + if (!t) + { + error(loc, "%s is not a type", s.toChars()); + goto Lerr; + } + } + else + { + error(loc, "cannot resolve .property for %s", toChars()); + goto Lerr; + } + } + return t; + + Lerr: + return tvoid; + } + + ulong size(Loc loc) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TypedefDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypedefDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,179 @@ +module dmd.TypedefDeclaration; + +import dmd.Declaration; +import dmd.Initializer; +import dmd.Type; +import dmd.Loc; +import dmd.Identifier; +import dmd.Dsymbol; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.ExpInitializer; +import dmd.HdrGenState; +import dmd.TypeTypedef; +import dmd.Global; +import dmd.STC; + +import dmd.backend.SC; +import dmd.backend.FL; +import dmd.backend.Symbol; +import dmd.backend.Util; + +class TypedefDeclaration : Declaration +{ + Type basetype; + Initializer init; + int sem = 0;// 0: semantic() has not been run + // 1: semantic() is in progress + // 2: semantic() has been run + // 3: semantic2() has been run + + this(Loc loc, Identifier id, Type basetype, Initializer init) + { + super(id); + + this.type = new TypeTypedef(this); + this.basetype = basetype.toBasetype(); + this.init = init; + + version (_DH) { + this.htype = null; + this.hbasetype = null; + } + this.loc = loc; + this.sinit = null; + } + +version (DumbClone) { +} else { + Type clone() + { + assert(false); + } +} + Dsymbol syntaxCopy(Dsymbol) + { + assert(false); + } + + void semantic(Scope sc) + { + //printf("TypedefDeclaration::semantic(%s) sem = %d\n", toChars(), sem); + if (sem == 0) + { + sem = 1; + basetype = basetype.semantic(loc, sc); + sem = 2; + type = type.semantic(loc, sc); + if (sc.parent.isFuncDeclaration() && init) + semantic2(sc); + storage_class |= sc.stc & STCdeprecated; + } + else if (sem == 1) + { + error("circular definition"); + } + } + + void semantic2(Scope sc) + { + //printf("TypedefDeclaration::semantic2(%s) sem = %d\n", toChars(), sem); + if (sem == 2) + { + sem = 3; + if (init) + { + init = init.semantic(sc, basetype); + + ExpInitializer ie = init.isExpInitializer(); + if (ie) + { + if (ie.exp.type == basetype) + ie.exp.type = type; + } + } + } + } + + string mangle() + { + //printf("TypedefDeclaration::mangle() '%s'\n", toChars()); + return Dsymbol.mangle(); + } + + string kind() + { + assert(false); + } + + Type getType() + { + return type; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + +version (_DH) { + Type htype; + Type hbasetype; +} + + void toDocBuffer(OutBuffer buf) + { + assert(false); + } + + void toObjFile(int multiobj) // compile to .obj file + { + //printf("TypedefDeclaration::toObjFile('%s')\n", toChars()); + if (global.params.symdebug) + toDebug(); + + type.getTypeInfo(null); // generate TypeInfo + + TypeTypedef tc = cast(TypeTypedef)type; + if (type.isZeroInit(Loc(0)) || !tc.sym.init) { + ; + } else + { + SC scclass = SCglobal; + if (inTemplateInstance()) + scclass = SCcomdat; + + // Generate static initializer + toInitializer(); + sinit.Sclass = scclass; + sinit.Sfl = FLdata; + + version (ELFOBJ) { // Burton + sinit.Sseg = Segment.CDATA; + } + version (MACHOBJ) { + sinit.Sseg = Segment.DATA; + } + sinit.Sdt = tc.sym.init.toDt(); + outdata(sinit); + } + } + + void toDebug() + { + assert(false); + } + + int cvMember(ubyte* p) + { + assert(false); + } + + TypedefDeclaration isTypedefDeclaration() { return this; } + + Symbol* sinit; + Symbol* toInitializer() + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/TypeidExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeidExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,52 @@ +module dmd.TypeidExp; + +import dmd.Expression; +import dmd.Type; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.HdrGenState; +import dmd.TOK; + +class TypeidExp : Expression +{ + Type typeidType; + + this(Loc loc, Type typeidType) + { + super(loc, TOK.TOKtypeid, TypeidExp.sizeof); + this.typeidType = typeidType; + } + +version (DumbClone) { +} else { + Type clone() + { + assert(false); + } +} + Expression syntaxCopy() + { + return new TypeidExp(loc, typeidType.syntaxCopy()); + } + + Expression semantic(Scope sc) + { + Expression e; + + version (LOGSEMANTIC) { + printf("TypeidExp.semantic()\n"); + } + typeidType = typeidType.semantic(loc, sc); + e = typeidType.getTypeInfo(sc); + if (e.loc.linnum == 0) + e.loc = loc; // so there's at least some line number info + return e; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/UAddExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/UAddExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,28 @@ +module dmd.UAddExp; + +import dmd.Expression; +import dmd.Identifier; +import dmd.UnaExp; +import dmd.Loc; +import dmd.Scope; +import dmd.TOK; + +class UAddExp : UnaExp +{ + this(Loc loc, Expression e) + { + assert(false); + super(loc, TOK.init, 0, e); + } + + Expression semantic(Scope sc) + { + assert(false); + } + + Identifier opId() + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/UnaExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/UnaExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,169 @@ +module dmd.UnaExp; + +import dmd.Expression; +import dmd.InterState; +import dmd.TY; +import dmd.TypeClass; +import dmd.TypeStruct; +import dmd.Dsymbol; +import dmd.AggregateDeclaration; +import dmd.Type; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.TOK; +import dmd.Scope; +import dmd.InlineCostState; +import dmd.InlineDoState; +import dmd.HdrGenState; +import dmd.InlineScanState; +import dmd.DotIdExp; +import dmd.ArrayExp; +import dmd.CallExp; +import dmd.PREC; +import dmd.Token; +import dmd.expression.Util; + +class UnaExp : Expression +{ + Expression e1; + + this(Loc loc, TOK op, int size, Expression e1) + { + super(loc, op, size); + this.e1 = e1; + } + + Expression syntaxCopy() + { + UnaExp e = cast(UnaExp)copy(); + e.type = null; + e.e1 = e.e1.syntaxCopy(); + + return e; + } + + Expression semantic(Scope sc) + { +version (LOGSEMANTIC) { + writef("UnaExp.semantic('%s')\n", toChars()); +} + e1 = e1.semantic(sc); + // if (!e1.type) + // error("%s has no value", e1.toChars()); + return this; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + buf.writestring(Token.toChars(op)); + expToCBuffer(buf, hgs, e1, precedence[op]); + } + + Expression optimize(int result) + { + e1 = e1.optimize(result); + return this; + } + + void dump(int indent) + { + assert(false); + } + + void scanForNestedRef(Scope sc) + { + assert(false); + } + + Expression interpretCommon(InterState* istate, Expression *(*fp)(Type* a0, Expression* a1)) + { + assert(false); + } + + bool canThrow() + { + return e1.canThrow(); + } + + int inlineCost(InlineCostState* ics) + { + return 1 + e1.inlineCost(ics); + } + + Expression doInline(InlineDoState ids) + { + UnaExp ue = cast(UnaExp)copy(); + + ue.e1 = e1.doInline(ids); + return ue; + } + + Expression inlineScan(InlineScanState* iss) + { + e1 = e1.inlineScan(iss); + return this; + } + + /************************************ + * Operator overload. + * Check for operator overload, if so, replace + * with function call. + * Return null if not an operator overload. + */ + Expression op_overload(Scope sc) + { + //printf("UnaExp.op_overload() (%s)\n", toChars()); + AggregateDeclaration ad; + Dsymbol fd; + Type t1 = e1.type.toBasetype(); + + if (t1.ty == TY.Tclass) + { + ad = (cast(TypeClass)t1).sym; + goto L1; + } + else if (t1.ty == TY.Tstruct) + { + ad = (cast(TypeStruct)t1).sym; + + L1: + fd = search_function(ad, opId()); + if (fd) + { + if (op == TOK.TOKarray) + { + /* Rewrite op e1[arguments] as: + * e1.fd(arguments) + */ + Expression e = new DotIdExp(loc, e1, fd.ident); + ArrayExp ae = cast(ArrayExp)this; + e = new CallExp(loc, e, ae.arguments); + e = e.semantic(sc); + return e; + } + else + { + // Rewrite +e1 as e1.add() + return build_overload(loc, sc, e1, null, fd.ident); + } + } + +version (DMDV2) { + // Didn't find it. Forward to aliasthis + if (ad.aliasthis) + { + /* Rewrite op(e1) as: + * op(e1.aliasthis) + */ + Expression e1 = new DotIdExp(loc, this.e1, ad.aliasthis.ident); + Expression e = copy(); + (cast(UnaExp)e).e1 = e1; + e = e.semantic(sc); + return e; + } +} + } + return null; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/UnionDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/UnionDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,27 @@ +module dmd.UnionDeclaration; + +import dmd.StructDeclaration; +import dmd.Loc; +import dmd.Identifier; +import dmd.Dsymbol; + +class UnionDeclaration : StructDeclaration +{ + this(Loc loc, Identifier id) + { + assert(false); + super(loc, id); + } + + Dsymbol syntaxCopy(Dsymbol s) + { + assert(false); + } + + string kind() + { + assert(false); + } + + UnionDeclaration isUnionDeclaration() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/UnitTestDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/UnitTestDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,92 @@ +module dmd.UnitTestDeclaration; + +import dmd.FuncDeclaration; +import dmd.Loc; +import dmd.Dsymbol; +import dmd.AggregateDeclaration; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Type; +import dmd.Scope; +import dmd.Global; +import dmd.LINK; +import dmd.TypeFunction; +import dmd.Module; +import dmd.STC; +import dmd.Lexer; +import dmd.Identifier; + +/******************************* + * Generate unique unittest function Id so we can have multiple + * instances per module. + */ +Identifier unitTestId() +{ + return Lexer.uniqueId("__unittest"); +} + +class UnitTestDeclaration : FuncDeclaration +{ + this(Loc loc, Loc endloc) + { + super(loc, endloc, unitTestId(), STC.STCundefined, null); + } + + Dsymbol syntaxCopy(Dsymbol s) + { + UnitTestDeclaration utd; + + assert(!s); + utd = new UnitTestDeclaration(loc, endloc); + + return FuncDeclaration.syntaxCopy(utd); + } + + void semantic(Scope sc) + { + if (global.params.useUnitTests) + { + type = new TypeFunction(null, Type.tvoid, false, LINKd); + Scope sc2 = sc.push(); + sc2.linkage = LINK.LINKd; + FuncDeclaration.semantic(sc2); + sc2.pop(); + } + + // We're going to need ModuleInfo even if the unit tests are not + // compiled in, because other modules may import this module and refer + // to this ModuleInfo. + Module m = getModule(); + if (!m) + m = sc.module_; + if (m) + m.needmoduleinfo = 1; + } + + AggregateDeclaration isThis() + { + assert(false); + } + + bool isVirtual() + { + assert(false); + } + + bool addPreInvariant() + { + assert(false); + } + + bool addPostInvariant() + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + UnitTestDeclaration isUnitTestDeclaration() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/UnrolledLoopStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/UnrolledLoopStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,92 @@ +module dmd.UnrolledLoopStatement; + +import dmd.Expression; +import dmd.Statement; +import dmd.InterState; +import dmd.ArrayTypes; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.InlineCostState; +import dmd.InlineDoState; +import dmd.IRState; +import dmd.HdrGenState; +import dmd.InlineScanState; +import dmd.BE; + +class UnrolledLoopStatement : Statement +{ + Statements statements; + + this(Loc loc, Statements statements) + { + assert(false); + super(loc); + } + + Statement syntaxCopy() + { + assert(false); + } + + Statement semantic(Scope sc) + { + assert(false); + } + + bool hasBreak() + { + assert(false); + } + + bool hasContinue() + { + assert(false); + } + + bool usesEH() + { + assert(false); + } + + BE blockExit() + { + assert(false); + } + + bool comeFrom() + { + assert(false); + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + int inlineCost(InlineCostState* ics) + { + assert(false); + } + + Expression doInline(InlineDoState ids) + { + assert(false); + } + + Statement inlineScan(InlineScanState* iss) + { + assert(false); + } + + void toIR(IRState* irs) + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/UshrAssignExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/UshrAssignExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,59 @@ +module dmd.UshrAssignExp; + +import dmd.BinExp; +import dmd.Loc; +import dmd.Expression; +import dmd.Scope; +import dmd.InterState; +import dmd.Identifier; +import dmd.IRState; +import dmd.Id; +import dmd.TOK; +import dmd.Type; +import dmd.backend.elem; +import dmd.expression.Util; + +class UshrAssignExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKushrass, UshrAssignExp.sizeof, e1, e2); + } + + Expression semantic(Scope sc) + { + Expression e; + + BinExp.semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + e1 = e1.modifiableLvalue(sc, e1); + e1.checkScalar(); + e1.checkNoBool(); + type = e1.type; + typeCombine(sc); + e1.checkIntegral(); + e2 = e2.checkIntegral(); + e2 = e2.castTo(sc, Type.tshiftcnt); + return this; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + Identifier opId() /* For operator overloading */ + { + return Id.ushrass; + } + + elem* toElem(IRState* irs) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/UshrExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/UshrExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,85 @@ +module dmd.UshrExp; + +import dmd.Expression; +import dmd.Identifier; +import dmd.InterState; +import dmd.Loc; +import dmd.Scope; +import dmd.Id; +import dmd.IntRange; +import dmd.IRState; +import dmd.BinExp; +import dmd.TOK; +import dmd.Type; + +import dmd.backend.elem; +import dmd.backend.OPER; +import dmd.backend.TYFL; +import dmd.backend.Util; +import dmd.expression.Util; +import dmd.expression.Ushr; +import dmd.expression.shift_optimize; + +class UshrExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKushr, UshrExp.sizeof, e1, e2); + } + + Expression semantic(Scope sc) + { + Expression e; + + if (!type) + { + BinExp.semanticp(sc); + e = op_overload(sc); + if (e) + return e; + e1 = e1.checkIntegral(); + e2 = e2.checkIntegral(); + e1 = e1.integralPromotions(sc); + e2 = e2.castTo(sc, Type.tshiftcnt); + type = e1.type; + } + return this; + } + + Expression optimize(int result) + { + //printf("UshrExp.optimize(result = %d) %s\n", result, toChars()); + return shift_optimize(result, this, &Ushr); + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + IntRange getIntRange() + { + assert(false); + } + + Identifier opId() + { + return Id.ushr; + } + + Identifier opId_r() + { + return Id.ushr_r; + } + + elem* toElem(IRState* irs) + { + elem *eleft = e1.toElem(irs); + eleft.Ety = touns(eleft.Ety); + elem *eright = e2.toElem(irs); + elem *e = el_bin(OPshr, type.totym(), eleft, eright); + el_setLoc(e, loc); + return e; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/Utf.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Utf.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,28 @@ +module dmd.Utf; + +import dmd.Dchar; + +import std.utf; + +string utf_decodeChar(const(char)[] s, size_t* pidx, dchar* presult) +{ + try { + *presult = decode(s, *pidx); + } catch (Exception e) { + return e.toString(); + } + + return null; +} + +string utf_decodeWchar(const(wchar)[] s, size_t* pidx, dchar* presult) +{ + assert(false); +} + +bool utf_isValidDchar(uint c) +{ + return isValidDchar(c); +} + +extern (C++) extern int HtmlNamedEntity(ubyte* p, int length); \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/Util.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/Util.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,1089 @@ +module dmd.Util; + +import dmd.Loc; +import dmd.Library; +import dmd.File; +import dmd.String; +import dmd.OutBuffer; +import dmd.FileName; +import dmd.Global; +import dmd.PREC; +import dmd.TOK; + +import std.process : getenv; +import std.c.string; +import std.stdio : writef, writefln, write; +import std.c.process : spawnl, spawnlp; +import core.stdc.stdlib; +import core.stdc.ctype; +import core.stdc.stdarg; +import core.stdc.stdio; + +extern(C) int putenv(char*); + +//version = LOG; + +version (Windows) { +} else { + import core.sys.posix.stdlib : putenv; +} + +enum MAX_PATH = 256; /// + +version (Windows) { + import core.sys.windows.windows : GetModuleFileNameA; +} + +string fromStringz(const(char)* s) +{ + return s[0..strlen(s)].idup; +} + +void warning(T...)(string format, T t) +{ + assert(false); +} + +void warning(T...)(Loc loc, string format, T t) +{ + assert(false); +} + +void error(T...)(Loc loc, string format, T t) +{ + if (!global.gag) + { + string p = loc.toChars(); + + if (p.length != 0) + writef("%s: ", p); + + write("Error: "); + writefln(format, t); + + //halt(); + } + global.errors++; +} + +char* strupr(char* s) +{ + char* t = s; + + while (*s) + { + *s = cast(char)toupper(*s); + s++; + } + + return t; +} + +char[] skipspace(char[] p) +{ + foreach (i, c; p) { + if (!isspace(c)) { + return p[i..$]; + } + } + + return null; +} + +char* skipspace(char* p) +{ + while (isspace(*p)) + p++; + + return p; +} + +void inifile(string argv0, string inifile) +{ + char *path; // need path for @P macro + string filename; + int i; + int k; + int envsection = 0; + +version (LOG) { + writef("inifile(argv0 = '%s', inifile = '%s')\n", argv0, inifile); +} + if (FileName.absolute(inifile)) { + filename = inifile; + } else { + /* Look for inifile in the following sequence of places: + * o current directory + * o home directory + * o directory off of argv0 + * o /etc/ + */ + if (FileName.exists(inifile)) { + filename = inifile; + } else { + filename = FileName.combine(getenv("HOME"), inifile); + if (!FileName.exists(filename)) { +version (_WIN32) { // This fix by Tim Matthews + char resolved_name_b[MAX_PATH + 1]; + auto resolved_name = resolved_name_b[].idup; + if (GetModuleFileNameA(null, resolved_name_b.ptr, MAX_PATH + 1) && FileName.exists(resolved_name)) + { + filename = FileName.replaceName(resolved_name, inifile); + if (FileName.exists(filename)) { + goto Ldone; + } + } +} + filename = FileName.replaceName(argv0, inifile); + if (!FileName.exists(filename)) { +version (XXX) { /// linux || __APPLE__ || __FreeBSD__ || __sun&&__SVR4 + version (XXX) { /// __GLIBC__ || __APPLE__ || __FreeBSD__ || __sun&&__SVR4 // This fix by Thomas Kuehne + /* argv0 might be a symbolic link, + * so try again looking past it to the real path + */ + version (XXX) {/// #if __APPLE__ || __FreeBSD__ || __sun&&__SVR4 + char resolved_name[PATH_MAX + 1]; + char* real_argv0 = realpath(argv0, resolved_name); + } else { + char* real_argv0 = realpath(argv0, null); + } + //printf("argv0 = %s, real_argv0 = %p\n", argv0, real_argv0); + if (real_argv0) { + filename = FileName.replaceName(real_argv0, inifile); + version (linux) { + free(real_argv0); + } + if (FileName.exists(filename)) { + goto Ldone; + } + } + } else { + static assert (false, "use of glibc non-standard extension realpath(char*, null)"); + } + if (true) { + // Search PATH for argv0 + const(char)* p = getenv("PATH"); + version (LOG) { + writef("\tPATH='%s'\n", p); + } + Array paths = FileName.splitPath(p); + filename = FileName.searchPath(paths, argv0, 0); + if (!filename) { + goto Letc; // argv0 not found on path + } + + filename = FileName.replaceName(filename, inifile); + if (FileName.exists(filename)) { + goto Ldone; + } + } +} + // Search /etc/ for inifile + Letc: + filename = FileName.combine("/etc/", inifile); + + Ldone: + ; + } + } + } + } + + path = cast(char*)toStringz(FileName.path(filename)); + +version (LOG) { + writef("\tpath = '%s', filename = '%s'\n", fromStringz(path), filename); +} + + scope File file = new File(filename); + + if (file.read()) { + return; // error reading file + } + + scope OutBuffer buf = new OutBuffer(); + + // Parse into lines + int eof = 0; + for (i = 0; i < file.len && !eof; i++) + { + int linestart = i; + + for (; i < file.len; i++) + { + switch (file.buffer[i]) + { + case '\r': + break; + + case '\n': + // Skip if it was preceded by '\r' + if (i && file.buffer[i - 1] == '\r') + goto Lskip; + break; + + case 0: + case 0x1A: + eof = 1; + break; + + default: + continue; + } + break; + } + + // The line is file.buffer[linestart..i] + char *line; + int len; + char *p; + char* pn; + + line = cast(char*)&file.buffer[linestart]; + len = i - linestart; + + buf.reset(); + + // First, expand the macros. + // Macros are bracketed by % characters. + + for (k = 0; k < len; k++) + { + if (line[k] == '%') + { + int j; + + for (j = k + 1; j < len; j++) + { + if (line[j] == '%') + { + if (j - k == 3 && memicmp(&line[k + 1], "@P", 2) == 0) + { + // %@P% is special meaning the path to the .ini file + p = path; + if (!*p) + p = cast(char*)"."; + } + else + { + int l = j - k; + char tmp[10]; // big enough most of the time + + if (l <= tmp.sizeof) + p = tmp.ptr; + else + p = cast(char*)alloca(l); + l--; + memcpy(p, &line[k + 1], l); + p[l] = 0; + strupr(p); + p = core.stdc.stdlib.getenv(p); + if (!p) + p = cast(char*)""; + } + buf.writestring(p[0..strlen(p)]); /// + k = j; + goto L1; + } + } + } + buf.writeByte(line[k]); + L1: + ; + } + + // Remove trailing spaces + while (buf.offset && isspace(buf.data[buf.offset - 1])) + buf.offset--; + + char[] pp = buf.getString(); + + // The expanded line is in p. + // Now parse it for meaning. + + pp = skipspace(pp); + if (pp.length != 0) { + switch (pp[0]) + { + case ';': // comment + break; + + case '[': // look for [Environment] + pp = skipspace(pp[1..$]); + for (pn = pp.ptr; isalnum(*pn); pn++) { + ; + } + + if (pn - pp.ptr == 11 && + memicmp(pp.ptr, "Environment", 11) == 0 && + *skipspace(pn) == ']' + ) + envsection = 1; + else + envsection = 0; + break; + + default: + if (envsection) + { + pn = pp.ptr; + + // Convert name to upper case; + // remove spaces bracketing = + auto p2 = pn; + for ( ; *p2; p2++) + { if (islower(*p2)) + *p2 &= ~0x20; + else if (isspace(*p)) + memmove(p2, p2 + 1, strlen(p2)); + else if (*p2 == '=') + { + p2++; + while (isspace(*p2)) + memmove(p2, p2 + 1, strlen(p2)); + break; + } + } + + //putenv(pn); + putenv(cast(char*)toStringz(pp)); + +version (LOG) { + writef("\tputenv('%s')\n", pn[0..strlen(pn)]); + //printf("getenv(\"TEST\") = '%s'\n",getenv("TEST")); +} + } + break; + } + } + + Lskip: + ; + } +} + +///int response_expand(int *pargc, char ***pargv); +void browse(const(char)* url) +{ + assert(false); +} + +string[] getenv_setargv(string envvar, string[] args) +{ + char *p; + + string[] argv = args.dup; + int argc = args.length; + + int wildcard; // do wildcard expansion + int instring; + int slash; + char c; + int j; + + string ienv = getenv(envvar); + if (ienv is null) + return args; + + char[] env = ienv.dup; // create our own writable copy + + j = 1; // leave argv[0] alone + char* e = env.ptr; + while (1) + { + wildcard = 1; + switch (*e) + { + case ' ': + case '\t': + e++; + break; + + case 0: + goto Ldone; + + case '"': + wildcard = 0; + default: + argv ~= assumeUnique(e[0..strlen(e)]); // append + //argv.insert(j, env); // insert at position j + j++; + argc++; + p = e; + slash = 0; + instring = 0; + c = 0; + + char* ecopy = e; + + while (1) + { + c = *e++; + switch (c) + { + case '"': + p -= (slash >> 1); + if (slash & 1) + { + p--; + goto Laddc; + } + instring ^= 1; + slash = 0; + continue; + + case '\\': + slash++; + *p++ = c; + continue; + + case ' ': + case '\t': + if (instring) + goto Laddc; + case 0: + *p = 0; + if (argv.length != 0) { + argv[$-1].length = p - argv[$-1].ptr; + } + //if (wildcard) + //wildcardexpand(); // not implemented + if (c == 0) goto Ldone; + break; + + default: + Laddc: + slash = 0; + *p++ = c; + continue; + } + break; + } + } + } + +Ldone: + return argv; +} + +void error(T...)(string format, T t) +{ + writefln(format, t); + exit(EXIT_FAILURE); +} + +void usage() +{ + writef("Digital Mars D Compiler %s\n%s %s\n", global.version_, global.copyright, global.written); + writef( +"Documentation: http://www.digitalmars.com/d/2.0/index.html\n" +"Usage:\n" +" dmd files.d ... { -switch }\n" +"\n" +" files.d D source files\n" +" @cmdfile read arguments from cmdfile\n" +" -c do not link\n" +" -cov do code coverage analysis\n" +" -D generate documentation\n" +" -Dddocdir write documentation file to docdir directory\n" +" -Dffilename write documentation file to filename\n" +" -d allow deprecated features\n" +" -debug compile in debug code\n" +" -debug=level compile in debug code <= level\n" +" -debug=ident compile in debug code identified by ident\n" +" -debuglib=name set symbolic debug library to name\n" +" -defaultlib=name set default library to name\n" +" -deps=filename write module dependencies to filename\n" +" -g add symbolic debug info\n" +" -gc add symbolic debug info, pretend to be C\n" +" -H generate 'header' file\n" +" -Hdhdrdir write 'header' file to hdrdir directory\n" +" -Hffilename write 'header' file to filename\n" +" --help print help\n" +" -Ipath where to look for imports\n" +" -ignore ignore unsupported pragmas\n" +" -inline do function inlining\n" +" -Jpath where to look for string imports\n" +" -Llinkerflag pass linkerflag to link\n" +" -lib generate library rather than object files\n" +" -man open web browser on manual page\n" +" -nofloat do not emit reference to floating point\n" +" -O optimize\n" +" -o- do not write object file\n" +" -odobjdir write object & library files to directory objdir\n" +" -offilename name output file to filename\n" +" -op do not strip paths from source file\n" +" -profile profile runtime performance of generated code\n" +" -quiet suppress unnecessary messages\n" +" -release compile release version\n" +" -run srcfile args... run resulting program, passing args\n" +" -safe safe memory model\n" +" -unittest compile in unit tests\n" +" -v verbose\n" +" -version=level compile in version code >= level\n" +" -version=ident compile in version code identified by ident\n" +" -vtls list all variables going into thread local storage\n" +" -w enable warnings\n" +); +} + +void fatal() +{ +static if (false) { + halt(); +} else { + exit(EXIT_FAILURE); +} +} + +void halt() +{ + assert(false); +} + +void initPrecedence() +{ + precedence[TOK.TOKdotvar] = PREC.PREC_primary; + precedence[TOK.TOKimport] = PREC.PREC_primary; + precedence[TOK.TOKidentifier] = PREC.PREC_primary; + precedence[TOK.TOKthis] = PREC.PREC_primary; + precedence[TOK.TOKsuper] = PREC.PREC_primary; + precedence[TOK.TOKint64] = PREC.PREC_primary; + precedence[TOK.TOKfloat64] = PREC.PREC_primary; + precedence[TOK.TOKnull] = PREC.PREC_primary; + precedence[TOK.TOKstring] = PREC.PREC_primary; + precedence[TOK.TOKarrayliteral] = PREC.PREC_primary; + precedence[TOK.TOKtypeid] = PREC.PREC_primary; + precedence[TOK.TOKis] = PREC.PREC_primary; + precedence[TOK.TOKassert] = PREC.PREC_primary; + precedence[TOK.TOKfunction] = PREC.PREC_primary; + precedence[TOK.TOKvar] = PREC.PREC_primary; +version (DMDV2) { + precedence[TOK.TOKdefault] = PREC.PREC_primary; +} + + // post + precedence[TOK.TOKdotti] = PREC.PREC_primary; + precedence[TOK.TOKdot] = PREC.PREC_primary; +// precedence[TOK.TOKarrow] = PREC.PREC_primary; + precedence[TOK.TOKplusplus] = PREC.PREC_primary; + precedence[TOK.TOKminusminus] = PREC.PREC_primary; + precedence[TOK.TOKcall] = PREC.PREC_primary; + precedence[TOK.TOKslice] = PREC.PREC_primary; + precedence[TOK.TOKarray] = PREC.PREC_primary; + + precedence[TOK.TOKaddress] = PREC.PREC_unary; + precedence[TOK.TOKstar] = PREC.PREC_unary; + precedence[TOK.TOKneg] = PREC.PREC_unary; + precedence[TOK.TOKuadd] = PREC.PREC_unary; + precedence[TOK.TOKnot] = PREC.PREC_unary; + precedence[TOK.TOKtobool] = PREC.PREC_add; + precedence[TOK.TOKtilde] = PREC.PREC_unary; + precedence[TOK.TOKdelete] = PREC.PREC_unary; + precedence[TOK.TOKnew] = PREC.PREC_unary; + precedence[TOK.TOKcast] = PREC.PREC_unary; + + precedence[TOK.TOKmul] = PREC.PREC_mul; + precedence[TOK.TOKdiv] = PREC.PREC_mul; + precedence[TOK.TOKmod] = PREC.PREC_mul; + + precedence[TOK.TOKadd] = PREC.PREC_add; + precedence[TOK.TOKmin] = PREC.PREC_add; + precedence[TOK.TOKcat] = PREC.PREC_add; + + precedence[TOK.TOKshl] = PREC.PREC_shift; + precedence[TOK.TOKshr] = PREC.PREC_shift; + precedence[TOK.TOKushr] = PREC.PREC_shift; + + precedence[TOK.TOKlt] = PREC.PREC_rel; + precedence[TOK.TOKle] = PREC.PREC_rel; + precedence[TOK.TOKgt] = PREC.PREC_rel; + precedence[TOK.TOKge] = PREC.PREC_rel; + precedence[TOK.TOKunord] = PREC.PREC_rel; + precedence[TOK.TOKlg] = PREC.PREC_rel; + precedence[TOK.TOKleg] = PREC.PREC_rel; + precedence[TOK.TOKule] = PREC.PREC_rel; + precedence[TOK.TOKul] = PREC.PREC_rel; + precedence[TOK.TOKuge] = PREC.PREC_rel; + precedence[TOK.TOKug] = PREC.PREC_rel; + precedence[TOK.TOKue] = PREC.PREC_rel; + precedence[TOK.TOKin] = PREC.PREC_rel; + +static if (false) { + precedence[TOK.TOKequal] = PREC.PREC_equal; + precedence[TOK.TOKnotequal] = PREC.PREC_equal; + precedence[TOK.TOKidentity] = PREC.PREC_equal; + precedence[TOK.TOKnotidentity] = PREC.PREC_equal; +} else { + /* Note that we changed precedence, so that < and != have the same + * precedence. This change is in the parser, too. + */ + precedence[TOK.TOKequal] = PREC.PREC_rel; + precedence[TOK.TOKnotequal] = PREC.PREC_rel; + precedence[TOK.TOKidentity] = PREC.PREC_rel; + precedence[TOK.TOKnotidentity] = PREC.PREC_rel; +} + + precedence[TOK.TOKand] = PREC.PREC_and; + + precedence[TOK.TOKxor] = PREC.PREC_xor; + + precedence[TOK.TOKor] = PREC.PREC_or; + + precedence[TOK.TOKandand] = PREC.PREC_andand; + + precedence[TOK.TOKoror] = PREC.PREC_oror; + + precedence[TOK.TOKquestion] = PREC.PREC_cond; + + precedence[TOK.TOKassign] = PREC.PREC_assign; + precedence[TOK.TOKconstruct] = PREC.PREC_assign; + precedence[TOK.TOKblit] = PREC.PREC_assign; + precedence[TOK.TOKaddass] = PREC.PREC_assign; + precedence[TOK.TOKminass] = PREC.PREC_assign; + precedence[TOK.TOKcatass] = PREC.PREC_assign; + precedence[TOK.TOKmulass] = PREC.PREC_assign; + precedence[TOK.TOKdivass] = PREC.PREC_assign; + precedence[TOK.TOKmodass] = PREC.PREC_assign; + precedence[TOK.TOKshlass] = PREC.PREC_assign; + precedence[TOK.TOKshrass] = PREC.PREC_assign; + precedence[TOK.TOKushrass] = PREC.PREC_assign; + precedence[TOK.TOKandass] = PREC.PREC_assign; + precedence[TOK.TOKorass] = PREC.PREC_assign; + precedence[TOK.TOKxorass] = PREC.PREC_assign; + + precedence[TOK.TOKcomma] = PREC.PREC_expr; +} + +int runLINK() +{ +version (_WIN32) { + string p; + int i; + int status; + scope OutBuffer cmdbuf = new OutBuffer(); + + global.params.libfiles.push(cast(void*)new String("user32")); + global.params.libfiles.push(cast(void*)new String("kernel32")); + + for (i = 0; i < global.params.objfiles.dim; i++) + { + if (i) + cmdbuf.writeByte('+'); + p = (cast(String)global.params.objfiles.data[i]).str; + string ext = FileName.ext(p); + if (ext) + // Write name sans extension + writeFilename(cmdbuf, p[0..p.length - ext.length - 1]); + else + writeFilename(cmdbuf, p); + } + cmdbuf.writeByte(','); + if (global.params.exefile) + writeFilename(cmdbuf, global.params.exefile); + else + { + /* Generate exe file name from first obj name. + * No need to add it to cmdbuf because the linker will default to it. + */ + string n = (cast(String)global.params.objfiles.data[0]).str; + n = FileName.name(n); + FileName fn = FileName.forceExt(n, "exe"); + global.params.exefile = fn.toChars(); + } + + // Make sure path to exe file exists + { + string pp = FileName.path(global.params.exefile); + FileName.ensurePathExists(pp); + } + + cmdbuf.writeByte(','); + if (global.params.run) + cmdbuf.writestring("nul"); + +// if (mapfile) +// cmdbuf.writestring(output); + cmdbuf.writeByte(','); + + for (i = 0; i < global.params.libfiles.dim; i++) + { + if (i) + cmdbuf.writeByte('+'); + writeFilename(cmdbuf, (cast(String)global.params.libfiles.data[i]).str); + } + + if (global.params.deffile) + { + cmdbuf.writeByte(','); + writeFilename(cmdbuf, global.params.deffile); + } + + /* Eliminate unnecessary trailing commas */ + while (1) + { + i = cmdbuf.offset; + if (!i || cmdbuf.data[i - 1] != ',') + break; + cmdbuf.offset--; + } + + if (global.params.resfile) + { + cmdbuf.writestring("/RC:"); + writeFilename(cmdbuf, global.params.resfile); + } + +static if (false) { + if (mapfile) + cmdbuf.writestring("/m"); + if (debuginfo) + cmdbuf.writestring("/li"); + if (codeview) + { + cmdbuf.writestring("/co"); + if (codeview3) + cmdbuf.writestring(":3"); + } +} else { + if (global.params.symdebug) + cmdbuf.writestring("/co"); +} + + cmdbuf.writestring("/noi"); + for (i = 0; i < global.params.linkswitches.dim; i++) + { + cmdbuf.writestring((cast(String)global.params.linkswitches.data[i]).str); + } + cmdbuf.writeByte(';'); + + p = cmdbuf.toChars(); + + FileName lnkfilename = null; + size_t plen = p.length; + if (plen > 7000) + { + lnkfilename = FileName.forceExt(global.params.exefile, "lnk"); + scope File flnk = new File(lnkfilename); + flnk.setbuffer(cast(void*)p.ptr, plen); + flnk.ref_ = 1; + if (flnk.write()) + error("error writing file %s", lnkfilename); + if (lnkfilename.len() < plen) + p = std.string.format("@%s", lnkfilename.toChars()); + } + + string linkcmd = getenv("LINKCMD"); + if (!linkcmd) + linkcmd = "link"; + + status = executecmd(linkcmd, p, 1); + if (lnkfilename) + { + remove(toStringz(lnkfilename.toChars())); + ///delete lnkfilename; + } + return status; +} else if (XXX) {/// linux || __APPLE__ || __FreeBSD__ || __sun&&__SVR4 + assert(false); + /+ + pid_t childpid; + int i; + int status; + + // Build argv[] + Array argv; + + const char *cc = getenv("CC"); + if (!cc) + cc = "gcc"; + argv.push((void *)cc); + argv.insert(1, global.params.objfiles); + + // None of that a.out stuff. Use explicit exe file name, or + // generate one from name of first source file. + argv.push((void *)"-o"); + if (global.params.exefile) + { + argv.push(global.params.exefile); + } + else + { // Generate exe file name from first obj name + char *n = (char *)global.params.objfiles.data[0]; + char *e; + char *ex; + + n = FileName.name(n); + e = FileName.ext(n); + if (e) + { + e--; // back up over '.' + ex = (char *)mem.malloc(e - n + 1); + memcpy(ex, n, e - n); + ex[e - n] = 0; + } + else + ex = (char *)"a.out"; // no extension, so give up + argv.push(ex); + global.params.exefile = ex; + } + + // Make sure path to exe file exists + { char *p = FileName.path(global.params.exefile); + FileName.ensurePathExists(p); + mem.free(p); + } + + if (global.params.symdebug) + argv.push((void *)"-g"); + + if (global.params.isX86_64) + argv.push((void *)"-m64"); + else + argv.push((void *)"-m32"); + + if (0 && global.params.exefile) + { + /* This switch enables what is known as 'smart linking' + * in the Windows world, where unreferenced sections + * are removed from the executable. It eliminates unreferenced + * functions, essentially making a 'library' out of a module. + * Although it is documented to work with ld version 2.13, + * in practice it does not, but just seems to be ignored. + * Thomas Kuehne has verified that it works with ld 2.16.1. + * BUG: disabled because it causes exception handling to fail + */ + argv.push((void *)"-Xlinker"); + argv.push((void *)"--gc-sections"); + } + + for (i = 0; i < global.params.linkswitches.dim; i++) + { char *p = (char *)global.params.linkswitches.data[i]; + if (!p || !p[0] || !(p[0] == '-' && p[1] == 'l')) + // Don't need -Xlinker if switch starts with -l + argv.push((void *)"-Xlinker"); + argv.push((void *) p); + } + + /* Add each library, prefixing it with "-l". + * The order of libraries passed is: + * 1. any libraries passed with -L command line switch + * 2. libraries specified on the command line + * 3. libraries specified by pragma(lib), which were appended + * to global.params.libfiles. + * 4. standard libraries. + */ + for (i = 0; i < global.params.libfiles.dim; i++) + { char *p = (char *)global.params.libfiles.data[i]; + size_t plen = strlen(p); + if (plen > 2 && p[plen - 2] == '.' && p[plen -1] == 'a') + argv.push((void *)p); + else + { + char *s = (char *)mem.malloc(plen + 3); + s[0] = '-'; + s[1] = 'l'; + memcpy(s + 2, p, plen + 1); + argv.push((void *)s); + } + } + + /* Standard libraries must go after user specified libraries + * passed with -l. + */ + const char *libname = (global.params.symdebug) + ? global.params.debuglibname + : global.params.defaultlibname; + char *buf = (char *)malloc(2 + strlen(libname) + 1); + strcpy(buf, "-l"); + strcpy(buf + 2, libname); + argv.push((void *)buf); // turns into /usr/lib/libphobos2.a + +// argv.push((void *)"-ldruntime"); + argv.push((void *)"-lpthread"); + argv.push((void *)"-lm"); + + if (!global.params.quiet || global.params.verbose) + { + // Print it + for (i = 0; i < argv.dim; i++) + printf("%s ", (char *)argv.data[i]); + printf("\n"); + fflush(stdout); + } + + argv.push(null); + childpid = fork(); + if (childpid == 0) + { + execvp((char *)argv.data[0], (char **)argv.data); + perror((char *)argv.data[0]); // failed to execute + return -1; + } + + waitpid(childpid, &status, 0); + + status=WEXITSTATUS(status); + if (status) + printf("--- errorlevel %d\n", status); + return status; + +/ +} else { + writef ("Linking is not yet supported for this version of DMD.\n"); + return -1; +} +} + +int runProgram() +{ + assert(false); +} + +void deleteExeFile() +{ + assert(false); +} + +/**************************************** + * Write filename to cmdbuf, quoting if necessary. + */ + +void writeFilename(OutBuffer buf, string filename) +{ + auto len = filename.length; + /* Loop and see if we need to quote + */ + for (size_t i = 0; i < len; i++) + { + char c = filename[i]; + + if (isalnum(c) || c == '_') + continue; + + /* Need to quote + */ + buf.writeByte('"'); + buf.writestring(filename); + buf.writeByte('"'); + return; + } + + /* No quoting necessary + */ + buf.writestring(filename); +} + +/****************************** + * Execute a rule. Return the status. + * cmd program to run + * args arguments to cmd, as a string + * useenv if cmd knows about _CMDLINE environment variable + */ + +version (_WIN32) { +int executecmd(string cmd, string args, int useenv) +{ + int status; + size_t len = args.length; + + if (!global.params.quiet || global.params.verbose) + { + printf("%s %s\n", cmd, args); + fflush(stdout); + } + + if (len > 255) + { + char* q; + static char[9] envname = "@_CMDLINE"; + + envname[0] = '@'; + switch (useenv) + { + case 0: goto L1; + case 2: envname[0] = '%'; break; + default: break; /// + } + q = cast(char*) alloca(envname.sizeof + len + 1); + sprintf(q, "%s=%s", envname.ptr + 1, args); + status = putenv(q); + if (status == 0) + args = envname[].idup; + else + { + L1: + error("command line length of %d is too long",len); + } + } + + status = executearg0(cmd, args); +version (_WIN32) { + if (status == -1) { + auto cmdZ = toStringz(cmd); + auto argsZ = toStringz(args); + status = spawnlp(0, cmdZ, cmdZ, argsZ, null); + } +} +// if (global.params.verbose) +// printf("\n"); + if (status) + { + if (status == -1) + printf("Can't run '%s', check PATH\n", cmd); + else + printf("--- errorlevel %d\n", status); + } + return status; +} +} + +/************************************** + * Attempt to find command to execute by first looking in the directory + * where DMD was run from. + * Returns: + * -1 did not find command there + * !=-1 exit status from command + */ + +version (_WIN32) { +int executearg0(string cmd, string args) +{ + string file; + string argv0 = global.params.argv0; + + //printf("argv0='%s', cmd='%s', args='%s'\n",argv0,cmd,args); + + // If cmd is fully qualified, we don't do this + if (FileName.absolute(cmd)) + return -1; + + file = FileName.replaceName(argv0, cmd); + + //printf("spawning '%s'\n",file); +version (_WIN32) { + auto fileZ = toStringz(file); + auto argsZ = toStringz(args); + return spawnl(0, fileZ, fileZ, argsZ, null); +} else version (XXX) { ///#elif linux || __APPLE__ || __FreeBSD__ || __sun&&__SVR4 + assert(false); + /+ + char *full; + int cmdl = strlen(cmd); + + full = (char*) mem.malloc(cmdl + strlen(args) + 2); + if (full == null) + return 1; + strcpy(full, cmd); + full [cmdl] = ' '; + strcpy(full + cmdl + 1, args); + + int result = system(full); + + mem.free(full); + return result; + +/ +} else { + static assert(false); +} +} +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/VarDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/VarDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,1188 @@ +module dmd.VarDeclaration; + +import dmd.Declaration; +import dmd.SliceExp; +import dmd.ClassDeclaration; +import dmd.DeleteExp; +import dmd.SymOffExp; +import dmd.DotIdExp; +import dmd.PtrExp; +import dmd.CallExp; +import dmd.DotVarExp; +import dmd.CommaExp; +import dmd.CastExp; +import dmd.WANT; +import dmd.StructDeclaration; +import dmd.DsymbolExp; +import dmd.TypeSArray; +import dmd.IntegerExp; +import dmd.VarExp; +import dmd.AssignExp; +import dmd.TypeTypedef; +import dmd.ArrayInitializer; +import dmd.StructInitializer; +import dmd.NewExp; +import dmd.TupleDeclaration; +import dmd.AggregateDeclaration; +import dmd.InterfaceDeclaration; +import dmd.TemplateInstance; +import dmd.Id; +import dmd.Initializer; +import dmd.TypeStruct; +import dmd.TypeTuple; +import dmd.Argument; +import dmd.ExpInitializer; +import dmd.ArrayTypes; +import dmd.Dsymbol; +import dmd.Expression; +import dmd.Loc; +import dmd.STC; +import dmd.TOK; +import dmd.TupleExp; +import dmd.Global; +import dmd.FuncDeclaration; +import dmd.Type; +import dmd.TY; +import dmd.LINK; +import dmd.Scope; +import dmd.Identifier; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.PROT; + +import dmd.backend.Symbol; +import dmd.backend.TYM; +import dmd.backend.FL; +import dmd.backend.DT; +import dmd.backend.mTY; +import dmd.backend.SC; +import dmd.backend.mTYman; +import dmd.backend.TYPE; +import dmd.backend.Util; +import dmd.backend.LIST; + +import std.stdio : writef; +import std.string : toStringz; + +class VarDeclaration : Declaration +{ + Initializer init; + uint offset; + bool noauto; // no auto semantics +version (DMDV2) { + FuncDeclarations nestedrefs; // referenced by these lexically nested functions +} else { + int nestedref; // referenced by a lexically nested function +} + int ctorinit; // it has been initialized in a ctor + int onstack; // 1: it has been allocated on the stack + // 2: on stack, run destructor anyway + int canassign; // it can be assigned to + Dsymbol aliassym; // if redone as alias to another symbol + Expression value; // when interpreting, this is the value + // (null if value not determinable) +version (DMDV2) { + VarDeclaration rundtor; // if !null, rundtor is tested at runtime to see + // if the destructor should be run. Used to prevent + // dtor calls on postblitted vars +} + + this(Loc loc, Type type, Identifier id, Initializer init) + { + super(id); + +debug { + if (!type && !init) + { + writef("VarDeclaration('%s')\n", id.toChars()); + //*(char*)0=0; + } +} + assert(type || init); + this.type = type; + this.init = init; + this.loc = loc; + + nestedrefs = new FuncDeclarations(); + } + + Dsymbol syntaxCopy(Dsymbol s) + { + //printf("VarDeclaration.syntaxCopy(%s)\n", toChars()); + + VarDeclaration sv; + if (s) + { + sv = cast(VarDeclaration)s; + } + else + { + Initializer init = null; + if (this.init) + { + init = this.init.syntaxCopy(); + //init.isExpInitializer().exp.print(); + //init.isExpInitializer().exp.dump(0); + } + + sv = new VarDeclaration(loc, type ? type.syntaxCopy() : null, ident, init); + sv.storage_class = storage_class; + } + + version (_DH) { + // Syntax copy for header file + if (!htype) // Don't overwrite original + { + if (type) // Make copy for both old and new instances + { htype = type.syntaxCopy(); + sv.htype = type.syntaxCopy(); + } + } + else // Make copy of original for new instance + sv.htype = htype.syntaxCopy(); + if (!hinit) + { + if (init) + { + hinit = init.syntaxCopy(); + sv.hinit = init.syntaxCopy(); + } + } + else + sv.hinit = hinit.syntaxCopy(); + } + return sv; + } + + void semantic(Scope sc) + { +static if (false) { + printf("VarDeclaration.semantic('%s', parent = '%s')\n", toChars(), sc.parent.toChars()); + printf(" type = %s\n", type ? type.toChars() : "null"); + printf(" stc = x%x\n", sc.stc); + printf(" storage_class = x%x\n", storage_class); + printf("linkage = %d\n", sc.linkage); + //if (strcmp(toChars(), "mul") == 0) halt(); +} + + storage_class |= sc.stc; + if (storage_class & STC.STCextern && init) + error("extern symbols cannot have initializers"); + + /* If auto type inference, do the inference + */ + int inferred = 0; + if (!type) + { + inuse++; + type = init.inferType(sc); + inuse--; + inferred = 1; + + /* This is a kludge to support the existing syntax for RAII + * declarations. + */ + storage_class &= ~STC.STCauto; + originalType = type; + } + else + { + if (!originalType) + originalType = type; + + type = type.semantic(loc, sc); + } + //printf(" semantic type = %s\n", type ? type.toChars() : "null"); + + type.checkDeprecated(loc, sc); + linkage = sc.linkage; + this.parent = sc.parent; + //printf("this = %p, parent = %p, '%s'\n", this, parent, parent.toChars()); + protection = sc.protection; + //printf("sc.stc = %x\n", sc.stc); + //printf("storage_class = x%x\n", storage_class); + +version (DMDV2) { + if (storage_class & STC.STCgshared && global.params.safe && !sc.module_.safe) + { + error("__gshared not allowed in safe mode; use shared"); + } +} + + Dsymbol parent = toParent(); + FuncDeclaration fd = parent.isFuncDeclaration(); + + Type tb = type.toBasetype(); + if (tb.ty == TY.Tvoid && !(storage_class & STC.STClazy)) + { error("voids have no value"); + type = Type.terror; + tb = type; + } + if (tb.ty == TY.Tfunction) + { error("cannot be declared to be a function"); + type = Type.terror; + tb = type; + } + if (tb.ty == TY.Tstruct) + { TypeStruct ts = cast(TypeStruct)tb; + + if (!ts.sym.members) + { + error("no definition of struct %s", ts.toChars()); + } + } + + if (tb.ty == TY.Ttuple) + { /* Instead, declare variables for each of the tuple elements + * and add those. + */ + TypeTuple tt = cast(TypeTuple)tb; + size_t nelems = Argument.dim(tt.arguments); + Objects exps = new Objects(); + exps.setDim(nelems); + Expression ie = init ? init.toExpression() : null; + + for (size_t i = 0; i < nelems; i++) + { Argument arg = Argument.getNth(tt.arguments, i); + + OutBuffer buf; + buf.printf("_%s_field_%zu", ident.toChars(), i); + buf.writeByte(0); + string name = buf.extractString(); + Identifier id = new Identifier(name, TOK.TOKidentifier); + + Expression einit = ie; + if (ie && ie.op == TOK.TOKtuple) + { einit = cast(Expression)(cast(TupleExp)ie).exps.data[i]; + } + Initializer ti = init; + if (einit) + { ti = new ExpInitializer(einit.loc, einit); + } + + VarDeclaration v = new VarDeclaration(loc, arg.type, id, ti); + //printf("declaring field %s of type %s\n", v.toChars(), v.type.toChars()); + v.semantic(sc); + + if (sc.scopesym) + { //printf("adding %s to %s\n", v.toChars(), sc.scopesym.toChars()); + if (sc.scopesym.members) + sc.scopesym.members.push(cast(void*)v); + } + + Expression e = new DsymbolExp(loc, v); + exps.data[i] = cast(void*)e; + } + TupleDeclaration v2 = new TupleDeclaration(loc, ident, exps); + v2.isexp = 1; + aliassym = v2; + return; + } + + Lagain: + /* Storage class can modify the type + */ + type = type.addStorageClass(storage_class); + + /* Adjust storage class to reflect type + */ + if (type.isConst()) + { storage_class |= STC.STCconst; + if (type.isShared()) + storage_class |= STC.STCshared; + } + else if (type.isInvariant()) + storage_class |= STC.STCimmutable; + else if (type.isShared()) + storage_class |= STC.STCshared; + + if (isSynchronized()) + { + error("variable %s cannot be synchronized", toChars()); + } + else if (isOverride()) + { + error("override cannot be applied to variable"); + } + else if (isAbstract()) + { + error("abstract cannot be applied to variable"); + } + else if (storage_class & STC.STCfinal) + { + error("final cannot be applied to variable"); + } + + if (storage_class & (STC.STCstatic | STC.STCextern | STC.STCmanifest | STC.STCtemplateparameter | STC.STCtls | STC.STCgshared)) + { + } + else + { + AggregateDeclaration aad = sc.anonAgg; + if (!aad) + aad = parent.isAggregateDeclaration(); + if (aad) + { +///version (DMDV2) { + assert(!(storage_class & (STC.STCextern | STC.STCstatic | STC.STCtls | STC.STCgshared))); + + if (storage_class & (STC.STCconst | STC.STCimmutable) && init) + { + if (!type.toBasetype().isTypeBasic()) + storage_class |= STC.STCstatic; + } + else +///} + aad.addField(sc, this); + } + + InterfaceDeclaration id = parent.isInterfaceDeclaration(); + if (id) + { + error("field not allowed in interface"); + } + + /* Templates cannot add fields to aggregates + */ + TemplateInstance ti = parent.isTemplateInstance(); + if (ti) + { + // Take care of nested templates + while (1) + { + TemplateInstance ti2 = ti.tempdecl.parent.isTemplateInstance(); + if (!ti2) + break; + ti = ti2; + } + + // If it's a member template + AggregateDeclaration ad = ti.tempdecl.isMember(); + if (ad && storage_class != STC.STCundefined) + { + error("cannot use template to add field to aggregate '%s'", ad.toChars()); + } + } + } + +version (DMDV2) { + if ((storage_class & (STC.STCref | STC.STCparameter | STC.STCforeach)) == STC.STCref && ident != Id.This) + { + error("only parameters or foreach declarations can be ref"); + } +} + + if (type.isauto() && !noauto) + { + if (storage_class & (STC.STCfield | STC.STCout | STC.STCref | STC.STCstatic | STC.STCmanifest | STC.STCtls | STC.STCgshared) || !fd) + { + error("globals, statics, fields, manifest constants, ref and out parameters cannot be scope"); + } + + if (!(storage_class & (STC.STCauto | STC.STCscope))) + { + if (!(storage_class & STC.STCparameter) && ident != Id.withSym) + error("reference to scope class must be scope"); + } + } + + if ((isConst() || isInvariant()) && !init && !fd) + { + // Initialize by constructor only + storage_class |= STC.STCctorinit; + } + + if (init) + storage_class |= STC.STCinit; // remember we had an explicit initializer + else if (storage_class & STC.STCmanifest) + error("manifest constants must have initializers"); + + TOK op = TOK.TOKconstruct; + if (!init && !sc.inunion && !isStatic() && fd && + (!(storage_class & (STC.STCfield | STC.STCin | STC.STCforeach | STC.STCparameter)) || (storage_class & STC.STCout)) && + type.size() != 0) + { + // Provide a default initializer + //printf("Providing default initializer for '%s'\n", toChars()); + if (type.ty == TY.Tstruct && + (cast(TypeStruct)type).sym.zeroInit) + { /* If a struct is all zeros, as a special case + * set it's initializer to the integer 0. + * In AssignExp.toElem(), we check for this and issue + * a memset() to initialize the struct. + * Must do same check in interpreter. + */ + Expression e = new IntegerExp(loc, 0, Type.tint32); + Expression e1; + e1 = new VarExp(loc, this); + e = new AssignExp(loc, e1, e); + e.op = TOK.TOKconstruct; + e.type = e1.type; // don't type check this, it would fail + init = new ExpInitializer(loc, e); + return; + } + else if (type.ty == TY.Ttypedef) + { TypeTypedef td = cast(TypeTypedef)type; + if (td.sym.init) + { init = td.sym.init; + ExpInitializer ie = init.isExpInitializer(); + if (ie) + // Make copy so we can modify it + init = new ExpInitializer(ie.loc, ie.exp); + } + else + init = getExpInitializer(); + } + else + { + init = getExpInitializer(); + } + // Default initializer is always a blit + op = TOK.TOKblit; + } + + if (init) + { + sc = sc.push(); + sc.stc &= ~(STC.STC_TYPECTOR | STC.STCpure | STC.STCnothrow | STC.STCref); + + ArrayInitializer ai = init.isArrayInitializer(); + if (ai && tb.ty == TY.Taarray) + { + init = ai.toAssocArrayInitializer(); + } + + StructInitializer si = init.isStructInitializer(); + ExpInitializer ei = init.isExpInitializer(); + + // See if initializer is a NewExp that can be allocated on the stack + if (ei && isScope() && ei.exp.op == TOK.TOKnew) + { NewExp ne = cast(NewExp)ei.exp; + if (!(ne.newargs && ne.newargs.dim)) + { ne.onstack = 1; + onstack = 1; + if (type.isBaseOf(ne.newtype.semantic(loc, sc), null)) + onstack = 2; + } + } + + // If inside function, there is no semantic3() call + if (sc.func) + { + // If local variable, use AssignExp to handle all the various + // possibilities. + if (fd && + !(storage_class & (STC.STCmanifest | STC.STCstatic | STC.STCtls | STC.STCgshared | STC.STCextern)) && + !init.isVoidInitializer()) + { + //printf("fd = '%s', var = '%s'\n", fd.toChars(), toChars()); + if (!ei) + { + Expression e = init.toExpression(); + if (!e) + { + init = init.semantic(sc, type); + e = init.toExpression(); + if (!e) + { error("is not a static and cannot have static initializer"); + return; + } + } + ei = new ExpInitializer(init.loc, e); + init = ei; + } + + Expression e1 = new VarExp(loc, this); + + Type t = type.toBasetype(); + if (t.ty == TY.Tsarray && !(storage_class & (STC.STCref | STC.STCout))) + { + ei.exp = ei.exp.semantic(sc); + if (!ei.exp.implicitConvTo(type)) + { + int dim = cast(int)(cast(TypeSArray)t).dim.toInteger(); /// + // If multidimensional static array, treat as one large array + while (1) + { + t = t.nextOf().toBasetype(); + if (t.ty != TY.Tsarray) + break; + dim *= (cast(TypeSArray)t).dim.toInteger(); + e1.type = new TypeSArray(t.nextOf(), new IntegerExp(Loc(0), dim, Type.tindex)); + } + } + e1 = new SliceExp(loc, e1, null, null); + } + else if (t.ty == TY.Tstruct) + { + ei.exp = ei.exp.semantic(sc); +version (DMDV2) { + /* Look to see if initializer is a call to the constructor + */ + StructDeclaration sd = (cast(TypeStruct)t).sym; + if (sd.ctor && // there are constructors + ei.exp.type.ty == TY.Tstruct && // rvalue is the same struct + (cast(TypeStruct)ei.exp.type).sym == sd && + ei.exp.op == TOK.TOKstar) + { + /* Look for form of constructor call which is: + * *__ctmp.ctor(arguments...) + */ + PtrExp pe = cast(PtrExp)ei.exp; + if (pe.e1.op == TOK.TOKcall) + { CallExp ce = cast(CallExp)pe.e1; + if (ce.e1.op == TOK.TOKdotvar) + { DotVarExp dve = cast(DotVarExp)ce.e1; + if (dve.var.isCtorDeclaration()) + { /* It's a constructor call, currently constructing + * a temporary __ctmp. + */ + /* Before calling the constructor, initialize + * variable with a bit copy of the default + * initializer + */ + Expression e = new AssignExp(loc, new VarExp(loc, this), t.defaultInit(loc)); + e.op = TOK.TOKblit; + e.type = t; + ei.exp = new CommaExp(loc, e, ei.exp); + + /* Replace __ctmp being constructed with e1 + */ + dve.e1 = e1; + return; + } + } + } + } +} + if (!ei.exp.implicitConvTo(type)) + { Type ti = ei.exp.type.toBasetype(); + // Don't cast away invariant or mutability in initializer + if (!(ti.ty == TY.Tstruct && t.toDsymbol(sc) == ti.toDsymbol(sc))) + ei.exp = new CastExp(loc, ei.exp, type); + } + } + ei.exp = new AssignExp(loc, e1, ei.exp); + ei.exp.op = op; + canassign++; + ei.exp = ei.exp.semantic(sc); + canassign--; + ei.exp.optimize(WANT.WANTvalue); + } + else + { + init = init.semantic(sc, type); + } + } + else if (storage_class & (STC.STCconst | STC.STCimmutable | STC.STCmanifest) || + type.isConst() || type.isInvariant()) + { + /* Because we may need the results of a const declaration in a + * subsequent type, such as an array dimension, before semantic2() + * gets ordinarily run, try to run semantic2() now. + * Ignore failure. + */ + + if (!global.errors && !inferred) + { + uint errors = global.errors; + global.gag++; + //printf("+gag\n"); + Expression e; + Initializer i2 = init; + inuse++; + if (ei) + { + e = ei.exp.syntaxCopy(); + e = e.semantic(sc); + e = e.implicitCastTo(sc, type); + } + else if (si || ai) + { i2 = init.syntaxCopy(); + i2 = i2.semantic(sc, type); + } + inuse--; + global.gag--; + //printf("-gag\n"); + if (errors != global.errors) // if errors happened + { + if (global.gag == 0) + global.errors = errors; // act as if nothing happened +version (DMDV2) { + /* Save scope for later use, to try again + */ + scope_ = new Scope(sc); + scope_.setNoFree(); +} + } + else if (ei) + { + if (isDataseg()) + /* static const/invariant does CTFE + */ + e = e.optimize(WANT.WANTvalue | WANT.WANTinterpret); + else + e = e.optimize(WANT.WANTvalue); + if (e.op == TOK.TOKint64 || e.op == TOK.TOKstring || e.op == TOK.TOKfloat64) + { + ei.exp = e; // no errors, keep result + } +///version (DMDV2) { + else + { + /* Save scope for later use, to try again + */ + scope_ = new Scope(sc); + scope_.setNoFree(); + } +///} + } + else + init = i2; // no errors, keep result + } + } + sc = sc.pop(); + } + } + + void semantic2(Scope sc) + { + //printf("VarDeclaration.semantic2('%s')\n", toChars()); + if (init && !toParent().isFuncDeclaration()) + { + inuse++; +static if (false) { + ExpInitializer ei = init.isExpInitializer(); + if (ei) + { + ei.exp.dump(0); + printf("type = %p\n", ei.exp.type); + } +} + init = init.semantic(sc, type); + inuse--; + } + } + + string kind() + { + return "variable"; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + +version (_DH) { + Type htype; + Initializer hinit; +} + bool needThis() + { + //printf("VarDeclaration.needThis(%s, x%x)\n", toChars(), storage_class); + return (storage_class & STC.STCfield) != 0; + } + + bool isImportedSymbol() + { + if (protection == PROT.PROTexport && !init && (storage_class & STC.STCstatic || parent.isModule())) + return true; + + return false; + } + + bool isDataseg() + { +static if (false) { + printf("VarDeclaration.isDataseg(%p, '%s')\n", this, toChars()); + printf("%x, %p, %p\n", storage_class & (STC.STCstatic | STC.STCconst), parent.isModule(), parent.isTemplateInstance()); + printf("parent = '%s'\n", parent.toChars()); +} + if (storage_class & STC.STCmanifest) + return false; + + Dsymbol parent = this.toParent(); + if (!parent && !(storage_class & STC.STCstatic)) + { + error("forward referenced"); + type = Type.terror; + return false; + } + + return canTakeAddressOf() && (storage_class & (STC.STCstatic | STC.STCextern | STC.STCtls | STC.STCgshared) || toParent().isModule() || toParent().isTemplateInstance()); + } + + bool isThreadlocal() + { + //printf("VarDeclaration.isThreadlocal(%p, '%s')\n", this, toChars()); +static if (false) { /// || TARGET_OSX + /* To be thread-local, must use the __thread storage class. + * BUG: OSX doesn't support thread local yet. + */ + return isDataseg() && (storage_class & (STC.STCtls | STC.STCconst | STC.STCimmutable | STC.STCshared | STC.STCgshared)) == STC.STCtls; +} else { + /* Data defaults to being thread-local. It is not thread-local + * if it is immutable, const or shared. + */ + bool i = isDataseg() && !(storage_class & (STC.STCimmutable | STC.STCconst | STC.STCshared | STC.STCgshared)); + //printf("\treturn %d\n", i); + return i; +} + } + + bool hasPointers() + { + //printf("VarDeclaration.hasPointers() %s, ty = %d\n", toChars(), type.ty); + return (!isDataseg() && type.hasPointers()); + } + +version (DMDV2) { + bool canTakeAddressOf() + { +static if (false) { + /* Global variables and struct/class fields of the form: + * const int x = 3; + * are not stored and hence cannot have their address taken. + */ + if ((isConst() || isInvariant()) && (storage_class & STC.STCinit) && (!(storage_class & (STC.STCstatic | STC.STCextern)) || (storage_class & STC.STCfield)) && + (!parent || toParent().isModule() || toParent().isTemplateInstance()) && type.toBasetype().isTypeBasic()) + { + return false; + } +} else { + if (storage_class & STC.STCmanifest) + return false; +} + return true; + } + + int needsAutoDtor() + { + assert(false); + } +} + + /****************************************** + * If a variable has an auto destructor call, return call for it. + * Otherwise, return null. + */ + Expression callAutoDtor(Scope sc) + { + Expression e = null; + + //printf("VarDeclaration.callAutoDtor() %s\n", toChars()); + + if (noauto || storage_class & STC.STCnodtor) + return null; + + // Destructors for structs and arrays of structs + bool array = false; + Type tv = type.toBasetype(); + while (tv.ty == TY.Tsarray) + { + TypeSArray ta = cast(TypeSArray)tv; + array = true; + tv = tv.nextOf().toBasetype(); + } + if (tv.ty == TY.Tstruct) + { + TypeStruct ts = cast(TypeStruct)tv; + StructDeclaration sd = ts.sym; + if (sd.dtor) + { + if (array) + { + // Typeinfo.destroy(cast(void*)&v); + Expression ea = new SymOffExp(loc, this, 0, 0); + ea = new CastExp(loc, ea, Type.tvoid.pointerTo()); + Expressions args = new Expressions(); + args.push(cast(void*)ea); + + Expression et = type.getTypeInfo(sc); + et = new DotIdExp(loc, et, Id.destroy); + + e = new CallExp(loc, et, args); + } + else + { + e = new VarExp(loc, this); + e = new DotVarExp(loc, e, sd.dtor, 0); + e = new CallExp(loc, e); + } + return e; + } + } + + // Destructors for classes + if (storage_class & (STC.STCauto | STC.STCscope)) + { + for (ClassDeclaration cd = type.isClassHandle(); cd; cd = cd.baseClass) + { + /* We can do better if there's a way with onstack + * classes to determine if there's no way the monitor + * could be set. + */ + //if (cd.isInterfaceDeclaration()) + //error("interface %s cannot be scope", cd.toChars()); + if (1 || onstack || cd.dtors.dim) // if any destructors + { + // delete this; + Expression ec = new VarExp(loc, this); + e = new DeleteExp(loc, ec); + e.type = Type.tvoid; + break; + } + } + } + return e; + } + + /**************************** + * Get ExpInitializer for a variable, if there is one. + */ + ExpInitializer getExpInitializer() + { + ExpInitializer ei; + + if (init) + ei = init.isExpInitializer(); + else + { + Expression e = type.defaultInit(loc); + if (e) + ei = new ExpInitializer(loc, e); + else + ei = null; + } + return ei; + } + + /******************************************* + * If variable has a constant expression initializer, get it. + * Otherwise, return null. + */ + Expression getConstInitializer() + { + if ((isConst() || isInvariant() || storage_class & STC.STCmanifest) && storage_class & STC.STCinit) + { + ExpInitializer ei = getExpInitializer(); + if (ei) + return ei.exp; + } + + return null; + } + + void checkCtorConstInit() + { + static if (false) { /* doesn't work if more than one static ctor */ + if (ctorinit == 0 && isCtorinit() && !(storage_class & STCfield)) + error("missing initializer in static constructor for const variable"); + } + } + + /************************************ + * Check to see if this variable is actually in an enclosing function + * rather than the current one. + */ + void checkNestedReference(Scope sc, Loc loc) + { + if (parent && !isDataseg() && parent != sc.parent && !(storage_class & STC.STCmanifest)) + { + // The function that this variable is in + FuncDeclaration fdv = toParent().isFuncDeclaration(); + // The current function + FuncDeclaration fdthis = sc.parent.isFuncDeclaration(); + + if (fdv && fdthis && fdv !is fdthis) + { + if (loc.filename) + fdthis.getLevel(loc, fdv); + + for (int i = 0; i < nestedrefs.dim; i++) + { + FuncDeclaration f = cast(FuncDeclaration)nestedrefs.data[i]; + if (f == fdthis) + goto L1; + } + nestedrefs.push(cast(void*)fdthis); + L1: ; + + for (int i = 0; i < fdv.closureVars.dim; i++) + { + Dsymbol s = cast(Dsymbol)fdv.closureVars.data[i]; + if (s == this) + goto L2; + } + + fdv.closureVars.push(cast(void*)this); + L2: ; + + //printf("fdthis is %s\n", fdthis.toChars()); + //printf("var %s in function %s is nested ref\n", toChars(), fdv.toChars()); + } + } + } + + Dsymbol toAlias() + { + //printf("VarDeclaration::toAlias('%s', this = %p, aliassym = %p)\n", toChars(), this, aliassym); + assert(this !is aliassym); + return aliassym ? aliassym.toAlias() : this; + } + + Symbol* toSymbol() + { + //printf("VarDeclaration.toSymbol(%s)\n", toChars()); + //if (needThis()) *(char*)0=0; + assert(!needThis()); + if (!csym) + { + Symbol* s; + TYPE* t; + string id; + + if (isDataseg()) + id = mangle(); + else + id = ident.toChars(); + + s = symbol_calloc(toStringz(id)); + + if (storage_class & (STC.STCout | STC.STCref)) + { + if (global.params.symdebug && storage_class & STC.STCparameter) + { + t = type_alloc(TYM.TYnptr); // should be TYref, but problems in back end + t.Tnext = type.toCtype(); + t.Tnext.Tcount++; + } + else + t = type_fake(TYM.TYnptr); + } + else if (storage_class & STC.STClazy) + t = type_fake(TYM.TYdelegate); // Tdelegate as C type + else if (isParameter()) + t = type.toCParamtype(); + else + t = type.toCtype(); + + t.Tcount++; + + if (isDataseg()) + { + if (isThreadlocal()) + { + /* Thread local storage + */ + TYPE* ts = t; + ts.Tcount++; // make sure a different t is allocated + type_setty(&t, t.Tty | mTY.mTYthread); + ts.Tcount--; + + if (global.params.vtls) + { + string p = loc.toChars(); + writef("%s: %s is thread local\n", p ? p : "", toChars()); + } + } + + s.Sclass = SC.SCextern; + s.Sfl = FL.FLextern; + slist_add(s); + } + else + { + s.Sclass = SC.SCauto; + s.Sfl = FL.FLauto; + + if (nestedrefs.dim) + { + /* Symbol is accessed by a nested function. Make sure + * it is not put in a register, and that the optimizer + * assumes it is modified across function calls and pointer + * dereferences. + */ + //printf("\tnested ref, not register\n"); + type_setcv(&t, t.Tty | mTY.mTYvolatile); + } + } + + mangle_t m = 0; + switch (linkage) + { + case LINK.LINKwindows: + m = mTYman.mTYman_std; + break; + + case LINK.LINKpascal: + m = mTYman.mTYman_pas; + break; + + case LINK.LINKc: + m = mTYman.mTYman_c; + break; + + case LINK.LINKd: + m = mTYman.mTYman_d; + break; + + case LINK.LINKcpp: + m = mTYman.mTYman_cpp; + break; + + default: + writef("linkage = %d\n", linkage); + assert(0); + } + type_setmangle(&t, m); + s.Stype = t; + + csym = s; + } + return csym; + } + + void toObjFile(int multiobj) // compile to .obj file + { + Symbol* s; + uint sz; + Dsymbol parent; + + //printf("VarDeclaration.toObjFile(%p '%s' type=%s) protection %d\n", this, toChars(), type.toChars(), protection); + //printf("\talign = %d\n", type.alignsize()); + + if (aliassym) + { + toAlias().toObjFile(0); + return; + } + + version (DMDV2) { + // Do not store variables we cannot take the address of + if (!canTakeAddressOf()) + { + return; + } + } + + if (isDataseg() && !(storage_class & STC.STCextern)) + { + s = toSymbol(); + sz = cast(uint)type.size(); + + parent = this.toParent(); +/// version (DMDV1) { /* private statics should still get a global symbol, in case +/// * another module inlines a function that references it. +/// */ +/// if (/*protection == PROT.PROTprivate ||*/ +/// !parent || parent.ident == null || parent.isFuncDeclaration()) +/// { +/// s.Sclass = SC.SCstatic; +/// } +/// else +/// } + { + if (storage_class & STC.STCcomdat) + s.Sclass = SC.SCcomdat; + else + s.Sclass = SC.SCglobal; + + do + { + /* Global template data members need to be in comdat's + * in case multiple .obj files instantiate the same + * template with the same types. + */ + if (parent.isTemplateInstance() && !parent.isTemplateMixin()) + { + version (DMDV1) { + /* These symbol constants have already been copied, + * so no reason to output them. + * Note that currently there is no way to take + * the address of such a const. + */ + if (isConst() && type.toBasetype().ty != TY.Tsarray && init && init.isExpInitializer()) + return; + } + s.Sclass = SC.SCcomdat; + break; + } + parent = parent.parent; + } while (parent); + } + + s.Sfl = FL.FLdata; + + if (init) + { + s.Sdt = init.toDt(); + + // Look for static array that is block initialized + Type tb; + ExpInitializer ie = init.isExpInitializer(); + + tb = type.toBasetype(); + if (tb.ty == TY.Tsarray && ie + && !tb.nextOf().equals(ie.exp.type.toBasetype().nextOf()) + && ie.exp.implicitConvTo(tb.nextOf())) + { + int dim = cast(int)(cast(TypeSArray)tb).dim.toInteger(); + + // Duplicate Sdt 'dim-1' times, as we already have the first one + while (--dim > 0) + { + ie.exp.toDt(&s.Sdt); + } + } + } + else if (storage_class & STC.STCextern) + { + s.Sclass = SC.SCextern; + s.Sfl = FL.FLextern; + s.Sdt = null; + // BUG: if isExport(), shouldn't we make it dllimport? + return; + } + else + { + type.toDt(&s.Sdt); + } + dt_optimize(s.Sdt); + + // See if we can convert a comdat to a comdef, + // which saves on exe file space. + if (s.Sclass == SC.SCcomdat && + s.Sdt && + s.Sdt.dt == DT.DT_azeros && + s.Sdt.DTnext is null && + !isThreadlocal()) + { + s.Sclass = SC.SCglobal; + s.Sdt.dt = DT.DT_common; + } + + version (ELFOBJ_OR_MACHOBJ) { // Burton + if (s.Sdt && s.Sdt.dt == DT.DT_azeros && s.Sdt.DTnext is null) + s.Sseg = Segment.UDATA; + else + s.Sseg = Segment.DATA; + } + if (sz) + { + outdata(s); + if (isExport()) + obj_export(s, 0); + } + } + } + + int cvMember(ubyte* p) + { + assert(false); + } + + // Eliminate need for dynamic_cast + VarDeclaration isVarDeclaration() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/VarExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/VarExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,258 @@ +module dmd.VarExp; + +import dmd.Expression; +import dmd.Declaration; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.InlineCostState; +import dmd.FuncLiteralDeclaration; +import dmd.VarDeclaration; +import dmd.Dsymbol; +import dmd.FuncDeclaration; +import dmd.InlineDoState; +import dmd.HdrGenState; +import dmd.TOK; +import dmd.TY; +import dmd.STC; +import dmd.SymbolExp; +import dmd.Type; +import dmd.backend.dt_t; +import dmd.expression.Util; + +// Variable + +class VarExp : SymbolExp +{ + this(Loc loc, Declaration var, int hasOverloads = 0) + { + super(loc, TOK.TOKvar, VarExp.sizeof, var, hasOverloads); + + //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var.toChars(), loc.toChars()); + //if (strcmp(var.ident.toChars(), "func") == 0) halt(); + this.type = var.type; + } + + int equals(Object o) + { + assert(false); + } + + Expression semantic(Scope sc) + { + FuncLiteralDeclaration fd; + + version (LOGSEMANTIC) { + printf("VarExp.semantic(%s)\n", toChars()); + } + if (!type) + { + type = var.type; +static if (false) { + if (var.storage_class & STC.STClazy) + { + TypeFunction tf = new TypeFunction(null, type, 0, LINK.LINKd); + type = new TypeDelegate(tf); + type = type.semantic(loc, sc); + } +} + } + + /* Fix for 1161 doesn't work because it causes protection + * problems when instantiating imported templates passing private + * variables as alias template parameters. + */ + //accessCheck(loc, sc, null, var); + + VarDeclaration v = var.isVarDeclaration(); + if (v) + { +static if (false) { + if ((v.isConst() || v.isInvariant()) && type.toBasetype().ty != TY.Tsarray && v.init) + { + ExpInitializer ei = v.init.isExpInitializer(); + if (ei) + { + //ei.exp.implicitCastTo(sc, type).print(); + return ei.exp.implicitCastTo(sc, type); + } + } +} + v.checkNestedReference(sc, loc); +version (DMDV2) { + static if (true) { + if (sc.func) + { + /* Determine if sc.func is pure or if any function that + * encloses it is also pure. + */ + bool hasPureParent = false; + for (FuncDeclaration outerfunc = sc.func; outerfunc;) + { + if (outerfunc.isPure()) + { + hasPureParent = true; + break; + } + Dsymbol parent = outerfunc.toParent2(); + if (!parent) + break; + outerfunc = parent.isFuncDeclaration(); + } + + /* If ANY of its enclosing functions are pure, + * it cannot do anything impure. + * If it is pure, it cannot access any mutable variables other + * than those inside itself + */ + if (hasPureParent && !sc.intypeof && v.isDataseg() && !v.isInvariant()) + { + error("pure function '%s' cannot access mutable static data '%s'", + sc.func.toChars(), v.toChars()); + } + else if (sc.func.isPure() && sc.parent != v.parent && !sc.intypeof && !v.isInvariant() && !(v.storage_class & STC.STCmanifest)) + { + error("pure nested function '%s' cannot access mutable data '%s'", sc.func.toChars(), v.toChars()); + if (v.isEnumDeclaration()) + error("enum"); + } + } + } else { + if (sc.func && sc.func.isPure() && !sc.intypeof) + { + if (v.isDataseg() && !v.isInvariant()) + error("pure function '%s' cannot access mutable static data '%s'", sc.func.toChars(), v.toChars()); + } + } +} + } + else + { +static if (false) { + if ((fd = var.isFuncLiteralDeclaration()) !is null) + { + Expression e = new FuncExp(loc, fd); + e.type = type; + return e; + } +} + } + + return this; + } + + Expression optimize(int result) + { + return fromConstInitializer(result, this); + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void dump(int indent) + { + assert(false); + } + + string toChars() + { + return var.toChars(); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + buf.writestring(var.toChars()); + } + + void checkEscape() + { + VarDeclaration v = var.isVarDeclaration(); + if (v) + { + Type tb = v.type.toBasetype(); + // if reference type + if (tb.ty == TY.Tarray || tb.ty == TY.Tsarray || tb.ty == TY.Tclass) + { + if ((v.isAuto() || v.isScope()) && !v.noauto) + error("escaping reference to scope local %s", v.toChars()); + else if (v.storage_class & STC.STCvariadic) + error("escaping reference to variadic parameter %s", v.toChars()); + } + } + } + +version (DMDV2) { + int isLvalue() + { + if (var.storage_class & STClazy) + return 0; + return 1; + } +} + Expression toLvalue(Scope sc, Expression e) + { +static if (false) { + tym = tybasic(e1.ET.Tty); + if (!(tyscalar(tym) || + tym == TYM.TYstruct || + tym == TYM.TYarray && e.Eoper == TOK.TOKaddr)) + { + synerr(EM_lvalue); // lvalue expected + } +} + if (var.storage_class & STC.STClazy) + error("lazy variables cannot be lvalues"); + + return this; + } + + Expression modifiableLvalue(Scope sc, Expression e) + { + //printf("VarExp::modifiableLvalue('%s')\n", var.toChars()); + if (type && type.toBasetype().ty == TY.Tsarray) + error("cannot change reference to static array '%s'", var.toChars()); + + var.checkModify(loc, sc, type); + + // See if this expression is a modifiable lvalue (i.e. not const) + return toLvalue(sc, e); + } + + dt_t** toDt(dt_t** pdt) + { + assert(false); + } + + void scanForNestedRef(Scope sc) + { + assert(false); + } + + int inlineCost(InlineCostState* ics) + { + //printf("VarExp.inlineCost() %s\n", toChars()); + return 1; + } + + Expression doInline(InlineDoState ids) + { + int i; + + //printf("VarExp.doInline(%s)\n", toChars()); + for (i = 0; i < ids.from.dim; i++) + { + if (var == cast(Declaration)ids.from.data[i]) + { + VarExp ve = cast(VarExp)copy(); + + ve.var = cast(Declaration)ids.to.data[i]; + return ve; + } + } + return this; + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/VersionCondition.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/VersionCondition.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,140 @@ +module dmd.VersionCondition; + +import dmd.DVCondition; +import dmd.Loc; +import dmd.Module; +import dmd.Scope; +import dmd.ScopeDsymbol; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Identifier; +import dmd.Global; +import dmd.String; +import dmd.Util : error; + +import std.string : startsWith; + +// for findCondition +import dmd.Array; +import core.stdc.string; + +import std.stdio; + +bool findCondition(Array ids, Identifier ident) +{ + if (ids !is null) { + foreach (i; 0..ids.dim) + { + string id = (cast(String)ids.data[i]).str; + if (id == ident.toChars()) { + return true; + } + } + } + + return false; +} + +class VersionCondition : DVCondition +{ + static void setGlobalLevel(uint level) + { + global.params.versionlevel = level; + } + + static void checkPredefined(Loc loc, string ident) + { +version (DMDV2) { + static string[] reserved = [ + "DigitalMars", "X86", "X86_64", + "Windows", "Win32", "Win64", + "linux", + /* Although Posix is predefined by D1, disallowing its + * redefinition breaks makefiles and older builds. + */ + "Posix", + "D_NET", + "OSX", "FreeBSD", + "Solaris", + "LittleEndian", "BigEndian", + "all", + "none", + ]; +} else { + static string[] reserved = [ + "DigitalMars", "X86", "X86_64", + "Windows", "Win32", "Win64", + "linux", + "OSX", "FreeBSD", + "Solaris", + "LittleEndian", "BigEndian", + "all", + "none", + ]; +} + foreach (reservedIdent; reserved) + { + if (ident == reservedIdent) + goto Lerror; + } + + if (ident.startsWith("D_")) { + goto Lerror; + } + + return; + + Lerror: + error(loc, "version identifier '%s' is reserved and cannot be set", ident); + } + + static void addGlobalIdent(string ident) + { + checkPredefined(Loc(0), ident); + addPredefinedGlobalIdent(ident); + } + + static void addPredefinedGlobalIdent(string ident) + { + global.params.versionids.push(cast(void*)new String(ident)); /// + } + + this(Module mod, uint level, Identifier ident) + { + super(mod, level, ident); + } + + final bool include(Scope sc, ScopeDsymbol s) + { + //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel); + //if (ident) printf("\tident = '%s'\n", ident->toChars()); + if (inc == 0) { + inc = 2; + if (ident !is null) { + if (findCondition(mod.versionids, ident)) { + inc = 1; + } else if (findCondition(global.params.versionids, ident)) { + inc = 1; + } else { + if (!mod.versionidsNot) { + mod.versionidsNot = new Array(); + } + mod.versionidsNot.push(cast(void*)new String(ident.toChars())); // + } + } else if (level <= global.params.versionlevel || level <= mod.versionlevel) { + inc = 1; + } + } + + return (inc == 1); + } + + final void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + if (ident !is null) { + buf.printf("version (%s)", ident.toChars()); + } else { + buf.printf("version (%u)", level); + } + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/VersionSymbol.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/VersionSymbol.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,87 @@ +module dmd.VersionSymbol; + +import dmd.Dsymbol; +import dmd.Loc; +import dmd.Identifier; +import dmd.Module; +import dmd.Array; +import dmd.VersionCondition; +import dmd.Scope; +import dmd.ScopeDsymbol; +import dmd.HdrGenState; +import dmd.String; +import dmd.OutBuffer; + +class VersionSymbol : Dsymbol +{ + uint level; + + /* VersionSymbol's happen for statements like: + * version = identifier; + * version = integer; + */ + this(Loc loc, Identifier ident) + { + super(ident); + this.loc = loc; + } + + this(Loc loc, uint level) + { + super(); + + this.level = level; + this.loc = loc; + } + + Dsymbol syntaxCopy(Dsymbol s) + { + assert(false); + } + + bool addMember(Scope sc, ScopeDsymbol s, int memnum) + { + //printf("VersionSymbol::addMember('%s') %s\n", sd->toChars(), toChars()); + + // Do not add the member to the symbol table, + // just make sure subsequent debug declarations work. + Module m = s.isModule(); + if (ident) + { + VersionCondition.checkPredefined(loc, ident.toChars()); + if (!m) + error("declaration must be at module level"); + else + { + if (findCondition(m.versionidsNot, ident)) + error("defined after use"); + if (!m.versionids) + m.versionids = new Array(); + m.versionids.push(cast(void*)new String(ident.toChars())); + } + } + else + { + if (!m) + error("level declaration must be at module level"); + else + m.versionlevel = level; + } + + return false; + } + + void semantic(Scope sc) + { + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + string kind() + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/VoidInitializer.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/VoidInitializer.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,50 @@ +module dmd.VoidInitializer; + +import dmd.Initializer; +import dmd.Type; +import dmd.Loc; +import dmd.Scope; +import dmd.Expression; +import dmd.OutBuffer; +import dmd.HdrGenState; + +import dmd.backend.dt_t; + +class VoidInitializer : Initializer +{ + Type type = null; // type that this will initialize to + + this(Loc loc) + { + super(loc); + } + + Initializer syntaxCopy() + { + assert(false); + } + + Initializer semantic(Scope sc, Type t) + { + //printf("VoidInitializer.semantic(t = %p)\n", t); + type = t; + return this; + } + + Expression toExpression() + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + dt_t* toDt() + { + assert(false); + } + + VoidInitializer isVoidInitializer() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/VolatileStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/VolatileStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,99 @@ +module dmd.VolatileStatement; + +import dmd.Statement; +import dmd.ArrayTypes; +import dmd.Scope; +import dmd.Loc; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.InlineScanState; +import dmd.IRState; +import dmd.BE; + +import dmd.backend.block; +import dmd.backend.Blockx; +import dmd.backend.Util; +import dmd.backend.BC; +//import dmd.backend.BFL; + +class VolatileStatement : Statement +{ + Statement statement; + + this(Loc loc, Statement statement) + { + super(loc); + this.statement = statement; + } + + Statement syntaxCopy() + { + assert(false); + } + + Statement semantic(Scope sc) + { + if (statement) + statement = statement.semantic(sc); + return this; + } + + Statements flatten(Scope sc) + { + Statements a = statement ? statement.flatten(sc) : null; + if (a) + { + for (int i = 0; i < a.dim; i++) + { + Statement s = cast(Statement)a.data[i]; + + s = new VolatileStatement(loc, s); + a.data[i] = cast(void*)s; + } + } + + return a; + } + + BE blockExit() + { + return statement ? statement.blockExit() : BE.BEfallthru; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + Statement inlineScan(InlineScanState* iss) + { + if (statement) + statement = statement.inlineScan(iss); + return this; + } + + void toIR(IRState* irs) + { + block* b; + + if (statement) + { + Blockx* blx = irs.blx; + + block_goto(blx, BCgoto, null); + b = blx.curblock; + + statement.toIR(irs); + + block_goto(blx, BCgoto, null); + + // Mark the blocks generated as volatile + for (; b != blx.curblock; b = b.Bnext) + { + b.Bflags |= BFL.BFLvolatile; + if (b.Belem) + el_setVolatile(b.Belem); + } + } + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/WANT.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/WANT.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,11 @@ +module dmd.WANT; + +enum WANT +{ + WANTflags = 1, + WANTvalue = 2, + WANTinterpret = 4, +} + +import dmd.EnumUtils; +mixin(BringToCurrentScope!(WANT)); \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/WhileStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/WhileStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,86 @@ +module dmd.WhileStatement; + +import dmd.Statement; +import dmd.Expression; +import dmd.Scope; +import dmd.InterState; +import dmd.HdrGenState; +import dmd.OutBuffer; +import dmd.InlineScanState; +import dmd.IRState; +import dmd.Loc; +import dmd.BE; +import dmd.ForStatement; + +class WhileStatement : Statement +{ + Expression condition; + Statement body_; + + this(Loc loc, Expression c, Statement b) + { + super(loc); + condition = c; + body_ = b; + } + + Statement syntaxCopy() + { + assert(false); + } + + Statement semantic(Scope sc) + { + /* Rewrite as a for(;condition;) loop + */ + + Statement s = new ForStatement(loc, null, condition, null, body_); + s = s.semantic(sc); + return s; + } + + bool hasBreak() + { + assert(false); + } + + bool hasContinue() + { + assert(false); + } + + bool usesEH() + { + assert(false); + } + + BE blockExit() + { + assert(false); + } + + bool comeFrom() + { + assert(false); + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + Statement inlineScan(InlineScanState* iss) + { + assert(false); + } + + void toIR(IRState* irs) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/WithScopeSymbol.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/WithScopeSymbol.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,24 @@ +module dmd.WithScopeSymbol; + +import dmd.ScopeDsymbol; +import dmd.WithStatement; +import dmd.Loc; +import dmd.Identifier; +import dmd.Dsymbol; + +class WithScopeSymbol : ScopeDsymbol +{ + WithStatement withstate; + + this(WithStatement withstate) + { + assert(false); + } + + Dsymbol search(Loc loc, Identifier ident, int flags) + { + assert(false); + } + + WithScopeSymbol isWithScopeSymbol() { return this; } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/WithStatement.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/WithStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,60 @@ +module dmd.WithStatement; + +import dmd.Statement; +import dmd.Expression; +import dmd.VarDeclaration; +import dmd.Loc; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.InlineScanState; +import dmd.IRState; +import dmd.Scope; +import dmd.BE; + +class WithStatement : Statement +{ + Expression exp; + Statement body_; + VarDeclaration wthis; + + this(Loc loc, Expression exp, Statement body_) + { + assert(false); + super(loc); + } + + Statement syntaxCopy() + { + assert(false); + } + + Statement semantic(Scope sc) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + bool usesEH() + { + assert(false); + } + + BE blockExit() + { + assert(false); + } + + Statement inlineScan(InlineScanState* iss) + { + assert(false); + } + + void toIR(IRState* irs) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/XorAssignExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/XorAssignExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,53 @@ +module dmd.XorAssignExp; + +import dmd.BinExp; +import dmd.Loc; +import dmd.Expression; +import dmd.Scope; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.ArrayTypes; +import dmd.Identifier; +import dmd.IRState; +import dmd.Id; +import dmd.TOK; +import dmd.backend.elem; + +class XorAssignExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + assert(false); + super(loc, TOK.init, 0, e1, e2); + } + + Expression semantic(Scope sc) + { + assert(false); + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void buildArrayIdent(OutBuffer buf, Expressions arguments) + { + assert(false); + } + + Expression buildArrayLoop(Arguments fparams) + { + assert(false); + } + + Identifier opId() /* For operator overloading */ + { + return Id.xorass; + } + + elem* toElem(IRState* irs) + { + assert(false); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/XorExp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/XorExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,118 @@ +module dmd.XorExp; + +import dmd.Expression; +import dmd.Identifier; +import dmd.InterState; +import dmd.MATCH; +import dmd.Id; +import dmd.Type; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.IntRange; +import dmd.IRState; +import dmd.ArrayTypes; +import dmd.BinExp; +import dmd.TOK; +import dmd.TY; + +import dmd.backend.elem; +import dmd.expression.Util; +import dmd.expression.Xor; + +class XorExp : BinExp +{ + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKxor, XorExp.sizeof, e1, e2); + } + + Expression semantic(Scope sc) + { + Expression e; + + if (!type) + { + BinExp.semanticp(sc); + e = op_overload(sc); + if (e) + return e; + if (e1.type.toBasetype().ty == Tbool && + e2.type.toBasetype().ty == Tbool) + { + type = e1.type; + e = this; + } + else + { + typeCombine(sc); + if (e1.op != TOKslice && e2.op != TOKslice) + { + e1.checkIntegral(); + e2.checkIntegral(); + } + } + } + return this; + } + + Expression optimize(int result) + { + Expression e; + + e1 = e1.optimize(result); + e2 = e2.optimize(result); + if (e1.isConst() == 1 && e2.isConst() == 1) + e = Xor(type, e1, e2); + else + e = this; + + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void buildArrayIdent(OutBuffer buf, Expressions arguments) + { + assert(false); + } + + Expression buildArrayLoop(Arguments fparams) + { + assert(false); + } + + MATCH implicitConvTo(Type t) + { + assert(false); + } + + IntRange getIntRange() + { + assert(false); + } + + bool isCommutative() + { + return true; + } + + Identifier opId() + { + return Id.ixor; + } + + Identifier opId_r() + { + return Id.ixor_r; + } + + elem* toElem(IRState* irs) + { + assert(false); + } +} + diff -r 000000000000 -r 10317f0c89a5 dmd/backend/BC.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/BC.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,42 @@ +module dmd.backend.BC; + +enum BC +{ + BCgoto = 1, // goto Bsucc block + BCiftrue = 2, // if (Belem) goto Bsucc[0] else Bsucc[1] + BCret = 3, // return (no return value) + BCretexp = 4, // return with return value + BCexit = 5, // never reaches end of block (like exit() was called) + BCasm = 6, // inline assembler block (Belem is NULL, Bcode + // contains code generated). + // These blocks have one or more successors in Bsucc, + // never 0 + BCswitch = 7, // switch statement + // Bswitch points to switch data + // Default is Bsucc + // Cases follow in linked list + BCifthen = 8, // a BCswitch is converted to if-then + // statements + BCjmptab = 9, // a BCswitch is converted to a jump + // table (switch value is index into + // the table) + BCtry = 10, // C++ try block + // first block in a try-block. The first block in + // Bsucc is the next one to go to, subsequent + // blocks are the catch blocks + BCcatch = 11, // C++ catch block + BCjump = 12, // Belem specifies (near) address to jump to + BC_try = 13, // SEH: first block of try-except or try-finally + // Jupiter, Mars: try-catch or try-finally + BC_filter = 14, // SEH exception-filter (always exactly one block) + BC_finally = 15, // first block of SEH termination-handler, + // or finally block + BC_ret = 16, // last block of SEH termination-handler or finally block + BC_except = 17, // first block of SEH exception-handler + BCjcatch = 18, // first block of Jupiter or Mars catch-block + BCjplace = 19, // Jupiter: placeholder + BCMAX +} + +import dmd.EnumUtils; +mixin(BringToCurrentScope!(BC)); \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/Blockx.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/Blockx.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,27 @@ +module dmd.backend.Blockx; + +import dmd.Module; +import dmd.Declaration; +import dmd.ClassDeclaration; + +import dmd.backend.Symbol; +import dmd.backend.block; +import dmd.backend.elem; + +alias Symbol Funcsym; + +struct Blockx +{ + block* startblock; + block* curblock; + Funcsym* funcsym; + Symbol* context; // eh frame context variable + int scope_index; // current scope index + int next_index; // value for next scope index + uint flags; // value to OR into Bflags + block* tryblock; // current enclosing try block + elem* init; // static initializer + ClassDeclaration classdec; + Declaration member; // member we're compiling for + Module module_; // module we're in +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/Classsym.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/Classsym.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,5 @@ +module dmd.backend.Classsym; + +import dmd.backend.Symbol; + +alias Symbol Classsym; \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/Config.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/Config.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,259 @@ +module dmd.backend.Config; + +import dmd.backend.LINKAGE; +import dmd.EnumUtils; + +extern (C) { + void cod3_set64(); + void cod3_set386(); +} + +extern (C++) extern +{ + __gshared char debuga; /* cg - watch assignaddr() */ + __gshared char debugb; /* watch block optimization */ + __gshared char debugc; /* watch code generated */ + __gshared char debugd; /* watch debug information generated */ + __gshared char debuge; // dump eh info + __gshared char debugf; /* trees after dooptim */ + __gshared char debugg; /* trees for code generator */ + __gshared char debugo; // watch optimizer + __gshared char debugr; // watch register allocation + __gshared char debugs; /* watch common subexp eliminator */ + __gshared char debugt; /* do test points */ + __gshared char debugu; + __gshared char debugw; /* watch progress */ + __gshared char debugx; /* suppress predefined CPP stuff */ + __gshared char debugy; /* watch output to il buffer */ +} + +// This part of the configuration is saved in the precompiled header for use +// in comparing to make sure it hasn't changed. + +enum CFG2 +{ + CFG2comdat = 1, // use initialized common blocks + CFG2nodeflib = 2, // no default library imbedded in OBJ file + CFG2browse = 4, // generate browse records + CFG2dyntyping = 8, // generate dynamic typing information + CFG2fulltypes = 0x10, // don't optimize CV4 class info + CFG2warniserr = 0x20, // treat warnings as errors + CFG2phauto = 0x40, // automatic precompiled headers + CFG2phuse = 0x80, // use precompiled headers + CFG2phgen = 0x100, // generate precompiled header + CFG2once = 0x200, // only include header files once + CFG2hdrdebug = 0x400, // generate debug info for header + CFG2phautoy = 0x800, // fast build precompiled headers + CFG2noobj = 0x1000, // we are not generating a .OBJ file + CFG2noerrmax = 0x4000, // no error count maximum + CFG2expand = 0x8000, // expanded output to list file + CFG2seh = 0x10000, // use Win32 SEH to support any exception handling + CFGX2 = (CFG2warniserr | CFG2phuse | CFG2phgen | CFG2phauto | CFG2once | CFG2hdrdebug | CFG2noobj | CFG2noerrmax | CFG2expand | CFG2nodeflib), +} + +enum CFG3ju = 1; // char == unsigned char +enum CFG3eh = 4; // generate exception handling stuff +enum CFG3strcod = 8; // strings are placed in code segment +enum CFG3eseqds = 0x10; // ES == DS at all times +enum CFG3ptrchk = 0x20; // generate pointer validation code +enum CFG3strictproto = 0x40; // strict prototyping +enum CFG3autoproto = 0x80; // auto prototyping +enum CFG3rtti = 0x100; // add RTTI support +enum CFG3relax = 0x200; // relaxed type checking (C only) +enum CFG3cpp = 0x400; // C++ compile +enum CFG3igninc = 0x800; // ignore standard include directory +version (XXX) {///TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS) { +enum CFG3mars = 0x1000; // use mars libs and headers +enum NO_FAR = true; // always ignore __far and __huge keywords +} else { +enum CFG3nofar = 0x1000; // ignore __far and __huge keywords +///enum NO_FAR = (config.flags3 & CFG3nofar); +} +enum CFG3noline = 0x2000; // do not output #line directives +enum CFG3comment = 0x4000; // leave comments in preprocessed output +enum CFG3cppcomment = 0x8000; // allow C++ style comments +enum CFG3wkfloat = 0x10000; // make floating point references weak externs +enum CFG3digraphs = 0x20000; // support ANSI C++ digraphs +///#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS +enum CFG3semirelax = 0x40000; // moderate relaxed type checking +///#endif +enum CFG3pic = 0x80000; // position independent code +enum CFGX3 = (CFG3strcod | CFG3ptrchk); + +enum CFG4speed = 1; // optimized for speed +enum CFG4space = 2; // optimized for space +enum CFG4optimized = (CFG4speed | CFG4space); +enum CFG4allcomdat = 4; // place all functions in COMDATs +enum CFG4fastfloat = 8; // fast floating point (-ff) +enum CFG4fdivcall = 0x10; // make function call for FDIV opcodes +enum CFG4tempinst = 0x20; // instantiate templates for undefined functions +enum CFG4oldstdmangle = 0x40; // do stdcall mangling without @ +enum CFG4pascal = 0x80; // default to pascal linkage +enum CFG4stdcall = 0x100; // default to std calling convention +enum CFG4cacheph = 0x200; // cache precompiled headers in memory +enum CFG4alternate = 0x400; // if alternate digraph tokens +enum CFG4bool = 0x800; // support 'bool' as basic type +enum CFG4wchar_t = 0x1000; // support 'wchar_t' as basic type +enum CFG4notempexp = 0x2000; // no instantiation of template functions +enum CFG4anew = 0x4000; // allow operator new[] and delete[] overloading +enum CFG4oldtmangle = 0x8000; // use old template name mangling +enum CFG4dllrtl = 0x10000; // link with DLL RTL +enum CFG4noemptybaseopt = 0x40000; // turn off empty base class optimization +enum CFG4stackalign = CFG4speed; // align stack to 8 bytes +enum CFG4nowchar_t = 0x80000; // use unsigned short name mangling for wchar_t +enum CFG4forscope = 0x100000; // new C++ for scoping rules +enum CFG4warnccast = 0x200000; // warn about C style casts +enum CFG4adl = 0x400000; // argument dependent lookup +enum CFG4enumoverload = 0x800000; // enum overloading +enum CFG4implicitfromvoid = 0x1000000; // allow implicit cast from void* to T* +enum CFG4dependent = 0x2000000; // dependent / non-dependent lookup +enum CFG4wchar_is_long = 0x4000000; // wchar_t is 4 bytes +enum CFG4underscore = 0x8000000; // prepend _ for C mangling +enum CFGX4 = (CFG4optimized | CFG4fastfloat | CFG4fdivcall | CFG4tempinst | CFG4cacheph | CFG4notempexp | CFG4stackalign | CFG4dependent); +enum CFGY4 = (CFG4nowchar_t | CFG4noemptybaseopt | CFG4adl | CFG4enumoverload | CFG4implicitfromvoid | CFG4wchar_is_long | CFG4underscore); + +mixin(BringToCurrentScope!(CFG2)); + +enum TARGET +{ + TARGET_8086= 0, + TARGET_80286= 2, + TARGET_80386= 3, + TARGET_80486= 4, + TARGET_Pentium= 5, + TARGET_PentiumMMX= 6, + TARGET_PentiumPro= 7, + TARGET_PentiumII= 8, + TARGET_AMD64= 9, //(32 or 64 bit mode) +} + +mixin(BringToCurrentScope!(TARGET)); + +enum CV4 = 2; // Codeview 4 symbolic info + +struct Config +{ + char language; // 'C' = C, 'D' = C++ +//#define CPP (config.language == 'D') + char version_[8]; // = VERSION + char exetype[3]; // distinguish exe types so PH + // files are distinct (= SUFFIX) + + char target_cpu; // instruction selection + char target_scheduler; // instruction scheduling (normally same as selection) + + short versionint; // intermediate file version (= VERSIONINT) + int defstructalign; // struct alignment specified by command line + short hxversion; // HX version number + char fulltypes; + uint wflags; // flags for Windows code generation + + char inline8087; /* 0: emulator + 1: IEEE 754 inline 8087 code + 2: fast inline 8087 code + */ + short memmodel; // 0:S,X,N,F, 1:M, 2:C, 3:L, 4:V + uint exe; // target operating system + +///#define EX_flat (EX_OS2 | EX_NT | EX_LINUX | EX_WIN64 | EX_LINUX64 | \ +/// EX_OSX | EX_OSX64 | EX_FREEBSD | EX_FREEBSD64 | \ +/// EX_SOLARIS | EX_SOLARIS64) +///#define EX_dos (EX_DOSX | EX_ZPM | EX_RATIONAL | EX_PHARLAP | \ +/// EX_COM | EX_MZ /*| EX_WIN16*/) + +/* CFGX: flags ignored in precompiled headers + * CFGY: flags copied from precompiled headers into current config + */ + uint flags; + uint flags2; + uint flags3; + uint flags4; + uint flags5; +///#define CFG5debug 1 // compile in __debug code +///#define CFG5in 2 // compile in __in code +///#define CFG5out 4 // compile in __out code +///#define CFG5invariant 8 // compile in __invariant code + +///#if HTOD +/// unsigned htodFlags; // configuration for htod +///#define HTODFinclude 1 // -hi drill down into #include files +///#define HTODFsysinclude 2 // -hs drill down into system #include files +///#define HTODFtypedef 4 // -ht drill down into typedefs +///#define HTODFcdecl 8 // -hc skip C declarations as comments +///#endif + char ansi_c; // strict ANSI C + // 89 for ANSI C89, 99 for ANSI C99 + char asian_char; /* 0: normal, 1: Japanese, 2: Chinese */ + /* and Taiwanese, 3: Korean */ + uint threshold; // data larger than threshold is assumed to + // be far (16 bit models only) +///#define THRESHMAX 0xFFFF // if threshold == THRESHMAX, all data defaults + // to near + LINKAGE linkage; // default function call linkage +} + +extern (C++) extern __gshared Config config; + +enum CVNONE = 0; // No symbolic info +///enum CVOLD = 1; // Codeview 1 symbolic info +///enum CV4 = 2; // Codeview 4 symbolic info +///enum CVSYM = 3; // Symantec format +///enum CVTDB = 4; // Symantec format written to file +///enum CVDWARF_C = 5; // Dwarf in C format +///enum CVDWARF_D = 6; // Dwarf in D format +///enum CVSTABS = 7; // Elf Stabs in C format + +enum CFGuchar = 1; // chars are unsigned +enum CFGsegs = 2; // new code seg for each far func +enum CFGtrace = 4; // output trace functions +enum CFGglobal = 8; // make all static functions global +enum CFGstack = 0x20; // add stack overflow checking +enum CFGalwaysframe = 0x40; // always generate stack frame +enum CFGnoebp = 0x80; // do not use EBP as general purpose register +enum CFGromable = 0x100; // put switch tables in code segment +enum CFGeasyomf = 0x200; // generate Pharlap Easy-OMF format +enum CFGfarvtbls = 0x800; // store vtables in far segments +enum CFGnoinlines = 0x1000; // do not inline functions +enum CFGnowarning = 0x8000; // disable warnings +enum CFGX = (CFGnowarning); + +enum EX_DOSX = 1; // DOSX 386 program +enum EX_ZPM = 2; // ZPM 286 program +enum EX_RATIONAL = 4; // RATIONAL 286 program +enum EX_PHARLAP = 8; // PHARLAP 386 program +enum EX_COM = 0x10; // MSDOS .COM program +//#define EX_WIN16 0x20 // Windows 3.x 16 bit program +enum EX_OS2 = 0x40; // OS/2 2.0 32 bit program +enum EX_OS1 = 0x80; // OS/2 1.x 16 bit program +enum EX_NT = 0x100; // NT +enum EX_MZ = 0x200; // MSDOS real mode program +enum EX_XENIX = 0x400; +enum EX_SCOUNIX = 0x800; +enum EX_UNIXSVR4 = 0x1000; +enum EX_LINUX = 0x2000; +enum EX_WIN64 = 0x4000; // AMD64 and Windows (64 bit mode) +enum EX_LINUX64 = 0x8000; // AMD64 and Linux (64 bit mode) +enum EX_OSX = 0x10000; +enum EX_OSX64 = 0x20000; +enum EX_FREEBSD = 0x40000; +enum EX_FREEBSD64 = 0x80000; +enum EX_SOLARIS = 0x100000; +enum EX_SOLARIS64 = 0x200000; + +enum WFwindows = 1; // generating code for Windows app or DLL +enum WFdll = 2; // generating code for Windows DLL +enum WFincbp = 4; // mark far stack frame with inc BP / dec BP +enum WFloadds = 8; // assume __loadds for all functions +enum WFexpdef = 0x10; // generate export definition records for + // exported functions +enum WFss = 0x20; // load DS from SS +enum WFreduced = 0x40; // skip DS load for non-exported functions +enum WFdgroup = 0x80; // load DS from DGROUP +enum WFexport = 0x100; // assume __export for all far functions +enum WFds = 0x200; // load DS from DS +enum WFmacros = 0x400; // define predefined windows macros +enum WFssneds = 0x800; // SS != DS +enum WFthunk = 0x1000; // use fixups instead of direct ref to CS +enum WFsaveds = 0x2000; // use push/pop DS for far functions +enum WFdsnedgroup = 0x4000; // DS != DGROUP +enum WFexe = 0x8000; // generating code for Windows EXE \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/Configv.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/Configv.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,19 @@ +module dmd.backend.Configv; + +import dmd.backend.LANG; + +// Configuration that is not saved in precompiled header + +struct Configv +{ + char addlinenumbers; // put line number info in .OBJ file + char verbose; // 0: compile quietly (no messages) + // 1: show progress to DLL (default) + // 2: full verbosity + char* csegname; // code segment name + char* deflibname; // default library name + LANG language; // message language + int errmax; // max error count +} + +Configv configv; \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/Cstate.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/Cstate.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,21 @@ +module dmd.backend.Cstate; + +import dmd.backend.Symbol; +import dmd.backend.LIST; +import dmd.backend.symtab_t; + +struct BLKLST; + +struct Cstate +{ + BLKLST* CSfilblk; // current source file we are parsing + Symbol* CSlinkage; // table of forward referenced linkage pragmas + list_t CSlist_freelist; // free list for list package + symtab_t* CSpsymtab; // pointer to current Symbol table +version (MEMORYHX) { + void** CSphx; // pointer to HX data block +} + char* modname; // module unique identifier +} + +extern (C++) extern __gshared Cstate cstate; \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/DT.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/DT.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,19 @@ +module dmd.backend.DT; + +import dmd.backend.dt_t; + +enum DT +{ + DT_abytes, + DT_azeros, // 1 + DT_xoff, + DT_1byte, + DT_nbytes, + DT_common, + DT_symsize, + DT_coff, + DT_ibytes, // 8 +} + +import dmd.EnumUtils; +mixin(BringToCurrentScope!(DT)); \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/F.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/F.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,60 @@ +module dmd.backend.F; + +enum F +{ + Fpending = 1, // if function has been queued for being written + Foutput = 2, /* if function has been written out */ + Finline = 0x10, /* if SCinline, and function really is inline */ + Foverload = 0x20, /* if function can be overloaded */ + Ftypesafe = 0x40, /* if function name needs type appended */ + Fmustoutput = 0x80, /* set for forward ref'd functions that */ + /* must be output */ + Finlinenest = 0x1000, /* used as a marker to prevent nested */ + /* inlines from expanding */ + Flinkage = 0x2000, /* linkage is already specified */ + Fstatic = 0x4000, /* static member function (no this) */ + Foperator = 4, /* if operator overload */ + Fcast = 8, /* if cast overload */ + Fvirtual = 0x100, /* if function is a virtual function */ + Fctor = 0x200, /* if function is a constructor */ + Fdtor = 0x400, /* if function is a destructor */ + Fnotparent = 0x800, /* if function is down Foversym chain */ + Fbitcopy = 0x8000, /* it's a simple bitcopy (op=() or X(X&)) */ + Fpure = 0x10000, // pure function + Finstance = 0x20000, // function is an instance of a template + Ffixed = 0x40000, // ctor has had cpp_fixconstructor() run on it, + // dtor has had cpp_fixdestructor() + Fintro = 0x80000, // function doesn't hide a previous virtual function + ///#if !TX86 + ///Fstcstd = 0x100000, // static constructor or static destructor + ///#endif + Fkeeplink = 0x200000, // don't change linkage to default + Fnodebug = 0x400000, // do not generate debug info for this function + Fgen = 0x800000, // compiler generated function + Finvariant = 0x1000000, // __invariant function + Fexplicit = 0x2000000, // explicit constructor + Fsurrogate = 0x4000000, // surrogate call function +} + +enum F3 +{ + Fvtblgen = 0x01, // generate vtbl[] when this function is defined + Femptyexc = 0x02, // empty exception specification (obsolete, use Tflags & TFemptyexc) + Fcppeh = 0x04, // uses C++ EH + Fdeclared = 0x10, // already declared function Symbol + Fmark = 0x20, // has unbalanced OPctor's + Fnteh = 0x08, // uses NT Structured EH + Fdoinline = 0x40, // do inline walk + Foverridden = 0x80, // ignore for overriding purposes +///#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS +/// Fnowrite = 0x100, // SCinline should never output definition +///#else + Fjmonitor = 0x100, // Jupiter synchronized function +///#endif + Fnosideeff = 0x200, // function has no side effects + F3badoparrow = 0x400, // bad operator->() + Fmain = 0x800, // function is main() or wmain() + Fnested = 0x1000, // D nested function with 'this' + Fmember = 0x2000, // D member function with 'this' + Fnotailrecursion = 0x4000, // no tail recursion optimizations +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/FL.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/FL.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,59 @@ +module dmd.backend.FL; + +/************************************** + * Element types. + * These should be combined with storage classes. + */ + +enum FL +{ + FLunde, + FLconst, // numerical constant + FLoper, // operator node + FLfunc, // function symbol + FLdata, // ref to data segment variable + FLreg, // ref to register variable + FLpseudo, // pseuodo register variable + FLauto, // ref to automatic variable + FLpara, // ref to function parameter variable + FLextern, // ref to external variable + FLtmp, // ref to a stack temporary, int contains temp number + FLcode, // offset to code + FLblock, // offset to block + FLudata, // ref to udata segment variable + FLcs, // ref to common subexpression number + FLswitch, // ref to offset of switch data block + FLfltreg, // ref to floating reg on stack, int contains offset + FLoffset, // offset (a variation on constant, needed so we + // can add offsets (different meaning for FLconst)) + FLdatseg, // ref to data segment offset + FLctor, // constructed object + FLdtor, // destructed object +///#if TX86 + FLndp, // saved 8087 register + FLfardata, // ref to far data segment + FLlocalsize, // replaced with # of locals in the stack frame + FLcsdata, // ref to code segment variable + FLtlsdata, // thread local storage + FLbprel, // ref to variable at fixed offset from frame pointer + FLframehandler, // ref to C++ frame handler for NT EH + FLasm, // (code) an ASM code + FLblockoff, // address of block + FLallocatmp, // temp for built-in alloca() + FLstack, // offset from ESP rather than EBP + FLdsymbol, // it's a Dsymbol +///#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS + // Change this, update debug.c too +/// FLgot, // global offset table entry outside this object file +/// FLgotoff, // global offset table entry inside this object file + //FLoncedata, // link once data + //FLoncecode, // link once code +///#endif +///#else +/// TARGET_enumFL +///#endif + FLMAX +} + +import dmd.EnumUtils; +mixin(BringToCurrentScope!(FL)); \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/Funcsym.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/Funcsym.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,3 @@ +module dmd.backend.Funcsym; + +struct Funcsym; \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/LANG.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/LANG.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,10 @@ +module dmd.backend.LANG; + +// Language for error messages +enum LANG +{ + LANGenglish, + LANGgerman, + LANGfrench, + LANGjapanese, +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/LINKAGE.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/LINKAGE.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,14 @@ +module dmd.backend.LINKAGE; + +/* Linkage type */ +enum LINKAGE +{ + LINK_C, /* C style */ + LINK_CPP, /* C++ style */ + LINK_PASCAL, /* Pascal style */ + LINK_FORTRAN, + LINK_SYSCALL, + LINK_STDCALL, + LINK_D, // D code + LINK_MAXDIM /* array dimension */ +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/LIST.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/LIST.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,1 @@ +module dmd.backend.LIST; import dmd.backend.Symbol; struct LIST { /* Do not access items in this struct directly, use the */ /* functions designed for that purpose. */ LIST* next; /* next element in list */ int count; /* when 0, element may be deleted */ union { void *ptr; /* data pointer */ int data; } } alias LIST* list_t; /* pointer to a list entry */ alias list_t symlist_t; /* pointer to a list entry */ extern (C++) extern { __gshared list_t slist; list_t list_prepend(list_t* plist, void* ptr); void slist_add(Symbol* s); } \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/OPER.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/OPER.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,358 @@ +module dmd.backend.OPER; + +enum OPER : ubyte /// +{ + OPunde, /* place holder for undefined operator */ + + OPadd, + OPmin, + OPmul, + OPdiv, + OPmod, + OPshr, // unsigned right shift + OPshl, + OPand, + OPxor, + OPor, + OPashr, // signed right shift + OPnot, + OPbool, /* "booleanize" */ + OPcom, + OPcond, + OPcomma, + OPoror, + OPandand, + OPbit, /* ref to bit field */ + OPind, /* *E */ + OPaddr, /* &E */ + OPneg, /* unary - */ + OPuadd, /* unary + */ +///#if TX86 + OPvoid, // where casting to void is not a no-op + OPabs, /* absolute value */ + OPsqrt, /* square root */ + OPrndtol, // round to short, long, long long (inline 8087 only) + OPsin, // sine + OPcos, // cosine + OPrint, // round to int + OPscale, // ldexp + OPyl2x, // y * log2(x) + OPyl2xp1, // y * log2(x + 1) + OPstrlen, /* strlen() */ + OPstrcpy, /* strcpy() */ + OPstrcat, /* strcat() */ + OPstrcmp, /* strcmp() */ + OPmemcpy, + OPmemcmp, + OPmemset, + OPsetjmp, // setjmp() + OPremquo, // / and % in one operation + + OPbsf, // bit scan forward + OPbsr, // bit scan reverse + OPbt, // bit test + OPbtc, // bit test and complement + OPbtr, // bit test and reset + OPbts, // bit test and set + OPbswap, // swap bytes +///#endif + + OPstreq, /* structure assignment */ + + OPnegass, // x = -x + OPpostinc, /* x++ */ + OPpostdec, /* x-- */ + + OPeq, + OPaddass, + OPminass, + OPmulass, + OPdivass, + OPmodass, + OPshrass, + OPshlass, + OPandass, + OPxorass, + OPorass, + +/* Convert from token to assignment operator */ +///#define asgtoktoop(tok) ((int) (tok) + ((int)OPeq - (int) TKeq)) + + OPashrass, + + /* relational operators (in same order as corresponding tokens) */ +///#define RELOPMIN ((int)OPle) + OPle, + OPgt, + OPlt, + OPge, + OPeqeq, + OPne, + + OPunord, /* !<>= */ + OPlg, /* <> */ + OPleg, /* <>= */ + OPule, /* !> */ + OPul, /* !>= */ + OPuge, /* !< */ + OPug, /* !<= */ + OPue, /* !<> */ + OPngt, + OPnge, + OPnlt, + OPnle, + OPord, + OPnlg, + OPnleg, + OPnule, + OPnul, + OPnuge, + OPnug, + OPnue, + +///#define rel_toktoop(tk) ((enum OPER)((int)tk - (int)TKle + (int)OPle)) + +/***************** End of relational operators ******************/ +///#define CNVOPMIN (OPnue+1) + +// parallel array inconvtab[] in cgelem.c) + +///#if TX86 + +/* Convert from conversion operator to conversion index */ +///#define convidx(op) ((int)(op) - CNVOPMIN) + +/* 8,16,32,64 integral type of unspecified sign + s,u signed/unsigned + f,d,ld float/double/long double + np,fp,vp,f16p near pointer/far pointer/handle pointer/far16 pointer + cvp const handle pointer + */ + + OPb_8, // convert bit to byte + OPd_s32, + OPs32_d, + OPd_s16, + OPs16_d, + OPd_u16, + OPu16_d, + OPd_u32, + OPu32_d, + OPd_s64, + OPs64_d, + OPd_u64, + OPu64_d, + OPd_f, + OPf_d, + OPvp_fp, + OPcvp_fp, // const handle * => far * + OPs16_32, // short to long + OPu16_32, // unsigned short to long + OP32_16, // long to short + OPu8_16, // unsigned char to short + OPs8_16, // signed char to short + OP16_8, // short to 8 bits + OPu32_64, // unsigned long to long long + OPs32_64, // long to long long + OP64_32, // long long to long +///#define OPsfltdbl OPunde +///#define OPdblsflt OPunde + OPoffset, // get offset of far pointer + OPnp_fp, // convert near pointer to far + OPnp_f16p, // from 0:32 to 16:16 + OPf16p_np, // from 16:16 to 0:32 + OPld_d, + OPd_ld, + OPld_u64, +///#else +///TARGET_CONVERSION_OPS +///#endif + +///#define CNVOPMAX (OPc_r-1) +///#define convidx(op) ((int)(op) - CNVOPMIN) +/* Convert from conversion operator to conversion index */ + +///#if 1 +// The old conversion operators - retain until we get the code fixed +///#define OPlngdbl OPs32_d +///#define OPdblint OPd_s16 +///#define OPintdbl OPs16_d +///#define OPdbluns OPd_u16 +///#define OPunsdbl OPu16_d +///#define OPdblulng OPd_u32 +///#define OPulngdbl OPu32_d +///#define OPdblllng OPd_s64 +///#define OPllngdbl OPs64_d +///#define OPdblullng OPd_u64 +///#define OPdblflt OPd_f +///#define OPvptrfptr OPvp_fp +///#define OPcvptrfptr OPcvp_fp // const handle * => far * +///#define OPshtlng OPs16_32 // short to long +///#define OPushtlng OPu16_32 // unsigned short to long +///#define OPlngsht OP32_16 // long to short +///#define OPu8int OPu8_16 // unsigned char to short +///#define OPs8int OPs8_16 // signed char to short +///#define OPint8 OP16_8 // short to 8 bits +///#define OPulngllng OPu32_64 // unsigned long to long long +///#define OPlngllng OPs32_64 // long to long long +///#define OPllnglng OP64_32 // long long to long +///#define OPsfltdbl OPunde +///#define OPdblsflt OPunde +///#define OPoffset OPoffset // get offset of far pointer +///#define OPptrlptr OPnp_fp // convert near pointer to far +///#define OPtofar16 OPnp_f16p // from 0:32 to 16:16 +///#define OPfromfar16 OPf16p_np // from 16:16 to 0:32 + +///#endif + +/***************** End of conversion operators ******************/ + + OPc_r, // complex to real + OPc_i, // complex to imaginary + OPmsw, // top 32 bits of 64 bit word (32 bit code gen) + // top 16 bits of 32 bit word (16 bit code gen) + + OPparam, /* function parameter separator */ + OPcall, /* binary function call */ + OPucall, /* unary function call */ + OPcallns, // binary function call, no side effects + OPucallns, // unary function call, no side effects + + OPsizeof, /* for forward-ref'd structs */ + OPstrctor, /* call ctor on struct param */ + OPstrthis, // 'this' pointer for OPstrctor + OPstrpar, /* structure func param */ + OPconst, /* constant */ + OPrelconst, /* constant that contains an address */ + OPvar, /* variable */ + OPreg, // register (used in inline asm operand expressions) + OPcolon, /* : as in ?: */ + OPcolon2, // alternate version with different EH semantics + OPstring, /* address of string */ + OPasm, /* in-line assembly code */ + OPinfo, // attach info (used to attach ctor/dtor + OPhalt, // insert HLT instruction + // info for exception handling) + OPctor, + OPdtor, + OPmark, + OPpair, // build register pair, E1 is lsb, E2 = msb + OPrpair, // build reversed register pair, E1 is msb, E2 = lsb + OPframeptr, // load pointer to base of frame + OPgot, // load pointer to global offset table + + // Jupiter operators + OParray, // access Jupiter array, left is handle, right is index + OParraylength, // evaluates array handle into array length + OPfield, // access Jupiter object field, left is handle, right is offset + OPnewarray, // allocate Jupiter array, left is dimension, right is type + OPmultinewarray, // allocate multidimensional Jupiter array + // left is dimensions, right is (numdims,type signature) + OPinstanceof, // left is class id, right is handle + OPfinalinstanceof, // left is class id, right is handle + OPcheckcast, // left is class id, right is handle + OPhstring, // handle to static string + OPnullcheck, // check if pointer is null + +///#if TX86 + OPinp, /* input from I/O port */ + OPoutp, /* output to I/O port */ +///#endif + /* C++ operators */ + OPnew, // operator new + OPanew, // operator new[] + OPdelete, // operator delete + OPadelete, // operator delete[] + OPbrack, /* [] subscript */ + OParrow, /* for -> overloading */ + OParrowstar, /* for ->* overloading */ + OPpreinc, /* ++x overloading */ + OPpredec, /* --x overloading */ + +///#ifdef TARGET_INLINEFUNC_OPS +/// TARGET_INLINEFUNC_OPS +///#endif + +///#if (TARGET_POWERPC) + OPeieio, +///#endif + + OPMAX /* 1 past last operator */ +} + +enum RELOPMIN = cast(int)OPER.OPle; + +extern(C++) extern __gshared const ubyte[OPER.OPMAX] optab1; +extern(C++) extern __gshared const ubyte[OPER.OPMAX] optab2; +extern(C++) extern __gshared const ubyte[OPER.OPMAX] optab3; +extern(C++) extern __gshared const ubyte[OPER.OPMAX] opcost; + +enum _OT +{ + _OTbinary = 1, + _OTunary = 2, + _OTcommut = 4, + _OTassoc = 8, + _OTsideff = 0x10, + _OTeop0e = 0x20, + _OTeop00 = 0x40, + _OTeop1e = 0x80, + + /* optab2[] */ + _OTlogical = 1, + _OTwid = 2, + _OTcall = 4, + _OTrtol = 8, + _OTassign = 0x10, + _OTdef = 0x20, + _OTae = 0x40, + _OTexp = 0x80, +} + +/+ +// optab3[] +#define _OTboolnop 1 ++/ + +ubyte OTbinary(OPER op) { + return (optab1[op] & _OT._OTbinary); +} + +/+ +#define OTunary(op) (optab1[op]&_OTunary) +#define OTleaf(op) (!(optab1[op]&(_OTunary|_OTbinary))) +#define OTcommut(op) (optab1[op]&_OTcommut) +#define OTassoc(op) (optab1[op]&_OTassoc) +#define OTassign(op) (optab2[op]&_OTassign) +#define OTpost(op) ((op) == OPpostinc || (op) == OPpostdec) +#define OTeop0e(op) (optab1[op]&_OTeop0e) +#define OTeop00(op) (optab1[op]&_OTeop00) +#define OTeop1e(op) (optab1[op]&_OTeop1e) +#define OTsideff(op) (optab1[op]&_OTsideff) +#define OTconv(op) ((op) >= CNVOPMIN && (op) <= CNVOPMAX) +#define OTlogical(op) (optab2[op]&_OTlogical) +#define OTwid(op) (optab2[op]&_OTwid) +#define OTopeq(op) ((op) >= OPaddass && (op) <= OPashrass) +#define OTop(op) ((op) >= OPadd && (op) <= OPor) +#define OTcall(op) (optab2[op]&_OTcall) +#define OTrtol(op) (optab2[op]&_OTrtol) +#define OTrel(op) ((op) >= OPle && (op) <= OPnue) +#define OTrel2(op) ((op) >= OPle && (op) <= OPge) +#define OTdef(op) (optab2[op]&_OTdef) +#define OTae(op) (optab2[op]&_OTae) +#define OTexp(op) (optab2[op]&_OTexp) +#if 1 +#define OTboolnop(op) (optab3[op]&_OTboolnop) +#define OTcalldef(op) (OTcall(op) || (op) == OPstrcpy || (op) == OPstrcat || (op) == OPmemcpy) +#else +#endif + +/* Convert op= to op */ +#define opeqtoop(opx) ((opx) - OPaddass + OPadd) + +/* Convert op to op= */ +#define optoopeq(opx) ((opx) - OPadd + OPaddass) ++/ + +import dmd.EnumUtils; +mixin(BringToCurrentScope!(OPER)); \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/PARAM.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/PARAM.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,4 @@ +module dmd.backend.PARAM; + +struct PARAM; +alias PARAM param_t; \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/REG.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/REG.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,22 @@ +module dmd.backend.REG; + +enum REG +{ + AX = 0, + CX = 1, + DX = 2, + BX = 3, + SP = 4, + BP = 5, + SI = 6, + DI = 7, + ES = 9, + PSW = 10, + STACK = 11, // top of stack + MEM = 12, // memory + OTHER = 13, // other things + ST0 = 14, // 8087 top of stack register + ST01 = 15, // top two 8087 registers; for complex types + + NOREG = 100, // no register +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/REGMAX.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/REGMAX.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,3 @@ +module dmd.backend.REGMAX; + +enum REGMAX = 10; \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/RTLSYM.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/RTLSYM.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,101 @@ +module dmd.backend.RTLSYM; + +import dmd.backend.Symbol; + +enum RTLSYM +{ + RTLSYM_THROW, + RTLSYM_MONITOR_HANDLER, + RTLSYM_MONITOR_PROLOG, + RTLSYM_MONITOR_EPILOG, + RTLSYM_DCOVER, + RTLSYM_DASSERT, + RTLSYM_DASSERT_MSG, + RTLSYM_DARRAY, + RTLSYM_DINVARIANT, + RTLSYM__DINVARIANT, + RTLSYM_MEMCPY, + RTLSYM_MEMSET8, + RTLSYM_MEMSET16, + RTLSYM_MEMSET32, + RTLSYM_MEMSET64, + RTLSYM_MEMSET128, + RTLSYM_MEMSET80, + RTLSYM_MEMSET160, + RTLSYM_MEMSETN, + RTLSYM_MODULO, + RTLSYM_MONITORENTER, + RTLSYM_MONITOREXIT, + RTLSYM_CRITICALENTER, + RTLSYM_CRITICALEXIT, + RTLSYM_SWITCH_STRING, + RTLSYM_SWITCH_USTRING, + RTLSYM_SWITCH_DSTRING, + RTLSYM_DSWITCHERR, + RTLSYM_DHIDDENFUNC, + RTLSYM_NEWCLASS, + RTLSYM_NEWARRAYT, + RTLSYM_NEWARRAYIT, + RTLSYM_NEWARRAYMT, + RTLSYM_NEWARRAYMIT, + RTLSYM_ARRAYLITERALT, + RTLSYM_ASSOCARRAYLITERALT, + RTLSYM_CALLFINALIZER, + RTLSYM_CALLINTERFACEFINALIZER, + RTLSYM_DELCLASS, + RTLSYM_DELINTERFACE, + RTLSYM_ALLOCMEMORY, + RTLSYM_DELARRAY, + RTLSYM_DELARRAYT, + RTLSYM_DELMEMORY, + RTLSYM_INTERFACE, + RTLSYM_DYNAMIC_CAST, + RTLSYM_INTERFACE_CAST, + RTLSYM_FATEXIT, + RTLSYM_ARRAYCATT, + RTLSYM_ARRAYCATNT, + RTLSYM_ARRAYAPPENDT, + RTLSYM_ARRAYAPPENDCT, + RTLSYM_ARRAYSETLENGTHT, + RTLSYM_ARRAYSETLENGTHIT, + RTLSYM_ARRAYCOPY, + RTLSYM_ARRAYASSIGN, + RTLSYM_ARRAYCTOR, + RTLSYM_ARRAYSETASSIGN, + RTLSYM_ARRAYSETCTOR, + RTLSYM_ARRAYCAST, + RTLSYM_ARRAYCAST_FROMBIT, + RTLSYM_ARRAYEQ, + RTLSYM_ARRAYEQ2, + RTLSYM_ARRAYEQBIT, + RTLSYM_ARRAYCMP, + RTLSYM_ARRAYCMP2, + RTLSYM_ARRAYCMPCHAR, + RTLSYM_ARRAYCMPBIT, + RTLSYM_OBJ_EQ, + RTLSYM_OBJ_CMP, + RTLSYM_EXCEPT_HANDLER2, + RTLSYM_EXCEPT_HANDLER3, + RTLSYM_CPP_HANDLER, + RTLSYM_D_LOCAL_UNWIND2, + RTLSYM_TLS_INDEX, + RTLSYM_TLS_ARRAY, + RTLSYM_EXCEPT_LIST, + RTLSYM_SETJMP3, + RTLSYM_LONGJMP, + RTLSYM_INTONLY, + RTLSYM_ALLOCA, + RTLSYM_CPP_LONGJMP, + RTLSYM_PTRCHK, + RTLSYM_CHKSTK, + RTLSYM_TRACE_PRO_N, + RTLSYM_TRACE_PRO_F, + RTLSYM_TRACE_EPI_N, + RTLSYM_TRACE_EPI_F, + RTLSYM_MAX +} + +import dmd.EnumUtils; +mixin(BringToCurrentScope!(RTLSYM)); + +extern(C++) extern __gshared Symbol* rtlsym[RTLSYM.RTLSYM_MAX]; \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/SC.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/SC.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,51 @@ +module dmd.backend.SC; + +enum SC : ubyte +{ + SCunde, + SCauto, + SCstatic, + SCextern, + SCregister, + SCpseudo, + SCglobal, + SCcomdat, + SCparameter, + SCregpar, + SCfastpar, + SCtypedef, + SCexplicit, + SCmutable, + SCtmp, + SClabel, + SCstruct, + SCenum, + SCfield, + SCconst, + SCmember, + SCanon, + SCinline, + SCsinline, + SCeinline, + SCoverload, + SCfriend, + SCvirtual, + SClocstat, + SCtemplate, + SCfunctempl, + SCftexpspec, + SClinkage, + SCpublic, + SCcomdef, + SCbprel, + SCnamespace, + SCalias, + SCfuncalias, + SCmemalias, + SCstack, + SCadl, + SCMAX +} + +import dmd.EnumUtils; +mixin(BringToCurrentScope!(SC)); \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/SEN.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/SEN.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,7 @@ +module dmd.backend.SEN; + +enum SEN +{ + SENnotagname = 1, // no tag name for enum + SENforward = 2, // forward referenced enum +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/SFL.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/SFL.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,67 @@ +module dmd.backend.SFL; + +enum SFL +{ + SFLmark = 0x08, // temporary marker + SFLvalue = 0x01, // Svalue contains const expression + SFLimplem = 0x02, // if seen implementation of Symbol + // (function body for functions, + // initializer for variables) + SFLdouble = 0x02, // SCregpar or SCparameter, where float + // is really passed as a double + SFLfree = 0x04, // if we can symbol_free() a Symbol in + // a Symbol table[] + SFLexit = 0x10, // tyfunc: function does not return + // (ex: exit,abort,_assert,longjmp) + SFLtrue = 0x200, // value of Symbol != 0 + SFLreplace = SFLmark, // variable gets replaced in inline expansion + SFLskipinit = 0x10000, // SCfield, SCmember: initializer is skipped + SFLnodebug = 0x20000, // don't generate debug info + SFLwasstatic = 0x800000, // was an uninitialized static + SFLweak = 0x1000000, // resolve to NULL if not found + + // CPP + SFLnodtor = 0x10, // set if destructor for Symbol is already called + SFLdtorexp = 0x80, // Svalue has expression to tack onto dtor + SFLmutable = 0x100000, // SCmember or SCfield is mutable + SFLdyninit = 0x200000, // symbol has dynamic initializer + SFLtmp = 0x400000, // symbol is a generated temporary + +///version (XXX) {///TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS +/// SFLthunk = 0x40000, // symbol is temporary for thunk +///} + + // Possible values for protection bits + SFLprivate = 0x60, + SFLprotected = 0x40, + SFLpublic = 0x20, + SFLnone = 0x00, + SFLpmask = 0x60, // mask for the protection bits +///version (VEC_VTBL_LIST) { +/// SFLvtbl = 0x2000, // Symbol is a vtable or vbtable +///} + + // OPTIMIZER and CODGEN + SFLdead = 0x800, // this variable is dead + + // OPTIMIZER only + SFLunambig = 0x400, // only accessible by unambiguous reference, + // i.e. cannot be addressed via pointer + // (GTregcand is a subset of this) + // P.S. code generator turns off this + // flag if any reads are done from it. + // This is to eliminate stores to it + // that are never read. + + SFLlivexit = 0x1000, // live on exit from function + SFLnotbasiciv = 0x4000, // not a basic induction variable + SFLnord = SFLdouble, // SCauto,SCregister,SCtmp: disallow redundant warnings + + // CODGEN only + SFLread = 0x40000, // variable is actually read from + // (to eliminate dead stores) + SFLspill = 0x80000, // only in register part of the time +} + +import dmd.EnumUtils; +mixin(BringToCurrentScope!(SFL)); \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/STR.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/STR.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,34 @@ +module dmd.backend.STR; + +enum STR +{ + STRanonymous = 0x01, // set for unions with no tag names + STRglobal = 0x02, // defined at file scope + + STRnotagname = 0x04, // struct/class with no tag name + STRoutdef = 0x08, // we've output the debug definition + STRbitfields = 0x10, // set if struct contains bit fields + STRpredef = 0x1000, // a predefined struct + STRunion = 0x4000, // actually, it's a union + + STRabstract = 0x20, // abstract class + STRbitcopy = 0x40, // set if operator=() is merely a bit copy + STRanyctor = 0x80, // set if any constructors were defined + // by the user + STRnoctor = 0x100, // no constructors allowed + STRgen = 0x200, // if struct is an instantiation of a + // template class, and was generated by + // that template + STRvtblext = 0x400, // generate vtbl[] only when first member function + // definition is encountered (see Fvtblgen) + STRexport = 0x800, // all member functions are to be _export + STRclass = 0x8000, // it's a class, not a struct +///version (TX86) { + STRimport = 0x40000, // imported class + STRstaticmems = 0x80000, // class has static members +///} + STR0size = 0x100000, // zero sized struct + STRinstantiating = 0x200000, // if currently being instantiated + STRexplicit = 0x400000, // if explicit template instantiation + STRgenctor0 = 0x800000, // need to gen X::X() +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/SYMIDX.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/SYMIDX.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,3 @@ +module dmd.backend.SYMIDX; + +alias int SYMIDX; // symbol table index \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/Srcpos.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/Srcpos.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,23 @@ +module dmd.backend.Srcpos; + +struct Srcpos +{ + uint Slinnum; // 0 means no info available +version (TX86) { +version (SPP_OR_SCPP) { + Sfile** Sfilptr; // file +/// #define srcpos_sfile(p) (**(p).Sfilptr) +/// #define srcpos_name(p) (srcpos_sfile(p).SFname) +} +version (MARS) { + char* Sfilename; +/// #define srcpos_name(p) ((p).SFname) +} +} +version (M_UNIX) { + short Sfilnum; // file number +} +version (SOURCE_OFFSETS) { + uint Sfiloff; // byte offset +} +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/StringTab.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/StringTab.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,17 @@ +module dmd.backend.StringTab; + +import dmd.Module; +import dmd.backend.Symbol; + +struct StringTab +{ + Module m; // module we're generating code for + Symbol* si; + void* string_; + size_t sz; + size_t len; +} + +enum STSIZE = 16; +__gshared StringTab[STSIZE] stringTab; +__gshared size_t stidx; \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/Symbol.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/Symbol.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,388 @@ +module dmd.backend.Symbol; + +import dmd.backend.dt_t; +import dmd.backend.TYPE; +import dmd.backend.LIST; +import dmd.backend.block; +import dmd.backend.func_t; +import dmd.backend.enum_t; +import dmd.backend.elem; +import dmd.backend.struct_t; +import dmd.backend.template_t; +import dmd.backend.targ_types; +import dmd.backend.vec_t; +import dmd.backend.SYMIDX; +import dmd.backend.regm_t; +import dmd.backend.Util; + +struct Symbol +{ + ushort id; + + Symbol* Sl; + Symbol* Sr; // left, right child + + Symbol *Snext; // next in threaded list + + dt_t* Sdt; // variables: initializer + type* Stype; // type of Symbol + + tym_t ty() + { + return Stype.Tty; + } + + union // variants for different Symbol types + { + enum_t* Senum; // SCenum + struct + { + func_t* Sfunc; // tyfunc + list_t Spath1; // SCfuncalias member functions: same as Spath + // and in same position + // SCadl: list of associated functions for ADL lookup + } + struct // SClabel + { + int Slabel; // TRUE if label was defined + block* Slabelblk; // label block + } +/// #define Senumlist Senum->SEenumlist + + struct // SClinkage + { + int Slinkage; // tym linkage bits + uint Smangle; + } + + struct + { + char Sbit; // SCfield: bit position of start of bit field + char Swidth; // SCfield: width in bits of bit field + targ_size_t Smemoff; // SCmember,SCfield: offset from start of struct + } + + elem* Svalue; /* SFLvalue: value of const + SFLdtorexp: for objects with destructor, + conditional expression to precede dtor call + */ + + struct_t* Sstruct; // SCstruct + template_t* Stemplate; // SCtemplate + Symbol* Simport; // SCextern: if dllimport Symbol, this is the + // Symbol it was imported from + + ubyte Spreg; // SCfastpar: register parameter is passed in + } + + Symbol* Sscope; // enclosing scope (could be struct tag, + // enclosing inline function for statics, + // or namespace) +///#define isclassmember(s) ((s)->Sscope && (s)->Sscope->Sclass == SCstruct) + + const(char)* prettyIdent; // the symbol identifer as the user sees it + + enum_SC Sclass; // storage class (SCxxxx) + char Sfl; // flavor (FLxxxx) + SYMFLGS Sflags; // flag bits (SFLxxxx) + + vec_t Srange; // live range, if any + vec_t Slvreg; // when symbol is in register + targ_size_t Ssize; // tyfunc: size of function + targ_size_t Soffset; // variables: offset of Symbol in its storage class + + SYMIDX Ssymnum; // Symbol number (index into globsym.tab[]) + // SCauto,SCparameter,SCtmp,SCregpar,SCregister + + short Sseg; // segment index + + int Sweight; // usage count, the higher the number, + // the more worthwhile it is to put in + // a register + union + { + uint Sxtrnnum; // SCcomdef,SCextern,SCcomdat: external symbol # (starting from 1) + uint Stypidx; // SCstruct,SCunion,SCclass,SCenum,SCtypedef: debug info type index + + struct + { + ubyte Sreglsw; + ubyte Sregmsw; + regm_t Sregm; // mask of registers + } + } + + regm_t Sregsaved; // mask of registers not affected by this func + + char Sident[35]; // identifier string (dynamic array) + // (the size is for static Symbols) + + bool needThis() // true if symbol needs a 'this' pointer + { + assert(false); + } +} + +void dumpSymbol(Symbol* foo) +{ + foreach (a, b; foo.tupleof) + { + static if (typeof(foo.tupleof[a]).stringof != "char[35u]") { + std.stdio.writeln(foo.tupleof[a].stringof, " ", cast(char*)&foo.tupleof[a] - cast(char*)foo, " = ", cast(int)foo.tupleof[a]); + //std.stdio.writeln("printf(\"", foo.tupleof[a].stringof, " %d = %d\\n\",(char*)(&", foo.tupleof[a].stringof, ")-(char*)foo, ", foo.tupleof[a].stringof, ");"); + } + } + + std.stdio.writefln("(*foo).Sclass %d = %d", (cast(char*)&foo.Sclass - cast(char*)foo), cast(int)foo.Sclass); + //std.stdio.writeln("printf(\"(*foo).Sclass %d %d\\n\", ((char*)&foo->Sclass - (char*)foo), (int)foo->Sclass);"); +} + +/+ +struct Symbol +{ +debug { + ushort id; +///#define IDsymbol 0x5678 +///#define symbol_debug(s) assert((s)->id == IDsymbol) +///#define class_debug(s) assert((s)->id == IDsymbol) +} else { +///#define symbol_debug(s) +///#define class_debug(s) +} + + Symbol* Sl; + Symbol* Sr; // left, right child + +version (TX86) { + Symbol *Snext; // next in threaded list +} + dt_t* Sdt; // variables: initializer + type* Stype; // type of Symbol + + auto ty() { + assert(false); + //return Stype.Tty; + } + + auto Senumlist() + { + return Senum.SEenumlist; + } + + union // variants for different Symbol types + { + enum_t* Senum; // SCenum + struct + { + func_t* Sfunc; // tyfunc + list_t Spath1; // SCfuncalias member functions: same as Spath + // and in same position + // SCadl: list of associated functions for ADL lookup + } + struct // SClabel + { + int Slabel; // TRUE if label was defined + block* Slabelblk_; // label block + } + +version (TX86) { + struct // SClinkage + { + long Slinkage; // tym linkage bits + uint Smangle; + } +} else { + long Slinkage; // SClinkage, tym linkage bits +} + + struct + { + char Sbit; // SCfield: bit position of start of bit field + char Swidth; // SCfield: width in bits of bit field +version (TX86) { + targ_size_t Smemoff; // SCmember,SCfield: offset from start of struct +} + } + + elem* Svalue; /* SFLvalue: value of const + SFLdtorexp: for objects with destructor, + conditional expression to precede dtor call + */ + struct_t* Sstruct; // SCstruct + + template_t* Stemplate; // SCtemplate + +version (SCPP) { + struct // SCnamespace + { + Symbol* Snameroot; // the Symbol table for the namespace + list_t Susing; // other namespaces from using-directives + } + struct + { + Symbol* Smemalias; // SCalias: pointer to Symbol to use instead + // (generated by using-declarations and + // namespace-alias-definitions) + // SCmemalias: pointer to member of base class + // to use instead (using-declarations) + symlist_t Spath; // SCmemalias: path of classes to get to base + // class of which Salias is a member + } +} + +version (TX86) { + Symbol* Simport; // SCextern: if dllimport Symbol, this is the + // Symbol it was imported from +} + ubyte Spreg; // SCfastpar: register parameter is passed in + } + +version (SCPP_OR_MARS) { + Symbol* Sscope; // enclosing scope (could be struct tag, + // enclosing inline function for statics, + // or namespace) + //#define isclassmember(s) ((s)->Sscope && (s)->Sscope->Sclass == SCstruct) +} + +version (SCPP) { + Symbol* Scover; // if there is a tag name and a regular name + // of the same identifier, Scover is the tag + // Scover can be SCstruct, SCenum, SCtemplate + // or an SCalias to them. + //#define isscover(s) ((s)->Sclass == SCstruct || (s)->Sclass == SCenum || (s)->Sclass == SCtemplate) + uint Ssequence; // sequence number (used for 2 level lookup) + // also used as 'parameter number' for SCTtemparg +} else version (MARS) { + const(char)* prettyIdent; // the symbol identifer as the user sees it +} else version (AUTONEST) { + ubyte Spush; // # of pushes followed by # of + ubyte Spop; // pops of scope level +} + +version (ELFOBJ_OR_MACHOBJ) { + int obj_si; // Symbol index of coff or elf symbol + uint dwarf_off; // offset into .debug section + targ_size_t code_off; // rel. offset from start of block where var is initialized + targ_size_t last_off; // last offset using var +} + +version (TARGET_OSX) { + targ_size_t Slocalgotoffset; +} + + SC Sclass; // storage class (SCxxxx) + char Sfl; // flavor (FLxxxx) + SYMFLGS Sflags; // flag bits (SFLxxxx) +/// #define SFLmark 0x08 // temporary marker +/// #define SFLvalue 0x01 // Svalue contains const expression +/// #define SFLimplem 0x02 // if seen implementation of Symbol + // (function body for functions, + // initializer for variables) +/// #define SFLdouble 0x02 // SCregpar or SCparameter, where float + // is really passed as a double +/// #define SFLfree 0x04 // if we can symbol_free() a Symbol in + // a Symbol table[] +/// #define SFLexit 0x10 // tyfunc: function does not return + // (ex: exit,abort,_assert,longjmp) +/// #define SFLtrue 0x200 // value of Symbol != 0 +/// #define SFLreplace SFLmark // variable gets replaced in inline expansion +/// #define SFLskipinit 0x10000 // SCfield, SCmember: initializer is skipped +/// #define SFLnodebug 0x20000 // don't generate debug info +/// #define SFLwasstatic 0x800000 // was an uninitialized static +/// #define SFLweak 0x1000000 // resolve to NULL if not found + + // CPP +/// #define SFLnodtor 0x10 // set if destructor for Symbol is already called +/// #define SFLdtorexp 0x80 // Svalue has expression to tack onto dtor +/// #define SFLmutable 0x100000 // SCmember or SCfield is mutable +/// #define SFLdyninit 0x200000 // symbol has dynamic initializer +/// #define SFLtmp 0x400000 // symbol is a generated temporary +version (XXX) { ///TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS + ///#define SFLthunk 0x40000 // symbol is temporary for thunk +} + + // Possible values for protection bits +/// #define SFLprivate 0x60 +/// #define SFLprotected 0x40 +/// #define SFLpublic 0x20 +/// #define SFLnone 0x00 +/// #define SFLpmask 0x60 // mask for the protection bits +version (VEC_VTBL_LIST) { +/// #define SFLvtbl 0x2000 // Symbol is a vtable or vbtable +} + + // OPTIMIZER and CODGEN +/// #define GTregcand 0x100 // if Symbol is a register candidate +/// #define SFLdead 0x800 // this variable is dead + + // OPTIMIZER only +/// #define SFLunambig 0x400 // only accessible by unambiguous reference, + // i.e. cannot be addressed via pointer + // (GTregcand is a subset of this) + // P.S. code generator turns off this + // flag if any reads are done from it. + // This is to eliminate stores to it + // that are never read. +/// #define SFLlivexit 0x1000 // live on exit from function +/// #define SFLnotbasiciv 0x4000 // not a basic induction variable +/// #define SFLnord SFLdouble // SCauto,SCregister,SCtmp: disallow redundant warnings + + // CODGEN only +/// #define GTtried SFLmark // tried to place in register +/// #define GTbyte 0x8000 // variable is sometimes accessed as +/// #define SFLread 0x40000 // variable is actually read from + // (to eliminate dead stores) +/// #define SFLspill 0x80000 // only in register part of the time + + vec_t Srange; // live range, if any + vec_t Slvreg; // when symbol is in register + targ_size_t Ssize; // tyfunc: size of function + targ_size_t Soffset; // variables: offset of Symbol in its storage class +version (TARGET_MAC) { +///#define Smemoff Soffset +} + + // CPP || OPTIMIZER + SYMIDX Ssymnum; // Symbol number (index into globsym.tab[]) + // SCauto,SCparameter,SCtmp,SCregpar,SCregister + // CODGEN +version (TX86) { + short Sseg; // segment index +} + int Sweight; // usage count, the higher the number, + // the more worthwhile it is to put in + // a register + union + { + uint Sxtrnnum; // SCcomdef,SCextern,SCcomdat: external symbol # (starting from 1) + uint Stypidx; // SCstruct,SCunion,SCclass,SCenum,SCtypedef: debug info type index + struct + { + ubyte Sreglsw; + ubyte Sregmsw; + regm_t Sregm; // mask of registers + } // SCregister,SCregpar,SCpseudo: register number + } + +version (TX86) { + regm_t Sregsaved; // mask of registers not affected by this func +} + +version (SOURCE_4SYMS) { + Srcpos Ssrcpos; // file position for definition +} + // Target Additions +/// TARGET_structSYMBOL +version (TX86) { + char Sident[SYM_PREDEF_SZ]; // identifier string (dynamic array) + // (the size is for static Symbols) +} else { + long[0] Sident; // identifier string (dynamic array) as a str4 +} + + bool needThis() // true if symbol needs a 'this' pointer + { + assert(false); + } +} ++/ \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/TF.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/TF.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,30 @@ +module dmd.backend.TF; + +enum TF +{ + TFprototype = 1, /* if this function is prototyped */ + TFfixed = 2, /* if prototype has a fixed # of parameters */ + TFforward = 8, // TYstruct: if forward reference of tag name + TFsizeunknown = 0x10, // TYstruct,TYarray: if size of type is unknown + // TYmptr: the Stag is TYident type + TFfuncret = 0x20, // C++,tyfunc(): overload based on function return value + TFfuncparam = 0x20, // TYarray: top level function parameter + TFstatic = 0x40, // TYarray: static dimension + TFvla = 0x80, // TYarray: variable length array + TFemptyexc = 0x100, // tyfunc(): empty exception specification + + // C + TFgenerated = 4, // if we generated the prototype ourselves + + // CPP + TFdependent = 4, // template dependent type + +///version (TX86) { +///} else { +/// TFhydrated = 0x20, // type data already hydrated +/// TFbasicrev = 0x80, // if basic reserved type +///} +} + +import dmd.EnumUtils; +mixin(BringToCurrentScope!(TF)); \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/TYFL.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/TYFL.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,175 @@ +module dmd.backend.TYFL; + +import dmd.backend.Util; + +extern(C++) ubyte* get_tytab(); +ubyte* tytab() { return get_tytab(); } + +extern(C++) ubyte* get_tytab2(); +ubyte* tytab2() { return get_tytab2(); } + +/* Array to give the size in bytes of a type, -1 means error */ +extern(C++) byte* get_tysize(); +byte* tysize() { return get_tysize(); } + +enum TYFL +{ + /* Flags in tytab[] array */ + TYFLptr = 1, + TYFLreal = 2, + TYFLintegral = 4, + TYFLcomplex = 8, + TYFLimaginary = 0x10, + TYFLuns = 0x20, + TYFLmptr = 0x40, + TYFLfv = 0x80, /* TYfptr || TYvptr */ + + /* Flags in tytab2[] array */ +///version (TX86) { + TYFLfarfunc = 1, + TYFLpascal = 2, /* callee cleans up stack */ + TYFLrevparam = 4, /* function parameters are reversed */ +///} else { +/// TYFLcallstkc = 1, /* callee cleans up stack */ +/// TYFLrevparam = 2, /* function parameters are reversed */ +///} + TYFLshort = 0x10, + TYFLaggregate = 0x20, + TYFLfunc = 0x40, + TYFLref = 0x80, +} + +/* Groupings of types */ + +ubyte tyintegral(uint ty) { + return (tytab[(ty) & 0xFF] & TYFL.TYFLintegral); +} + +ubyte tyarithmetic(uint ty) { + return (tytab[(ty) & 0xFF] & (TYFL.TYFLintegral | TYFL.TYFLreal | TYFL.TYFLimaginary | TYFL.TYFLcomplex)); +} + +ubyte tyaggregate(uint ty) { + return (tytab2[(ty) & 0xFF] & TYFL.TYFLaggregate); +} + +ubyte tyscalar(uint ty) { + return (tytab[(ty) & 0xFF] & (TYFL.TYFLintegral | TYFL.TYFLreal | TYFL.TYFLimaginary | TYFL.TYFLcomplex | TYFL.TYFLptr | TYFL.TYFLmptr)); +} + +ubyte tyfloating(uint ty) { + return (tytab[(ty) & 0xFF] & (TYFL.TYFLreal | TYFL.TYFLimaginary | TYFL.TYFLcomplex)); +} + +ubyte tyimaginary(uint ty) { + return (tytab[(ty) & 0xFF] & TYFL.TYFLimaginary); +} + +ubyte tycomplex(uint ty) { + return (tytab[(ty) & 0xFF] & TYFL.TYFLcomplex); +} + +ubyte tyreal(uint ty) { + return (tytab[(ty) & 0xFF] & TYFL.TYFLreal); +} + +/* Types that are chars or shorts */ +ubyte tyshort(uint ty) { + return (tytab2[(ty) & 0xFF] & TYFL.TYFLshort); +} + +/+ +/* Detect TYlong or TYulong */ +#define tylong(ty) (tybasic(ty) == TYlong || tybasic(ty) == TYulong) ++/ + +/* Use to detect a pointer type */ +ubyte typtr(uint ty) { + return (tytab[(ty) & 0xFF] & TYFL.TYFLptr); +} + +/* Use to detect a reference type */ +ubyte tyref(uint ty) { + return (tytab2[(ty) & 0xFF] & TYFL.TYFLref); +} + +/* Use to detect a pointer type or a member pointer */ +ubyte tymptr(uint ty) { + return (tytab[(ty) & 0xFF] & (TYFL.TYFLptr | TYFL.TYFLmptr)); +} + +/* Detect TYfptr or TYvptr */ +ubyte tyfv(uint ty) { + return (tytab[(ty) & 0xFF] & TYFL.TYFLfv); +} + +/+ +// Give size of type +char tysize(uint ty) { + return tysize[(ty) & 0xFF]; +} + +/* All data types that fit in exactly 8 bits */ +bool tybyte(uint ty) { + return (tysize(ty) == 1); +} + +/* Types that fit into a single machine register */ +bool tyreg(TY ty) { + return (tysize(ty) <= REGSIZE); +} ++/ + +/* Detect function type */ +ubyte tyfunc(uint ty) { + return (tytab2[(ty) & 0xFF] & TYFL.TYFLfunc); +} + +/* Detect function type where parameters are pushed in reverse order */ +ubyte tyrevfunc(uint ty) { + return (tytab2[(ty) & 0xFF] & TYFL.TYFLrevparam); +} + +/* Detect unsigned types */ +ubyte tyuns(uint ty) { + return (tytab[(ty) & 0xFF] & (TYFL.TYFLuns | TYFL.TYFLptr)); +} + +/* Target dependent info */ +version (TX86) { +/// #define TYoffset TYuint /* offset to an address */ + + /* Detect cpp function type (callee cleans up stack) */ + ubyte typfunc(uint ty) { + return (tytab2[(ty) & 0xFF] & TYFL.TYFLpascal); + } +} else { + /* Detect cpp function type (callee cleans up stack) */ + ubyte typfunc(uint ty) { + return (tytab2[(ty) & 0xFF] & TYFL.TYFLcallstkc); + } +} + +/* Array to convert a type to its unsigned equivalent */ +extern(C++) extern tym_t* get_tytouns(); + +tym_t touns(int ty) { + return get_tytouns[ty & 0xFF]; +} + +/* Determine if TYffunc or TYfpfunc (a far function) */ +ubyte tyfarfunc(uint ty) { + return (tytab2[(ty) & 0xFF] & TYFL.TYFLfarfunc); +} + +/+ +// Determine if parameter can go in register for TYjfunc +#ifndef tyjparam +#define tyjparam(ty) (tysize(ty) <= intsize && !tyfloating(ty) && tybasic(ty) != TYstruct) +#endif + +/* Determine relaxed type */ +#ifndef tyrelax +#define tyrelax(ty) (_tyrelax[tybasic(ty)]) +#endif ++/ \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/TYM.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/TYM.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,84 @@ +module dmd.backend.TYM; + +enum TYM +{ + TYbool = 0, + TYchar = 1, + TYschar = 2, // signed char + TYuchar = 3, // unsigned char + TYshort = 4, + TYwchar_t = 5, + TYushort = 6, // unsigned short + TYenum = 7, // enumeration value + TYint = 8, + TYuint = 9, // unsigned + TYlong = 0xA, + TYulong = 0xB, // unsigned long + TYdchar = 0xC, // 32 bit Unicode char + TYllong = 0xD, // 64 bit long + TYullong = 0xE, // 64 bit unsigned long + TYfloat = 0xF, // 32 bit real + TYdouble = 0x10, // 64 bit real + + // long double is mapped to either of the following at runtime: + TYdouble_alias = 0x11, // 64 bit real (but distinct for overload purposes) + TYldouble = 0x12, // 80 bit real + + // Add imaginary and complex types for D and C99 + TYifloat = 0x13, + TYidouble = 0x14, + TYildouble = 0x15, + TYcfloat = 0x16, + TYcdouble = 0x17, + TYcldouble = 0x18, + +///#if TX86 + TYjhandle = 0x19, // Jupiter handle type, equals TYnptr except + // that the debug type is different so the + // debugger can distinguish them + TYnptr = 0x1A, // data segment relative pointer + TYsptr = 0x1B, // stack segment relative pointer + TYcptr = 0x1C, // code segment relative pointer + TYf16ptr = 0x1D, // special OS/2 far16 pointer + TYfptr = 0x1E, // far pointer (has segment and offset) + TYhptr = 0x1F, // huge pointer (has segment and offset) + TYvptr = 0x20, // __handle pointer (has segment and offset) + TYref = 0x21, // reference to another type + TYvoid = 0x22, + TYstruct = 0x23, // watch tyaggregate() + TYarray = 0x24, // watch tyaggregate() + TYnfunc = 0x25, // near C func + TYffunc = 0x26, // far C func + TYnpfunc = 0x27, // near Cpp func + TYfpfunc = 0x28, // far Cpp func + TYnsfunc = 0x29, // near stdcall func + TYfsfunc = 0x2A, // far stdcall func + TYifunc = 0x2B, // interrupt func + TYmemptr = 0x2C, // pointer to member + TYident = 0x2D, // type-argument + TYtemplate = 0x2E, // unexpanded class template + TYvtshape = 0x2F, // virtual function table + TYptr = 0x30, // generic pointer type + TYf16func = 0x31, // _far16 _pascal function + TYnsysfunc = 0x32, // near __syscall func + TYfsysfunc = 0x33, // far __syscall func + TYmfunc = 0x34, // NT C++ member func + TYjfunc = 0x35, // LINKd D function + TYhfunc = 0x36, // C function with hidden parameter + TYnref = 0x37, // near reference + TYfref = 0x38, // far reference + TYMAX = 0x39, + +///#if MARS + TYaarray = TYnptr, + TYdelegate = TYllong, + TYdarray = TYullong, +///#endif +} + +extern (C++) extern { + __gshared int TYptrdiff, TYsize, TYsize_t; +} + +import dmd.EnumUtils; +mixin(BringToCurrentScope!(TYM)); \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/TYPE.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/TYPE.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,127 @@ +module dmd.backend.TYPE; + +import dmd.backend.Util; +import dmd.backend.Srcpos; +import dmd.backend.elem; +import dmd.backend.LIST; +import dmd.backend.TYM; +import dmd.backend.PARAM; +import dmd.backend.targ_types; +import dmd.backend.Classsym; + +struct TYPE +{ +debug { + ushort id; + enum IDtype = 0x1234; +///#define type_debug(t) assert((t)->id == IDtype) +} else { +///#define type_debug(t) +} + + tym_t Tty; /* mask (TYxxx) */ + ushort Tflags; // TFxxxxx + +version (TX86) { +version (XXX) { ///TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS +///#define mTYnoret 0x010000 // function has no return +///#define mTYtransu 0x010000 // transparent union +} else { +///#define mTYfar16 0x010000 +} +///#define mTYstdcall 0x020000 +///#define mTYfastcall 0x040000 +///#define mTYinterrupt 0x080000 +///#define mTYcdecl 0x100000 +///#define mTYpascal 0x200000 +///#define mTYsyscall 0x400000 +///#define mTYjava 0x800000 + +version (XXX) { ///TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS +///#define mTYTFF 0xFE0000 +} else { +///#define mTYTFF 0xFF0000 +} + + +///#define TARGET_strucTYPE + mangle_t Tmangle; // name mangling +// Return name mangling of type +///#define type_mangle(t) ((t)->Tmangle) +} + + uint Tcount; // # pointing to this type + TYPE* Tnext; // next in list + // TYenum: gives base type + union + { + targ_size_t Tdim; // TYarray: # of elements in array + elem* Tel; // TFvla: gives dimension (NULL if '*') + PARAM* Tparamtypes; // TYfunc, TYtemplate: types of function parameters + Classsym* Ttag; // TYstruct,TYmemptr: tag symbol + // TYenum,TYvtshape: tag symbol + char* Tident; // TYident: identifier +version (SCPP) { + TYPE* Talternate; // typtr: type of parameter before converting +} +version (MARS) { + TYPE* Tkey; // typtr: key type for associative arrays +} + } + + list_t Texcspec; // tyfunc(): list of types of exception specification + +static if (false) { + ushort Tstabidx; // Index into stab types +} +/// TARGET_strucTYPE +version (SOURCE_4TYPES) { + Srcpos Tsrcpos; /* position of type definition */ +} +version (HTOD) { + Symbol* Ttypedef; // if this type came from a typedef, this is + // the typedef symbol +} +} + +void dumpTYPE(TYPE* foo) +{ + foreach (a, b; foo.tupleof) + { + std.stdio.writeln(foo.tupleof[a].stringof, " ", cast(char*)&foo.tupleof[a] - cast(char*)foo, " = ", foo.tupleof[a]); + //std.stdio.writeln("printf(\"", foo.tupleof[a].stringof, " %d = %d\\n\",(char*)(&", foo.tupleof[a].stringof, ")-(char*)foo, ", foo.tupleof[a].stringof, ");"); + } +} + +alias TYPE type; + +alias type* typep_t; + +extern(C++) extern __gshared typep_t tstypes[TYM.TYMAX]; +extern(C++) extern __gshared typep_t tsptr2types[TYM.TYMAX]; + +ref type* tsbool () { return tstypes[TYM.TYbool]; } +ref type* tschar () { return tstypes[TYM.TYchar]; } +ref type* tsschar () { return tstypes[TYM.TYschar]; } +ref type* tsuchar () { return tstypes[TYM.TYuchar]; } +ref type* tsshort () { return tstypes[TYM.TYshort]; } +ref type* tsushort () { return tstypes[TYM.TYushort]; } +ref type* tswchar_t () { return tstypes[TYM.TYwchar_t]; } +ref type* tsint () { return tstypes[TYM.TYint]; } +ref type* tsuns () { return tstypes[TYM.TYuint]; } +ref type* tslong () { return tstypes[TYM.TYlong]; } +ref type* tsulong () { return tstypes[TYM.TYulong]; } +ref type* tsdchar () { return tstypes[TYM.TYdchar]; } +ref type* tsllong () { return tstypes[TYM.TYllong]; } +ref type* tsullong () { return tstypes[TYM.TYullong]; } +ref type* tsfloat () { return tstypes[TYM.TYfloat]; } +ref type* tsdouble () { return tstypes[TYM.TYdouble]; } +ref type* tsreal64 () { return tstypes[TYM.TYdouble_alias]; } +ref type* tsldouble () { return tstypes[TYM.TYldouble]; } +ref type* tsvoid () { return tstypes[TYM.TYvoid]; } +ref type* tsifloat () { return tstypes[TYM.TYifloat]; } +ref type* tsidouble () { return tstypes[TYM.TYidouble]; } +ref type* tsildouble () { return tstypes[TYM.TYildouble]; } +ref type* tscfloat () { return tstypes[TYM.TYcfloat]; } +ref type* tscdouble () { return tstypes[TYM.TYcdouble]; } +ref type* tscldouble () { return tstypes[TYM.TYcldouble]; } \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/Thunk.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/Thunk.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,3 @@ +module dmd.backend.Thunk; + +struct Thunk; \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/Util.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/Util.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,133 @@ +module dmd.backend.Util; + +import dmd.Array; +import dmd.Loc; + +import dmd.backend.elem; +import dmd.backend.Symbol; +import dmd.backend.TYPE; +import dmd.backend.SC; +import dmd.backend.dt_t; +import dmd.backend.LIST; +import dmd.backend.block; +import dmd.backend.targ_types; +import dmd.backend.SYMIDX; +import dmd.backend.PARAM; +import dmd.backend.Blockx; +import dmd.backend.struct_t; +import dmd.backend.BC; +import dmd.backend.code; + +import std.string; + +alias ubyte mangle_t; + +alias SC enum_SC; +alias uint SYMFLGS; + +version (MARS) { + enum SYM_PREDEF_SZ = 35; +} else { + enum SYM_PREDEF_SZ = 22; +} + +//extern (C++) extern { + elem* eictor; + Symbol* ictorlocalgot; + elem* ector; + Array ectorgates; + elem* edtor; + elem* etest; + int dtorcount; + Symbol* localgot; +//} + +static this() +{ + ectorgates = new Array(); +} + +alias uint tym_t; // data type big enough for type masks +alias elem* elem_p; // data type big enough for type masks + +void el_setLoc(elem* e, Loc loc) { + e.Esrcpos.Sfilename = cast(char*)toStringz(loc.filename); + e.Esrcpos.Slinnum = loc.linnum; +} + +void elem_setLoc(elem* e, Loc loc) { + return el_setLoc(e, loc); +} + +struct_t* struct_calloc() { + return cast(struct_t *) mem_fcalloc(struct_t.sizeof); +} +///#define struct_free(st) ((void)(st)) + +extern (C++) { + void* mem_fcalloc(uint numbytes); + void obj_initfile(const(char)* filename, const(char)* csegname, const(char)* modname); + Symbol* symbol_calloc(const(char)* id); + type* type_fake(tym_t); + dt_t** dtnzeros(dt_t** pdtend, targ_size_t size); + void outdata(Symbol* s); + int reftoident(int seg, targ_size_t offset, Symbol* s, targ_size_t val, int flags); + dt_t ** dtnbytes(dt_t** pdtend, targ_size_t size, const(char)* ptr); + type* type_alloc(tym_t ty); + elem_p el_params(elem_p, ...); + elem_p el_ptr(Symbol*); + elem_p el_long(tym_t, targ_long); + elem_p el_bin(uint, tym_t, elem_p, elem_p); + elem_p el_var(Symbol*); + elem_p el_combine(elem_p, elem_p); + block* block_calloc(); + void writefunc(Symbol* sfunc); + void obj_termfile(); + int objextdef(const(char)* name); + void obj_includelib(const(char)* name); + SYMIDX symbol_add(Symbol* s); + elem* el_param(elem* e1, elem* e2); + elem* el_una(uint op, tym_t ty, elem* e1); + Symbol* symbol_name(const(char)* name, int sclass, type* t); + type* type_setcv(type** pt, tym_t cv); + int type_jparam(type* t); + void obj_export(Symbol* s, uint argsize); + void obj_startaddress(Symbol* s); + void symbol_func(Symbol* s); + type* type_allocn(tym_t, type* tn); + param_t* param_append_type(param_t** pp, type* t); + void block_appendexp(block* b, elem* e); + void block_next(Blockx* bctx, BC bc, block* bn); + dt_t** dtxoff(dt_t** pdtend, Symbol* s,targ_size_t offset, tym_t ty); + dt_t** dtdword(dt_t** pdtend, int value); + dt_t** dtabytes(dt_t** pdtend, tym_t ty, targ_size_t offset, targ_size_t size, const(char)* ptr); + void obj_moduleinfo(Symbol* scc); + Symbol* symbol_genauto(TYPE* t); + elem* el_same(elem**); + void el_free(elem*); + Symbol* symbol_generate(int sclass, type* t); + elem* el_calloc(); + void dt_optimize(dt_t* dt); + type* type_setty(type**, int); + type* type_setmangle(type** pt, mangle_t mangle); + list_t list_append(list_t* plist, void* ptr); + dt_t** dtcat(dt_t** pdtend, dt_t* dt); + elem_p el_copytree(elem_p); + elem_p el_pair(tym_t, elem_p, elem_p); + int el_allbits(elem *e, int bit); + block* block_goto(Blockx* bctx, BC bc, block* bn); + block* block_calloc(Blockx* blx); + targ_size_t type_paramsize_i(type* t); + int os_critsecsize(); + void el_setVolatile(elem* e); + elem* exp2_copytotemp(elem* e); + elem* el_const(tym_t, eve*); + elem *el_params(void** args, int length); + + void cod3_thunk(Symbol* sthunk, Symbol* sfunc, uint p, tym_t thisty, targ_size_t d, int i, targ_size_t d2); + + version (SEH) { + void nteh_declarvars(Blockx* bx); + elem* nteh_setScopeTableIndex(Blockx* blx, int scope_index); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/block.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/block.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,153 @@ +module dmd.backend.block; + +import dmd.backend.elem; +import dmd.backend.LIST; +import dmd.backend.regm_t; +import dmd.backend.Symbol; +import dmd.backend.Srcpos; +import dmd.backend.code; +import dmd.backend.SYMIDX; +import dmd.backend.vec_t; +import dmd.backend.targ_types; +import dmd.backend.con_t; + +struct block +{ + union + { + elem* Belem; // pointer to elem tree + list_t Blist; // list of expressions + }; + + block* Bnext; // pointer to next block in list + list_t Bsucc; // linked list of pointers to successors + // of this block + list_t Bpred; // and the predecessor list + + int Bindex; // into created object stack + int Bendindex; // index at end of block + block* Btry; // BCtry,BC_try: enclosing try block, if any + // BC???: if in try-block, points to BCtry or BC_try + // note that can't have a BCtry and BC_try in + // the same function. + union + { + targ_llong *Bswitch; // BCswitch: pointer to switch data + struct + { + regm_t usIasmregs; // Registers modified + ubyte bIasmrefparam; // References parameters? + } + + struct + { + Symbol* catchvar; // __throw() fills in this + } + + struct + { + Symbol* catchtype; // one type for each catch block + } + + struct + { + Symbol* jcatchvar; // __j_throw() fills in this + int Bscope_index; // index into scope table + int Blast_index; // enclosing index into scope table + } + } + + public alias catchtype Bcatchtype; + + Srcpos Bsrcpos; // line number (0 if not known) + ubyte BC; // exit condition (enum BC) +// NEW + ubyte Balign; // alignment + + ushort Bflags; // flags (BFLxxxx) + code* Bcode; // code generated for this block + + uint Bweight; // relative number of times this block + // is executed (optimizer and codegen) + + uint Bdfoidx; // index of this block in dfo[] + union + { + // CPP + struct + { + SYMIDX symstart; // (symstart <= symnum < symend) Symbols + SYMIDX symend; // are declared in this block + block* endscope; // block that forms the end of the + // scope for the declared Symbols + uint blknum; // position of block from startblock + Symbol* Binitvar; // !=NULL points to an auto variable with + // an explicit or implicit initializer + block* gotolist; // BCtry, BCcatch: backward list of try scopes + block* gotothread; // BCgoto: threaded list of goto's to + // unknown labels + } + + // OPTIMIZER + struct + { + vec_t Bdom; // mask of dominators for this block + vec_t Binrd; + vec_t Boutrd; // IN and OUT for reaching definitions + vec_t Binlv; + vec_t Boutlv; // IN and OUT for live variables + vec_t Bin; + vec_t Bout; // IN and OUT for other flow analyses + vec_t Bgen; + vec_t Bkill; // pointers to bit vectors used by data + // flow analysis + + // BCiftrue can have different vectors for the 2nd successor: + vec_t Bout2; + vec_t Bgen2; + vec_t Bkill2; + } + + // CODGEN + struct + { + targ_size_t Btablesize; // BCswitch, BCjmptab + targ_size_t Btableoffset; // BCswitch, BCjmptab + targ_size_t Boffset; // code offset of start of this block + targ_size_t Bsize; // code size of this block + con_t Bregcon; // register state at block exit + targ_size_t Btryoff; // BCtry: offset of try block data + } + } +} + +enum BFL +{ + BFLvisited = 1, // set if block is visited + BFLmark = 2, // set if block is visited + BFLjmpoptdone = 4, // set when no more jump optimizations + // are possible for this block + BFLnostackopt = 8, // set when stack elimination should not + // be done +///version (NTEXCEPTIONS) { + BFLehcode = 0x10, // set when we need to load exception code + BFLunwind = 0x1000, // do local_unwind following block +///} +///version (TARGET_POWERPC) { +/// BFLstructret = 0x10, /* Set if a struct return is changed to +/// block type BCret. This is done to avoid +/// error messages */ +///} + BFLnomerg = 0x20, // do not merge with other blocks +///version (TX86) { + BFLprolog = 0x80, // generate function prolog + BFLepilog = 0x100, // generate function epilog + BFLrefparam = 0x200, // referenced parameter + BFLreflocal = 0x400, // referenced local + BFLoutsideprolog = 0x800, // outside function prolog/epilog + BFLlabel = 0x2000, // block preceded by label +///} else { +/// BFLlooprt = 0x40, // set if looprotate() changes it's Bnext +///} + BFLvolatile = 0x4000, // block is volatile +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/code.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/code.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,146 @@ +module dmd.backend.code; + +import dmd.backend.targ_types; +import dmd.backend.Srcpos; +import dmd.backend.elem; +import dmd.backend.block; +import dmd.backend.Symbol; +import dmd.Declaration; +import dmd.LabelDsymbol; + +/********************************** + * Code data type + */ + +union evc +{ + targ_int Vint; // also used for tmp numbers (FLtmp) + targ_uns Vuns; + targ_long Vlong; + + struct EP + { + targ_size_t Vpointer; + int Vseg; // segment the pointer is in + } EP _EP; + + Srcpos Vsrcpos; // source position for OPlinnum + elem* Vtor; // OPctor/OPdtor elem + block* Vswitch; // when FLswitch and we have a switch table + code* Vcode; // when code is target of a jump (FLcode) + block* Vblock; // when block " (FLblock) + + struct SP + { + targ_size_t Voffset; // offset from symbol + Symbol* Vsym; // pointer to symbol table (FLfunc,FLextern) + } SP sp; + +version (MARS) { + struct DSP + { + targ_size_t Voffset; // offset from symbol + Declaration Vsym; // pointer to D symbol table + } DSP dsp; +} + +version (MARS) { + struct LAB + { + targ_size_t Voffset; // offset from symbol + LabelDsymbol Vsym; // pointer to Label + } LAB lab; +} + + struct AS + { + uint len; + char* bytes; + } AS as; // asm node (FLasm) +} + +enum CF +{ + CFes = 1, // generate an ES: segment override for this instr + CFjmp16 = 2, // need 16 bit jump offset (long branch) + CFtarg = 4, // this code is the target of a jump + CFseg = 8, // get segment of immediate value + CFoff = 0x10, // get offset of immediate value + CFss = 0x20, // generate an SS: segment override (not with + // CFes at the same time, though!) + CFpsw = 0x40, // we need the flags result after this instruction + CFopsize = 0x80, // prefix with operand size + CFaddrsize = 0x100, // prefix with address size + CFds = 0x200, // need DS override (not with es, ss, or cs ) + CFcs = 0x400, // need CS override + CFfs = 0x800, // need FS override + CFgs = (CFcs | CFfs), // need GS override + CFwait = 0x1000, // If I32 it indicates when to output a WAIT + CFselfrel = 0x2000, // if self-relative + CFunambig = 0x4000, // indicates cannot be accessed by other addressing + // modes + CFtarg2 = 0x8000, // like CFtarg, but we can't optimize this away + CFvolatile = 0x10000, // volatile reference, do not schedule + CFclassinit= 0x20000, // class init code + + CFSEG = (CFes | CFss | CFds | CFcs | CFfs | CFgs), + CFPREFIX = (CFSEG | CFopsize | CFaddrsize), +} + +struct code +{ + code* next; + uint Iflags; + + ubyte Ijty = 0; // type of operand, 0 if unknown + + ubyte Iop; + ubyte Irm; // reg/mode + + ubyte Iop2; // second opcode byte + ubyte Isib = 0; // SIB byte + + ubyte Iop3; // third opcode byte + + ubyte IFL1; + ubyte IFL2; // FLavors of 1st, 2nd operands + evc IEV1; // 1st operand, if any + + ref targ_size_t IEVpointer1 () { return IEV1._EP.Vpointer; } + ref int IEVseg1 () { return IEV1._EP.Vseg; } + ref Symbol* IEVsym1 () { return IEV1.sp.Vsym; } + ref Declaration IEVdsym1 () { return IEV1.dsp.Vsym; } + ref targ_size_t IEVoffset1 () { return IEV1.sp.Voffset; } + ref LabelDsymbol IEVlsym1 () { return IEV1.lab.Vsym; } + ref targ_int IEVint1 () { return IEV1.Vint; } + + evc IEV2; // 2nd operand, if any + + ref targ_size_t IEVpointer2 () { return IEV2._EP.Vpointer; } + ref int IEVseg2 () { return IEV2._EP.Vseg; } + ref Symbol* IEVsym2 () { return IEV2.sp.Vsym; } + ref Declaration IEVdsym2 () { return IEV2.dsp.Vsym; } + ref targ_size_t IEVoffset2 () { return IEV2.sp.Voffset; } + ref LabelDsymbol IEVlsym2 () { return IEV2.lab.Vsym; } + ref targ_int IEVint2 () { return IEV2.Vint; } +/+ + void print(); // pretty-printer ++/ +} + +import std.stdio; + +void dumpCode(code* foo) +{ + writefln("code.sizeof: %d", code.sizeof); + writefln("Srcpos.sizeof: %d", Srcpos.sizeof); + writefln("evc.sizeof: %d", evc.sizeof); + writefln("EP.sizeof: %d", evc.EP.sizeof); + writefln("SP.sizeof: %d", evc.SP.sizeof); + writefln("targ_long.sizeof: %d", targ_long.sizeof); + foreach (a, b; foo.tupleof) + { + std.stdio.writeln(foo.tupleof[a].stringof, " ", cast(char*)&foo.tupleof[a] - cast(char*)foo, " = ", foo.tupleof[a]); + //std.stdio.writeln("printf(\"", foo.tupleof[a].stringof, " %d = %d\\n\",(char*)(&", foo.tupleof[a].stringof, ")-(char*)foo, ", foo.tupleof[a].stringof, ");"); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/con_t.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/con_t.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,17 @@ +module dmd.backend.con_t; + +import dmd.backend.cse_t; +import dmd.backend.immed_t; +import dmd.backend.regm_t; + +struct con_t +{ + cse_t cse; // CSEs in registers + immed_t immed; // immediate values in registers + regm_t mvar; // mask of register variables + regm_t mpvar; // mask of SCfastpar register variables + regm_t indexregs; // !=0 if more than 1 uncommitted index register + regm_t used; // mask of registers used + regm_t params; // mask of registers which still contain register + // function parameters +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/cse_t.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/cse_t.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,14 @@ +module dmd.backend.cse_t; + +import dmd.backend.elem; +import dmd.backend.regm_t; + +enum REGMAX = 10; + +struct cse_t +{ + elem* value[REGMAX]; // expression values in registers + regm_t mval; // mask of which values in value[] are valid + regm_t mops; // subset of mval that contain common subs that need + // to be stored in csextab[] if they are destroyed +}; \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/dt_t.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/dt_t.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,51 @@ +module dmd.backend.dt_t; + +import dmd.backend.targ_types; +import dmd.backend.Symbol; + +struct dt_t +{ + dt_t* DTnext; // next in list + char dt; // type (DTxxxx) + ubyte Dty; // pointer type + + union + { + struct // DTibytes + { + char DTn; // number of bytes + char DTdata[7]; // data + } + + char DTonebyte; // DT1byte + + targ_size_t DTazeros; // DTazeros,DTcommon,DTsymsize + + struct // DTabytes + { + char* DTpbytes; // pointer to the bytes + uint DTnbytes; // # of bytes +version (TX86) { + int DTseg; // segment it went into +} + targ_size_t DTabytes; // offset of abytes for DTabytes + } + + struct // DTxoff + { + Symbol* DTsym; // symbol pointer + targ_size_t DToffset; // offset from symbol + } + } +} + +import std.stdio; + +void dumpDt(dt_t* foo) +{ + foreach (a, b; foo.tupleof) + { + std.stdio.writeln(foo.tupleof[a].stringof, " ", cast(char*)&foo.tupleof[a] - cast(char*)foo, " = ", foo.tupleof[a]); + //std.stdio.writeln("printf(\"", foo.tupleof[a].stringof, " %d = %d\\n\",(char*)(&", foo.tupleof[a].stringof, ")-(char*)foo, ", foo.tupleof[a].stringof, ");"); + } +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/elem.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/elem.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,156 @@ +module dmd.backend.elem; + +import dmd.Port; +import dmd.Complex; + +import dmd.backend.targ_types; +import dmd.backend.Symbol; +import dmd.backend.PARAM; +import dmd.backend.LIST; +import dmd.backend.Classsym; +import dmd.backend.TYPE; +import dmd.backend.Util; +import dmd.backend.Srcpos; + +/********************************* + * Union of all data types. Storage allocated must be the right + * size of the data on the TARGET, not the host. + */ + +union eve +{ + targ_char Vchar; + targ_schar Vschar; + targ_uchar Vuchar; + targ_short Vshort; + targ_ushort Vushort; + targ_int Vint; // also used for tmp numbers (FLtmp) + targ_uns Vuns; + targ_long Vlong; + targ_ulong Vulong; + targ_llong Vllong; + targ_ullong Vullong; + targ_float Vfloat; + targ_double Vdouble; + targ_ldouble Vldouble; + Complex!(float) Vcfloat; + Complex!(double)Vcdouble; + Complex!(real) Vcldouble; + targ_size_t Vpointer; + targ_ptrdiff_t Vptrdiff; + targ_uchar Vreg; // register number for OPreg elems + + struct VFP // 48 bit 386 far pointer + { targ_long Voff; + targ_ushort Vseg; + } VFP Vfp; + + struct SP + { + targ_size_t Voffset;// offset from symbol + Symbol* Vsym; // pointer to symbol table + union SPU + { + PARAM* Vtal; // template-argument-list for SCfunctempl, + // used only to transmit it to cpp_overload() + LIST* Erd; // OPvar: reaching definitions + } SPU spu; + } SP sp; + + struct SM + { + targ_size_t Voffset;// member pointer offset + Classsym* Vsym; // struct tag + elem* ethis; // OPrelconst: 'this' for member pointer + } SM sm; + + struct SS + { + targ_size_t Voffset;// offset from string + char* Vstring; // pointer to string (OPstring or OPasm) + targ_size_t Vstrlen;// length of string + } SS ss; + + struct EOP + { + elem* Eleft; // left child for unary & binary nodes + elem* Eright; // right child for binary nodes + Symbol* Edtor; // OPctor: destructor + } EOP eop; +} // variants for each type of elem + +/****************************************** + * Elems: + * Elems are the basic tree element. They can be either + * terminal elems (leaves), unary elems (left subtree exists) + * or binary elems (left and right subtrees exist). + */ +struct elem +{ +debug { + ushort id; +} + + ubyte Eoper; // operator (OPxxxx) + ubyte Ecount; // # of parents of this elem - 1, + // always 0 until CSE elimination is done + eve EV; // variants for each type of elem + + ref elem* E1() + { + return EV.eop.Eleft; /* left child */ + } + + ref elem* E2() + { + return EV.eop.Eright; /* right child */ + } + + ref LIST* Erd() + { + return EV.sp.spu.Erd; // reaching definition + } + + union + { + // PARSER + struct + { + TYPE* ET; // pointer to type of elem + ubyte PEFflags; + } + + // OPTIMIZER + struct + { + tym_t Ety; // data type (TYxxxx) + uint Eexp; // index into expnod[] + + // These flags are all temporary markers, used once and then + // thrown away. + ubyte Nflags; // NFLxxx +version (MARS) { + ubyte Ejty; // original Jupiter/Mars type +} + } + + // CODGEN + struct + { + // Ety2: Must be in same position as Ety! + tym_t Ety2; // data type (TYxxxx) + ubyte Ecomsub; // number of remaining references to + // this common subexp (used to determine + // first, intermediate, and last references + // to a CSE) + +version (TARGET_POWERPC) { + ubyte Gflags; +} + } + } + + targ_size_t Enumbytes; // number of bytes for type if TYstruct | TYarray +// TARGET_structELEM // target specific additions + Srcpos Esrcpos; // source file position +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/enum_t.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/enum_t.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,15 @@ +module dmd.backend.enum_t; + +import dmd.backend.SEN; +import dmd.backend.Symbol; +import dmd.backend.LIST; + +struct enum_t +{ + uint SEflags; + + Symbol* SEalias; // pointer to identifier E to use if + /* enum was defined as: */ + /* typedef enum { ... } E; */ + symlist_t SEenumlist; // all members of enum +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/func_t.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/func_t.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,68 @@ +module dmd.backend.func_t; + +import dmd.backend.LIST; +import dmd.backend.block; +import dmd.backend.symtab_t; +import dmd.backend.Srcpos; +import dmd.backend.Symbol; +import dmd.backend.Classsym; +import dmd.backend.Funcsym; +import dmd.backend.elem; +import dmd.backend.token_t; +import dmd.backend.Thunk; +import dmd.backend.PARAM; + +struct func_t +{ + symlist_t Fsymtree; // local Symbol table + block* Fstartblock; // list of blocks comprising function + symtab_t Flocsym; // local Symbol table + Srcpos Fstartline; // starting line # of function + Srcpos Fendline; // line # of closing brace of function + Symbol* F__func__; // symbol for __func__[] string + uint Fflags; + uint Fflags3; + ubyte Foper; // operator number (OPxxxx) if Foperator + + Symbol* Fparsescope; // use this scope to parse friend functions + // which are defined within a class, so the + // class is in scope, but are not members + // of the class + + Classsym* Fclass; // if member of a class, this is the class + // (I think this is redundant with Sscope) + Funcsym* Foversym; // overloaded function at same scope + symlist_t Fclassfriends; /* Symbol list of classes of which this */ + /* function is a friend */ + block* Fbaseblock; // block where base initializers get attached + block* Fbaseendblock; // block where member destructors get attached + elem* Fbaseinit; /* list of member initializers (meminit_t) */ + /* this field has meaning only for */ + /* functions which are constructors */ + token_t* Fbody; /* if deferred parse, this is the list */ + /* of tokens that make up the function */ + /* body */ + // also used if SCfunctempl, SCftexpspec + uint Fsequence; // sequence number at point of definition + union + { + Symbol* Ftempl; // if Finstance this is the template that generated it + Thunk* Fthunk; // !=NULL if this function is actually a thunk + } + + Funcsym* Falias; // SCfuncalias: function Symbol referenced + // by using-declaration + + symlist_t Fthunks; // list of thunks off of this function + + param_t* Farglist; // SCfunctempl: the template-parameter-list + param_t* Fptal; // Finstance: this is the template-argument-list + // SCftexpspec: for explicit specialization, this + // is the template-argument-list + list_t Ffwdrefinstances; // SCfunctempl: list of forward referenced instances + list_t Fexcspec; // List of types in the exception-specification + // (NULL if none or empty) + Funcsym* Fexplicitspec; // SCfunctempl, SCftexpspec: threaded list + // of SCftexpspec explicit specializations + Funcsym* Fsurrogatesym; // Fsurrogate: surrogate cast function +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/glue.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/glue.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,552 @@ +module dmd.backend.glue; + +import dmd.Array; +import dmd.Dsymbol; +import dmd.File; +import dmd.FileName; +import dmd.Library; +import dmd.OutBuffer; +import dmd.Module; +import dmd.Identifier; +import dmd.AssertExp; +import dmd.TOK; +import dmd.Global; +import dmd.Param; +import dmd.backend.Config; +import dmd.backend.Configv; +import dmd.backend.StringTab; + +import core.stdc.string; + +__gshared Array obj_symbols_towrite; + +extern (C++) extern +{ + __gshared Outbuffer objbuf; + int go_flag(char* cp); + void util_set64(); + void util_set386(); +} + +import std.contracts; +import std.string; + +string lastmname; + +struct Outbuffer +{ + ubyte* buf; // the buffer itself + ubyte* pend; // pointer past the end of the buffer + ubyte* p; // current position in buffer + uint len; // size of buffer + uint inc; // default increment size + + this(uint inc) + { + assert(false); + } + + ~this() + { + assert(false); + } + + void reset() + { + assert(false); + } + + // Reserve nbytes in buffer + void reserve(uint nbytes) + { + assert(false); + } + + // Write n zeros; return pointer to start of zeros + void* writezeros(uint n) + { + assert(false); + } + + // Position buffer to accept the specified number of bytes at offset + int position(uint offset, uint nbytes); + + // Write an array to the buffer, no reserve check + void writen(const(void)* b, int len) + { + memcpy(p,b,len); + p += len; + } + + // Clear bytes, no reserve check + void clearn(int len) + { + int i; + for (i=0; i< len; i++) + *p++ = 0; + } + + // Write an array to the buffer. + void write(const void *b, int len) + { + assert(false); + } + + void write(Outbuffer* b) + { + write(b.buf, b.p - b.buf); + } + + /** + * Flushes the stream. This will write any buffered + * output bytes. + */ + void flush() { } + + /** + * Writes an 8 bit byte, no reserve check. + */ + void writeByten(char v) + { + *p++ = v; + } + + /** + * Writes an 8 bit byte. + */ + void writeByte(int v) + { + assert(false); + } + + /** + * Writes a 16 bit little-end short, no reserve check. + */ + void writeWordn(int v) + { +version (_WIN32) { + *cast(ushort*)p = cast(short)v; +} else { + p[0] = v; + p[1] = v >> 8; +} + p += 2; + } + + /** + * Writes a 16 bit little-end short. + */ + void writeWord(int v) + { + reserve(2); + writeWordn(v); + } + + /** + * Writes a 16 bit big-end short. + */ + void writeShort(int v) + { + if (pend - p < 2) + reserve(2); + +static if (false) { + p[0] = (cast(ubyte*)&v)[1]; + p[1] = v; +} else { + ubyte* q = p; + q[0] = cast(ubyte)(v >> 8); + q[1] = cast(ubyte)v; +} + p += 2; + } + + /** + * Writes a 16 bit char. + */ + void writeChar(int v) + { + writeShort(v); + } + + /** + * Writes a 32 bit int. + */ + void write32(long v) + { + assert(false); + } + + /** + * Writes a 64 bit long. + */ +///#if __INTSIZE == 4 + void write64(long v) + { + assert(false); + } +///#endif + + /** + * Writes a 32 bit float. + */ + void writeFloat(float v) + { + assert(false); + } + + /** + * Writes a 64 bit double. + */ + void writeDouble(double v) + { + assert(false); + } + + void write(const(char)* s) + { + assert(false); + } + + void write(const(ubyte)* s) + { + assert(false); + } + + void writeString(const(char)* s) + { + assert(false); + } + + void prependBytes(const(char)* s) + { + assert(false); + } + + void bracket(char c1, char c2) + { + assert(false); + } + + /** + * Returns the number of bytes written. + */ + int size() + { + return p - buf; + } + + char* toString() + { + assert(false); + } + + void setsize(uint size) + { + assert(false); + } + + void writesLEB128(long value) + { + assert(false); + } + + void writeuLEB128(uint value) + { + assert(false); + } +} + +static this() +{ + obj_symbols_towrite = new Array(); +} + +/************************************** + * Append s to list of object files to generate later. + */ + +void obj_append(Dsymbol s) +{ + obj_symbols_towrite.push(cast(void*)s); +} + +extern (C++) { + void backend_init(); + void backend_term(); + void obj_term(); + void rtlsym_reset(); + void slist_reset(); + void el_reset(); + void cg87_reset(); + void out_reset(); + void obj_init(Outbuffer* objbuf, const(char)* filename, const(char)* csegname); +} + +void clearStringTab() +{ + //printf("clearStringTab()\n"); + memset(stringTab.ptr, 0, stringTab.sizeof); + stidx = 0; + + assertexp_sfilename = null; + assertexp_name = null; + assertexp_mn = null; +} + +void obj_start(char *srcfile) +{ + //printf("obj_start()\n"); + + out_config_init(); + + rtlsym_reset(); + slist_reset(); + clearStringTab(); + + obj_init(&objbuf, srcfile, null); + + el_reset(); + cg87_reset(); + out_reset(); +} + +void obj_end(Library library, File objfile) +{ + obj_term(); + + if (library) + { + // Transfer image to library + library.addObject(objfile.name.toChars(), objbuf.buf, objbuf.p - objbuf.buf); + objbuf.buf = null; + } + else + { + // Transfer image to file + objfile.setbuffer(objbuf.buf, objbuf.p - objbuf.buf); + objbuf.buf = null; + + string p = FileName.path(objfile.name.toChars()); + FileName.ensurePathExists(p); + //mem.free(p); + + //printf("write obj %s\n", objfile.name.toChars()); + objfile.writev(); + } + + objbuf.pend = null; + objbuf.p = null; + objbuf.len = 0; + objbuf.inc = 0; +} + +void obj_write_deferred(Library library) +{ + for (int i = 0; i < obj_symbols_towrite.dim; i++) + { + Dsymbol s = cast(Dsymbol)obj_symbols_towrite.data[i]; + Module m = s.getModule(); + + string mname; + if (m) + { + mname = m.srcfile.toChars(); + lastmname = mname; + } + else + { + //mname = s->ident->toChars(); + mname = lastmname; + assert(mname.length != 0); + } + + obj_start(cast(char*)toStringz(mname)); + + static int count; + count++; // sequence for generating names + + /* Create a module that's a doppelganger of m, with just + * enough to be able to create the moduleinfo. + */ + OutBuffer idbuf = new OutBuffer(); + idbuf.printf("%s.%d", m ? m.ident.toChars() : mname, count); + string idstr = idbuf.extractString(); + idbuf.data = null; + Identifier id = new Identifier(idstr, TOK.TOKidentifier); + + Module md = new Module(mname, id, 0, 0); + md.members = new Array(); + md.members.push(cast(void*)s); // its only 'member' is s + if (m) + { + md.doppelganger = 1; // identify this module as doppelganger + md.md = m.md; + md.aimports.push(cast(void*)m); // it only 'imports' m + md.massert = m.massert; + md.marray = m.marray; + } + + md.genobjfile(0); + + /* Set object file name to be source name with sequence number, + * as mangled symbol names get way too long. + */ + string fname = FileName.removeExt(mname); + + OutBuffer namebuf = new OutBuffer(); + uint hash = 0; + foreach (char c; s.toChars()) + hash += c; + + namebuf.printf("%s_%x_%x.%s", fname, count, hash, global.obj_ext); + fname = namebuf.extractString(); + + //printf("writing '%s'\n", fname); + File objfile = new File(fname); + obj_end(library, objfile); + } + + obj_symbols_towrite.dim = 0; +} + +/************************************** + * Initialize config variables. + */ + +void out_config_init() +{ + Param* params = &global.params; + + if (!config.target_cpu) + { + config.target_cpu = TARGET_PentiumPro; + config.target_scheduler = config.target_cpu; + } + config.fulltypes = CVNONE; + config.inline8087 = 1; + config.memmodel = 0; + config.flags |= CFGuchar; // make sure TYchar is unsigned +version (TARGET_WINDOS) { + if (params.isX86_64) + config.exe = EX_WIN64; + else + config.exe = EX_NT; + + // Win32 eh + config.flags2 |= CFG2seh; + + if (params.run) + config.wflags |= WFexe; // EXE file only optimizations + else if (params.link && !global.params.deffile) + config.wflags |= WFexe; // EXE file only optimizations + else if (params.exefile) // if writing out EXE file + { + size_t len = params.exefile.length; + if (len >= 4 && icmp(params.exefile[len-3..len], "exe") == 0) + config.wflags |= WFexe; + } + config.flags4 |= CFG4underscore; +} +version (TARGET_LINUX) { + if (params.isX86_64) + config.exe = EX_LINUX64; + else + config.exe = EX_LINUX; + config.flags |= CFGnoebp; + config.flags |= CFGalwaysframe; + if (params.pic) + config.flags3 |= CFG3pic; +} +version (TARGET_OSX) { + if (params.isX86_64) + config.exe = EX_OSX64; + else + config.exe = EX_OSX; + config.flags |= CFGnoebp; + config.flags |= CFGalwaysframe; + if (params.pic) + config.flags3 |= CFG3pic; +} +version (TARGET_FREEBSD) { + if (params.isX86_64) + config.exe = EX_FREEBSD64; + else + config.exe = EX_FREEBSD; + config.flags |= CFGnoebp; + config.flags |= CFGalwaysframe; + if (params.pic) + config.flags3 |= CFG3pic; +} +version (TARGET_SOLARIS) { + if (params.isX86_64) + config.exe = EX_SOLARIS64; + else + config.exe = EX_SOLARIS; + config.flags |= CFGnoebp; + config.flags |= CFGalwaysframe; + if (params.pic) + config.flags3 |= CFG3pic; +} + config.flags2 |= CFG2nodeflib; // no default library + config.flags3 |= CFG3eseqds; +static if (false) { + if (env.getEEcontext().EEcompile != 2) + config.flags4 |= CFG4allcomdat; + if (env.nochecks()) + config.flags4 |= CFG4nochecks; // no runtime checking +} else version (TARGET_OSX) { +} else { + config.flags4 |= CFG4allcomdat; +} + if (params.trace) + config.flags |= CFGtrace; // turn on profiler + if (params.nofloat) + config.flags3 |= CFG3wkfloat; + + configv.verbose = params.verbose; + + if (params.optimize) + go_flag(cast(char*)"-o".ptr); + + if (params.symdebug) + { +version (ELFOBJ_OR_MACHOBJ) { + configv.addlinenumbers = 1; + config.fulltypes = (params.symdebug == 1) ? CVDWARF_D : CVDWARF_C; +} +version (OMFOBJ) { + configv.addlinenumbers = 1; + config.fulltypes = CV4; +} + if (!params.optimize) + config.flags |= CFGalwaysframe; + } + else + { + configv.addlinenumbers = 0; + config.fulltypes = CVNONE; + //config.flags &= ~CFGalwaysframe; + } + + if (params.isX86_64) + { + util_set64(); + cod3_set64(); + } + else + { + util_set386(); + cod3_set386(); + } + +debug { + debugb = params.debugb; + debugc = params.debugc; + debugf = params.debugf; + debugr = params.debugr; + debugw = params.debugw; + debugx = params.debugx; + debugy = params.debugy; +} +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/iasm.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/iasm.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,4433 @@ +module dmd.backend.iasm; + +import dmd.Dsymbol; +import dmd.LabelDsymbol; +import dmd.AsmStatement; +import dmd.Type; +import dmd.Scope; +import dmd.Loc; +import dmd.Token; +import dmd.TOK; +import dmd.Identifier; +import dmd.Declaration; +import dmd.VarDeclaration; +import dmd.EnumMember; +import dmd.ExpInitializer; +import dmd.Expression; +import dmd.IdentifierExp; +import dmd.StringExp; +import dmd.Global; +import dmd.WANT; +import dmd.STC; +import dmd.TY; +import dmd.EnumUtils; +import dmd.TupleDeclaration; +import dmd.VarExp; +import dmd.Id; +import dmd.FuncExp; +import dmd.DotIdExp; + +import dmd.backend.code; +import dmd.backend.Srcpos; +import dmd.backend.FL; +import dmd.backend.Util; +import dmd.backend.regm_t; +import dmd.backend.Config; +import dmd.backend.targ_types; +import dmd.backend.elem; +import dmd.Util; + +import std.stdio : writef, writefln; +import std.string : toStringz; +import std.algorithm : min; + +import core.stdc.stdlib : realloc; +import core.stdc.stdio : printf; +import core.stdc.string : strlen; +import core.stdc.limits; + +import std.bitmanip; + +alias int[10] jmp_buf; + +extern (C) extern +{ + int setjmp(jmp_buf env); + void longjmp(jmp_buf env, int value); + + void cod3_set386(); + code* genlinnum(code*, Srcpos); + code *code_calloc(); + + __gshared int BPRM; +} + +const(char)*[ASMTK.ASMTKmax] apszAsmtk = [ + "__LOCAL_SIZE", + "dword".ptr, + "even".ptr, + "far".ptr, + "naked".ptr, + "near".ptr, + "ptr".ptr, + "qword".ptr, + "seg".ptr, + "word".ptr, +]; + +extern (Pascal) extern { + code* cat(code* c1 , code* c2 ); +} + +extern (C++) extern +{ + void init_optab(); + OP* asm_op_lookup(const(char)* s); + const(char)* asm_opstr(OP* pop); + int binary(const(char)* p , const(char)** tab, int high); +} + +static ubyte asm_TKlbra_seen = false; + +struct REG +{ + char regstr[6]; + ubyte val; + opflag_t ty; +} + +OP* asm_op_lookup(string s) +{ + return asm_op_lookup(toStringz(s)); +} + +// For amod (3 bits) +enum ASM_MODIFIERS : ubyte +{ + _normal, // Normal register value + _rseg, // Segment registers + _rspecial, // Special registers + _addr16, // 16 bit address + _addr32, // 32 bit address + _fn16, // 16 bit function call + _fn32, // 32 bit function call + _flbl // Label +} + +mixin(BringToCurrentScope!(ASM_MODIFIERS)); + +// For aopty (3 bits) +enum ASM_OPERAND_TYPE : ubyte +{ + _reg, // _r8, _r16, _r32 + _m, // _m8, _m16, _m32, _m48 + _imm, // _imm8, _imm16, _imm32 + _rel, // _rel8, _rel16, _rel32 + _mnoi, // _m1616, _m1632 + _p, // _p1616, _p1632 + _rm, // _rm8, _rm16, _rm32 + _float // Floating point operand, look at cRegmask for the + // actual size +} + +mixin(BringToCurrentScope!(ASM_OPERAND_TYPE)); + +/* Register definitions */ + +enum AX = 0; +enum CX = 1; +enum DX = 2; +enum BX = 3; +enum SP = 4; +enum BP = 5; +enum SI = 6; +enum DI = 7; + +enum ES = 9; +enum PSW = 10; +enum STACK = 11; // top of stack +enum MEM = 12; // memory +enum OTHER = 13; // other things +enum ST0 = 14; // 8087 top of stack register +enum ST01 = 15; // top two 8087 registers; for complex types + +enum NOREG = 100; // no register + +enum AL = 0; +enum CL = 1; +enum DL = 2; +enum BL = 3; +enum AH = 4; +enum CH = 5; +enum DH = 6; +enum BH = 7; + +enum mAX = 1; +enum mCX = 2; +enum mDX = 4; +enum mBX = 8; +enum mSP = 0x10; +enum mBP = 0x20; +enum mSI = 0x40; +enum mDI = 0x80; +enum mES = (1 << ES); // 0x200 +enum mPSW = (1 << PSW); // 0x400 + +enum mSTACK = (1 << STACK); // 0x800 +enum mMEM = (1 << MEM); // 0x1000 +enum mOTHER = (1 << OTHER); // 0x2000 + +enum mST0 = (1 << ST0); // 0x4000 +enum mST01 = (1 << ST01); // 0x8000 + +version (XXX) { ///TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS + // To support positional independent code, + // must be able to remove BX from available registers +///extern regm_t ALLREGS; +///#define ALLREGS_INIT (mAX|mBX|mCX|mDX|mSI|mDI) +///#define ALLREGS_INIT_PIC (mAX|mCX|mDX|mSI|mDI) +///extern regm_t BYTEREGS; +///#define BYTEREGS_INIT (mAX|mBX|mCX|mDX) +///#define BYTEREGS_INIT_PIC (mAX|mCX|mDX) +} else { +enum ALLREGS = (mAX|mBX|mCX|mDX|mSI|mDI); +///#define ALLREGS_INIT ALLREGS +///#undef BYTEREGS +///#define BYTEREGS (mAX|mBX|mCX|mDX) +} + +//#define NPTRSIZE tysize[TYnptr] +enum NPTRSIZE = 4; + +uint ADDFWAIT() { return 0; } + +enum I16 = 0; // no 16 bit code for D +enum I32 = (NPTRSIZE == 4); +enum I64 = (NPTRSIZE == 8); // true if generating 64 bit code + +// For uRegmask (6 bits) + +// uRegmask flags when aopty == _float +enum _rst = 0x1; +enum _rsti = 0x2; +enum _64 = 0x4; +enum _80 = 0x8; +enum _128 = 0x40; +enum _112 = 0x10; +enum _224 = 0x20; + +ushort CONSTRUCT_FLAGS(ushort uSizemask, ubyte aopty, ubyte amod, ushort uRegmask ) { + return cast(ushort)( (uSizemask) | (aopty) << 4 | (amod) << 7 | (uRegmask) << 10); +} + +// _seg register values (amod == _rseg) +// +enum _ds = CONSTRUCT_FLAGS( 0, 0, _rseg, 0x01 ); +enum _es = CONSTRUCT_FLAGS( 0, 0, _rseg, 0x02 ); +enum _ss = CONSTRUCT_FLAGS( 0, 0, _rseg, 0x04 ); +enum _fs = CONSTRUCT_FLAGS( 0, 0, _rseg, 0x08 ); +enum _gs = CONSTRUCT_FLAGS( 0, 0, _rseg, 0x10 ); +enum _cs = CONSTRUCT_FLAGS( 0, 0, _rseg, 0x20 ); + +// +// _special register values +// +enum _crn = CONSTRUCT_FLAGS( 0, 0, ASM_MODIFIERS._rspecial, 0x01 ); // CRn register (0,2,3) +enum _drn = CONSTRUCT_FLAGS( 0, 0, ASM_MODIFIERS._rspecial, 0x02 ); // DRn register (0-3,6-7) +enum _trn = CONSTRUCT_FLAGS( 0, 0, ASM_MODIFIERS._rspecial, 0x04 ); // TRn register (3-7) +enum _mm = CONSTRUCT_FLAGS( 0, 0, ASM_MODIFIERS._rspecial, 0x08 ); // MMn register (0-7) +enum _xmm = CONSTRUCT_FLAGS( 0, 0, ASM_MODIFIERS._rspecial, 0x10 ); // XMMn register (0-7) + +// +// Default register values +// +enum _al = CONSTRUCT_FLAGS( 0, 0, ASM_MODIFIERS._normal, 0x01 ); // AL register +enum _ax = CONSTRUCT_FLAGS( 0, 0, ASM_MODIFIERS._normal, 0x02 ); // AX register +enum _eax = CONSTRUCT_FLAGS( 0, 0, ASM_MODIFIERS._normal, 0x04 ); // EAX register +enum _dx = CONSTRUCT_FLAGS( 0, 0, ASM_MODIFIERS._normal, 0x08 ); // DX register +enum _cl = CONSTRUCT_FLAGS( 0, 0, ASM_MODIFIERS._normal, 0x10 ); // CL register + +enum _rplus_r = 0x20; +//#define _plus_r CONSTRUCT_FLAGS( 0, 0, 0, _rplus_r ) + // Add the register to the opcode (no mod r/m) + +ubyte ASM_GET_uSizemask(uint us) { + return ((us) & 0x0F); +} + +ASM_OPERAND_TYPE ASM_GET_aopty(uint us) { + return cast(ASM_OPERAND_TYPE)(((us) & 0x70) >> 4); +} + +ASM_MODIFIERS ASM_GET_amod(uint us) { + return (cast(ASM_MODIFIERS)(((us) & 0x380) >> 7)); +} + +ubyte ASM_GET_uRegmask(uint us) { + return (((us) & 0xFC00) >> 10); +} + +enum _st = CONSTRUCT_FLAGS( 0, _float, 0, _rst ); // stack register 0 +enum _m112 = CONSTRUCT_FLAGS( 0, _m, 0, _112 ); +enum _m224 = CONSTRUCT_FLAGS( 0, _m, 0, _224 ); +enum _m512 = _m224; +enum _sti = CONSTRUCT_FLAGS( 0, _float, 0, _rsti ); + +REG regFp = { "ST", 0, _st }; + +REG[8] aregFp = [ + { "ST(0)", 0, _sti }, + { "ST(1)", 1, _sti }, + { "ST(2)", 2, _sti }, + { "ST(3)", 3, _sti }, + { "ST(4)", 4, _sti }, + { "ST(5)", 5, _sti }, + { "ST(6)", 6, _sti }, + { "ST(7)", 7, _sti } +]; + +// For uSizemask (4 bits) +enum _8 = 0x1; +enum _16 = 0x2; +enum _32 = 0x4; +enum _48 = 0x8; +enum _anysize = (_8 | _16 | _32 | _48 ); + +enum _modrm = 0x10; + +//// This is for when the reg field of modregrm specifies which instruction it is +enum NUM_MASK = 0x7; +//#define _0 (0x0 | _modrm) // insure that some _modrm bit is set +//#define _1 0x1 // with _0 +//#define _2 0x2 +//#define _3 0x3 +//#define _4 0x4 +//#define _5 0x5 +//#define _6 0x6 +//#define _7 0x7 +// +//#define _modrm 0x10 +// +//#define _r _modrm +//#define _cb _modrm +//#define _cw _modrm +//#define _cd _modrm +//#define _cp _modrm +//#define _ib 0 +//#define _iw 0 +//#define _id 0 +//#define _rb 0 +//#define _rw 0 +//#define _rd 0 +enum _16_bit = 0x20; +enum _32_bit = 0x40; +enum _I386 = 0x80; // opcode is only for 386 and later +enum _16_bit_addr = 0x100; +enum _32_bit_addr = 0x200; +enum _fwait = 0x400; // Add an FWAIT prior to the instruction opcode +enum _nfwait = 0x800; // Do not add an FWAIT prior to the instruction + +enum MOD_MASK = 0xF000; // Mod mask +enum _modsi = 0x1000; // Instruction modifies SI +enum _moddx = 0x2000; // Instruction modifies DX +enum _mod2 = 0x3000; // Instruction modifies second operand +enum _modax = 0x4000; // Instruction modifies AX +enum _modnot1 = 0x5000; // Instruction does not modify first operand +enum _modaxdx = 0x6000; // instruction modifies AX and DX +enum _moddi = 0x7000; // Instruction modifies DI +enum _modsidi = 0x8000; // Instruction modifies SI and DI +enum _modcx = 0x9000; // Instruction modifies CX +enum _modes = 0xa000; // Instruction modifies ES +enum _modall = 0xb000; // Instruction modifies all register values +enum _modsiax = 0xc000; // Instruction modifies AX and SI +enum _modsinot1 = 0xd000; // Instruction modifies SI and not first param + +///////////////////////////////////////////////// +// Operand flags - usOp1, usOp2, usOp3 +// + +alias ushort opflag_t; + +// Operand flags for normal opcodes + +enum _r8 = CONSTRUCT_FLAGS( _8, ASM_OPERAND_TYPE._reg, ASM_MODIFIERS._normal, 0 ); +enum _r16 = CONSTRUCT_FLAGS(_16, ASM_OPERAND_TYPE._reg, ASM_MODIFIERS._normal, 0 ); +enum _r32 = CONSTRUCT_FLAGS(_32, ASM_OPERAND_TYPE._reg, ASM_MODIFIERS._normal, 0 ); +enum _m8 = CONSTRUCT_FLAGS(_8, ASM_OPERAND_TYPE._m, ASM_MODIFIERS._normal, 0 ); +enum _m16 = CONSTRUCT_FLAGS(_16, ASM_OPERAND_TYPE._m, ASM_MODIFIERS._normal, 0 ); +enum _m32 = CONSTRUCT_FLAGS(_32, ASM_OPERAND_TYPE._m, ASM_MODIFIERS._normal, 0 ); +enum _m48 = CONSTRUCT_FLAGS( _48, ASM_OPERAND_TYPE._m, ASM_MODIFIERS._normal, 0 ); +enum _m64 = CONSTRUCT_FLAGS( _anysize, ASM_OPERAND_TYPE._m, ASM_MODIFIERS._normal, 0 ); +enum _m128 = CONSTRUCT_FLAGS( _anysize, ASM_OPERAND_TYPE._m, ASM_MODIFIERS._normal, 0 ); +enum _rm8 = CONSTRUCT_FLAGS(_8, ASM_OPERAND_TYPE._rm, ASM_MODIFIERS._normal, 0 ); +enum _rm16 = CONSTRUCT_FLAGS(_16, ASM_OPERAND_TYPE._rm, ASM_MODIFIERS._normal, 0 ); +enum _rm32 = CONSTRUCT_FLAGS(_32, ASM_OPERAND_TYPE._rm, ASM_MODIFIERS._normal, 0); +enum _r32m16 = CONSTRUCT_FLAGS(_32|_16, ASM_OPERAND_TYPE._rm, ASM_MODIFIERS._normal, 0); +enum _imm8 = CONSTRUCT_FLAGS(_8, ASM_OPERAND_TYPE._imm, ASM_MODIFIERS._normal, 0 ); +enum _imm16 = CONSTRUCT_FLAGS(_16, ASM_OPERAND_TYPE._imm, ASM_MODIFIERS._normal, 0); +enum _imm32 = CONSTRUCT_FLAGS(_32, ASM_OPERAND_TYPE._imm, ASM_MODIFIERS._normal, 0); +enum _rel8 = CONSTRUCT_FLAGS(_8, ASM_OPERAND_TYPE._rel, ASM_MODIFIERS._normal, 0); +enum _rel16 = CONSTRUCT_FLAGS(_16, ASM_OPERAND_TYPE._rel, ASM_MODIFIERS._normal, 0); +enum _rel32 = CONSTRUCT_FLAGS(_32, ASM_OPERAND_TYPE._rel, ASM_MODIFIERS._normal, 0); +enum _p1616 = CONSTRUCT_FLAGS(_32, ASM_OPERAND_TYPE._p, ASM_MODIFIERS._normal, 0); +enum _m1616 = CONSTRUCT_FLAGS(_32, ASM_OPERAND_TYPE._mnoi, ASM_MODIFIERS._normal, 0); +enum _p1632 = CONSTRUCT_FLAGS(_48, ASM_OPERAND_TYPE._p, ASM_MODIFIERS._normal, 0 ); +enum _m1632 = CONSTRUCT_FLAGS(_48, ASM_OPERAND_TYPE._mnoi, ASM_MODIFIERS._normal, 0); +enum _special = CONSTRUCT_FLAGS( 0, 0, ASM_MODIFIERS._rspecial, 0 ); +enum _seg = CONSTRUCT_FLAGS( 0, 0, ASM_MODIFIERS._rseg, 0 ); +enum _a16 = CONSTRUCT_FLAGS( 0, 0, ASM_MODIFIERS._addr16, 0 ); +enum _a32 = CONSTRUCT_FLAGS( 0, 0, ASM_MODIFIERS._addr32, 0 ); +enum _f16 = CONSTRUCT_FLAGS( 0, 0, ASM_MODIFIERS._fn16, 0); + // Near function pointer +enum _f32 = CONSTRUCT_FLAGS( 0, 0, ASM_MODIFIERS._fn32, 0); + // Far function pointer +enum _lbl = CONSTRUCT_FLAGS( 0, 0, ASM_MODIFIERS._flbl, 0 ); + // Label (in current function) + +enum _mmm32 = CONSTRUCT_FLAGS( 0, ASM_OPERAND_TYPE._m, 0, _32); +enum _mmm64 = CONSTRUCT_FLAGS( 0, ASM_OPERAND_TYPE._m, 0, _64); +enum _mmm128 = CONSTRUCT_FLAGS( 0, ASM_OPERAND_TYPE._m, 0, _128); + +enum _xmm_m32 = CONSTRUCT_FLAGS( _32, ASM_OPERAND_TYPE._m, ASM_MODIFIERS._rspecial, 0); +enum _xmm_m64 =CONSTRUCT_FLAGS( _anysize, ASM_OPERAND_TYPE._m, ASM_MODIFIERS._rspecial, 0); +enum _xmm_m128 =CONSTRUCT_FLAGS( _anysize, ASM_OPERAND_TYPE._m, ASM_MODIFIERS._rspecial, 0); + +enum _moffs8 = (_rel8); +enum _moffs16 = (_rel16 ); +enum _moffs32 = (_rel32 ); + +//////////////////////////////////////////////////////////////////// +// Operand flags for floating point opcodes are all just aliases for +// normal opcode variants and only asm_determine_operator_flags should +// need to care. +// +enum _fm80 = CONSTRUCT_FLAGS( 0, ASM_OPERAND_TYPE._m, 0, _80 ); +enum _fm64 = CONSTRUCT_FLAGS( 0, ASM_OPERAND_TYPE._m, 0, _64 ); +enum _fm128 = CONSTRUCT_FLAGS( 0, ASM_OPERAND_TYPE._m, 0, _128 ); +enum _fanysize = (_64 | _80 | _112 | _224); + +enum _AL =0; +enum _AH =4; +enum _AX =0; +enum _EAX =0; +enum _BL =3; +enum _BH =7; +enum _BX =3; +enum _EBX =3; +enum _CL =1; +enum _CH =5; +enum _CX =1; +enum _ECX =1; +enum _DL =2; +enum _DH =6; +enum _DX =2; +enum _EDX =2; +enum _BP =5; +enum _EBP =5; +enum _SP =4; +enum _ESP =4; +enum _DI =7; +enum _EDI =7; +enum _SI =6; +enum _ESI =6; +enum _ES =0; +enum _CS =1; +enum _SS =2; +enum _DS =3; +enum _GS =5; +enum _FS =4; + +enum ASM = 0x36; // string of asm bytes, actually an SS: opcode +enum ASM_END = 0xffff; // special opcode meaning end of table + +struct PTRNTAB0 +{ + uint usOpcode; +// #define ASM_END 0xffff // special opcode meaning end of table + ushort usFlags; +} + +struct PTRNTAB1 +{ + uint usOpcode; + ushort usFlags; + opflag_t usOp1; +} + +struct PTRNTAB2 +{ + uint usOpcode; + ushort usFlags; + opflag_t usOp1; + opflag_t usOp2; +} + +struct PTRNTAB3 +{ + uint usOpcode; + ushort usFlags; + opflag_t usOp1; + opflag_t usOp2; + opflag_t usOp3; +} + +union PTRNTAB +{ + PTRNTAB0 *pptb0; + PTRNTAB1 *pptb1; + PTRNTAB2 *pptb2; + PTRNTAB3 *pptb3; +} + +struct OP +{ + ubyte usNumops; + PTRNTAB ptb; +} + +enum ASM_JUMPTYPE +{ + ASM_JUMPTYPE_UNSPECIFIED, + ASM_JUMPTYPE_SHORT, + ASM_JUMPTYPE_NEAR, + ASM_JUMPTYPE_FAR +} // ajt + +mixin(BringToCurrentScope!(ASM_JUMPTYPE)); + +struct OPND +{ + REG* base; // if plain register + REG* pregDisp1; // if [register1] + REG* pregDisp2; + REG* segreg; // if segment override + char indirect = 0; // if had a '*' or '.' + char bOffset = 0; // if 'offset' keyword + char bSeg = 0; // if 'segment' keyword + char bPtr = 0; // if 'ptr' keyword + uint uchMultiplier; // register multiplier; valid values are 0,1,2,4,8 + opflag_t usFlags; + Dsymbol s; + int disp; + real real_ = 0; + Type ptype; + ASM_JUMPTYPE ajt; +} + +struct ASM_STATE +{ + ubyte ucItype; // Instruction type + Loc loc; + ubyte bInit; + LabelDsymbol psDollar; + Dsymbol psLocalsize; + jmp_buf env; + ubyte bReturnax; + AsmStatement statement; + Scope sc; +} + +enum IT +{ + ITprefix = 0x10, // special prefix + ITjump = 0x20, // jump instructions CALL, Jxx and LOOPxx + ITimmed = 0x30, // value of an immediate operand controls + // code generation + ITopt = 0x40, // not all operands are required + ITshift = 0x50, // rotate and shift instructions + ITfloat = 0x60, // floating point coprocessor instructions + ITdata = 0x70, // DB, DW, DD, DQ, DT pseudo-ops + ITaddr = 0x80, // DA (define addresss) pseudo-op + ITMASK = 0xF0, + ITSIZE = 0x0F, // mask for size +} + +alias IT.ITprefix ITprefix; +alias IT.ITjump ITjump; +alias IT.ITimmed ITimmed; +alias IT.ITopt ITopt; +alias IT.ITshift ITshift; +alias IT.ITfloat ITfloat; +alias IT.ITdata ITdata; +alias IT.ITaddr ITaddr; +alias IT.ITMASK ITMASK; +alias IT.ITSIZE ITSIZE; + +__gshared ASM_STATE asmstate; +__gshared Token* asmtok; +__gshared TOK tok_value; + +// Additional tokens for the inline assembler +enum ASMTK +{ + ASMTKlocalsize = TOKMAX + 1, + ASMTKdword, + ASMTKeven, + ASMTKfar, + ASMTKnaked, + ASMTKnear, + ASMTKptr, + ASMTKqword, + ASMTKseg, + ASMTKword, + ASMTKmax = ASMTKword - (TOK.TOKMAX + 1) + 1 +} + +mixin(BringToCurrentScope!(ASMTK)); + +enum OP_DB +{ +///version (SCPP) { +/// // These are the number of bytes +/// OPdb = 1, +/// OPdw = 2, +/// OPdd = 4, +/// OPdq = 8, +/// OPdt = 10, +/// OPdf = 4, +/// OPde = 10, +/// OPds = 2, +/// OPdi = 4, +/// OPdl = 8, +///} +///version (MARS) { + // Integral types + OPdb, + OPds, + OPdi, + OPdl, + + // Float types + OPdf, + OPdd, + OPde, + + // Deprecated + OPdw = OPds, + OPdq = OPdl, + OPdt = OPde, +///} +} + +OPND* opnd_calloc() +{ + return new OPND(); +} + +void opnd_free(OPND* o) +{ + delete o; +} + +/****************************** + * Convert assembly instruction into a code, and append + * it to the code generated for this block. + */ + +code* asm_emit(Loc loc, uint usNumops, PTRNTAB ptb, OP* pop, OPND* popnd1, OPND* popnd2, OPND* popnd3) +{ +debug { + ubyte auchOpcode[16]; + uint usIdx = 0; + void emit(ubyte op) { + auchOpcode[usIdx++] = op; + } +} else { + void emit(ubyte op) {} +} + Identifier id; +// ushort us; + ubyte* puc; + uint usDefaultseg; + code* pc = null; + OPND* popndTmp; + ASM_OPERAND_TYPE aoptyTmp; + ushort uSizemaskTmp; + REG* pregSegment; + code* pcPrefix = null; + + uint uSizemask1 = 0; + uint uSizemask2 = 0; + uint uSizemask3 = 0; + + //ASM_OPERAND_TYPE aopty1 = ASM_OPERAND_TYPE._reg , aopty2 = 0, aopty3 = 0; + ASM_MODIFIERS amod1 = ASM_MODIFIERS._normal; + ASM_MODIFIERS amod2 = ASM_MODIFIERS._normal; + ASM_MODIFIERS amod3 = ASM_MODIFIERS._normal; + + uint uRegmask1 = 0; + uint uRegmask2 = 0; + uint uRegmask3 = 0; + + uint uSizemaskTable1 = 0; + uint uSizemaskTable2 = 0; + uint uSizemaskTable3 = 0; + + ASM_OPERAND_TYPE aoptyTable1 = ASM_OPERAND_TYPE._reg; + ASM_OPERAND_TYPE aoptyTable2 = ASM_OPERAND_TYPE._reg; + ASM_OPERAND_TYPE aoptyTable3 = ASM_OPERAND_TYPE._reg; + + ASM_MODIFIERS amodTable1 = ASM_MODIFIERS._normal; + ASM_MODIFIERS amodTable2 = ASM_MODIFIERS._normal; + ASM_MODIFIERS amodTable3 = ASM_MODIFIERS._normal; + + uint uRegmaskTable1 = 0; + uint uRegmaskTable2 = 0; + uint uRegmaskTable3 = 0; + + pc = code_calloc(); + pc.Iflags |= CF.CFpsw; // assume we want to keep the flags + + if (popnd1) + { + uSizemask1 = ASM_GET_uSizemask(popnd1.usFlags); + //aopty1 = ASM_GET_aopty(popnd1.usFlags); + amod1 = ASM_GET_amod(popnd1.usFlags); + uRegmask1 = ASM_GET_uRegmask(popnd1.usFlags); + + uSizemaskTable1 = ASM_GET_uSizemask(ptb.pptb1.usOp1); + aoptyTable1 = ASM_GET_aopty(ptb.pptb1.usOp1); + amodTable1 = ASM_GET_amod(ptb.pptb1.usOp1); + uRegmaskTable1 = ASM_GET_uRegmask(ptb.pptb1.usOp1); + + } + + if (popnd2) + { +static if (false) { + printf("\nasm_emit:\nop: "); + asm_output_flags(popnd2.usFlags); + printf("\ntb: "); + asm_output_flags(ptb.pptb2.usOp2); + printf("\n"); +} + uSizemask2 = ASM_GET_uSizemask(popnd2.usFlags); + //aopty2 = ASM_GET_aopty(popnd2.usFlags); + amod2 = ASM_GET_amod(popnd2.usFlags); + uRegmask2 = ASM_GET_uRegmask(popnd2.usFlags); + + uSizemaskTable2 = ASM_GET_uSizemask(ptb.pptb2.usOp2); + aoptyTable2 = ASM_GET_aopty(ptb.pptb2.usOp2); + amodTable2 = ASM_GET_amod(ptb.pptb2.usOp2); + uRegmaskTable2 = ASM_GET_uRegmask(ptb.pptb2.usOp2); + } + if (popnd3) + { + uSizemask3 = ASM_GET_uSizemask(popnd3.usFlags); + //aopty3 = ASM_GET_aopty(popnd3.usFlags); + amod3 = ASM_GET_amod(popnd3.usFlags); + uRegmask3 = ASM_GET_uRegmask(popnd3.usFlags); + + uSizemaskTable3 = ASM_GET_uSizemask(ptb.pptb3.usOp3); + aoptyTable3 = ASM_GET_aopty(ptb.pptb3.usOp3); + amodTable3 = ASM_GET_amod(ptb.pptb3.usOp3); + uRegmaskTable3 = ASM_GET_uRegmask(ptb.pptb3.usOp3); + } + + asmstate.statement.regs |= asm_modify_regs(ptb, popnd1, popnd2); + + if (!I32 && ptb.pptb0.usFlags & _I386) + { + switch (usNumops) + { + case 0: + break; + + case 1: + if (popnd1 && popnd1.s) + { +L386_WARNING: + id = popnd1.s.ident; +L386_WARNING2: + if (config.target_cpu < TARGET.TARGET_80386) + { + // Reference to %s caused a 386 instruction to be generated + //warerr(WM_386_op, id.toChars()); + } + } + break; + + case 2: + case 3: // The third operand is always an ASM_OPERAND_TYPE._imm + if (popnd1 && popnd1.s) + goto L386_WARNING; + if (popnd2 && popnd2.s) + { + id = popnd2.s.ident; + goto L386_WARNING2; + } + break; + } + } + + switch (usNumops) + { + case 0: + if ((I32 && (ptb.pptb0.usFlags & _16_bit)) || (!I32 && (ptb.pptb0.usFlags & _32_bit))) + { + emit(0x66); + pc.Iflags |= CF.CFopsize; + } + break; + + // 3 and 2 are the same because the third operand is always + // an immediate and does not affect operation size + case 3: + case 2: + if ((I32 && + (amod2 == ASM_MODIFIERS._addr16 || + (uSizemaskTable2 & _16 && aoptyTable2 == ASM_OPERAND_TYPE._rel) || + (uSizemaskTable2 & _32 && aoptyTable2 == ASM_OPERAND_TYPE._mnoi) || + (ptb.pptb2.usFlags & _16_bit_addr) + ) + ) || + (!I32 && + (amod2 == ASM_MODIFIERS._addr32 || + (uSizemaskTable2 & _32 && aoptyTable2 == ASM_OPERAND_TYPE._rel) || + (uSizemaskTable2 & _48 && aoptyTable2 == ASM_OPERAND_TYPE._mnoi) || + (ptb.pptb2.usFlags & _32_bit_addr))) + ) + { + emit(0x67); + pc.Iflags |= CF.CFaddrsize; + + if (I32) + amod2 = ASM_MODIFIERS._addr16; + else + amod2 = ASM_MODIFIERS._addr32; + + popnd2.usFlags &= ~CONSTRUCT_FLAGS(0,0,7,0); + popnd2.usFlags |= CONSTRUCT_FLAGS(0,0,amod2,0); + } + + + /* Fall through, operand 1 controls the opsize, but the + address size can be in either operand 1 or operand 2, + hence the extra checking the flags tested for SHOULD + be mutex on operand 1 and operand 2 because there is + only one MOD R/M byte + */ + + case 1: + if ((I32 && + (amod1 == ASM_MODIFIERS._addr16 || + (uSizemaskTable1 & _16 && aoptyTable1 == ASM_OPERAND_TYPE._rel) || + (uSizemaskTable1 & _32 && aoptyTable1 == ASM_OPERAND_TYPE._mnoi) || + (ptb.pptb1.usFlags & _16_bit_addr))) || + (!I32 && + (amod1 == ASM_MODIFIERS._addr32 || + (uSizemaskTable1 & _32 && aoptyTable1 == ASM_OPERAND_TYPE._rel) || + (uSizemaskTable1 & _48 && aoptyTable1 == ASM_OPERAND_TYPE._mnoi) || + (ptb.pptb1.usFlags & _32_bit_addr)))) + { + emit(0x67); // address size prefix + pc.Iflags |= CF.CFaddrsize; + if (I32) + amod1 = ASM_MODIFIERS._addr16; + else + amod1 = ASM_MODIFIERS._addr32; + popnd1.usFlags &= ~CONSTRUCT_FLAGS(0,0,7,0); + popnd1.usFlags |= CONSTRUCT_FLAGS(0,0,amod1,0); + } + + // If the size of the operand is unknown, assume that it is + // the default size + if ((I32 && (ptb.pptb0.usFlags & _16_bit)) || + (!I32 && (ptb.pptb0.usFlags & _32_bit))) + { + //if (asmstate.ucItype != ITjump) + { emit(0x66); + pc.Iflags |= CF.CFopsize; + } + } + if (((pregSegment = (popndTmp = popnd1).segreg) != null) || + ((popndTmp = popnd2) != null && + (pregSegment = popndTmp.segreg) != null) + ) + { + if ((popndTmp.pregDisp1 && + popndTmp.pregDisp1.val == _BP) || + popndTmp.pregDisp2 && + popndTmp.pregDisp2.val == _BP) + usDefaultseg = _SS; + else + usDefaultseg = _DS; + if (pregSegment.val != usDefaultseg) + switch (pregSegment.val) { + case _CS: + emit(0x2e); + pc.Iflags |= CF.CFcs; + break; + case _SS: + emit(0x36); + pc.Iflags |= CF.CFss; + break; + case _DS: + emit(0x3e); + pc.Iflags |= CF.CFds; + break; + case _ES: + emit(0x26); + pc.Iflags |= CF.CFes; + break; + case _FS: + emit(0x64); + pc.Iflags |= CF.CFfs; + break; + case _GS: + emit(0x65); + pc.Iflags |= CF.CFgs; + break; + default: + assert(0); + } + } + break; + } + uint usOpcode = ptb.pptb0.usOpcode; + + if ((usOpcode & 0xFFFFFF00) == 0x660F3A00 || // SSE4 + (usOpcode & 0xFFFFFF00) == 0x660F3800) // SSE4 + { + pc.Iflags |= CF.CFopsize; + pc.Iop = 0x0F; + pc.Iop2 = (usOpcode >> 8) & 0xFF; + pc.Iop3 = usOpcode & 0xFF; + goto L3; + } + switch (usOpcode & 0xFF0000) + { + case 0: + break; + + case 0x660000: + pc.Iflags |= CF.CFopsize; + usOpcode &= 0xFFFF; + break; + + case 0xF20000: // REPNE + case 0xF30000: // REP/REPE + // BUG: What if there's an address size prefix or segment + // override prefix? Must the REP be adjacent to the rest + // of the opcode? + pcPrefix = code_calloc(); + pcPrefix.Iop = cast(ubyte)(usOpcode >> 16); + usOpcode &= 0xFFFF; + break; + + case 0x0F0000: // an AMD instruction + puc = (cast(ubyte*) &usOpcode); + if (puc[1] != 0x0F) // if not AMD instruction 0x0F0F + goto L4; + emit(puc[2]); + emit(puc[1]); + emit(puc[0]); + pc.Iop = puc[2]; + pc.Iop2 = puc[1]; + pc.IEVint2() = puc[0]; + pc.IFL2 = FL.FLconst; + goto L3; + + default: + puc = (cast(ubyte*) &usOpcode); + L4: + emit(puc[2]); + emit(puc[1]); + emit(puc[0]); + pc.Iop = puc[2]; + pc.Iop2 = puc[1]; + pc.Irm = puc[0]; + goto L3; + } + if (usOpcode & 0xff00) + { + puc = (cast(ubyte*) &(usOpcode)); + emit(puc[1]); + emit(puc[0]); + pc.Iop = puc[1]; + if (pc.Iop == 0x0f) + pc.Iop2 = puc[0]; + else + { + if (usOpcode == 0xDFE0) // FSTSW AX + { pc.Irm = puc[0]; + goto L2; + } + if (asmstate.ucItype == IT.ITfloat) + pc.Irm = puc[0]; + else + { + pc.IEVint2() = puc[0]; + pc.IFL2 = FL.FLconst; + } + } + } + else + { + emit(cast(ubyte)usOpcode); + pc.Iop = cast(ubyte)usOpcode; + } + L3: ; + + // If CALL, Jxx or LOOPx to a symbolic location + if (/*asmstate.ucItype == ITjump &&*/ + popnd1 && popnd1.s && popnd1.s.isLabel()) + { + Dsymbol s = popnd1.s; + if (s == asmstate.psDollar) + { + pc.IFL2 = FL.FLconst; + if (uSizemaskTable1 & (_8 | _16)) + pc.IEVint2() = popnd1.disp; + else if (uSizemaskTable1 & _32) + pc.IEVpointer2() = cast(targ_size_t) popnd1.disp; + } + else + { + LabelDsymbol label = s.isLabel(); + if (label) + { + if ((pc.Iop & 0xF0) == 0x70) + pc.Iflags |= CF.CFjmp16; + if (usNumops == 1) + { + pc.IFL2 = FL.FLblock; + pc.IEVlsym2() = label; + } + else + { + pc.IFL1 = FL.FLblock; + pc.IEVlsym1() = label; + } + } + } + } + + switch (usNumops) + { + case 0: + break; + + case 1: + if (((aoptyTable1 == ASM_OPERAND_TYPE._reg || aoptyTable1 == ASM_OPERAND_TYPE._float) && + amodTable1 == ASM_MODIFIERS._normal && (uRegmaskTable1 & _rplus_r))) + { + if (asmstate.ucItype == IT.ITfloat) + pc.Irm += popnd1.base.val; + else if (pc.Iop == 0x0f) + pc.Iop2 += popnd1.base.val; + else + pc.Iop += popnd1.base.val; +debug { + auchOpcode[usIdx-1] += popnd1.base.val; +} + } + else + { + asm_make_modrm_byte( +///debug { + auchOpcode, &usIdx, +///} + pc, + ptb.pptb1.usFlags, + popnd1, null); + } + + popndTmp = popnd1; + aoptyTmp = aoptyTable1; + uSizemaskTmp = cast(ushort)uSizemaskTable1; + L1: + if (aoptyTmp == ASM_OPERAND_TYPE._imm) + { + Declaration d = popndTmp.s ? popndTmp.s.isDeclaration() : null; + if (popndTmp.bSeg) + { + if (!(d && d.isDataseg())) + asmerr(ASMERRMSGS.EM_bad_addr_mode); // illegal addressing mode + } + switch (uSizemaskTmp) + { + case _8: + case _16: + case _32: + if (popndTmp.s is asmstate.psLocalsize) + { + pc.IFL2 = FL.FLlocalsize; + pc.IEVdsym2() = null; + pc.Iflags |= CF.CFoff; + pc.IEVoffset2() = popndTmp.disp; + } + else if (d) + { +static if (false) { + if ((pc.IFL2 = d.Sfl) == 0) + pc.IFL2 = FL.FLdsymbol; +} else { + pc.IFL2 = FL.FLdsymbol; +} + pc.Iflags &= ~(CF.CFseg | CF.CFoff); + if (popndTmp.bSeg) + pc.Iflags |= CF.CFseg; + else + pc.Iflags |= CF.CFoff; + + pc.IEVoffset2() = popndTmp.disp; + pc.IEVdsym2() = d; + } + else + { + pc.IEVint2() = popndTmp.disp; + pc.IFL2 = FL.FLconst; + } + break; + } + } + + break; + case 2: + // + // If there are two immediate operands then + // + if (aoptyTable1 == ASM_OPERAND_TYPE._imm && aoptyTable2 == ASM_OPERAND_TYPE._imm) + { + pc.IEVint1() = popnd1.disp; + pc.IFL1 = FL.FLconst; + pc.IEVint2() = popnd2.disp; + pc.IFL2 = FL.FLconst; + break; + } + if (aoptyTable2 == ASM_OPERAND_TYPE._m || + aoptyTable2 == ASM_OPERAND_TYPE._rel || + // If not MMX register (_mm) or XMM register (_xmm) + (amodTable1 == ASM_MODIFIERS._rspecial && !(uRegmaskTable1 & (0x08 | 0x10)) && !uSizemaskTable1) || + aoptyTable2 == ASM_OPERAND_TYPE._rm || + (popnd1.usFlags == _r32 && popnd2.usFlags == _xmm) || + (popnd1.usFlags == _r32 && popnd2.usFlags == _mm)) + { +static if (false) { + printf("test4 %d,%d,%d,%d\n", + (aoptyTable2 == ASM_OPERAND_TYPE._m), + (aoptyTable2 == ASM_OPERAND_TYPE._rel), + (amodTable1 == ASM_MODIFIERS._rspecial && !(uRegmaskTable1 & (0x08 | 0x10))), + (aoptyTable2 == ASM_OPERAND_TYPE._rm) + ); + printf("usOpcode = %x\n", usOpcode); +} + if (ptb.pptb0.usOpcode == 0x0F7E || // MOVD _rm32,_mm + ptb.pptb0.usOpcode == 0x660F7E // MOVD _rm32,_xmm + ) + { + asm_make_modrm_byte( +///debug { + auchOpcode, &usIdx, +///} + pc, + ptb.pptb1.usFlags, + popnd1, popnd2); + } + else + { + asm_make_modrm_byte( +///debug { + auchOpcode, &usIdx, +///} + pc, + ptb.pptb1.usFlags, + popnd2, popnd1); + } + popndTmp = popnd1; + aoptyTmp = aoptyTable1; + uSizemaskTmp = cast(ushort)uSizemaskTable1; + } + else + { + if (((aoptyTable1 == ASM_OPERAND_TYPE._reg || aoptyTable1 == ASM_OPERAND_TYPE._float) && + amodTable1 == ASM_MODIFIERS._normal && + (uRegmaskTable1 & _rplus_r))) + { + if (asmstate.ucItype == IT.ITfloat) + pc.Irm += popnd1.base.val; + else if (pc.Iop == 0x0f) + pc.Iop2 += popnd1.base.val; + else + pc.Iop += popnd1.base.val; +debug { + auchOpcode[usIdx-1] += popnd1.base.val; +} + } + else if (((aoptyTable2 == ASM_OPERAND_TYPE._reg || aoptyTable2 == ASM_OPERAND_TYPE._float) && + amodTable2 == ASM_MODIFIERS._normal && + (uRegmaskTable2 & _rplus_r))) + { + if (asmstate.ucItype == IT.ITfloat) + pc.Irm += popnd2.base.val; + else if (pc.Iop == 0x0f) + pc.Iop2 += popnd2.base.val; + else + pc.Iop += popnd2.base.val; +debug { + auchOpcode[usIdx-1] += popnd2.base.val; +} + } + else if (ptb.pptb0.usOpcode == 0xF30FD6 || + ptb.pptb0.usOpcode == 0x0F12 || + ptb.pptb0.usOpcode == 0x0F16 || + ptb.pptb0.usOpcode == 0x660F50 || + ptb.pptb0.usOpcode == 0x0F50 || + ptb.pptb0.usOpcode == 0x660FD7 || + ptb.pptb0.usOpcode == 0x0FD7) + { + asm_make_modrm_byte( +///debug { + auchOpcode, &usIdx, +///} + pc, + ptb.pptb1.usFlags, + popnd2, popnd1); + } + else + { + asm_make_modrm_byte( +///debug { + auchOpcode, &usIdx, +///} + pc, + ptb.pptb1.usFlags, + popnd1, popnd2); + + } + if (aoptyTable1 == ASM_OPERAND_TYPE._imm) + { + popndTmp = popnd1; + aoptyTmp = aoptyTable1; + uSizemaskTmp = cast(ushort)uSizemaskTable1; + } + else + { + popndTmp = popnd2; + aoptyTmp = aoptyTable2; + uSizemaskTmp = cast(ushort)uSizemaskTable2; + } + } + goto L1; + + case 3: + if (aoptyTable2 == ASM_OPERAND_TYPE._m || aoptyTable2 == ASM_OPERAND_TYPE._rm || + usOpcode == 0x0FC5) // PEXTRW + { + asm_make_modrm_byte( +///debug { + auchOpcode, &usIdx, +///} + pc, + ptb.pptb1.usFlags, + popnd2, popnd1); + popndTmp = popnd3; + aoptyTmp = aoptyTable3; + uSizemaskTmp = cast(ushort)uSizemaskTable3; + } else { + if (((aoptyTable1 == ASM_OPERAND_TYPE._reg || aoptyTable1 == ASM_OPERAND_TYPE._float) && + amodTable1 == ASM_MODIFIERS._normal && + (uRegmaskTable1 &_rplus_r))) + { + if (asmstate.ucItype == IT.ITfloat) + pc.Irm += popnd1.base.val; + else if (pc.Iop == 0x0f) + pc.Iop2 += popnd1.base.val; + else + pc.Iop += popnd1.base.val; +debug { + auchOpcode[usIdx-1] += popnd1.base.val; +} + } + else if (((aoptyTable2 == ASM_OPERAND_TYPE._reg || aoptyTable2 == ASM_OPERAND_TYPE._float) && + amodTable2 == ASM_MODIFIERS._normal && + (uRegmaskTable2 &_rplus_r))) + { + if (asmstate.ucItype == IT.ITfloat) + pc.Irm += popnd1.base.val; + else if (pc.Iop == 0x0f) + pc.Iop2 += popnd1.base.val; + else + pc.Iop += popnd2.base.val; +debug { + auchOpcode[usIdx-1] += popnd2.base.val; +} + } + else + asm_make_modrm_byte( +///debug { + auchOpcode, &usIdx, +///} + pc, + ptb.pptb1.usFlags, + popnd1, popnd2); + + popndTmp = popnd3; + aoptyTmp = aoptyTable3; + uSizemaskTmp = cast(ushort)uSizemaskTable3; + } + goto L1; + } +L2: + + if ((pc.Iop & 0xF8) == 0xD8 && + ADDFWAIT() && + !(ptb.pptb0.usFlags & _nfwait)) + pc.Iflags |= CF.CFwait; + else if ((ptb.pptb0.usFlags & _fwait) && + config.target_cpu >= TARGET.TARGET_80386) + pc.Iflags |= CF.CFwait; + +debug { + if (debuga) + { + uint u; + + for (u = 0; u < usIdx; u++) + printf(" %02X", auchOpcode[u]); + + printf("\t%s\t", asm_opstr(pop)); + if (popnd1) + asm_output_popnd(popnd1); + if (popnd2) { + printf(","); + asm_output_popnd(popnd2); + } + if (popnd3) { + printf(","); + asm_output_popnd(popnd3); + } + printf("\n"); + } +} + + pc = cat(pcPrefix, pc); + pc = asm_genloc(loc, pc); + return pc; +} + +void asm_token_trans(Token* tok) +{ + tok_value = TOK.TOKeof; + + if (tok) + { + tok_value = tok.value; + if (tok_value == TOK.TOKidentifier) + { + string id = tok.ident.toChars(); + size_t len = id.length; + if (len < 20) + { + ASMTK asmtk = cast(ASMTK) binary(toStringz(id), apszAsmtk.ptr, ASMTK.ASMTKmax); + if (cast(int)asmtk >= 0) + tok_value = cast(TOK)(asmtk + TOK.TOKMAX + 1); + } + } + } +} + +void asm_token() +{ + if (asmtok) + asmtok = asmtok.next; + + asm_token_trans(asmtok); +} + + +/********************** + * If c is a power of 2, return that power else -1. + */ + +int ispow2(ulong c) +{ + int i; + + if (c == 0 || (c & (c - 1))) + i = -1; + else + for (i = 0; c >>= 1; i++) { + ; + } + + return i; +} + +// Error numbers +enum ASMERRMSGS +{ + EM_bad_float_op, + EM_bad_addr_mode, + EM_align, + EM_opcode_exp, + EM_prefix, + EM_eol, + EM_bad_operand, + EM_bad_integral_operand, + EM_ident_exp, + EM_not_struct, + EM_nops_expected, + EM_bad_op, + EM_const_init, + EM_undefined, + EM_pointer, + EM_colon, + EM_rbra, + EM_rpar, + EM_ptr_exp, + EM_num, + EM_float, + EM_char, + EM_label_expected, + EM_uplevel, + EM_type_as_operand, +} + +mixin(BringToCurrentScope!(ASMERRMSGS)); + +string[] asmerrmsgs = +[ + "unknown operand for floating point instruction", + "bad addr mode", + "align %d must be a power of 2", + "opcode expected, not %s", + "prefix", + "end of instruction", + "bad operand", + "bad integral operand", + "identifier expected", + "not struct", + "nops expected", + "bad type/size of operands '%s'", + "constant initializer expected", + "undefined identifier '%s'", + "pointer", + "colon", + "] expected instead of '%s'", + ") expected instead of '%s'", + "ptr expected", + "integer expected", + "floating point expected", + "character is truncated", + "label expected", + "uplevel nested reference to variable %s", + "cannot use type %s as an operand" +]; + +void asmerr(T...)(int errnum, T t) +{ + string format = asmerrmsgs[errnum]; + asmerr(format, t); +} + +void asmerr(T...)(string format, T t) +{ + string p = asmstate.loc.toChars(); + if (p.length != 0) + writef("%s: ", p); + + writefln(format, t); + + longjmp(asmstate.env,1); +} + +PTRNTAB asm_classify(OP* pop, OPND* popnd1, OPND* popnd2, OPND* popnd3, uint* pusNumops) +{ + uint usNumops; + uint usActual; + PTRNTAB ptbRet = { null }; + opflag_t usFlags1 = 0 ; + opflag_t usFlags2 = 0; + opflag_t usFlags3 = 0; + + PTRNTAB1 *pptb1; + PTRNTAB2 *pptb2; + PTRNTAB3 *pptb3; + + char bFake = false; + + ubyte bMatch1, bMatch2, bMatch3, bRetry = false; + + // How many arguments are there? the parser is strictly left to right + // so this should work. + + if (!popnd1) + usNumops = 0; + else + { + popnd1.usFlags = usFlags1 = asm_determine_operand_flags(popnd1); + if (!popnd2) + usNumops = 1; + else + { + popnd2.usFlags = usFlags2 = asm_determine_operand_flags(popnd2); + if (!popnd3) + usNumops = 2; + else + { + popnd3.usFlags = usFlags3 = asm_determine_operand_flags(popnd3); + usNumops = 3; + } + } + } + + // Now check to insure that the number of operands is correct + usActual = (pop.usNumops & IT.ITSIZE); + if (usActual != usNumops && asmstate.ucItype != IT.ITopt && + asmstate.ucItype != IT.ITfloat) + { +PARAM_ERROR: + asmerr(ASMERRMSGS.EM_nops_expected, usActual, asm_opstr(pop), usNumops); + } + *pusNumops = usNumops; +// +// The number of arguments matches, now check to find the opcode +// in the associated opcode table +// +RETRY: + //printf("usActual = %d\n", usActual); + switch (usActual) + { + case 0: + ptbRet = pop.ptb ; + goto RETURN_IT; + + case 1: + //printf("usFlags1 = "); asm_output_flags(usFlags1); printf("\n"); + for (pptb1 = pop.ptb.pptb1; pptb1.usOpcode != ASM_END; + pptb1++) + { + //printf("table = "); asm_output_flags(pptb1.usOp1); printf("\n"); + bMatch1 = asm_match_flags(usFlags1, pptb1.usOp1); + if (bMatch1) + { if (pptb1.usOpcode == 0x68 && + I32 && + pptb1.usOp1 == _imm16 + ) + // Don't match PUSH imm16 in 32 bit code + continue; + break; + } + if ((asmstate.ucItype == IT.ITimmed) && + asm_match_flags(usFlags1, + CONSTRUCT_FLAGS(_8 | _16 | _32, ASM_OPERAND_TYPE._imm, ASM_MODIFIERS._normal, + 0)) && + popnd1.disp == pptb1.usFlags) + break; + if ((asmstate.ucItype == IT.ITopt || + asmstate.ucItype == IT.ITfloat) && + !usNumops && + !pptb1.usOp1) + { + if (usNumops > 1) + goto PARAM_ERROR; + break; + } + } + if (pptb1.usOpcode == ASM_END) + { +debug { + if (debuga) + { + printf("\t%s\t", asm_opstr(pop)); + if (popnd1) + asm_output_popnd(popnd1); + if (popnd2) { + printf(","); + asm_output_popnd(popnd2); + } + if (popnd3) { + printf(","); + asm_output_popnd(popnd3); + } + printf("\n"); + + printf("OPCODE mism = "); + if (popnd1) + asm_output_flags(popnd1.usFlags); + else + printf("NONE"); + printf("\n"); + } +} +TYPE_SIZE_ERROR: + if (popnd1 && ASM_GET_aopty(popnd1.usFlags) != ASM_OPERAND_TYPE._reg) + { + usFlags1 = popnd1.usFlags |= _anysize; + if (asmstate.ucItype == IT.ITjump) + { + if (bRetry && popnd1.s && !popnd1.s.isLabel()) + { + asmerr(ASMERRMSGS.EM_label_expected, popnd1.s.toChars()); + } + + popnd1.usFlags |= CONSTRUCT_FLAGS(0, 0, 0, _fanysize); + } + } + if (popnd2 && ASM_GET_aopty(popnd2.usFlags) != ASM_OPERAND_TYPE._reg) { + usFlags2 = popnd2.usFlags |= (_anysize); + if (asmstate.ucItype == IT.ITjump) + popnd2.usFlags |= CONSTRUCT_FLAGS(0, 0, 0, + _fanysize); + } + if (popnd3 && ASM_GET_aopty(popnd3.usFlags) != ASM_OPERAND_TYPE._reg) { + usFlags3 = popnd3.usFlags |= (_anysize); + if (asmstate.ucItype == IT.ITjump) + popnd3.usFlags |= CONSTRUCT_FLAGS(0, 0, 0, + _fanysize); + } + if (bRetry) + { + asmerr(ASMERRMSGS.EM_bad_op, fromStringz(asm_opstr(pop))); // illegal type/size of operands + } + bRetry = true; + goto RETRY; + } + ptbRet.pptb1 = pptb1; + goto RETURN_IT; + + case 2: + //printf("usFlags1 = "); asm_output_flags(usFlags1); printf(" "); + //printf("usFlags2 = "); asm_output_flags(usFlags2); printf("\n"); + for (pptb2 = pop.ptb.pptb2; + pptb2.usOpcode != ASM_END; + pptb2++) + { + //printf("table1 = "); asm_output_flags(pptb2.usOp1); printf(" "); + //printf("table2 = "); asm_output_flags(pptb2.usOp2); printf("\n"); + bMatch1 = asm_match_flags(usFlags1, pptb2.usOp1); + bMatch2 = asm_match_flags(usFlags2, pptb2.usOp2); + //printf("match1 = %d, match2 = %d\n",bMatch1,bMatch2); + if (bMatch1 && bMatch2) { + + //printf("match\n"); + + // OK, if they both match and the first op in the table is not AL + // or size of 8 and the second is immediate 8, + // then check to see if the constant + // is a signed 8 bit constant. If so, then do not match, otherwise match + // + if (!bRetry && + !((ASM_GET_uSizemask(pptb2.usOp1) & _8) || + (ASM_GET_uRegmask(pptb2.usOp1) & _al)) && + (ASM_GET_aopty(pptb2.usOp2) == ASM_OPERAND_TYPE._imm) && + (ASM_GET_uSizemask(pptb2.usOp2) & _8)) + { + if (popnd2.disp <= char.max) + break; + else + bFake = true; + } + else + break; + } + if (asmstate.ucItype == IT.ITopt || asmstate.ucItype == IT.ITfloat) + { + switch (usNumops) + { + case 0: + if (!pptb2.usOp1) + goto Lfound2; + break; + case 1: + if (bMatch1 && !pptb2.usOp2) + goto Lfound2; + break; + case 2: + break; + default: + goto PARAM_ERROR; + } + } +static if (false) { + if (asmstate.ucItype == IT.ITshift && + !pptb2.usOp2 && + bMatch1 && popnd2.disp == 1 && + asm_match_flags(usFlags2, + CONSTRUCT_FLAGS(_8|_16|_32, ASM_OPERAND_TYPE._imm,ASM_MODIFIERS._normal,0)) + ) + { + break; + } +} + } + Lfound2: + if (pptb2.usOpcode == ASM_END) + { +debug { + if (debuga) + { + printf("\t%s\t", asm_opstr(pop)); + if (popnd1) + asm_output_popnd(popnd1); + if (popnd2) { + printf(","); + asm_output_popnd(popnd2); + } + if (popnd3) { + printf(","); + asm_output_popnd(popnd3); + } + printf("\n"); + + printf("OPCODE mismatch = "); + if (popnd1) + asm_output_flags(popnd1.usFlags); + else + printf("NONE"); + printf( " Op2 = "); + if (popnd2) + asm_output_flags(popnd2.usFlags); + else + printf("NONE"); + printf("\n"); + } +} + goto TYPE_SIZE_ERROR; + } + ptbRet.pptb2 = pptb2; + goto RETURN_IT; + + case 3: + for (pptb3 = pop.ptb.pptb3; + pptb3.usOpcode != ASM_END; + pptb3++) + { + bMatch1 = asm_match_flags(usFlags1, pptb3.usOp1); + bMatch2 = asm_match_flags(usFlags2, pptb3.usOp2); + bMatch3 = asm_match_flags(usFlags3, pptb3.usOp3); + if (bMatch1 && bMatch2 && bMatch3) + goto Lfound3; + + if (asmstate.ucItype == IT.ITopt) + { + switch (usNumops) + { + case 0: + if (!pptb3.usOp1) + goto Lfound3; + break; + case 1: + if (bMatch1 && !pptb3.usOp2) + goto Lfound3; + break; + case 2: + if (bMatch1 && bMatch2 && !pptb3.usOp3) + goto Lfound3; + break; + case 3: + break; + default: + goto PARAM_ERROR; + } + } + } + Lfound3: + if (pptb3.usOpcode == ASM_END) + { +debug { + if (debuga) + { + printf("\t%s\t", asm_opstr(pop)); + if (popnd1) + asm_output_popnd(popnd1); + if (popnd2) { + printf(","); + asm_output_popnd(popnd2); + } + if (popnd3) { + printf(","); + asm_output_popnd(popnd3); + } + printf("\n"); + + printf("OPCODE mismatch = "); + if (popnd1) + asm_output_flags(popnd1.usFlags); + else + printf("NONE"); + printf( " Op2 = "); + if (popnd2) + asm_output_flags(popnd2.usFlags); + else + printf("NONE"); + if (popnd3) + asm_output_flags(popnd3.usFlags); + printf("\n"); + } +} + goto TYPE_SIZE_ERROR; + } + + ptbRet.pptb3 = pptb3; + goto RETURN_IT; + } + +RETURN_IT: + if (bRetry && !bFake) + { + asmerr(ASMERRMSGS.EM_bad_op, fromStringz(asm_opstr(pop))); + } + return ptbRet; +} + +/******************************* + * start of inline assemblers expression parser + * NOTE: functions in call order instead of alphabetical + */ + +/******************************************* + * Parse DA expression + * + * Very limited define address to place a code + * address in the assembly + * Problems: + * o Should use dw offset and dd offset instead, + * for near/far support. + * o Should be able to add an offset to the label address. + * o Blocks addressed by DA should get their Bpred set correctly + * for optimizer. + */ + +code* asm_da_parse(OP* pop) +{ + code* clst = null; + elem* e; + + while (1) + { + code* c; + + if (tok_value == TOK.TOKidentifier) + { + LabelDsymbol label = asmstate.sc.func.searchLabel(asmtok.ident); + if (!label) + error(asmstate.loc, "label '%s' not found\n", asmtok.ident.toChars()); + + c = code_calloc(); + c.Iop = ASM; + c.Iflags = CF.CFaddrsize; + c.IFL1 = FL.FLblockoff; + c.IEVlsym1() = label; + c = asm_genloc(asmstate.loc, c); + clst = cat(clst,c); + } + else + asmerr(ASMERRMSGS.EM_bad_addr_mode); // illegal addressing mode + + asm_token(); + if (tok_value != TOK.TOKcomma) + break; + + asm_token(); + } + + asmstate.statement.regs |= mES | ALLREGS; + asmstate.bReturnax = true; + + return clst; +} + +/******************************************* + * Parse DB, DW, DD, DQ and DT expressions. + */ + +code* asm_db_parse(OP* pop) +{ + uint usSize; + uint usMaxbytes; + uint usBytes; + + union DT + { + targ_ullong ul; + targ_float f; + targ_double d; + targ_ldouble ld; + char value[10]; + } + + DT dt; + + code* c; + uint op; + static ubyte[7] opsize = [ 1,2,4,8,4,8,10 ]; + + op = pop.usNumops & IT.ITSIZE; + usSize = opsize[op]; + + usBytes = 0; + usMaxbytes = 0; + c = code_calloc(); + c.Iop = ASM; + + while (1) + { + size_t len; + ubyte* q; + + if (usBytes+usSize > usMaxbytes) + { + usMaxbytes = usBytes + usSize + 10; + c.IEV1.as.bytes = cast(char*)realloc(c.IEV1.as.bytes,usMaxbytes); + } + switch (tok_value) + { + case TOK.TOKint32v: + dt.ul = asmtok.int32value; + goto L1; + case TOK.TOKuns32v: + dt.ul = asmtok.uns32value; + goto L1; + case TOK.TOKint64v: + dt.ul = asmtok.int64value; + goto L1; + case TOK.TOKuns64v: + dt.ul = asmtok.uns64value; + goto L1; + L1: + switch (op) + { + case OP_DB.OPdb: + case OP_DB.OPds: + case OP_DB.OPdi: + case OP_DB.OPdl: + break; + default: + asmerr(ASMERRMSGS.EM_float); + } + goto L2; + + case TOK.TOKfloat32v: + case TOK.TOKfloat64v: + case TOK.TOKfloat80v: + switch (op) + { + case OP_DB.OPdf: + dt.f = asmtok.float80value; + break; + case OP_DB.OPdd: + dt.d = asmtok.float80value; + break; + case OP_DB.OPde: + dt.ld = asmtok.float80value; + break; + default: + asmerr(ASMERRMSGS.EM_num); + } + goto L2; + + L2: + memcpy(c.IEV1.as.bytes + usBytes,&dt,usSize); + usBytes += usSize; + break; + + case TOK.TOKstring: + len = asmtok.len; + q = cast(ubyte*)asmtok.ustring; + L3: + if (len) + { + usMaxbytes += len * usSize; + c.IEV1.as.bytes = cast(char*)realloc(c.IEV1.as.bytes,usMaxbytes); + memcpy(c.IEV1.as.bytes + usBytes,asmtok.ustring,len); + + char* p = c.IEV1.as.bytes + usBytes; + for (size_t i = 0; i < len; i++) + { + // Be careful that this works + memset(p, 0, usSize); + switch (op) + { + case OP_DB.OPdb: + *p = cast(ubyte)*q; + if (*p != *q) + asmerr(ASMERRMSGS.EM_char); + break; + + case OP_DB.OPds: + *cast(short*)p = *cast(ubyte*)q; + if (*cast(short*)p != *q) + asmerr(ASMERRMSGS.EM_char); + break; + + case OP_DB.OPdi: + case OP_DB.OPdl: + *cast(int*)p = *q; + break; + + default: + asmerr(ASMERRMSGS.EM_float); + } + q++; + p += usSize; + } + + usBytes += len * usSize; + } + break; + + case TOK.TOKidentifier: + { + Expression e = new IdentifierExp(asmstate.loc, asmtok.ident); + e = e.semantic(asmstate.sc); + e = e.optimize(WANT.WANTvalue | WANT.WANTinterpret); + if (e.op == TOK.TOKint64) + { + dt.ul = e.toInteger(); + goto L2; + } + else if (e.op == TOK.TOKfloat64) + { + switch (op) + { + case OP_DB.OPdf: + dt.f = e.toReal(); + break; + case OP_DB.OPdd: + dt.d = e.toReal(); + break; + case OP_DB.OPde: + dt.ld = e.toReal(); + break; + default: + asmerr(ASMERRMSGS.EM_num); + } + goto L2; + } + else if (e.op == TOK.TOKstring) + { + StringExp se = cast(StringExp)e; + q = cast(ubyte*)se.string_; + len = se.len; + goto L3; + } + goto Ldefault; + } + + default: + Ldefault: + asmerr(ASMERRMSGS.EM_const_init); // constant initializer + break; + } + c.IEV1.as.len = usBytes; + + asm_token(); + if (tok_value != TOK.TOKcomma) + break; + + asm_token(); + } + + c = asm_genloc(asmstate.loc, c); + + asmstate.statement.regs |= /* mES| */ ALLREGS; + asmstate.bReturnax = true; + + return c; +} + +/********************************** + * Parse and get integer expression. + */ + +int asm_getnum() +{ + int v; + long i; + + switch (tok_value) + { + case TOK.TOKint32v: + v = asmtok.int32value; + break; + + case TOK.TOKuns32v: + v = asmtok.uns32value; + break; + + case TOK.TOKidentifier: + Expression e = new IdentifierExp(asmstate.loc, asmtok.ident); + e = e.semantic(asmstate.sc); + e = e.optimize(WANT.WANTvalue | WANT.WANTinterpret); + i = e.toInteger(); + v = cast(int) i; + if (v != i) + asmerr(ASMERRMSGS.EM_num); + break; + + default: + asmerr(ASMERRMSGS.EM_num); + break; + } + + asm_token(); + + return v; +} + + +/******************************* + */ + +OPND* asm_cond_exp() +{ + OPND* o1; + OPND* o2; + OPND* o3; + + //printf("asm_cond_exp()\n"); + o1 = asm_log_or_exp(); + if (tok_value == TOK.TOKquestion) + { + asm_token(); + o2 = asm_cond_exp(); + asm_token(); + asm_chktok(TOK.TOKcolon, ASMERRMSGS.EM_colon); + o3 = asm_cond_exp(); + o1 = (o1.disp) ? o2 : o3; + } + + return o1; +} + +regm_t asm_modify_regs(PTRNTAB ptb, OPND* popnd1, OPND* popnd2) +{ + regm_t usRet = 0; + + switch (ptb.pptb0.usFlags & MOD_MASK) { + case _modsi: + usRet |= mSI; + break; + case _moddx: + usRet |= mDX; + break; + case _mod2: + if (popnd2) + usRet |= asm_modify_regs(ptb, popnd2, null); + break; + case _modax: + usRet |= mAX; + break; + case _modnot1: + popnd1 = null; + break; + case _modaxdx: + usRet |= (mAX | mDX); + break; + case _moddi: + usRet |= mDI; + break; + case _modsidi: + usRet |= (mSI | mDI); + break; + case _modcx: + usRet |= mCX; + break; + case _modes: + /*usRet |= mES;*/ + break; + case _modall: + asmstate.bReturnax = true; + return /*mES |*/ ALLREGS; + case _modsiax: + usRet |= (mSI | mAX); + break; + case _modsinot1: + usRet |= mSI; + popnd1 = null; + break; + default: + break; /// + } + if (popnd1 && ASM_GET_aopty(popnd1.usFlags) == ASM_OPERAND_TYPE._reg) { + switch (ASM_GET_amod(popnd1.usFlags)) { + default: + if (ASM_GET_uSizemask(popnd1.usFlags) == _8) { + switch(popnd1.base.val) { + case _AL: + case _AH: + usRet |= mAX; + break; + case _BL: + case _BH: + usRet |= mBX; + break; + case _CL: + case _CH: + usRet |= mCX; + break; + case _DL: + case _DH: + usRet |= mDX; + break; + } + } + else { + switch (popnd1.base.val) { + case _AX: + usRet |= mAX; + break; + case _BX: + usRet |= mBX; + break; + case _CX: + usRet |= mCX; + break; + case _DX: + usRet |= mDX; + break; + case _SI: + usRet |= mSI; + break; + case _DI: + usRet |= mDI; + break; + default: + break; /// + } + } + break; + + case ASM_MODIFIERS._rseg: + //if (popnd1.base.val == _ES) + //usRet |= mES; + break; + + case ASM_MODIFIERS._rspecial: + break; + } + } + if (usRet & mAX) + asmstate.bReturnax = true; + + return usRet; +} + + +/**************************** + * Fill in the modregrm and sib bytes of code. + */ + +uint X(ubyte r1, ubyte r2) { + return (((r1) * 16) + (r2)); +} + +uint Y(ubyte r1) { + return X(r1, 9); +} + +void asm_make_modrm_byte( +///debug { + ubyte[] puchOpcode, uint* pusIdx, +///} + code *pc, + ushort usFlags, + OPND *popnd, OPND *popnd2) +{ +/// #undef modregrm + + union MODRM_BYTE // mrmb + { + struct MODRM + { + mixin(bitfields!( + uint, "rm", 3, + uint, "reg", 3, + uint, "mod", 2)); + } + + ubyte uchOpcode; + MODRM modregrm; + } + + union SIB_BYTE + { + struct SIB + { + + mixin(bitfields!( + uint, "base", 3, + uint, "index", 3, + uint, "ss", 2)); + } + + ubyte uchOpcode; + SIB sib; + } + + + MODRM_BYTE mrmb; + SIB_BYTE sib; + char bSib = false; + char bDisp = false; + char b32bit = false; + ubyte* puc; + char bModset = false; + Dsymbol s; + + uint uSizemask = 0; + ASM_OPERAND_TYPE aopty; + ASM_MODIFIERS amod; + ushort uRegmask; + ubyte bOffsetsym = false; + +static if (false) { + printf("asm_make_modrm_byte(usFlags = x%x)\n", usFlags); + printf("op1: "); + asm_output_flags(popnd.usFlags); + if (popnd2) + { + printf(" op2: "); + asm_output_flags(popnd2.usFlags); + } + printf("\n"); +} + + uSizemask = ASM_GET_uSizemask(popnd.usFlags); + aopty = ASM_GET_aopty(popnd.usFlags); + amod = ASM_GET_amod(popnd.usFlags); + uRegmask = ASM_GET_uRegmask(popnd.usFlags); + s = popnd.s; + if (s) + { + Declaration d = s.isDeclaration(); + + if (amod == ASM_MODIFIERS._fn16 && aopty == ASM_OPERAND_TYPE._rel && popnd2) + { + aopty = ASM_OPERAND_TYPE._m; + goto L1; + } + + if (amod == ASM_MODIFIERS._fn16 || amod == ASM_MODIFIERS._fn32) + { + pc.Iflags |= CF.CFoff; +debug { + puchOpcode[(*pusIdx)++] = 0; + puchOpcode[(*pusIdx)++] = 0; +} + if (aopty == ASM_OPERAND_TYPE._m || aopty == ASM_OPERAND_TYPE._mnoi) + { + pc.IFL1 = FL.FLdata; + pc.IEVdsym1() = d; + pc.IEVoffset1() = 0; + } + else + { + if (aopty == ASM_OPERAND_TYPE._p) + pc.Iflags |= CF.CFseg; + + debug if (aopty == ASM_OPERAND_TYPE._p || aopty == ASM_OPERAND_TYPE._rel) + { + puchOpcode[(*pusIdx)++] = 0; + puchOpcode[(*pusIdx)++] = 0; + } + + pc.IFL2 = FL.FLfunc; + pc.IEVdsym2() = d; + pc.IEVoffset2() = 0; + //return; + } + } + else + { + L1: + LabelDsymbol label = s.isLabel(); + if (label) + { + if (s == asmstate.psDollar) + { + pc.IFL1 = FL.FLconst; + if (uSizemask & (_8 | _16)) + pc.IEVint1() = popnd.disp; + else if (uSizemask & _32) + pc.IEVpointer1() = cast(targ_size_t) popnd.disp; + } + else + { + pc.IFL1 = FL.FLblockoff; + pc.IEVlsym1() = label; + } + } + else if (s == asmstate.psLocalsize) + { + pc.IFL1 = FL.FLlocalsize; + pc.IEVdsym1() = null; + pc.Iflags |= CF.CFoff; + pc.IEVoffset1() = popnd.disp; + } + else if (s.isFuncDeclaration()) + { + pc.IFL1 = FL.FLfunc; + pc.IEVdsym1() = d; + pc.IEVoffset1() = popnd.disp; + } + else + { + debug if (debuga) + printf("Setting up symbol %s\n", d.ident.toChars()); + + pc.IFL1 = FL.FLdsymbol; + pc.IEVdsym1() = d; + pc.Iflags |= CF.CFoff; + pc.IEVoffset1() = popnd.disp; + } + } + } + + mrmb.modregrm.reg = usFlags & NUM_MASK; + + if (s && (aopty == ASM_OPERAND_TYPE._m || aopty == ASM_OPERAND_TYPE._mnoi) && !s.isLabel()) + { + if (s == asmstate.psLocalsize) + { + DATA_REF: + mrmb.modregrm.rm = BPRM; + if (amod == ASM_MODIFIERS._addr16 || amod == ASM_MODIFIERS._addr32) + mrmb.modregrm.mod = 0x2; + else + mrmb.modregrm.mod = 0x0; + } + else + { + Declaration d = s.isDeclaration(); + assert(d); + if (d.isDataseg() || d.isCodeseg()) + { + if (( I32 && amod == ASM_MODIFIERS._addr16) || + (!I32 && amod == ASM_MODIFIERS._addr32)) + asmerr(ASMERRMSGS.EM_bad_addr_mode); // illegal addressing mode + goto DATA_REF; + } + mrmb.modregrm.rm = BPRM; + mrmb.modregrm.mod = 0x2; + } + } + + if (aopty == ASM_OPERAND_TYPE._reg || amod == ASM_MODIFIERS._rspecial) { + mrmb.modregrm.mod = 0x3; + mrmb.modregrm.rm = mrmb.modregrm.rm | popnd.base.val; + } + else if (amod == ASM_MODIFIERS._addr16 || (amod == ASM_MODIFIERS._flbl && !I32)) + { + uint rm; + + debug if (debuga) + printf("This is an ADDR16\n"); + + if (!popnd.pregDisp1) + { rm = 0x6; + if (!s) + bDisp = true; + } + else + { + uint r1r2; + + if (popnd.pregDisp2) + r1r2 = X(popnd.pregDisp1.val,popnd.pregDisp2.val); + else + r1r2 = Y(popnd.pregDisp1.val); + + switch (r1r2) + { + case X(_BX,_SI): rm = 0; break; + case X(_BX,_DI): rm = 1; break; + case Y(_BX): rm = 7; break; + + case X(_BP,_SI): rm = 2; break; + case X(_BP,_DI): rm = 3; break; + case Y(_BP): rm = 6; bDisp = true; break; + + case X(_SI,_BX): rm = 0; break; + case X(_SI,_BP): rm = 2; break; + case Y(_SI): rm = 4; break; + + case X(_DI,_BX): rm = 1; break; + case X(_DI,_BP): rm = 3; break; + case Y(_DI): rm = 5; break; + + default: + asmerr(ASMERRMSGS.EM_bad_addr_mode); // illegal addressing mode + } + } + mrmb.modregrm.rm = rm; + + debug if (debuga) + printf("This is an mod = %d, popnd.s =%ld, popnd.disp = %ld\n", + mrmb.modregrm.mod, s, popnd.disp); + + if (!s || (!mrmb.modregrm.mod && popnd.disp)) + { + if ((!popnd.disp && !bDisp) || !popnd.pregDisp1) + mrmb.modregrm.mod = 0x0; + else if (popnd.disp >= CHAR_MIN && popnd.disp <= SCHAR_MAX) + mrmb.modregrm.mod = 0x1; + else + mrmb.modregrm.mod = 0X2; + } + else + bOffsetsym = true; + + } + else if (amod == ASM_MODIFIERS._addr32 || (amod == ASM_MODIFIERS._flbl && I32)) + { + debug if (debuga) + printf("This is an ADDR32\n"); + + if (!popnd.pregDisp1) + mrmb.modregrm.rm = 0x5; + else if (popnd.pregDisp2 || + popnd.uchMultiplier || + popnd.pregDisp1.val == _ESP) + { + if (popnd.pregDisp2) + { + if (popnd.pregDisp2.val == _ESP) + asmerr(ASMERRMSGS.EM_bad_addr_mode); // illegal addressing mode + } + else + { + if (popnd.uchMultiplier && popnd.pregDisp1.val ==_ESP) + asmerr(ASMERRMSGS.EM_bad_addr_mode); // illegal addressing mode + bDisp = true; + } + + mrmb.modregrm.rm = 0x4; + bSib = true; + if (bDisp) + { + if (!popnd.uchMultiplier && + popnd.pregDisp1.val==_ESP) + { + sib.sib.base = popnd.pregDisp1.val; + sib.sib.index = 0x4; + } + else + { + debug if (debuga) + printf("Resetting the mod to 0\n"); + + if (popnd.pregDisp2) + { + if (popnd.pregDisp2.val != _EBP) + asmerr(ASMERRMSGS.EM_bad_addr_mode); // illegal addressing mode + } + else + { + mrmb.modregrm.mod = 0x0; + bModset = true; + } + + sib.sib.base = 0x5; + sib.sib.index = popnd.pregDisp1.val; + } + } + else + { + sib.sib.base = popnd.pregDisp1.val; + // + // This is to handle the special case + // of using the EBP register and no + // displacement. You must put in an + // 8 byte displacement in order to + // get the correct opcodes. + // + if (popnd.pregDisp1.val == _EBP && (!popnd.disp && !s)) + { + debug if (debuga) + printf("Setting the mod to 1 in the _EBP case\n"); + + mrmb.modregrm.mod = 0x1; + bDisp = true; // Need a + // displacement + bModset = true; + } + + sib.sib.index = popnd.pregDisp2.val; + } + switch (popnd.uchMultiplier) + { + case 0: sib.sib.ss = 0; break; + case 1: sib.sib.ss = 0; break; + case 2: sib.sib.ss = 1; break; + case 4: sib.sib.ss = 2; break; + case 8: sib.sib.ss = 3; break; + + default: + asmerr(ASMERRMSGS.EM_bad_addr_mode); // illegal addressing mode + break; + } + if (bDisp && sib.sib.base == 0x5) + b32bit = true; + } + else + { + uint rm; + + if (popnd.uchMultiplier) + asmerr(ASMERRMSGS.EM_bad_addr_mode); // illegal addressing mode + switch (popnd.pregDisp1.val) + { + case _EAX: rm = 0; break; + case _ECX: rm = 1; break; + case _EDX: rm = 2; break; + case _EBX: rm = 3; break; + case _ESI: rm = 6; break; + case _EDI: rm = 7; break; + + case _EBP: + if (!popnd.disp && !s) + { + mrmb.modregrm.mod = 0x1; + bDisp = true; // Need a displacement + bModset = true; + } + rm = 5; + break; + + default: + asmerr(ASMERRMSGS.EM_bad_addr_mode); // illegal addressing mode + break; + } + mrmb.modregrm.rm = rm; + } + if (!bModset && (!s || (!mrmb.modregrm.mod && popnd.disp))) + { + if ((!popnd.disp && !mrmb.modregrm.mod) || + (!popnd.pregDisp1 && !popnd.pregDisp2)) + { + mrmb.modregrm.mod = 0x0; + bDisp = true; + } + else if (popnd.disp >= CHAR_MIN && popnd.disp <= SCHAR_MAX) + mrmb.modregrm.mod = 0x1; + else + mrmb.modregrm.mod = 0x2; + } + else + bOffsetsym = true; + } + if (popnd2 && !mrmb.modregrm.reg && + asmstate.ucItype != IT.ITshift && + (ASM_GET_aopty(popnd2.usFlags) == ASM_OPERAND_TYPE._reg || + ASM_GET_amod(popnd2.usFlags) == ASM_MODIFIERS._rseg || + ASM_GET_amod(popnd2.usFlags) == ASM_MODIFIERS._rspecial)) + { + mrmb.modregrm.reg = popnd2.base.val; + } + debug puchOpcode[ (*pusIdx)++ ] = mrmb.uchOpcode; + + pc.Irm = mrmb.uchOpcode; + //printf("Irm = %02x\n", pc.Irm); + if (bSib) + { + debug puchOpcode[ (*pusIdx)++ ] = sib.uchOpcode; + pc.Isib= sib.uchOpcode; + } + if ((!s || (popnd.pregDisp1 && !bOffsetsym)) && + aopty != ASM_OPERAND_TYPE._imm && + (popnd.disp || bDisp)) + { + if (popnd.usFlags & _a16) + { + debug { + puc = (cast(ubyte*) &(popnd.disp)); + puchOpcode[(*pusIdx)++] = puc[1]; + puchOpcode[(*pusIdx)++] = puc[0]; + } + if (usFlags & (_modrm | NUM_MASK)) { + debug if (debuga) + printf("Setting up value %ld\n", popnd.disp); + + pc.IEVint1() = popnd.disp; + pc.IFL1 = FL.FLconst; + } + else { + pc.IEVint2() = popnd.disp; + pc.IFL2 = FL.FLconst; + } + + } + else + { + debug { + puc = (cast(ubyte*) &(popnd.disp)); + puchOpcode[(*pusIdx)++] = puc[3]; + puchOpcode[(*pusIdx)++] = puc[2]; + puchOpcode[(*pusIdx)++] = puc[1]; + puchOpcode[(*pusIdx)++] = puc[0]; + } + if (usFlags & (_modrm | NUM_MASK)) { + debug if (debuga) + printf("Setting up value %ld\n", popnd.disp); + + pc.IEVpointer1() = cast(targ_size_t) popnd.disp; + pc.IFL1 = FL.FLconst; + } else { + pc.IEVpointer2() = cast(targ_size_t) popnd.disp; + pc.IFL2 = FL.FLconst; + } + } + } +} + +void asm_output_popnd(OPND* popnd) +{ + if (popnd.segreg) + printf("%s:", popnd.segreg.regstr); + + if (popnd.s) + writef("%s", popnd.s.ident.toChars()); + + if (popnd.base) + printf("%s", popnd.base.regstr); + + if (popnd.pregDisp1) { + if (popnd.pregDisp2) { + if (popnd.usFlags & _a32) + if (popnd.uchMultiplier) + printf("[%s][%s*%d]", + popnd.pregDisp1.regstr, + popnd.pregDisp2.regstr, + popnd.uchMultiplier); + else + printf("[%s][%s]", + popnd.pregDisp1.regstr, + popnd.pregDisp2.regstr); + else + printf("[%s+%s]", + popnd.pregDisp1.regstr, + popnd.pregDisp2.regstr); + } + else { + if (popnd.uchMultiplier) + printf("[%s*%d]", + popnd.pregDisp1.regstr, + popnd.uchMultiplier); + else + printf("[%s]", + popnd.pregDisp1.regstr); + } + } + if (ASM_GET_aopty(popnd.usFlags) == ASM_OPERAND_TYPE._imm) + printf("%lxh", popnd.disp); + else if (popnd.disp) + printf("+%lxh", popnd.disp); +} + +/******************************* + * Prepend line number to c. + */ + +code* asm_genloc(Loc loc, code* c) +{ + if (global.params.symdebug) + { + code* pcLin; + Srcpos srcpos; + + srcpos.Slinnum = loc.linnum; + srcpos.Sfilename = cast(char*)toStringz(loc.filename); + pcLin = genlinnum(null, srcpos); + + c = cat(pcLin, c); + } + + return c; +} + +opflag_t asm_determine_operand_flags(OPND* popnd) +{ + Dsymbol ps; + int ty; + opflag_t us; + opflag_t sz; + ASM_OPERAND_TYPE opty; + ASM_MODIFIERS amod; + + // If specified 'offset' or 'segment' but no symbol + if ((popnd.bOffset || popnd.bSeg) && !popnd.s) + asmerr(ASMERRMSGS.EM_bad_addr_mode); // illegal addressing mode + + if (asmstate.ucItype == IT.ITfloat) + return asm_determine_float_flags(popnd); + + // If just a register + if (popnd.base && !popnd.s && !popnd.disp && !popnd.real_) + return popnd.base.ty; + + debug if (debuga) + printf("popnd.base = %s\n, popnd.pregDisp1 = %ld\n", popnd.base ? popnd.base.regstr : "NONE", popnd.pregDisp1); + + ps = popnd.s; + Declaration ds = ps ? ps.isDeclaration() : null; + if (ds && ds.storage_class & STC.STClazy) + sz = _anysize; + else + sz = cast(ushort)asm_type_size((ds && ds.storage_class & (STC.STCout | STC.STCref)) ? popnd.ptype.pointerTo() : popnd.ptype); + if (popnd.pregDisp1 && !popnd.base) + { + if (ps && ps.isLabel() && sz == _anysize) + sz = I32 ? _32 : _16; + return (popnd.pregDisp1.ty & _r32) + ? CONSTRUCT_FLAGS(sz, ASM_OPERAND_TYPE._m, ASM_MODIFIERS._addr32, 0) + : CONSTRUCT_FLAGS(sz, ASM_OPERAND_TYPE._m, ASM_MODIFIERS._addr16, 0); + } + else if (ps) + { + if (popnd.bOffset || popnd.bSeg || ps == asmstate.psLocalsize) + return I32 + ? CONSTRUCT_FLAGS(_32, ASM_OPERAND_TYPE._imm, ASM_MODIFIERS._normal, 0) + : CONSTRUCT_FLAGS(_16, ASM_OPERAND_TYPE._imm, ASM_MODIFIERS._normal, 0); + + if (ps.isLabel()) + { + switch (popnd.ajt) + { + case ASM_JUMPTYPE.ASM_JUMPTYPE_UNSPECIFIED: + if (ps == asmstate.psDollar) + { + if (popnd.disp >= CHAR_MIN && + popnd.disp <= CHAR_MAX) + us = CONSTRUCT_FLAGS(_8, _rel, ASM_MODIFIERS._flbl,0); + else + if (popnd.disp >= SHRT_MIN && + popnd.disp <= SHRT_MIN) + us = CONSTRUCT_FLAGS(_16, _rel, ASM_MODIFIERS._flbl,0); + else + us = CONSTRUCT_FLAGS(_32, _rel, ASM_MODIFIERS._flbl,0); + } + else if (asmstate.ucItype != ITjump) + { + if (sz == _8) + { us = CONSTRUCT_FLAGS(_8,ASM_OPERAND_TYPE._rel,ASM_MODIFIERS._flbl,0); + break; + } + goto case_near; + } + else + us = I32 + ? CONSTRUCT_FLAGS(_8|_32, ASM_OPERAND_TYPE._rel, ASM_MODIFIERS._flbl, 0) + : CONSTRUCT_FLAGS(_8|_16, ASM_OPERAND_TYPE._rel, ASM_MODIFIERS._flbl, 0); + break; + + case ASM_JUMPTYPE.ASM_JUMPTYPE_NEAR: + case_near: + us = I32 + ? CONSTRUCT_FLAGS(_32, _rel, _flbl, 0) + : CONSTRUCT_FLAGS(_16, _rel, _flbl, 0); + break; + case ASM_JUMPTYPE.ASM_JUMPTYPE_SHORT: + us = CONSTRUCT_FLAGS(_8, _rel, _flbl, 0); + break; + case ASM_JUMPTYPE.ASM_JUMPTYPE_FAR: + us = I32 + ? CONSTRUCT_FLAGS(_48, _rel, _flbl, 0) + : CONSTRUCT_FLAGS(_32, _rel, _flbl, 0); + break; + default: + assert(0); + } + return us; + } + if (!popnd.ptype) + return CONSTRUCT_FLAGS(sz, _m, _normal, 0); + ty = popnd.ptype.ty; + if (ty == Tpointer && popnd.ptype.nextOf().ty == Tfunction && + !ps.isVarDeclaration()) + { +static if (true) { + return CONSTRUCT_FLAGS(_32, _m, _fn16, 0); +} else { + ty = popnd.ptype.Tnext.Tty; + if (tyfarfunc(tybasic(ty))) { + return I32 + ? CONSTRUCT_FLAGS(_48, _mnoi, _fn32, 0) + : CONSTRUCT_FLAGS(_32, _mnoi, _fn32, 0); + } + else { + return I32 + ? CONSTRUCT_FLAGS(_32, _m, _fn16, 0) + : CONSTRUCT_FLAGS(_16, _m, _fn16, 0); + } +} + } + else if (ty == TY.Tfunction) + { +static if (true) { + return CONSTRUCT_FLAGS(_32, _rel, _fn16, 0); +} else { + if (tyfarfunc(tybasic(ty))) + return I32 + ? CONSTRUCT_FLAGS(_48, _p, _fn32, 0) + : CONSTRUCT_FLAGS(_32, _p, _fn32, 0); + else + return I32 + ? CONSTRUCT_FLAGS(_32, _rel, _fn16, 0) + : CONSTRUCT_FLAGS(_16, _rel, _fn16, 0); +} + } + else if (asmstate.ucItype == IT.ITjump) + { + amod = _normal; + goto L1; + } + else + return CONSTRUCT_FLAGS(sz, _m, _normal, 0); + } + if (popnd.segreg /*|| popnd.bPtr*/) + { + amod = I32 ? _addr32 : _addr16; + if (asmstate.ucItype == ITjump) + { + L1: + opty = _m; + if (I32) + { if (sz == _48) + opty = _mnoi; + } + else + { + if (sz == _32) + opty = _mnoi; + } + us = CONSTRUCT_FLAGS(sz,opty,amod,0); + } + else + us = CONSTRUCT_FLAGS(sz, +// _rel, amod, 0); + _m, amod, 0); + } + + else if (popnd.ptype) + us = CONSTRUCT_FLAGS(sz, _imm, _normal, 0); + + else if (popnd.disp >= CHAR_MIN && popnd.disp <= UCHAR_MAX) + us = CONSTRUCT_FLAGS(_8 | _16 | _32, _imm, _normal, 0); + else if (popnd.disp >= SHRT_MIN && popnd.disp <= USHRT_MAX) + us = CONSTRUCT_FLAGS(_16 | _32, _imm, _normal, 0); + else + us = CONSTRUCT_FLAGS(_32, _imm, _normal, 0); + return us; +} + +/******************************* + * Match flags in operand against flags in opcode table. + * Returns: + * !=0 if match + */ + +ubyte asm_match_flags(opflag_t usOp, opflag_t usTable) +{ + ASM_OPERAND_TYPE aoptyTable; + ASM_OPERAND_TYPE aoptyOp; + ASM_MODIFIERS amodTable; + ASM_MODIFIERS amodOp; + uint uRegmaskTable; + uint uRegmaskOp; + ubyte bRegmatch; + ubyte bRetval = false; + uint uSizemaskOp; + uint uSizemaskTable; + ubyte bSizematch; + + //printf("asm_match_flags(usOp = x%x, usTable = x%x)\n", usOp, usTable); + if (asmstate.ucItype == IT.ITfloat) + { + bRetval = asm_match_float_flags(usOp, usTable); + goto EXIT; + } + + uSizemaskOp = ASM_GET_uSizemask(usOp); + uSizemaskTable = ASM_GET_uSizemask(usTable); + + // Check #1, if the sizes do not match, NO match + bSizematch = (uSizemaskOp & uSizemaskTable) != 0; + + amodOp = ASM_GET_amod(usOp); + + aoptyTable = ASM_GET_aopty(usTable); + aoptyOp = ASM_GET_aopty(usOp); + + // _mmm64 matches with a 64 bit mem or an MMX register + if (usTable == _mmm64) + { + if (usOp == _mm) + goto Lmatch; + if (aoptyOp == _m && (bSizematch || uSizemaskOp == _anysize)) + goto Lmatch; + goto EXIT; + } + + // _xmm_m32, _xmm_m64, _xmm_m128 match with XMM register or memory + if (usTable == _xmm_m32 || + usTable == _xmm_m64 || + usTable == _xmm_m128) + { + if (usOp == _xmm) + goto Lmatch; + if (aoptyOp == _m && (bSizematch || uSizemaskOp == _anysize)) + goto Lmatch; + } + + if (!bSizematch && uSizemaskTable) + { + //printf("no size match\n"); + goto EXIT; + } + + +// +// The operand types must match, otherwise return false. +// There is one exception for the _rm which is a table entry which matches +// _reg or _m +// + if (aoptyTable != aoptyOp) + { + if (aoptyTable == _rm && (aoptyOp == _reg || + aoptyOp == _m || + aoptyOp == _rel)) + goto Lok; + + if (aoptyTable == _mnoi && aoptyOp == _m && + (uSizemaskOp == _32 && amodOp == _addr16 || + uSizemaskOp == _48 && amodOp == _addr32 || + uSizemaskOp == _48 && amodOp == _normal) + ) + goto Lok; + goto EXIT; + } +Lok: + +// +// Looks like a match so far, check to see if anything special is going on +// + amodTable = ASM_GET_amod(usTable); + uRegmaskOp = ASM_GET_uRegmask(usOp); + uRegmaskTable = ASM_GET_uRegmask(usTable); + bRegmatch = ((!uRegmaskTable && !uRegmaskOp) || + (uRegmaskTable & uRegmaskOp)); + + switch (amodTable) + { + case _normal: // Normal's match with normals + switch(amodOp) { + case _normal: + case _addr16: + case _addr32: + case _fn16: + case _fn32: + case _flbl: + bRetval = (bSizematch || bRegmatch); + goto EXIT; + default: + goto EXIT; + } + case _rseg: + case _rspecial: + bRetval = (amodOp == amodTable && bRegmatch); + goto EXIT; + } +EXIT: +static if (false) { + printf("OP : "); + asm_output_flags(usOp); + printf("\nTBL: "); + asm_output_flags(usTable); + writef(": %s\n", bRetval ? "MATCH" : "NOMATCH"); +} + return bRetval; + +Lmatch: + //printf("match\n"); + return 1; +} + +void asm_output_flags(opflag_t usFlags) +{ + ASM_OPERAND_TYPE aopty = ASM_GET_aopty(usFlags); + ASM_MODIFIERS amod = ASM_GET_amod(usFlags); + uint uRegmask = ASM_GET_uRegmask(usFlags); + uint uSizemask = ASM_GET_uSizemask(usFlags); + + if (uSizemask == _anysize) + printf("_anysize "); + else if (uSizemask == 0) + printf("0 "); + else + { + if (uSizemask & _8) + printf("_8 "); + if (uSizemask & _16) + printf("_16 "); + if (uSizemask & _32) + printf("_32 "); + if (uSizemask & _48) + printf("_48 "); + } + + printf("_"); + switch (aopty) { + case ASM_OPERAND_TYPE._reg: + printf("reg "); + break; + case ASM_OPERAND_TYPE._m: + printf("m "); + break; + case ASM_OPERAND_TYPE._imm: + printf("imm "); + break; + case ASM_OPERAND_TYPE._rel: + printf("rel "); + break; + case ASM_OPERAND_TYPE._mnoi: + printf("mnoi "); + break; + case ASM_OPERAND_TYPE._p: + printf("p "); + break; + case ASM_OPERAND_TYPE._rm: + printf("rm "); + break; + case ASM_OPERAND_TYPE._float: + printf("float "); + break; + default: + printf(" UNKNOWN "); + } + + printf("_"); + switch (amod) { + case ASM_MODIFIERS._normal: + printf("normal "); + if (uRegmask & 1) printf("_al "); + if (uRegmask & 2) printf("_ax "); + if (uRegmask & 4) printf("_eax "); + if (uRegmask & 8) printf("_dx "); + if (uRegmask & 0x10) printf("_cl "); + return; + case ASM_MODIFIERS._rseg: + printf("rseg "); + break; + case ASM_MODIFIERS._rspecial: + printf("rspecial "); + break; + case ASM_MODIFIERS._addr16: + printf("addr16 "); + break; + case ASM_MODIFIERS._addr32: + printf("addr32 "); + break; + case ASM_MODIFIERS._fn16: + printf("fn16 "); + break; + case ASM_MODIFIERS._fn32: + printf("fn32 "); + break; + case ASM_MODIFIERS._flbl: + printf("flbl "); + break; + default: + printf("UNKNOWN "); + break; + } + + printf("uRegmask=x%02x", uRegmask); +} + +OPND* asm_log_or_exp() +{ + OPND* o1 = asm_log_and_exp(); + OPND* o2; + + while (tok_value == TOK.TOKoror) + { + asm_token(); + o2 = asm_log_and_exp(); + if (asm_isint(o1) && asm_isint(o2)) + o1.disp = o1.disp || o2.disp; + else + asmerr(ASMERRMSGS.EM_bad_integral_operand); // illegal operand + o2.disp = 0; + o1 = asm_merge_opnds(o1, o2); + } + return o1; +} + +void asm_chktok(TOK toknum, uint errnum) +{ + if (tok_value == toknum) + asm_token(); // scan past token + else + /* When we run out of tokens, asmtok is null. + * But when this happens when a ';' was hit. + */ + asmerr(errnum, asmtok ? asmtok.toChars() : ";"); +} + +opflag_t asm_determine_float_flags(OPND* popnd) +{ + //printf("asm_determine_float_flags()\n"); + + opflag_t us; + opflag_t usFloat; + + // Insure that if it is a register, that it is not a normal processor + // register. + + if (popnd.base && + !popnd.s && !popnd.disp && !popnd.real_ + && !(popnd.base.ty & (_r8 | _r16 | _r32))) + { + return popnd.base.ty; + } + if (popnd.pregDisp1 && !popnd.base) + { + us = asm_float_type_size(popnd.ptype, &usFloat); + //printf("us = x%x, usFloat = x%x\n", us, usFloat); + if (popnd.pregDisp1.ty & _r32) + return(CONSTRUCT_FLAGS(us, _m, _addr32, usFloat)); + else if (popnd.pregDisp1.ty & _r16) + return(CONSTRUCT_FLAGS(us, _m, _addr16, usFloat)); + } + else if (popnd.s !is null) + { + us = asm_float_type_size(popnd.ptype, &usFloat); + return CONSTRUCT_FLAGS(us, _m, _normal, usFloat); + } + + if (popnd.segreg) + { + us = asm_float_type_size(popnd.ptype, &usFloat); + if (I32) + return(CONSTRUCT_FLAGS(us, _m, _addr32, usFloat)); + else + return(CONSTRUCT_FLAGS(us, _m, _addr16, usFloat)); + } + +static if (false) { + if (popnd.real_) + { + switch (popnd.ptype.ty) + { + case TY.Tfloat32: + popnd.s = fconst(popnd.real_); + return(CONSTRUCT_FLAGS(_32, _m, _normal, 0)); + + case TY.Tfloat64: + popnd.s = dconst(popnd.real_); + return(CONSTRUCT_FLAGS(0, _m, _normal, _64)); + + case TY.Tfloat80: + popnd.s = ldconst(popnd.real_); + return(CONSTRUCT_FLAGS(0, _m, _normal, _80)); + } + } +} + + asmerr(ASMERRMSGS.EM_bad_float_op); // unknown operand for floating point instruction + return 0; +} + +uint asm_type_size(Type ptype) +{ + //if (ptype) printf("asm_type_size('%s') = %d\n", ptype.toChars(), (int)ptype.size()); + uint u = _anysize; + if (ptype && ptype.ty != TY.Tfunction /*&& ptype.isscalar()*/) + { + switch (cast(int)ptype.size()) + { + case 0: asmerr(ASMERRMSGS.EM_bad_op, "0 size"); break; + case 1: u = _8; break; + case 2: u = _16; break; + case 4: u = _32; break; + case 6: u = _48; break; + default: + break; /// + } + } + return u; +} + +bool asm_match_float_flags(opflag_t usOp, opflag_t usTable) +{ + ASM_OPERAND_TYPE aoptyTable; + ASM_OPERAND_TYPE aoptyOp; + ASM_MODIFIERS amodTable; + ASM_MODIFIERS amodOp; + uint uRegmaskTable; + uint uRegmaskOp; + ubyte bRegmatch; + + +// +// Check #1, if the sizes do not match, NO match +// + uRegmaskOp = ASM_GET_uRegmask(usOp); + uRegmaskTable = ASM_GET_uRegmask(usTable); + bRegmatch = (uRegmaskTable & uRegmaskOp) != 0; + + if (!(ASM_GET_uSizemask(usTable) & ASM_GET_uSizemask(usOp) || bRegmatch)) + return false; + + aoptyTable = ASM_GET_aopty(usTable); + aoptyOp = ASM_GET_aopty(usOp); +// +// The operand types must match, otherwise return false. +// There is one exception for the _rm which is a table entry which matches +// _reg or _m +// + if (aoptyTable != aoptyOp) + { + if (aoptyOp != _float) + return false; + } + +// +// Looks like a match so far, check to see if anything special is going on +// + amodOp = ASM_GET_amod(usOp); + amodTable = ASM_GET_amod(usTable); + switch (amodTable) + { + // Normal's match with normals + case _normal: + switch(amodOp) + { + case _normal: + case _addr16: + case _addr32: + case _fn16: + case _fn32: + case _flbl: + return true; + + default: + return false; + } + + case _rseg: + case _rspecial: + return false; + default: + assert(0); + } +} + +OPND* asm_log_and_exp() +{ + OPND* o1 = asm_inc_or_exp(); + OPND* o2; + + while (tok_value == TOKandand) + { + asm_token(); + o2 = asm_inc_or_exp(); + if (asm_isint(o1) && asm_isint(o2)) + o1.disp = o1.disp && o2.disp; + else { + asmerr(EM_bad_integral_operand); // illegal operand + } + o2.disp = 0; + o1 = asm_merge_opnds(o1, o2); + } + return o1; +} + +bool asm_isint(OPND *o) +{ + if (!o || o.base || o.s) + return false; + + //return o.disp != 0; + return true; +} + +/******************************* + * Merge operands o1 and o2 into a single operand. + */ + +OPND* asm_merge_opnds(OPND* o1, OPND* o2) +{ + debug immutable(char)* psz; + debug if (debuga) + { + printf("asm_merge_opnds(o1 = "); + if (o1) asm_output_popnd(o1); + printf(", o2 = "); + if (o2) asm_output_popnd(o2); + printf(")\n"); + } + + if (!o1) + return o2; + if (!o2) + return o1; +version (EXTRA_DEBUG) { + printf("Combining Operands: mult1 = %d, mult2 = %d", + o1.uchMultiplier, o2.uchMultiplier); +} + /* combine the OPND's disp field */ + if (o2.segreg) { + if (o1.segreg) { + debug psz = "o1.segment && o2.segreg".ptr; + goto ILLEGAL_ADDRESS_ERROR; + } + else + o1.segreg = o2.segreg; + } + + // combine the OPND's symbol field + if (o1.s && o2.s) + { + debug psz = "o1.s && os.s"; +ILLEGAL_ADDRESS_ERROR: + debug printf("Invalid addr because /%s/\n", psz); + + asmerr(EM_bad_addr_mode); // illegal addressing mode + } + else if (o2.s) + o1.s = o2.s; + else if (o1.s && o1.s.isTupleDeclaration()) + { + TupleDeclaration tup = o1.s.isTupleDeclaration(); + + size_t index = o2.disp; + if (index >= tup.objects.dim) + error(asmstate.loc, "tuple index %u exceeds %u", index, tup.objects.dim); + else + { + Object o = cast(Object)tup.objects.data[index]; + if (auto d = cast(Dsymbol)o) + { + o1.s = d; + return o1; + } + else if (auto e = cast(Expression)o) + { + if (e.op == TOKvar) + { + o1.s = (cast(VarExp)e).var; + return o1; + } + else if (e.op == TOKfunction) + { + o1.s = (cast(FuncExp)e).fd; + return o1; + } + } + error(asmstate.loc, "invalid asm operand %s", o1.s.toChars()); + } + } + + if (o1.disp && o2.disp) + o1.disp += o2.disp; + else if (o2.disp) + o1.disp = o2.disp; + + /* combine the OPND's base field */ + if (o1.base !is null && o2.base !is null) { + debug psz = "o1.base != null && o2.base != null".ptr; + goto ILLEGAL_ADDRESS_ERROR; + } + else if (o2.base) + o1.base = o2.base; + + /* Combine the displacement register fields */ + if (o2.pregDisp1) + { + if (o1.pregDisp2) + { + debug psz = "o2.pregDisp1 && o1.pregDisp2"; + goto ILLEGAL_ADDRESS_ERROR; + } + else if (o1.pregDisp1) + { + if (o1.uchMultiplier || + (o2.pregDisp1.val == _ESP && + (o2.pregDisp1.ty & _r32) && + !o2.uchMultiplier)) + { + o1.pregDisp2 = o1.pregDisp1; + o1.pregDisp1 = o2.pregDisp1; + } + else + o1.pregDisp2 = o2.pregDisp1; + } + else + o1.pregDisp1 = o2.pregDisp1; + } + if (o2.pregDisp2) { + if (o1.pregDisp2) { + debug psz = "o1.pregDisp2 && o2.pregDisp2"; + goto ILLEGAL_ADDRESS_ERROR; + } + else + o1.pregDisp2 = o2.pregDisp2; + } + if (o2.uchMultiplier) + { + if (o1.uchMultiplier) + { + debug psz = "o1.uchMultiplier && o2.uchMultiplier"; + goto ILLEGAL_ADDRESS_ERROR; + } + else + o1.uchMultiplier = o2.uchMultiplier; + } + if (o2.ptype && !o1.ptype) + o1.ptype = o2.ptype; + if (o2.bOffset) + o1.bOffset = o2.bOffset; + if (o2.bSeg) + o1.bSeg = o2.bSeg; + + if (o2.ajt && !o1.ajt) + o1.ajt = o2.ajt; + + opnd_free(o2); +version (EXTRA_DEBUG) { + printf("Result = %d\n", o1.uchMultiplier); +} + debug if (debuga) + { printf("Merged result = /"); + asm_output_popnd(o1); + printf("/\n"); + } + + return o1; +} + +opflag_t asm_float_type_size(Type ptype, opflag_t* pusFloat) +{ + *pusFloat = 0; + + //printf("asm_float_type_size('%s')\n", ptype.toChars()); + if (ptype && ptype.isscalar()) + { + int sz = cast(int)ptype.size(); + if (sz == REALSIZE) + { + *pusFloat = _80; + return 0; + } + switch (sz) + { + case 2: + return _16; + case 4: + return _32; + case 8: + *pusFloat = _64; + return 0; + default: + break; + } + } + + *pusFloat = _fanysize; + return _anysize; +} + +OPND* asm_inc_or_exp() +{ + OPND* o1 = asm_xor_exp(); + OPND* o2; + + while (tok_value == TOKor) + { + asm_token(); + o2 = asm_xor_exp(); + if (asm_isint(o1) && asm_isint(o2)) + o1.disp |= o2.disp; + else { + asmerr(EM_bad_integral_operand); // illegal operand + } + o2.disp = 0; + o1 = asm_merge_opnds(o1, o2); + } + return o1; +} + +OPND* asm_xor_exp() +{ + OPND* o1 = asm_and_exp(); + OPND* o2; + + while (tok_value == TOKxor) + { + asm_token(); + o2 = asm_and_exp(); + if (asm_isint(o1) && asm_isint(o2)) + o1.disp ^= o2.disp; + else { + asmerr(EM_bad_integral_operand); // illegal operand + } + o2.disp = 0; + o1 = asm_merge_opnds(o1, o2); + } + return o1; +} + +OPND* asm_and_exp() +{ + OPND* o1 = asm_equal_exp(); + OPND* o2; + + while (tok_value == TOKand) + { + asm_token(); + o2 = asm_equal_exp(); + if (asm_isint(o1) && asm_isint(o2)) + o1.disp &= o2.disp; + else { + asmerr(EM_bad_integral_operand); // illegal operand + } + o2.disp = 0; + o1 = asm_merge_opnds(o1, o2); + } + return o1; +} + +OPND* asm_equal_exp() +{ + OPND* o1 = asm_rel_exp(); + OPND* o2; + + while (1) + { + switch (tok_value) + { + case TOKequal: + asm_token(); + o2 = asm_rel_exp(); + if (asm_isint(o1) && asm_isint(o2)) + o1.disp = o1.disp == o2.disp; + else { + asmerr(EM_bad_integral_operand); // illegal operand + } + o2.disp = 0; + o1 = asm_merge_opnds(o1, o2); + break; + + case TOKnotequal: + asm_token(); + o2 = asm_rel_exp(); + if (asm_isint(o1) && asm_isint(o2)) + o1.disp = o1.disp != o2.disp; + else { + asmerr(EM_bad_integral_operand); + } + o2.disp = 0; + o1 = asm_merge_opnds(o1, o2); + break; + + default: + return o1; + } + } + + assert(false); +} + +OPND* asm_rel_exp() +{ + OPND* o1 = asm_shift_exp(); + OPND* o2; + + TOK tok_save; + + while (1) + { + switch (tok_value) + { + case TOKgt: + case TOKge: + case TOKlt: + case TOKle: + tok_save = tok_value; + asm_token(); + o2 = asm_shift_exp(); + if (asm_isint(o1) && asm_isint(o2)) + { + switch (tok_save) + { + case TOKgt: + o1.disp = o1.disp > o2.disp; + break; + case TOKge: + o1.disp = o1.disp >= o2.disp; + break; + case TOKlt: + o1.disp = o1.disp < o2.disp; + break; + case TOKle: + o1.disp = o1.disp <= o2.disp; + break; + } + } + else + asmerr(EM_bad_integral_operand); + o2.disp = 0; + o1 = asm_merge_opnds(o1, o2); + break; + + default: + return o1; + } + } + + assert(false); +} + +OPND* asm_shift_exp() +{ + OPND* o1 = asm_add_exp(); + OPND* o2; + + int op; + TOK tk; + + while (tok_value == TOKshl || tok_value == TOKshr || tok_value == TOKushr) + { + tk = tok_value; + asm_token(); + o2 = asm_add_exp(); + if (asm_isint(o1) && asm_isint(o2)) + { if (tk == TOKshl) + o1.disp <<= o2.disp; + else if (tk == TOKushr) + o1.disp = cast(uint)o1.disp >> o2.disp; + else + o1.disp >>= o2.disp; + } + else + asmerr(EM_bad_integral_operand); + o2.disp = 0; + o1 = asm_merge_opnds(o1, o2); + } + return o1; +} + +/******************************* + */ + +OPND* asm_add_exp() +{ + OPND* o1 = asm_mul_exp(); + OPND* o2; + + while (1) + { + switch (tok_value) + { + case TOKadd: + asm_token(); + o2 = asm_mul_exp(); + o1 = asm_merge_opnds(o1, o2); + break; + + case TOKmin: + asm_token(); + o2 = asm_mul_exp(); + if (asm_isint(o1) && asm_isint(o2)) + { + o1.disp -= o2.disp; + o2.disp = 0; + } + else + o2.disp = - o2.disp; + o1 = asm_merge_opnds(o1, o2); + break; + + default: + return o1; + } + } + + assert(false); +} + +/******************************* + */ + +OPND* asm_mul_exp() +{ + OPND* o1; + OPND* o2; + OPND* popndTmp; + + //printf("+asm_mul_exp()\n"); + o1 = asm_br_exp(); + while (1) + { + switch (tok_value) + { + case TOKmul: + asm_token(); + o2 = asm_br_exp(); +version (EXTRA_DEBUG) { + printf("Star o1.isint=%d, o2.isint=%d, lbra_seen=%d\n", + asm_isint(o1), asm_isint(o2), asm_TKlbra_seen ); +} + if (asm_isNonZeroInt(o1) && asm_isNonZeroInt(o2)) + o1.disp *= o2.disp; + else if (asm_TKlbra_seen && o1.pregDisp1 && asm_isNonZeroInt(o2)) + { + o1.uchMultiplier = o2.disp; +version (EXTRA_DEBUG) { + printf("Multiplier: %d\n", o1.uchMultiplier); +} + } + else if (asm_TKlbra_seen && o2.pregDisp1 && asm_isNonZeroInt(o1)) + { + popndTmp = o2; + o2 = o1; + o1 = popndTmp; + o1.uchMultiplier = o2.disp; +version (EXTRA_DEBUG) { + printf("Multiplier: %d\n", + o1.uchMultiplier); +} + } + else if (asm_isint(o1) && asm_isint(o2)) + o1.disp *= o2.disp; + else + asmerr(EM_bad_operand); + o2.disp = 0; + o1 = asm_merge_opnds(o1, o2); + break; + + case TOKdiv: + asm_token(); + o2 = asm_br_exp(); + if (asm_isint(o1) && asm_isint(o2)) + o1.disp /= o2.disp; + else + asmerr(EM_bad_integral_operand); + o2.disp = 0; + o1 = asm_merge_opnds(o1, o2); + break; + + case TOKmod: + asm_token(); + o2 = asm_br_exp(); + if (asm_isint(o1) && asm_isint(o2)) + o1.disp %= o2.disp; + else + asmerr(EM_bad_integral_operand); + o2.disp = 0; + o1 = asm_merge_opnds(o1, o2); + break; + + default: + return o1; + } + } + + return o1; +} + +OPND* asm_br_exp() +{ + //printf("asm_br_exp()\n"); + + OPND* o1 = asm_una_exp(); + OPND* o2; + Declaration s; + + while (1) + { + switch (tok_value) + { + case TOKlbracket: + { +version (EXTRA_DEBUG) { + printf("Saw a left bracket\n"); +} + asm_token(); + asm_TKlbra_seen++; + o2 = asm_cond_exp(); + asm_TKlbra_seen--; + asm_chktok(TOKrbracket,EM_rbra); +version (EXTRA_DEBUG) { + printf("Saw a right bracket\n"); +} + o1 = asm_merge_opnds(o1, o2); + if (tok_value == TOKidentifier) + { o2 = asm_una_exp(); + o1 = asm_merge_opnds(o1, o2); + } + break; + } + default: + return o1; + } + } + + assert(false); +} + +/******************************* + */ + +OPND* asm_una_exp() +{ + OPND* o1; + int op; + Type ptype; + Type ptypeSpec; + ASM_JUMPTYPE ajt = ASM_JUMPTYPE_UNSPECIFIED; + char bPtr = 0; + + switch (cast(int)tok_value) + { +static if (false) { + case TOKand: + asm_token(); + o1 = asm_una_exp(); + break; + + case TOKmul: + asm_token(); + o1 = asm_una_exp(); + ++o1.indirect; + break; +} + case TOKadd: + asm_token(); + o1 = asm_una_exp(); + break; + + case TOKmin: + asm_token(); + o1 = asm_una_exp(); + if (asm_isint(o1)) + o1.disp = -o1.disp; + break; + + case TOKnot: + asm_token(); + o1 = asm_una_exp(); + if (asm_isint(o1)) + o1.disp = !o1.disp; + break; + + case TOKtilde: + asm_token(); + o1 = asm_una_exp(); + if (asm_isint(o1)) + o1.disp = ~o1.disp; + break; + +static if (false) { + case TOKlparen: + // stoken() is called directly here because we really + // want the INT token to be an INT. + stoken(); + if (type_specifier(&ptypeSpec)) /* if type_name */ + { + ptype = declar_abstract(ptypeSpec); + /* read abstract_declarator */ + fixdeclar(ptype);/* fix declarator */ + type_free(ptypeSpec);/* the declar() function + allocates the typespec again */ + chktok(TOKrparen,EM_rpar); + ptype.Tcount--; + goto CAST_REF; + } + else + { + type_free(ptypeSpec); + o1 = asm_cond_exp(); + chktok(TOKrparen, EM_rpar); + } + break; +} + + case TOKidentifier: + // Check for offset keyword + if (asmtok.ident == Id.offset) + { + if (!global.params.useDeprecated) + error(asmstate.loc, "offset deprecated, use offsetof"); + goto Loffset; + } + if (asmtok.ident == Id.offsetof) + { + Loffset: + asm_token(); + o1 = asm_cond_exp(); + if (!o1) + o1 = opnd_calloc(); + o1.bOffset= true; + } + else + o1 = asm_primary_exp(); + break; + + case ASMTK.ASMTKseg: + asm_token(); + o1 = asm_cond_exp(); + if (!o1) + o1 = opnd_calloc(); + o1.bSeg= true; + break; + + case TOKint16: + if (asmstate.ucItype != ITjump) + { + ptype = Type.tint16; + goto TYPE_REF; + } + ajt = ASM_JUMPTYPE_SHORT; + asm_token(); + goto JUMP_REF2; + + case ASMTKnear: + ajt = ASM_JUMPTYPE_NEAR; + goto JUMP_REF; + + case ASMTKfar: + ajt = ASM_JUMPTYPE_FAR; +JUMP_REF: + asm_token(); + asm_chktok(cast(TOK) ASMTKptr, EM_ptr_exp); +JUMP_REF2: + o1 = asm_cond_exp(); + if (!o1) + o1 = opnd_calloc(); + o1.ajt= ajt; + break; + + case TOKint8: + ptype = Type.tint8; + goto TYPE_REF; + case TOKint32: + case ASMTKdword: + ptype = Type.tint32; + goto TYPE_REF; + case TOKfloat32: + ptype = Type.tfloat32; + goto TYPE_REF; + case ASMTKqword: + case TOKfloat64: + ptype = Type.tfloat64; + goto TYPE_REF; + case TOKfloat80: + ptype = Type.tfloat80; + goto TYPE_REF; + case ASMTKword: + ptype = Type.tint16; +TYPE_REF: + bPtr = 1; + asm_token(); + asm_chktok(cast(TOK) ASMTKptr, EM_ptr_exp); +CAST_REF: + o1 = asm_cond_exp(); + if (!o1) + o1 = opnd_calloc(); + o1.ptype = ptype; + o1.bPtr = bPtr; + break; + + default: + o1 = asm_primary_exp(); + break; + } + return o1; +} + +bool asm_isNonZeroInt(OPND* o) +{ + if (!o || o.base || o.s) + return false; + + return o.disp != 0; +} + +OPND* asm_primary_exp() +{ + OPND* o1 = null; + OPND* o2 = null; + Type ptype; + Dsymbol s; + Dsymbol scopesym; + + TOK tkOld; + int global; + REG* regp; + + global = 0; + switch (cast(int)tok_value) + { + case TOKdollar: + o1 = opnd_calloc(); + o1.s = asmstate.psDollar; + asm_token(); + break; + +static if (false) { + case TOKthis: + strcpy(tok.TKid,cpp_name_this); +} + case TOKidentifier: + case_ident: + o1 = opnd_calloc(); + regp = asm_reg_lookup(asmtok.ident.toChars()); + if (regp !is null) + { + asm_token(); + // see if it is segment override (like SS:) + if (!asm_TKlbra_seen && + (regp.ty & _seg) && + tok_value == TOKcolon) + { + o1.segreg = regp; + asm_token(); + o2 = asm_cond_exp(); + o1 = asm_merge_opnds(o1, o2); + } + else if (asm_TKlbra_seen) + { // should be a register + if (o1.pregDisp1) + asmerr(EM_bad_operand); + else + o1.pregDisp1 = regp; + } + else + { if (o1.base == null) + o1.base = regp; + else + asmerr(EM_bad_operand); + } + break; + } + // If floating point instruction and id is a floating register + else if (asmstate.ucItype == ITfloat && + asm_is_fpreg(asmtok.ident.toChars())) + { + asm_token(); + if (tok_value == TOKlparen) + { + uint n; + + asm_token(); + asm_chktok(TOKint32v, EM_num); + n = cast(uint)asmtok.uns64value; + if (n > 7) + asmerr(EM_bad_operand); + o1.base = &(aregFp[n]); + asm_chktok(TOKrparen, EM_rpar); + } + else + o1.base = ®Fp; + } + else + { + if (asmstate.ucItype == ITjump) + { + s = null; + if (asmstate.sc.func.labtab) + s = asmstate.sc.func.labtab.lookup(asmtok.ident); + if (!s) + s = asmstate.sc.search(Loc(0), asmtok.ident, &scopesym); + if (!s) + { // Assume it is a label, and define that label + s = asmstate.sc.func.searchLabel(asmtok.ident); + } + } + else + s = asmstate.sc.search(Loc(0), asmtok.ident, &scopesym); + + if (!s) + asmerr(EM_undefined, asmtok.toChars()); + + Identifier id = asmtok.ident; + asm_token(); + if (tok_value == TOKdot) + { + Expression e; + VarExp v; + + e = new IdentifierExp(asmstate.loc, id); + while (1) + { + asm_token(); + if (tok_value == TOKidentifier) + { + e = new DotIdExp(asmstate.loc, e, asmtok.ident); + asm_token(); + if (tok_value != TOKdot) + break; + } + else + { + asmerr(EM_ident_exp); + break; + } + } + e = e.semantic(asmstate.sc); + e = e.optimize(WANTvalue | WANTinterpret); + if (e.isConst()) + { + if (e.type.isintegral()) + { + o1.disp = cast(int)e.toInteger(); + goto Lpost; + } + else if (e.type.isreal()) + { + o1.real_ = e.toReal(); + o1.ptype = e.type; + goto Lpost; + } + else + { + asmerr(EM_bad_op, e.toChars()); + } + } + else if (e.op == TOKvar) + { + v = cast(VarExp)e; + s = v.var; + } + else + { + asmerr(EM_bad_op, e.toChars()); + } + } + + asm_merge_symbol(o1,s); + + /* This attempts to answer the question: is + * char[8] foo; + * of size 1 or size 8? Presume it is 8 if foo + * is the last token of the operand. + */ + if (o1.ptype && tok_value != TOKcomma && tok_value != TOKeof) + { + for (; + o1.ptype.ty == Tsarray; + o1.ptype = o1.ptype.nextOf()) + { + ; + } + } + + Lpost: +static if (false) { + // for [] + if (tok_value == TOKlbracket) + o1 = asm_prim_post(o1); +} + goto Lret; + } + break; + + case TOKint32v: + case TOKuns32v: + o1 = opnd_calloc(); + o1.disp = asmtok.int32value; + asm_token(); + break; + + case TOKfloat32v: + o1 = opnd_calloc(); + o1.real_ = asmtok.float80value; + o1.ptype = Type.tfloat32; + asm_token(); + break; + + case TOKfloat64v: + o1 = opnd_calloc(); + o1.real_ = asmtok.float80value; + o1.ptype = Type.tfloat64; + asm_token(); + break; + + case TOKfloat80v: + o1 = opnd_calloc(); + o1.real_ = asmtok.float80value; + o1.ptype = Type.tfloat80; + asm_token(); + break; + + case ASMTKlocalsize: + o1 = opnd_calloc(); + o1.s = asmstate.psLocalsize; + o1.ptype = Type.tint32; + asm_token(); + break; + + default: + break; /// + } +Lret: + return o1; +} + +void asm_merge_symbol(OPND* o1, Dsymbol s) +{ + Type ptype; + VarDeclaration v; + EnumMember em; + + //printf("asm_merge_symbol(s = %s %s)\n", s.kind(), s.toChars()); + s = s.toAlias(); + //printf("s = %s %s\n", s.kind(), s.toChars()); + if (s.isLabel()) + { + o1.s = s; + return; + } + + v = s.isVarDeclaration(); + if (v) + { + if (v.isParameter()) + asmstate.statement.refparam = true; + + v.checkNestedReference(asmstate.sc, asmstate.loc); +static if (false) { + if (!v.isDataseg() && v.parent != asmstate.sc.parent && v.parent) + { + asmerr(EM_uplevel, v.toChars()); + } +} + if (v.storage_class & STCfield) + { + o1.disp += v.offset; + goto L2; + } + if ((v.isConst() +///version (DMDV2) { + || v.isInvariant() || v.storage_class & STCmanifest +///} + ) && !v.type.isfloating() && v.init) + { + ExpInitializer ei = v.init.isExpInitializer(); + + if (ei) + { + o1.disp = cast(int)ei.exp.toInteger(); + return; + } + } + } + em = s.isEnumMember(); + if (em) + { + o1.disp = cast(int)em.value.toInteger(); + return; + } + o1.s = s; // a C identifier +L2: + Declaration d = s.isDeclaration(); + if (!d) + { + asmerr("%s %s is not a declaration", s.kind(), s.toChars()); + } + else if (d.getType()) + asmerr(EM_type_as_operand, d.getType().toChars()); + else if (d.isTupleDeclaration()) { + ; + } else + o1.ptype = d.type.toBasetype(); +} + +REG[63] regtab = +[ + {"AL", _AL, _r8 | _al,}, + {"AH", _AH, _r8,}, + {"AX", _AX, _r16 | _ax,}, + {"EAX", _EAX, _r32 | _eax,}, + {"BL", _BL, _r8,}, + {"BH", _BH, _r8,}, + {"BX", _BX, _r16,}, + {"EBX", _EBX, _r32,}, + {"CL", _CL, _r8 | _cl,}, + {"CH", _CH, _r8,}, + {"CX", _CX, _r16,}, + {"ECX", _ECX, _r32,}, + {"DL", _DL, _r8,}, + {"DH", _DH, _r8,}, + {"DX", _DX, _r16 | _dx,}, + {"EDX", _EDX, _r32,}, + {"BP", _BP, _r16,}, + {"EBP", _EBP, _r32,}, + {"SP", _SP, _r16,}, + {"ESP", _ESP, _r32,}, + {"DI", _DI, _r16,}, + {"EDI", _EDI, _r32,}, + {"SI", _SI, _r16,}, + {"ESI", _ESI, _r32,}, + {"ES", _ES, _seg | _es,}, + {"CS", _CS, _seg | _cs,}, + {"SS", _SS, _seg | _ss,}, + {"DS", _DS, _seg | _ds,}, + {"GS", _GS, _seg | _gs,}, + {"FS", _FS, _seg | _fs,}, + {"CR0", 0, _special | _crn,}, + {"CR2", 2, _special | _crn,}, + {"CR3", 3, _special | _crn,}, + {"CR4", 4, _special | _crn,}, + {"DR0", 0, _special | _drn,}, + {"DR1", 1, _special | _drn,}, + {"DR2", 2, _special | _drn,}, + {"DR3", 3, _special | _drn,}, + {"DR4", 4, _special | _drn,}, + {"DR5", 5, _special | _drn,}, + {"DR6", 6, _special | _drn,}, + {"DR7", 7, _special | _drn,}, + {"TR3", 3, _special | _trn,}, + {"TR4", 4, _special | _trn,}, + {"TR5", 5, _special | _trn,}, + {"TR6", 6, _special | _trn,}, + {"TR7", 7, _special | _trn,}, + {"MM0", 0, _mm,}, + {"MM1", 1, _mm,}, + {"MM2", 2, _mm,}, + {"MM3", 3, _mm,}, + {"MM4", 4, _mm,}, + {"MM5", 5, _mm,}, + {"MM6", 6, _mm,}, + {"MM7", 7, _mm,}, + {"XMM0", 0, _xmm,}, + {"XMM1", 1, _xmm,}, + {"XMM2", 2, _xmm,}, + {"XMM3", 3, _xmm,}, + {"XMM4", 4, _xmm,}, + {"XMM5", 5, _xmm,}, + {"XMM6", 6, _xmm,}, + {"XMM7", 7, _xmm,}, +]; + +REG* asm_reg_lookup(string s) +{ + //dbg_printf("asm_reg_lookup('%s')\n",s); + + for (int i = 0; i < regtab.length; i++) + { + if (regtab[i].regstr[0..min(s.length, $)] == s) + { + return ®tab[i]; + } + } + + return null; +} + +int asm_is_fpreg(string szReg) +{ +static if (true) { + return(szReg.length == 2 && szReg[0] == 'S' && + szReg[1] == 'T'); +} else { + return(szReg.length == 2 && (szReg[0] == 's' || szReg[0] == 'S') && + (szReg[1] == 't' || szReg[1] == 'T')); +} +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/immed_t.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/immed_t.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,11 @@ +module dmd.backend.immed_t; + +import dmd.backend.targ_types; +import dmd.backend.regm_t; +import dmd.backend.REGMAX; + +struct immed_t +{ + targ_int value[REGMAX]; // immediate values in registers + regm_t mval; // Mask of which values in regimmed.value[] are valid +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/mTY.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/mTY.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,43 @@ +module dmd.backend.mTY; + +enum mTY +{ + /* Linkage type */ + mTYnear = 0x100, + mTYfar = 0x200, + mTYcs = 0x400, // in code segment + mTYthread = 0x800, + mTYLINK = 0xF00, // all linkage bits + + mTYloadds = 0x1000, + mTYexport = 0x2000, + mTYweak = 0x0000, + mTYimport = 0x4000, + mTYnaked = 0x8000, + mTYMOD = 0xF000, // all modifier bits + + mTYbasic = 0x3F, /* bit mask for basic types */ + + /* Modifiers to basic types */ +/// #ifdef JHANDLE +/// mTYarrayhandle = 0x80, +/// #else + mTYarrayhandle = 0x0, +/// #endif + mTYconst = 0x40, + mTYvolatile = 0x80, + mTYrestrict = 0, // BUG: add for C99 + mTYmutable = 0, // need to add support + mTYunaligned = 0, // non-zero for PowerPC + + mTYimmutable = 0x1000000, // immutable data + mTYshared = 0x2000000, // shared data + mTYnothrow = 0x4000000, // nothrow function +} + +import dmd.EnumUtils; +mixin(BringToCurrentScope!(mTY)); + +uint tybasic(uint ty) { + return ((ty) & mTY.mTYbasic); +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/mTYman.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/mTYman.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,14 @@ +module dmd.backend.mTYman; + +enum mTYman { + mTYman_c = 1, // C mangling + mTYman_cpp = 2, // C++ mangling + mTYman_pas = 3, // Pascal mangling + mTYman_for = 4, // FORTRAN mangling + mTYman_sys = 5, // _syscall mangling + mTYman_std = 6, // _stdcall mangling + mTYman_d = 7, // D mangling +} + +import dmd.EnumUtils; +mixin(BringToCurrentScope!(mTYman)); \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/regm_t.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/regm_t.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,3 @@ +module dmd.backend.regm_t; + +alias ushort regm_t; \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/rel.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/rel.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,32 @@ +module dmd.backend.rel; + +import dmd.backend.OPER; + +extern (C++) extern +{ + ubyte* get_rel_not(); + ubyte* get_rel_swap(); + ubyte* get_rel_integral(); + ubyte* get_rel_exception(); + ubyte* get_rel_unord(); +} + +ubyte rel_not(OPER op) { + return get_rel_not[cast(int)(op) - RELOPMIN]; +} + +ubyte rel_swap(OPER op) { + return get_rel_swap[cast(int)(op) - RELOPMIN]; +} + +ubyte rel_integral(OPER op){ + return get_rel_integral[cast(int)(op) - RELOPMIN]; +} + +ubyte rel_exception(OPER op) { + return get_rel_exception[cast(int)(op) - RELOPMIN]; +} + +ubyte rel_unord(OPER op) { + return get_rel_unord[cast(int)(op) - RELOPMIN]; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/struct_t.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/struct_t.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,134 @@ +module dmd.backend.struct_t; + +import dmd.backend.targ_types; +import dmd.backend.LIST; +import dmd.backend.Symbol; + +/*********************************** + * Special information for structs. + */ + +struct struct_t +{ + targ_size_t Sstructsize; // size of struct + symlist_t Sfldlst; // all members of struct (list freeable) + Symbol* Sroot; // root of binary tree Symbol table + uint Salignsize; // size of struct for alignment purposes + ubyte Sstructalign; // struct member alignment in effect + uint Sflags; +/+ +#define STRanonymous 0x01 // set for unions with no tag names +#define STRglobal 0x02 // defined at file scope +#define STRnotagname 0x04 // struct/class with no tag name +#define STRoutdef 0x08 // we've output the debug definition +#define STRbitfields 0x10 // set if struct contains bit fields +#define STRpredef 0x1000 // a predefined struct +#define STRunion 0x4000 // actually, it's a union + +#define STRabstract 0x20 // abstract class +#define STRbitcopy 0x40 // set if operator=() is merely a bit copy +#define STRanyctor 0x80 // set if any constructors were defined + // by the user +#define STRnoctor 0x100 // no constructors allowed +#define STRgen 0x200 // if struct is an instantiation of a + // template class, and was generated by + // that template +#define STRvtblext 0x400 // generate vtbl[] only when first member function + // definition is encountered (see Fvtblgen) +#define STRexport 0x800 // all member functions are to be _export +#define STRclass 0x8000 // it's a class, not a struct +#if TX86 +#define STRimport 0x40000 // imported class +#define STRstaticmems 0x80000 // class has static members +#endif +#define STR0size 0x100000 // zero sized struct +#define STRinstantiating 0x200000 // if currently being instantiated +#define STRexplicit 0x400000 // if explicit template instantiation +#define STRgenctor0 0x800000 // need to gen X::X() + tym_t ptrtype; // type of pointer to refer to classes by + unsigned short access; // current access privilege, here so + // enum declarations can get at it + targ_size_t Snonvirtsize; // size of struct excluding virtual classes + list_t Svirtual; // freeable list of mptrs + // that go into vtbl[] +#if TX86 + list_t *Spvirtder; // pointer into Svirtual that points to start + // of virtual functions for this (derived) class + symlist_t Sopoverload; // overloaded operator funcs (list freeable) +#endif + symlist_t Scastoverload; // overloaded cast funcs (list freeable) + symlist_t Sclassfriends; // list of classes of which this is a friend + // (list is freeable) + symlist_t Sfriendclass; // classes which are a friend to this class + // (list is freeable) + symlist_t Sfriendfuncs; // functions which are a friend to this class + // (list is freeable) + symlist_t Sinlinefuncs; // list of tokenized functions + baseclass_t *Sbase; // list of direct base classes + baseclass_t *Svirtbase; // list of all virtual base classes + baseclass_t *Smptrbase; // list of all base classes that have + // their own vtbl[] + baseclass_t *Sprimary; // if not NULL, then points to primary + // base class + Funcsym *Svecctor; // constructor for use by vec_new() + Funcsym *Sctor; // constructor function + + Funcsym *Sdtor; // basic destructor +#if VBTABLES + Funcsym *Sprimdtor; // primary destructor + Funcsym *Spriminv; // primary invariant + Funcsym *Sscaldeldtor; // scalar deleting destructor +#endif + + Funcsym *Sinvariant; // basic invariant function + + Symbol *Svptr; // Symbol of vptr + Symbol *Svtbl; // Symbol of vtbl[] +#if VBTABLES + Symbol *Svbptr; // Symbol of pointer to vbtbl[] + Symbol *Svbptr_parent; // base class for which Svbptr is a member. + // NULL if Svbptr is a member of this class + targ_size_t Svbptr_off; // offset of Svbptr member + Symbol *Svbtbl; // virtual base offset table + baseclass_t *Svbptrbase; // list of all base classes in canonical + // order that have their own vbtbl[] +#endif + Funcsym *Sopeq; // X& X::operator =(X&) + Funcsym *Sopeq2; // Sopeq, but no copy of virtual bases + Funcsym *Scpct; // copy constructor + Funcsym *Sveccpct; // vector copy constructor + Symbol *Salias; // pointer to identifier S to use if + // struct was defined as: + // typedef struct { ... } S; + + Symbol *Stempsym; // if this struct is an instantiation + // of a template class, this is the + // template class Symbol + + /* For: + * template struct A { }; + * template struct A { }; + * + * A a; // primary + * Gives: + * Sarglist = + * Spr_arglist = NULL; + * + * A a; // specialization + * Gives: + * Sarglist = + * Spr_arglist = ; + */ + + param_t *Sarglist; // if this struct is an instantiation + // of a template class, this is the + // actual arg list used + param_t *Spr_arglist; // if this struct is an instantiation + // of a specialized template class, this is the + // actual primary arg list used. + // It is NULL for the + // primary template class (since it would be + // identical to Sarglist). + TARGET_structSTRUCT ++/ +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/symtab_t.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/symtab_t.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,12 @@ +module dmd.backend.symtab_t; + +import dmd.backend.Symbol; +import dmd.backend.Util; +import dmd.backend.SYMIDX; + +struct symtab_t +{ + SYMIDX top; // 1 past end + SYMIDX symmax; // max # of entries in tab[] possible + Symbol** tab; // local Symbol table +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/targ_types.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/targ_types.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,37 @@ +module dmd.backend.targ_types; + +/*************************** + * Target machine data types as they appear on the host. + */ + +alias char targ_char; +alias ubyte targ_uchar; +alias byte targ_schar; +alias short targ_short; +alias ushort targ_ushort; +alias long targ_long; +alias ulong targ_ulong; +alias long targ_llong; +alias ulong targ_ullong; +alias float targ_float; +alias double targ_double; +alias real targ_ldouble; +alias int targ_int; +alias uint targ_uns; +alias size_t targ_size_t; +alias ptrdiff_t targ_ptrdiff_t; + +alias cfloat Complex_f; +alias cdouble Complex_d; +alias creal Complex_ld; + +extern(C) extern __gshared targ_size_t localsize; +extern(C) extern __gshared targ_size_t Toff; +extern(C) extern __gshared targ_size_t Poff; +extern(C) extern __gshared targ_size_t Aoff; +extern(C) extern __gshared targ_size_t Poffset; +extern(C) extern __gshared targ_size_t funcoffset; +extern(C) extern __gshared targ_size_t framehandleroffset; +extern(C) extern __gshared targ_size_t Aoffset; +extern(C) extern __gshared targ_size_t Toffset; +extern(C) extern __gshared targ_size_t EEoffset; \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/template_t.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/template_t.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,31 @@ +module dmd.backend.template_t; + +/*********************************** + * Special information for class templates. + */ + +struct template_t +{ +/+ + symlist_t TMinstances; // list of Symbols that are instances + param_t *TMptpl; // template-parameter-list + struct token_t *TMbody; // tokens making up class body + unsigned TMsequence; // sequence number at point of definition + list_t TMmemberfuncs; // templates for member functions (list of TMF's) + list_t TMexplicit; // list of TME's: primary member template explicit specializations + list_t TMnestedexplicit; // list of TMNE's: primary member template nested explicit specializations + Symbol *TMnext; // threaded list of template classes headed + // up by template_class_list + enum_TK TMtk; // TKstruct, TKclass or TKunion + int TMflags; // STRxxx flags + + symbol *TMprimary; // primary class template + symbol *TMpartial; // next class template partial specialization + param_t *TMptal; // template-argument-list for partial specialization + // (NULL for primary class template) + list_t TMfriends; // list of Classsym's for which any instantiated + // classes of this template will be friends of + list_t TMnestedfriends; // list of TMNF's + int TMflags2; // !=0 means dummy template created by template_createargtab() ++/ +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/token_t.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/token_t.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,3 @@ +module dmd.backend.token_t; + +struct token_t; \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/backend/vec_t.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/backend/vec_t.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,4 @@ +module dmd.backend.vec_t; + +alias uint vec_base_t; /* base type of vector */ +alias vec_base_t* vec_t; \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/codegen/Util.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/codegen/Util.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,1149 @@ +module dmd.codegen.Util; + +import dmd.Loc; +import dmd.IRState; +import dmd.Type; +import dmd.Array; +import dmd.Dsymbol; +import dmd.FuncDeclaration; +import dmd.Identifier; +import dmd.RET; +import dmd.TY; +import dmd.LINK; +import dmd.Expression; +import dmd.Argument; +import dmd.STC; +import dmd.Global; +import dmd.InterfaceDeclaration; +import dmd.AggregateDeclaration; +import dmd.AttribDeclaration; +import dmd.TupleDeclaration; +import dmd.StructDeclaration; +import dmd.VarDeclaration; +import dmd.ClassDeclaration; +import dmd.TemplateMixin; +import dmd.TypedefDeclaration; +import dmd.ExpInitializer; +import dmd.TypeFunction; +import dmd.TypeStruct; +import dmd.TypeSArray; +import dmd.TOK; +import dmd.Util; +import dmd.LabelStatement; +import dmd.DsymbolExp; +import dmd.LabelDsymbol; +import dmd.backend.elem; +import dmd.backend.TYPE; +import dmd.backend.Util; +import dmd.backend.Classsym; +import dmd.backend.SC; +import dmd.backend.FL; +import dmd.backend.SFL; +import dmd.backend.STR; +import dmd.backend.TYM; +import dmd.backend.TF; +import dmd.backend.OPER; +import dmd.backend.mTYman; +import dmd.backend.TYFL; +import dmd.backend.mTY; +import dmd.backend.Symbol; +import dmd.backend.Blockx; +import dmd.backend.RTLSYM; +import dmd.backend.block; +import dmd.backend.LIST; + +import std.string; +import core.stdc.string; + +/************************************ + * Call a function. + */ + +elem* callfunc(Loc loc, + IRState* irs, + int directcall, // 1: don't do virtual call + Type tret, // return type + elem *ec, // evaluates to function address + Type ectype, // original type of ec + FuncDeclaration fd, // if !=null, this is the function being called + Type t, // TypeDelegate or TypeFunction for this function + elem* ehidden, // if !=null, this is the 'hidden' argument + Array arguments) +{ + elem* ep; + elem* e; + elem* ethis = null; + elem* eside = null; + int i; + tym_t ty; + tym_t tyret; + RET retmethod; + int reverse; + TypeFunction tf; + OPER op; + +static if (false) { + printf("callfunc(directcall = %d, tret = '%s', ec = %p, fd = %p)\n", + directcall, tret.toChars(), ec, fd); + printf("ec: "); elem_print(ec); + if (fd) + printf("fd = '%s'\n", fd.toChars()); +} + + t = t.toBasetype(); + if (t.ty == TY.Tdelegate) + { + // A delegate consists of: + // { Object *this; Function *funcptr; } + assert(!fd); + assert(t.nextOf().ty == TY.Tfunction); + tf = cast(TypeFunction)t.nextOf(); + ethis = ec; + ec = el_same(ðis); + ethis = el_una(OPER.OP64_32, TYM.TYnptr, ethis); // get this + ec = array_toPtr(t, ec); // get funcptr + ec = el_una(OPER.OPind, tf.totym(), ec); + } + else + { + assert(t.ty == TY.Tfunction); + tf = cast(TypeFunction)t; + } + + retmethod = tf.retStyle(); + ty = ec.Ety; + if (fd) + ty = fd.toSymbol().Stype.Tty; + reverse = tyrevfunc(ty); + ep = null; + if (arguments) + { + // j=1 if _arguments[] is first argument + int j = (tf.linkage == LINK.LINKd && tf.varargs == 1); + + for (i = 0; i < arguments.dim ; i++) + { + Expression arg; + elem* ea; + + arg = cast(Expression)arguments.data[i]; + //printf("\targ[%d]: %s\n", i, arg.toChars()); + + size_t nparams = Argument.dim(tf.parameters); + if (i - j < nparams && i >= j) + { + Argument p = Argument.getNth(tf.parameters, i - j); + + if (p.storageClass & (STC.STCout | STC.STCref)) + { + // Convert argument to a pointer, + // use AddrExp.toElem() + Expression ae = arg.addressOf(null); + ea = ae.toElem(irs); + goto L1; + } + } + ea = arg.toElem(irs); + L1: + if (tybasic(ea.Ety) == TYM.TYstruct) + { + ea = el_una(OPER.OPstrpar, TYM.TYstruct, ea); + ea.Enumbytes = ea.E1.Enumbytes; + assert(ea.Enumbytes); + } + if (reverse) + ep = el_param(ep,ea); + else + ep = el_param(ea,ep); + } + } + + if (retmethod == RET.RETstack) + { + if (!ehidden) + { + // Don't have one, so create one + type* tt; + + if (tf.next.toBasetype().ty == TY.Tstruct) + tt = tf.next.toCtype(); + else + tt = type_fake(tf.next.totym()); + + Symbol* stmp = symbol_genauto(tt); + ehidden = el_ptr(stmp); + } + if ((global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isSolaris) && tf.linkage != LINK.LINKd) { + ; // ehidden goes last on Linux/OSX C++ + } else { + if (ep) + { +static if (false) { // BUG: implement + if (reverse && type_mangle(tfunc) == mTYman.mTYman_cpp) { + ep = el_param(ehidden,ep); + } else { + ep = el_param(ep,ehidden); + } +} else { + ep = el_param(ep,ehidden); +} + } + else + ep = ehidden; + ehidden = null; + } + } + + if (fd && fd.isMember2()) + { + InterfaceDeclaration intd; + Symbol* sfunc; + AggregateDeclaration ad; + + ad = fd.isThis(); + if (ad) + { + ethis = ec; + if (ad.isStructDeclaration() && tybasic(ec.Ety) != TYM.TYnptr) + { + ethis = addressElem(ec, ectype); + } + } + else + { + // Evaluate ec for side effects + eside = ec; + } + sfunc = fd.toSymbol(); + + if (!fd.isVirtual() || + directcall || // BUG: fix + fd.isFinal()) + { + // make static call + ec = el_var(sfunc); + } + else + { + // make virtual call + elem* ev; + uint vindex; + + assert(ethis); + ev = el_same(ðis); + ev = el_una(OPER.OPind, TYM.TYnptr, ev); + vindex = fd.vtblIndex; + + // Build *(ev + vindex * 4) + ec = el_bin(OPER.OPadd, TYM.TYnptr, ev, el_long(TYM.TYint, vindex * 4)); + ec = el_una(OPER.OPind, TYM.TYnptr, ec); + ec = el_una(OPER.OPind, tybasic(sfunc.Stype.Tty), ec); + } + } + else if (fd && fd.isNested()) + { + assert(!ethis); + ethis = getEthis(Loc(0), irs, fd); + } + + ep = el_param(ep, ethis); + if (ehidden) + ep = el_param(ep, ehidden); // if ehidden goes last + + tyret = tret.totym(); + + // Look for intrinsic functions + if (ec.Eoper == OPER.OPvar && (op = intrinsic_oper(ec.EV.sp.Vsym.Sident.ptr)) != OPER.OPMAX) + { + el_free(ec); + if (OTbinary(op)) + { + ep.Eoper = op; + ep.Ety = tyret; + e = ep; + if (op == OPER.OPscale) + { + elem *et = e.E1; + e.E1() = el_una(OPER.OPd_ld, TYM.TYldouble, e.E1); + e.E1() = el_una(OPER.OPs32_d, TYM.TYdouble, e.E2); + e.E2() = et; + } + else if (op == OPER.OPyl2x || op == OPER.OPyl2xp1) + { + elem *et = e.E1; + e.E1() = e.E2; + e.E2() = et; + } + } + else + e = el_una(op,tyret,ep); + } + else if (ep) + e = el_bin(tf.ispure ? OPER.OPcallns : OPER.OPcall, tyret, ec, ep); + else + e = el_una(tf.ispure ? OPER.OPucallns : OPER.OPucall, tyret, ec); + + if (retmethod == RET.RETstack) + { + e.Ety = TYM.TYnptr; + e = el_una(OPER.OPind, tyret, e); + } + +version (DMDV2) { + if (tf.isref) + { + e.Ety = TYM.TYnptr; + e = el_una(OPER.OPind, tyret, e); + } +} + + if (tybasic(tyret) == TYM.TYstruct) + { + e.Enumbytes = cast(uint)tret.size(); + } + + e = el_combine(eside, e); + return e; +} + +/************************************** + * Fake a struct symbol. + */ + +Classsym* fake_classsym(Identifier id) +{ + TYPE* t; + Classsym* scc; + + scc = cast(Classsym*)symbol_calloc(toStringz(id.toChars())); + scc.Sclass = SC.SCstruct; + scc.Sstruct = struct_calloc(); + scc.Sstruct.Sstructalign = 8; + //scc.Sstruct.ptrtype = TYM.TYnptr; + scc.Sstruct.Sflags = STR.STRglobal; + + t = type_alloc(TYM.TYstruct); + t.Tflags |= TF.TFsizeunknown | TF.TFforward; + t.Ttag = scc; // structure tag name + assert(t.Tmangle == 0); + t.Tmangle = mTYman.mTYman_d; + t.Tcount++; + scc.Stype = t; + slist_add(scc); + return scc; +} + +/****************************************** + * Return elem that evaluates to the static frame pointer for function fd. + * If fd is a member function, the returned expression will compute the value + * of fd's 'this' variable. + * This routine is critical for implementing nested functions. + */ + +elem* getEthis(Loc loc, IRState* irs, Dsymbol fd) +{ + elem* ethis; + FuncDeclaration thisfd = irs.getFunc(); + Dsymbol fdparent = fd.toParent2(); + + //printf("getEthis(thisfd = '%s', fd = '%s', fdparent = '%s')\n", thisfd.toChars(), fd.toChars(), fdparent.toChars()); + if (fdparent == thisfd) + { + /* Going down one nesting level, i.e. we're calling + * a nested function from its enclosing function. + */ +///version (DMDV2) { + if (irs.sclosure) + ethis = el_var(irs.sclosure); + else +///} + if (irs.sthis) + { + // We have a 'this' pointer for the current function + ethis = el_var(irs.sthis); + + /* If no variables in the current function's frame are + * referenced by nested functions, then we can 'skip' + * adding this frame into the linked list of stack + * frames. + */ +version (DMDV2) { + bool cond = (thisfd.closureVars.dim != 0); +} else { + bool cond = thisfd.nestedFrameRef; +} + if (cond) + { + /* Local variables are referenced, can't skip. + * Address of 'this' gives the 'this' for the nested + * function + */ + ethis = el_una(OPER.OPaddr, TYM.TYnptr, ethis); + } + } + else + { + /* No 'this' pointer for current function, + * use null if no references to the current function's frame + */ + ethis = el_long(TYM.TYnptr, 0); +version (DMDV2) { + bool cond = (thisfd.closureVars.dim != 0); +} else { + bool cond = thisfd.nestedFrameRef; +} + if (cond) + { + /* OPframeptr is an operator that gets the frame pointer + * for the current function, i.e. for the x86 it gets + * the value of EBP + */ + ethis.Eoper = OPER.OPframeptr; + } + } + } + else + { + if (!irs.sthis) // if no frame pointer for this function + { + fd.error(loc, "is a nested function and cannot be accessed from %s", irs.getFunc().toChars()); + ethis = el_long(TYM.TYnptr, 0); // error recovery + } + else + { + ethis = el_var(irs.sthis); + Dsymbol s = thisfd; + while (fd != s) + { + /* Go up a nesting level, i.e. we need to find the 'this' + * of an enclosing function. + * Our 'enclosing function' may also be an inner class. + */ + + //printf("\ts = '%s'\n", s.toChars()); + thisfd = s.isFuncDeclaration(); + if (thisfd) + { + /* Enclosing function is a function. + */ + if (fdparent == s.toParent2()) + break; + + if (thisfd.isNested()) + { + FuncDeclaration p = s.toParent2().isFuncDeclaration(); +version (DMDV2) { + bool cond = !p || p.closureVars.dim; +} else { + bool cond = !p || p.nestedFrameRef; +} + if (cond) { + ethis = el_una(OPER.OPind, TYM.TYnptr, ethis); + } + } + else if (thisfd.vthis) + { + ; + } + else + { + // Error should have been caught by front end + assert(0); + } + } + else + { + /* Enclosed by an aggregate. That means the current + * function must be a member function of that aggregate. + */ + ClassDeclaration cd; + StructDeclaration sd; + AggregateDeclaration ad = s.isAggregateDeclaration(); + + if (!ad) + goto Lnoframe; + + cd = s.isClassDeclaration(); + + if (cd && fd.isClassDeclaration() && fd.isClassDeclaration().isBaseOf(cd, null)) + break; + + sd = s.isStructDeclaration(); + + if (fd == sd) + break; + + if (!ad.isNested() || !ad.vthis) + { + Lnoframe: + irs.getFunc().error(loc, "cannot get frame pointer to %s", fd.toChars()); + return el_long(TYM.TYnptr, 0); // error recovery + } + + ethis = el_bin(OPER.OPadd, TYM.TYnptr, ethis, el_long(TYM.TYint, ad.vthis.offset)); + ethis = el_una(OPER.OPind, TYM.TYnptr, ethis); + + if (fdparent == s.toParent2()) + break; + + if (auto fdd = s.toParent2().isFuncDeclaration()) + { + /* Remember that frames for functions that have no + * nested references are skipped in the linked list + * of frames. + */ +version (DMDV2) { + bool cond = (fdd.closureVars.dim != 0); +} else { + bool cond = fdd.nestedFrameRef; +} + if (cond) { + ethis = el_una(OPER.OPind, TYM.TYnptr, ethis); + } + break; + } + } + s = s.toParent2(); + assert(s); + } + } + } + +static if (false) { + printf("ethis:\n"); + elem_print(ethis); + printf("\n"); +} + + return ethis; +} + +/***************************************** + * Convert array to a pointer to the data. + */ + +elem* array_toPtr(Type t, elem* e) +{ + //printf("array_toPtr()\n"); + //elem_print(e); + t = t.toBasetype(); + switch (t.ty) + { + case TY.Tpointer: + break; + + case TY.Tarray: + case TY.Tdelegate: + if (e.Eoper == OPER.OPcomma) + { + e.Ety = TYM.TYnptr; + e.E2() = array_toPtr(t, e.E2); + } + else if (e.Eoper == OPER.OPpair) + { + e.Eoper = OPER.OPcomma; + e.Ety = TYM.TYnptr; + } + else + { +static if (true) { + e = el_una(OPER.OPmsw, TYM.TYnptr, e); +} else { + e = el_una(OPER.OPaddr, TYM.TYnptr, e); + e = el_bin(OPER.OPadd, TYM.TYnptr, e, el_long(TYM.TYint, 4)); + e = el_una(OPER.OPind, TYM.TYnptr, e); +} + } + break; + + case TY.Tsarray: + e = el_una(OPER.OPaddr, TYM.TYnptr, e); + break; + + default: + ///t.print(); + assert(0); + } + return e; +} + +/******************************************* + * Take address of an elem. + */ + +elem* addressElem(elem* e, Type t) +{ + elem** pe; + + //printf("addressElem()\n"); + + for (pe = &e; (*pe).Eoper == OPER.OPcomma; pe = &(*pe).E2()) { + ; + } + + if ((*pe).Eoper != OPER.OPvar && (*pe).Eoper != OPER.OPind) + { + Symbol* stmp; + elem* eeq; + elem* ee = *pe; + type* tx; + + // Convert to ((tmp=ee),tmp) + TY ty; + if (t && ((ty = t.toBasetype().ty) == TY.Tstruct || ty == TY.Tsarray)) + tx = t.toCtype(); + else + tx = type_fake(ee.Ety); + stmp = symbol_genauto(tx); + eeq = el_bin(OPER.OPeq,ee.Ety,el_var(stmp),ee); + + if (tybasic(ee.Ety) == TYM.TYstruct) + { + eeq.Eoper = OPER.OPstreq; + eeq.Enumbytes = ee.Enumbytes; + } + else if (tybasic(ee.Ety) == TYM.TYarray) + { + eeq.Eoper = OPER.OPstreq; + eeq.Ety = TYM.TYstruct; + eeq.Ejty = cast(ubyte)eeq.Ety; + eeq.Enumbytes = cast(uint)t.size(); + } + *pe = el_bin(OPER.OPcomma, ee.Ety, eeq, el_var(stmp)); + } + + e = el_una(OPER.OPaddr, TYM.TYnptr, e); + return e; +} + +/******************************************* + * Convert intrinsic function to operator. + * Returns that operator, -1 if not an intrinsic function. + */ + +extern (C++) extern int intrinsic_op(char* name); + +OPER intrinsic_oper(const(char)* name) +{ + int result = intrinsic_op(cast(char*)name); + if (result == -1) return OPER.OPMAX; + return cast(OPER)result; +} + +/************************************** + */ + +elem* Dsymbol_toElem(Dsymbol s, IRState *irs) +{ + elem *e = null; + Symbol* sp; + AttribDeclaration ad; + VarDeclaration vd; + ClassDeclaration cd; + StructDeclaration sd; + FuncDeclaration fd; + TemplateMixin tm; + TupleDeclaration td; + TypedefDeclaration tyd; + + //printf("Dsymbol_toElem() %s\n", s.toChars()); + ad = s.isAttribDeclaration(); + if (ad) + { + Array decl = ad.include(null, null); + if (decl && decl.dim) + { + for (size_t i = 0; i < decl.dim; i++) + { + s = cast(Dsymbol)decl.data[i]; + e = el_combine(e, Dsymbol_toElem(s, irs)); + } + } + } + else if ((vd = s.isVarDeclaration()) !is null) + { + s = s.toAlias(); + if (s != vd) + return Dsymbol_toElem(s, irs); + if (vd.isStatic() || vd.storage_class & (STC.STCextern | STC.STCtls | STC.STCgshared)) + vd.toObjFile(0); + else + { + sp = s.toSymbol(); + symbol_add(sp); + //printf("\tadding symbol '%s'\n", sp.Sident); + if (vd.init) + { + ExpInitializer ie = vd.init.isExpInitializer(); + if (ie) { + e = ie.exp.toElem(irs); + } + } + } + } + else if ((cd = s.isClassDeclaration()) !is null) + { + irs.deferToObj.push(cast(void*)s); + } + else if ((sd = s.isStructDeclaration()) !is null) + { + irs.deferToObj.push(cast(void*)sd); + } + else if ((fd = s.isFuncDeclaration()) !is null) + { + //printf("function %s\n", fd.toChars()); + irs.deferToObj.push(cast(void*)fd); + } + else if ((tm = s.isTemplateMixin()) !is null) + { + //printf("%s\n", tm.toChars()); + if (tm.members) + { + for (size_t i = 0; i < tm.members.dim; i++) + { + Dsymbol sm = cast(Dsymbol)tm.members.data[i]; + e = el_combine(e, Dsymbol_toElem(sm, irs)); + } + } + } + else if ((td = s.isTupleDeclaration()) !is null) + { + for (size_t i = 0; i < td.objects.dim; i++) + { + Object o = cast(Object)td.objects.data[i]; + ///if (o.dyncast() == DYNCAST_EXPRESSION) + if (Expression eo = cast(Expression)o) + { + if (eo.op == TOK.TOKdsymbol) + { + DsymbolExp se = cast(DsymbolExp)eo; + e = el_combine(e, Dsymbol_toElem(se.s, irs)); + } + } + } + } + else if ((tyd = s.isTypedefDeclaration()) !is null) + { + irs.deferToObj.push(cast(void*)tyd); + } + + return e; +} + +/************************************** + * Given an expression e that is an array, + * determine and set the 'length' variable. + * Input: + * lengthVar Symbol of 'length' variable + * &e expression that is the array + * t1 Type of the array + * Output: + * e is rewritten to avoid side effects + * Returns: + * expression that initializes 'length' + */ + +elem* resolveLengthVar(VarDeclaration lengthVar, elem** pe, Type t1) +{ + //printf("resolveLengthVar()\n"); + elem* einit = null; + + if (lengthVar && !(lengthVar.storage_class & STC.STCconst)) + { + elem* elength; + Symbol* slength; + + if (t1.ty == TY.Tsarray) + { + TypeSArray tsa = cast(TypeSArray)t1; + long length = tsa.dim.toInteger(); + + elength = el_long(TYM.TYuint, length); + goto L3; + } + else if (t1.ty == TY.Tarray) + { + elength = *pe; + *pe = el_same(&elength); + elength = el_una(OPER.OP64_32, TYM.TYuint, elength); + + L3: + slength = lengthVar.toSymbol(); + //symbol_add(slength); + + einit = el_bin(OPER.OPeq, TYM.TYuint, el_var(slength), elength); + } + } + return einit; +} + +/******************************************* + * Set an array pointed to by eptr to evalue: + * eptr[0..edim] = evalue; + * Input: + * eptr where to write the data to + * evalue value to write + * edim number of times to write evalue to eptr[] + * tb type of evalue + */ + +elem* setArray(elem* eptr, elem* edim, Type tb, elem* evalue, IRState* irs, int op) +{ + int r; + elem* e; + int sz = cast(int)tb.size(); + + if (tb.ty == TY.Tfloat80 || tb.ty == TY.Timaginary80) + r = RTLSYM.RTLSYM_MEMSET80; + else if (tb.ty == TY.Tcomplex80) + r = RTLSYM.RTLSYM_MEMSET160; + else if (tb.ty == TY.Tcomplex64) + r = RTLSYM.RTLSYM_MEMSET128; + else + { + switch (sz) + { + case 1: r = RTLSYM.RTLSYM_MEMSET8; break; + case 2: r = RTLSYM.RTLSYM_MEMSET16; break; + case 4: r = RTLSYM.RTLSYM_MEMSET32; break; + case 8: r = RTLSYM.RTLSYM_MEMSET64; break; + default: r = RTLSYM.RTLSYM_MEMSETN; break; + } + + /* Determine if we need to do postblit + */ + if (op != TOK.TOKblit) + { + StructDeclaration sd = needsPostblit(tb); + if (sd) + { + /* Need to do postblit. + * void *_d_arraysetassign(void *p, void *value, int dim, TypeInfo ti); + */ + r = (op == TOK.TOKconstruct) ? RTLSYM.RTLSYM_ARRAYSETCTOR : RTLSYM.RTLSYM_ARRAYSETASSIGN; + evalue = el_una(OPER.OPaddr, TYM.TYnptr, evalue); + Expression ti = tb.getTypeInfo(null); + elem* eti = ti.toElem(irs); + e = el_params(eti, edim, evalue, eptr, null); + e = el_bin(OPER.OPcall, TYM.TYnptr, el_var(rtlsym[r]), e); + return e; + } + } + + if (r == RTLSYM.RTLSYM_MEMSETN) + { + // void *_memsetn(void *p, void *value, int dim, int sizelem) + evalue = el_una(OPER.OPaddr, TYM.TYnptr, evalue); + elem *esz = el_long(TYM.TYint, sz); + e = el_params(esz, edim, evalue, eptr, null); + e = el_bin(OPER.OPcall, TYM.TYnptr, el_var(rtlsym[r]), e); + return e; + } + } + if (sz > 1 && sz <= 8 && evalue.Eoper == OPER.OPconst && el_allbits(evalue, 0)) + { + r = RTLSYM.RTLSYM_MEMSET8; + edim = el_bin(OPER.OPmul, TYM.TYuint, edim, el_long(TYM.TYuint, sz)); + } + + if (tybasic(evalue.Ety) == TYM.TYstruct) + { + evalue = el_una(OPER.OPstrpar, TYM.TYstruct, evalue); + evalue.Enumbytes = evalue.E1.Enumbytes; + assert(evalue.Enumbytes); + } + + // Be careful about parameter side effect ordering + if (r == RTLSYM.RTLSYM_MEMSET8) + { + e = el_param(edim, evalue); + e = el_bin(OPER.OPmemset, TYM.TYnptr, eptr, e); + } + else + { + e = el_params(edim, evalue, eptr, null); + e = el_bin(OPER.OPcall, TYM.TYnptr, el_var(rtlsym[r]), e); + } + return e; +} + +/************************* + * Initialize the hidden aggregate member, vthis, with + * the context pointer. + * Returns: + * *(ey + ad.vthis.offset) = this; + */ +version (DMDV2) { + elem* setEthis(Loc loc, IRState* irs, elem* ey, AggregateDeclaration ad) + { + elem* ethis; + FuncDeclaration thisfd = irs.getFunc(); + int offset = 0; + Dsymbol cdp = ad.toParent2(); // class/func we're nested in + + //printf("setEthis(ad = %s, cdp = %s, thisfd = %s)\n", ad.toChars(), cdp.toChars(), thisfd.toChars()); + + if (cdp is thisfd) + { + /* Class we're new'ing is a local class in this function: + * void thisfd() { class ad { } } + */ + if (irs.sclosure) + ethis = el_var(irs.sclosure); + else if (irs.sthis) + { +/// version (DMDV2) { + if (thisfd.closureVars.dim) +/// } else { +/// if (thisfd.nestedFrameRef) +/// } + { + ethis = el_ptr(irs.sthis); + } + else + ethis = el_var(irs.sthis); + } + else + { + ethis = el_long(TYM.TYnptr, 0); +/// version (DMDV2) { + if (thisfd.closureVars.dim) +/// } else { +/// if (thisfd.nestedFrameRef) +/// } + { + ethis.Eoper = OPER.OPframeptr; + } + } + } + else if (thisfd.vthis && ( + cdp == thisfd.toParent2() || ( + cdp.isClassDeclaration() && cdp.isClassDeclaration().isBaseOf(thisfd.toParent2().isClassDeclaration(), &offset) + ) + ) + ) + { + /* Class we're new'ing is at the same level as thisfd + */ + assert(offset == 0); // BUG: should handle this case + ethis = el_var(irs.sthis); + } + else + { + ethis = getEthis(loc, irs, ad.toParent2()); + ethis = el_una(OPER.OPaddr, TYM.TYnptr, ethis); + } + + ey = el_bin(OPER.OPadd, TYM.TYnptr, ey, el_long(TYM.TYint, ad.vthis.offset)); + ey = el_una(OPER.OPind, TYM.TYnptr, ey); + ey = el_bin(OPER.OPeq, TYM.TYnptr, ey, ethis); + + return ey; + } +} + +/******************************************** + * Determine if t is an array of structs that need a postblit. + */ +StructDeclaration needsPostblit(Type t) +{ + t = t.toBasetype(); + + while (t.ty == TY.Tsarray) + t = t.nextOf().toBasetype(); + + if (t.ty == TY.Tstruct) + { + StructDeclaration sd = (cast(TypeStruct)t).sym; + if (sd.postblit) + return sd; + } + + return null; +} + +/***************************************** + * Convert array to a dynamic array. + */ + +elem* array_toDarray(Type t, elem* e) +{ + uint dim; + elem* ef = null; + elem* ex; + + //printf("array_toDarray(t = %s)\n", t.toChars()); + //elem_print(e); + t = t.toBasetype(); + switch (t.ty) + { + case TY.Tarray: + break; + + case TY.Tsarray: + e = el_una(OPER.OPaddr, TYM.TYnptr, e); + dim = cast(uint)(cast(TypeSArray)t).dim.toInteger(); + e = el_pair(TYM.TYullong, el_long(TYM.TYint, dim), e); + break; + + default: + L1: + switch (e.Eoper) + { + case OPER.OPconst: + { + size_t len = tysize[tybasic(e.Ety)]; + elem* es = el_calloc(); + es.Eoper = OPER.OPstring; + + // Match MEM_PH_FREE for OPstring in ztc\el.c + es.EV.ss.Vstring = cast(char*)malloc(len); /// + memcpy(es.EV.ss.Vstring, &e.EV, len); + + es.EV.ss.Vstrlen = len; + es.Ety = TYM.TYnptr; + e = es; + break; + } + + case OPER.OPvar: + e = el_una(OPER.OPaddr, TYM.TYnptr, e); + break; + + case OPER.OPcomma: + ef = el_combine(ef, e.E1); + ex = e; + e = e.E2; + ex.E1() = null; + ex.E2() = null; + el_free(ex); + goto L1; + + case OPER.OPind: + ex = e; + e = e.E1; + ex.E1() = null; + ex.E2() = null; + el_free(ex); + break; + + default: + { + // Copy expression to a variable and take the + // address of that variable. + Symbol* stmp; + tym_t ty = tybasic(e.Ety); + + if (ty == TYM.TYstruct) + { + if (e.Enumbytes == 4) + ty = TYM.TYint; + else if (e.Enumbytes == 8) + ty = TYM.TYllong; + } + e.Ety = ty; + stmp = symbol_genauto(type_fake(ty)); + e = el_bin(OPER.OPeq, e.Ety, el_var(stmp), e); + e = el_bin(OPER.OPcomma, TYM.TYnptr, e, el_una(OPER.OPaddr, TYM.TYnptr, el_var(stmp))); + break; + } + } + dim = 1; + e = el_pair(TYM.TYullong, el_long(TYM.TYint, dim), e); + break; + } + + return el_combine(ef, e); +} + +elem* sarray_toDarray(Loc loc, Type tfrom, Type tto, elem* e) +{ + //printf("sarray_toDarray()\n"); + //elem_print(e); + + elem* elen; + uint dim = cast(uint)(cast(TypeSArray)tfrom).dim.toInteger(); + + if (tto) + { + uint fsize = cast(uint)tfrom.nextOf().size(); + uint tsize = cast(uint)tto.nextOf().size(); + + if ((dim * fsize) % tsize != 0) + { + Lerr: + error(loc, "cannot cast %s to %s since sizes don't line up", tfrom.toChars(), tto.toChars()); + } + dim = (dim * fsize) / tsize; + } + + L1: + elen = el_long(TYM.TYint, dim); + e = el_una(OPER.OPaddr, TYM.TYnptr, e); + e = el_pair(TYM.TYullong, elen, e); + return e; +} + +elem* eval_Darray(IRState* irs, Expression e) +{ + elem* ex = e.toElem(irs); + return array_toDarray(e.type, ex); +} + +/*********************************************** + * Generate code to set index into scope table. + */ + +void setScopeIndex(Blockx* blx, block* b, int scope_index) +{ +version (SEH) { + block_appendexp(b, nteh_setScopeTableIndex(blx, scope_index)); +} +} + +/**************************************** + * Create a static symbol we can hang DT initializers onto. + */ + +Symbol* static_sym() +{ + Symbol* s; + type* t; + + t = type_alloc(TYint); + t.Tcount++; + s = symbol_calloc("internal"); + s.Sclass = SCstatic; + s.Sfl = FLextern; + s.Sflags |= SFLnodebug; + s.Stype = t; +version (ELFOBJ_OR_MACHOBJ) { + s.Sseg = DATA; +} + slist_add(s); + return s; +} + +/************************************** + * Convert label to block. + */ + +block* labelToBlock(Loc loc, Blockx *blx, LabelDsymbol label) +{ + LabelStatement s; + + if (!label.statement) + { + error(loc, "undefined label %s", label.toChars()); + return null; + } + + s = label.statement; + if (!s.lblock) + { + s.lblock = block_calloc(blx); + if (s.isReturnLabel) + s.lblock.Btry = null; + } + return s.lblock; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/condition/util/findCondition.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/condition/util/findCondition.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,22 @@ +module dmd.condition.util.findCondition; + +import dmd.String; +import dmd.Array; +import dmd.Identifier; + +bool findCondition(Array ids, Identifier ident) +{ + if (ids) + { + for (int i = 0; i < ids.dim; i++) + { + String id = cast(String)ids.data[i]; + + if (id.str == ident.toChars()) { + return true; + } + } + } + + return false; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/declaration/Match.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/declaration/Match.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,14 @@ +module dmd.declaration.Match; + +import dmd.FuncDeclaration; +import dmd.MATCH; + +struct Match +{ + int count; // number of matches found + MATCH last; // match level of lastf + FuncDeclaration lastf; // last matching function we found + FuncDeclaration nextf; // current matching function + FuncDeclaration anyf; // pick a func, any func, to use for error recovery +} + diff -r 000000000000 -r 10317f0c89a5 dmd/expression/Add.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/expression/Add.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,105 @@ +module dmd.expression.Add; + +import dmd.Expression; +import dmd.Type; +import dmd.Loc; +import dmd.RealExp; +import dmd.ComplexExp; +import dmd.IntegerExp; +import dmd.TOK; +import dmd.SymOffExp; +import dmd.Complex; + +Expression Add(Type type, Expression e1, Expression e2) +{ + Expression e; + Loc loc = e1.loc; + +version (LOG) { + printf("Add(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars()); +} + if (type.isreal()) + { + e = new RealExp(loc, e1.toReal() + e2.toReal(), type); + } + else if (type.isimaginary()) + { + e = new RealExp(loc, e1.toImaginary() + e2.toImaginary(), type); + } + else if (type.iscomplex()) + { + // This rigamarole is necessary so that -0.0 doesn't get + // converted to +0.0 by doing an extraneous add with +0.0 + Complex!(real) c1; + real r1; + real i1; + + Complex!(real) c2; + real r2; + real i2; + + Complex!(real) v; + int x; + + if (e1.type.isreal()) + { + r1 = e1.toReal(); + x = 0; + } + else if (e1.type.isimaginary()) + { + i1 = e1.toImaginary(); + x = 3; + } + else + { + c1 = e1.toComplex(); + x = 6; + } + + if (e2.type.isreal()) + { + r2 = e2.toReal(); + } + else if (e2.type.isimaginary()) + { + i2 = e2.toImaginary(); + x += 1; + } + else + { + c2 = e2.toComplex(); + x += 2; + } + + switch (x) + { + case 0+0: v = Complex!(real)(r1 + r2, 0); break; + case 0+1: v = Complex!(real)(r1, i2); break; + case 0+2: v = Complex!(real)(r1 + c2.re, c2.im); break; + case 3+0: v = Complex!(real)(r2, i1); break; + case 3+1: v = Complex!(real)(0, i1 + i2); break; + case 3+2: v = Complex!(real)(c2.re, i1 + c2.im); break; + case 6+0: v = Complex!(real)(c1.re + r2, c1.im); break; + case 6+1: v = Complex!(real)(c1.re, c1.im + i2); break; + case 6+2: v = Complex!(real)(c1.re + c2.re, c1.im + c2.im); break; + } + e = new ComplexExp(loc, v, type); + } + else if (e1.op == TOK.TOKsymoff) + { + SymOffExp soe = cast(SymOffExp)e1; + e = new SymOffExp(loc, soe.var, soe.offset + cast(uint)e2.toInteger()); + e.type = type; + } + else if (e2.op == TOK.TOKsymoff) + { + SymOffExp soe = cast(SymOffExp)e2; + e = new SymOffExp(loc, soe.var, soe.offset + cast(uint)e1.toInteger()); + e.type = type; + } + else + e = new IntegerExp(loc, e1.toInteger() + e2.toInteger(), type); + + return e; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/expression/And.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/expression/And.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,10 @@ +module dmd.expression.And; + +import dmd.Expression; +import dmd.Type; +import dmd.IntegerExp; + +Expression And(Type type, Expression e1, Expression e2) +{ + return new IntegerExp(e1.loc, e1.toInteger() & e2.toInteger(), type); +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/expression/ArrayLength.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/expression/ArrayLength.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,39 @@ +module dmd.expression.ArrayLength; + +import dmd.Type; +import dmd.Expression; +import dmd.StringExp; +import dmd.IntegerExp; +import dmd.ArrayLiteralExp; +import dmd.Loc; +import dmd.TOK; +import dmd.AssocArrayLiteralExp; +import dmd.GlobalExpressions; + +Expression ArrayLength(Type type, Expression e1) +{ + Expression e; + Loc loc = e1.loc; + + if (e1.op == TOKstring) + { + StringExp es1 = cast(StringExp)e1; + e = new IntegerExp(loc, es1.len, type); + } + else if (e1.op == TOKarrayliteral) + { + ArrayLiteralExp ale = cast(ArrayLiteralExp)e1; + size_t dim = ale.elements ? ale.elements.dim : 0; + e = new IntegerExp(loc, dim, type); + } + else if (e1.op == TOKassocarrayliteral) + { + AssocArrayLiteralExp ale = cast(AssocArrayLiteralExp)e1; + size_t dim = ale.keys.dim; + e = new IntegerExp(loc, dim, type); + } + else + e = EXP_CANT_INTERPRET; + + return e; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/expression/Cat.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/expression/Cat.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,267 @@ +module dmd.expression.Cat; + +import dmd.Type; +import dmd.Expression; +import dmd.Loc; +import dmd.TOK; +import dmd.StringExp; +import dmd.ArrayLiteralExp; +import dmd.Global; +import dmd.TY; +import dmd.Type; +import dmd.GlobalExpressions; +import dmd.ArrayTypes; +import dmd.TypeSArray; +import dmd.IntegerExp; + +import core.stdc.string; +import core.stdc.stdlib; + +import std.contracts; + +/* Also return EXP_CANT_INTERPRET if this fails + */ +Expression Cat(Type type, Expression e1, Expression e2) +{ + Expression e = EXP_CANT_INTERPRET; + Loc loc = e1.loc; + + Type t; + + Type t1 = e1.type.toBasetype(); + Type t2 = e2.type.toBasetype(); + + //printf("Cat(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars()); + //printf("\tt1 = %s, t2 = %s\n", t1.toChars(), t2.toChars()); + + if (e1.op == TOKnull && (e2.op == TOKint64 || e2.op == TOKstructliteral)) + { + e = e2; + goto L2; + } + else if ((e1.op == TOKint64 || e1.op == TOKstructliteral) && e2.op == TOKnull) + { + e = e1; + L2: + Type tn = e.type.toBasetype(); + if (tn.ty == Tchar || tn.ty == Twchar || tn.ty == Tdchar) + { + // Create a StringExp + size_t len = 1; + int sz = cast(int)tn.size(); + ulong v = e.toInteger(); + + char* s = cast(char*)malloc((len + 1) * sz); + memcpy(s, &v, sz); + + // Add terminating 0 + memset(s + len * sz, 0, sz); + + StringExp es = new StringExp(loc, assumeUnique(s[0..len])); + es.sz = cast(ubyte)sz; + es.committed = 1; + e = es; + } + else + { + // Create an ArrayLiteralExp + Expressions elements = new Expressions(); + elements.push(cast(void*)e); + e = new ArrayLiteralExp(e.loc, elements); + } + e.type = type; + return e; + } + else if (e1.op == TOKstring && e2.op == TOKstring) + { + // Concatenate the strings + StringExp es1 = cast(StringExp)e1; + StringExp es2 = cast(StringExp)e2; + + size_t len = es1.len + es2.len; + int sz = es1.sz; + + if (sz != es2.sz) + { + /* Can happen with: + * auto s = "foo"d ~ "bar"c; + */ + assert(global.errors); + return e; + } + + char* s = cast(char*)malloc((len + 1) * sz); + memcpy(s, es1.string_, es1.len * sz); + memcpy(s + es1.len * sz, es2.string_, es2.len * sz); + + // Add terminating 0 + memset(s + len * sz, 0, sz); + + StringExp es = new StringExp(loc, assumeUnique(s[0..len])); + es.sz = cast(ubyte)sz; + es.committed = es1.committed | es2.committed; + + Type tt; + if (es1.committed) + tt = es1.type; + else + tt = es2.type; + + es.type = type; + e = es; + } + else if (e1.op == TOKstring && e2.op == TOKint64) + { + // Concatenate the strings + StringExp es1 = cast(StringExp)e1; + size_t len = es1.len + 1; + int sz = es1.sz; + ulong v = e2.toInteger(); + + char* s = cast(char*)malloc((len + 1) * sz); + memcpy(s, es1.string_, es1.len * sz); + memcpy(s + es1.len * sz, &v, sz); + + // Add terminating 0 + memset(s + len * sz, 0, sz); + + StringExp es = new StringExp(loc, assumeUnique(s[0..len])); + es.sz = cast(ubyte)sz; + es.committed = es1.committed; + Type tt = es1.type; + es.type = type; + e = es; + } + else if (e1.op == TOKint64 && e2.op == TOKstring) + { + // Concatenate the strings + StringExp es2 = cast(StringExp)e2; + size_t len = 1 + es2.len; + int sz = es2.sz; + ulong v = e1.toInteger(); + + char* s = cast(char*)malloc((len + 1) * sz); + memcpy(s, &v, sz); + memcpy(s + sz, es2.string_, es2.len * sz); + + // Add terminating 0 + memset(s + len * sz, 0, sz); + + StringExp es = new StringExp(loc, assumeUnique(s[0..len])); + es.sz = cast(ubyte)sz; + es.committed = es2.committed; + Type tt = es2.type; + es.type = type; + e = es; + } + else if (e1.op == TOKarrayliteral && e2.op == TOKarrayliteral && + t1.nextOf().equals(t2.nextOf())) + { + // Concatenate the arrays + ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1; + ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2; + + es1 = new ArrayLiteralExp(es1.loc, cast(Expressions)es1.elements.copy()); + es1.elements.insert(es1.elements.dim, es2.elements); + e = es1; + + if (type.toBasetype().ty == Tsarray) + { + e.type = new TypeSArray(t1.nextOf(), new IntegerExp(loc, es1.elements.dim, Type.tindex)); + e.type = e.type.semantic(loc, null); + } + else + e.type = type; + } + else if (e1.op == TOKarrayliteral && e2.op == TOKnull && + t1.nextOf().equals(t2.nextOf())) + { + e = e1; + goto L3; + } + else if (e1.op == TOKnull && e2.op == TOKarrayliteral && + t1.nextOf().equals(t2.nextOf())) + { + e = e2; + L3: + // Concatenate the array with null + ArrayLiteralExp es = cast(ArrayLiteralExp)e; + + es = new ArrayLiteralExp(es.loc, cast(Expressions)es.elements.copy()); + e = es; + + if (type.toBasetype().ty == Tsarray) + { + e.type = new TypeSArray(t1.nextOf(), new IntegerExp(loc, es.elements.dim, Type.tindex)); + e.type = e.type.semantic(loc, null); + } + else + e.type = type; + } + else if ((e1.op == TOKarrayliteral || e1.op == TOKnull) && + e1.type.toBasetype().nextOf().equals(e2.type)) + { + ArrayLiteralExp es1; + if (e1.op == TOKarrayliteral) + { es1 = cast(ArrayLiteralExp)e1; + es1 = new ArrayLiteralExp(es1.loc, cast(Expressions)es1.elements.copy()); + es1.elements.push(cast(void*)e2); + } + else + { + es1 = new ArrayLiteralExp(e1.loc, e2); + } + e = es1; + + if (type.toBasetype().ty == Tsarray) + { + e.type = new TypeSArray(e2.type, new IntegerExp(loc, es1.elements.dim, Type.tindex)); + e.type = e.type.semantic(loc, null); + } + else + e.type = type; + } + else if (e2.op == TOKarrayliteral && + e2.type.toBasetype().nextOf().equals(e1.type)) + { + ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2; + + es2 = new ArrayLiteralExp(es2.loc, cast(Expressions)es2.elements.copy()); + es2.elements.shift(cast(void*)e1); + e = es2; + + if (type.toBasetype().ty == Tsarray) + { + e.type = new TypeSArray(e1.type, new IntegerExp(loc, es2.elements.dim, Type.tindex)); + e.type = e.type.semantic(loc, null); + } + else + e.type = type; + } + else if (e1.op == TOKnull && e2.op == TOKstring) + { + t = e1.type; + e = e2; + goto L1; + } + else if (e1.op == TOKstring && e2.op == TOKnull) + { + e = e1; + t = e2.type; + L1: + Type tb = t.toBasetype(); + if (tb.ty == Tarray && tb.nextOf().equals(e.type)) + { + Expressions expressions = new Expressions(); + expressions.push(cast(void*)e); + e = new ArrayLiteralExp(loc, expressions); + e.type = t; + } + if (!e.type.equals(type)) + { + StringExp se = cast(StringExp)e.copy(); + e = se.castTo(null, type); + } + } + return e; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/expression/Cmp.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/expression/Cmp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,148 @@ +module dmd.expression.Cmp; + +import dmd.IntegerExp; +import dmd.Loc; +import dmd.TOK; +import dmd.Type; +import dmd.Expression; +import dmd.StringExp; +import dmd.GlobalExpressions; + +import core.stdc.string; + +Expression Cmp(TOK op, Type type, Expression e1, Expression e2) +{ + Expression e; + Loc loc = e1.loc; + ulong n; + real r1; + real r2; + + //printf("Cmp(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars()); + + if (e1.op == TOKstring && e2.op == TOKstring) + { + StringExp es1 = cast(StringExp)e1; + StringExp es2 = cast(StringExp)e2; + size_t sz = es1.sz; + assert(sz == es2.sz); + + size_t len = es1.len; + if (es2.len < len) + len = es2.len; + + int cmp = memcmp(es1.string_, es2.string_, sz * len); + if (cmp == 0) + cmp = es1.len - es2.len; + + switch (op) + { + case TOKlt: n = cmp < 0; break; + case TOKle: n = cmp <= 0; break; + case TOKgt: n = cmp > 0; break; + case TOKge: n = cmp >= 0; break; + + case TOKleg: n = 1; break; + case TOKlg: n = cmp != 0; break; + case TOKunord: n = 0; break; + case TOKue: n = cmp == 0; break; + case TOKug: n = cmp > 0; break; + case TOKuge: n = cmp >= 0; break; + case TOKul: n = cmp < 0; break; + case TOKule: n = cmp <= 0; break; + + default: + assert(0); + } + } + else if (e1.isConst() != 1 || e2.isConst() != 1) + return EXP_CANT_INTERPRET; + else if (e1.type.isreal()) + { + r1 = e1.toReal(); + r2 = e2.toReal(); + goto L1; + } + else if (e1.type.isimaginary()) + { + r1 = e1.toImaginary(); + r2 = e2.toImaginary(); + L1: + + // DMC is the only compiler I know of that handles NAN arguments + // correctly in comparisons. + switch (op) + { + case TOKlt: n = r1 < r2; break; + case TOKle: n = r1 <= r2; break; + case TOKgt: n = r1 > r2; break; + case TOKge: n = r1 >= r2; break; + case TOKleg: n = r1 <>= r2; break; + case TOKlg: n = r1 <> r2; break; + case TOKunord: n = r1 !<>= r2; break; + case TOKue: n = r1 !<> r2; break; + case TOKug: n = r1 !<= r2; break; + case TOKuge: n = r1 !< r2; break; + case TOKul: n = r1 !>= r2; break; + case TOKule: n = r1 !> r2; break; + + default: assert(0); + } + } + else if (e1.type.iscomplex()) + { + assert(0); + } + else + { + long n1; + long n2; + + n1 = e1.toInteger(); + n2 = e2.toInteger(); + + if (e1.type.isunsigned() || e2.type.isunsigned()) + { + switch (op) + { + case TOKlt: n = (cast(ulong) n1) < (cast(ulong) n2); break; + case TOKle: n = (cast(ulong) n1) <= (cast(ulong) n2); break; + case TOKgt: n = (cast(ulong) n1) > (cast(ulong) n2); break; + case TOKge: n = (cast(ulong) n1) >= (cast(ulong) n2); break; + case TOKleg: n = 1; break; + case TOKlg: n = (cast(ulong) n1) != (cast(ulong) n2); break; + case TOKunord: n = 0; break; + case TOKue: n = (cast(ulong) n1) == (cast(ulong) n2); break; + case TOKug: n = (cast(ulong) n1) > (cast(ulong) n2); break; + case TOKuge: n = (cast(ulong) n1) >= (cast(ulong) n2); break; + case TOKul: n = (cast(ulong) n1) < (cast(ulong) n2); break; + case TOKule: n = (cast(ulong) n1) <= (cast(ulong) n2); break; + + default: assert(0); + } + } + else + { + switch (op) + { + case TOKlt: n = n1 < n2; break; + case TOKle: n = n1 <= n2; break; + case TOKgt: n = n1 > n2; break; + case TOKge: n = n1 >= n2; break; + case TOKleg: n = 1; break; + case TOKlg: n = n1 != n2; break; + case TOKunord: n = 0; break; + case TOKue: n = n1 == n2; break; + case TOKug: n = n1 > n2; break; + case TOKuge: n = n1 >= n2; break; + case TOKul: n = n1 < n2; break; + case TOKule: n = n1 <= n2; break; + default: assert(0); + } + } + } + + e = new IntegerExp(loc, n, type); + + return e; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/expression/Com.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/expression/Com.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,12 @@ +module dmd.expression.Com; + +import dmd.Expression; +import dmd.Type; +import dmd.IntegerExp; +import dmd.Loc; + +Expression Com(Type type, Expression e1) +{ + Loc loc = e1.loc; + return new IntegerExp(loc, ~e1.toInteger(), type); +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/expression/Div.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/expression/Div.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,93 @@ +module dmd.expression.Div; + +import dmd.Type; +import dmd.Expression; +import dmd.Loc; +import dmd.RealExp; +import dmd.ComplexExp; +import dmd.IntegerExp; +import dmd.Complex; + +Expression Div(Type type, Expression e1, Expression e2) +{ + Expression e; + Loc loc = e1.loc; + + if (type.isfloating()) + { + Complex!(real) c; + real r; + + //e1.type.print(); + //e2.type.print(); + if (e2.type.isreal()) + { + if (e1.type.isreal()) + { + e = new RealExp(loc, e1.toReal() / e2.toReal(), type); + return e; + } + + //r = e2.toReal(); + //c = e1.toComplex(); + //printf("(%Lg + %Lgi) / %Lg\n", creall(c), cimagl(c), r); + r = e2.toReal(); + c = e1.toComplex(); + c = Complex!(real)(c.re / r, c.im / r); + } + else if (e2.type.isimaginary()) + { + //r = e2.toImaginary(); + //c = e1.toComplex(); + //printf("(%Lg + %Lgi) / %Lgi\n", creall(c), cimagl(c), r); + r = e2.toImaginary(); + c = e1.toComplex(); + c = Complex!(real)(c.im / r, -c.re / r); + } + else + { + Complex!(real) c1 = e1.toComplex(); + Complex!(real) c2 = e2.toComplex(); + + real denumerator = c2.re*c2.re + c2.im*c2.im; + real numerator_re = c1.re*c2.re + c1.im*c2.im; + real numerator_im = c1.im*c2.re - c1.re*c2.im; + + c = Complex!(real)(numerator_re / denumerator, numerator_im / denumerator); + } + + if (type.isreal()) + e = new RealExp(loc, c.re, type); + else if (type.isimaginary()) + e = new RealExp(loc, c.im, type); + else if (type.iscomplex()) + e = new ComplexExp(loc, c, type); + else + assert(0); + } + else + { + long n1; + long n2; + long n; + + n1 = e1.toInteger(); + n2 = e2.toInteger(); + + if (n2 == 0) + { + e2.error("divide by 0"); + e2 = new IntegerExp(loc, 1, e2.type); + n2 = 1; + } + + if (e1.type.isunsigned() || e2.type.isunsigned()) + n = (cast(ulong) n1) / (cast(ulong) n2); + else + n = n1 / n2; + + e = new IntegerExp(loc, n, type); + } + + return e; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/expression/Equal.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/expression/Equal.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,209 @@ +module dmd.expression.Equal; + +import dmd.Expression; +import dmd.Type; +import dmd.TOK; +import dmd.Loc; +import dmd.StringExp; +import dmd.GlobalExpressions; +import dmd.ArrayLiteralExp; +import dmd.StructLiteralExp; +import dmd.Global; +import dmd.IntegerExp; + +import core.stdc.string; + +/* Also returns EXP_CANT_INTERPRET if cannot be computed. + */ +Expression Equal(TOK op, Type type, Expression e1, Expression e2) +{ + Expression e; + Loc loc = e1.loc; + bool cmp; + real r1; + real r2; + + //printf("Equal(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars()); + + assert(op == TOK.TOKequal || op == TOK.TOKnotequal); + + if (e1.op == TOK.TOKnull) + { + if (e2.op == TOK.TOKnull) + cmp = true; + else if (e2.op == TOK.TOKstring) + { StringExp es2 = cast(StringExp)e2; + cmp = (0 == es2.len); + } + else if (e2.op == TOK.TOKarrayliteral) + { + ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2; + cmp = !es2.elements || (0 == es2.elements.dim); + } + else + return EXP_CANT_INTERPRET; + } + else if (e2.op == TOK.TOKnull) + { + if (e1.op == TOK.TOKstring) + { + StringExp es1 = cast(StringExp)e1; + cmp = (0 == es1.len); + } + else if (e1.op == TOK.TOKarrayliteral) + { + ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1; + cmp = !es1.elements || (0 == es1.elements.dim); + } + else + return EXP_CANT_INTERPRET; + } + else if (e1.op == TOK.TOKstring && e2.op == TOK.TOKstring) + { + StringExp es1 = cast(StringExp)e1; + StringExp es2 = cast(StringExp)e2; + + if (es1.sz != es2.sz) + { + assert(global.errors); + return EXP_CANT_INTERPRET; + } + if (es1.len == es2.len && memcmp(es1.string_, es2.string_, es1.sz * es1.len) == 0) + cmp = true; + else + cmp = false; + } + else if (e1.op == TOK.TOKarrayliteral && e2.op == TOK.TOKarrayliteral) + { + ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1; + ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2; + + if ((!es1.elements || !es1.elements.dim) && (!es2.elements || !es2.elements.dim)) + cmp = true; // both arrays are empty + else if (!es1.elements || !es2.elements) + cmp = false; + else if (es1.elements.dim != es2.elements.dim) + cmp = false; + else + { + for (size_t i = 0; i < es1.elements.dim; i++) + { + Expression ee1 = cast(Expression)es1.elements.data[i]; + Expression ee2 = cast(Expression)es2.elements.data[i]; + + Expression v = Equal(TOK.TOKequal, Type.tint32, ee1, ee2); + if (v == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + long tmp = v.toInteger(); + cmp = (tmp != 0); + if (!cmp) + break; + } + } + } + else if (e1.op == TOK.TOKarrayliteral && e2.op == TOK.TOKstring) + { + // Swap operands and use common code + Expression ee = e1; + e1 = e2; + e2 = ee; + goto Lsa; + } + else if (e1.op == TOK.TOKstring && e2.op == TOK.TOKarrayliteral) + { + Lsa: + StringExp es1 = cast(StringExp)e1; + ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2; + size_t dim1 = es1.len; + size_t dim2 = es2.elements ? es2.elements.dim : 0; + if (dim1 != dim2) + cmp = false; + else + { + for (size_t i = 0; i < dim1; i++) + { + ulong c = es1.charAt(i); + Expression ee2 = cast(Expression)es2.elements.data[i]; + if (ee2.isConst() != 1) + return EXP_CANT_INTERPRET; + cmp = (c == ee2.toInteger()); + if (!cmp) + break; + } + } + } + else if (e1.op == TOK.TOKstructliteral && e2.op == TOK.TOKstructliteral) + { + StructLiteralExp es1 = cast(StructLiteralExp)e1; + StructLiteralExp es2 = cast(StructLiteralExp)e2; + + if (es1.sd != es2.sd) + cmp = false; + else if ((!es1.elements || !es1.elements.dim) && (!es2.elements || !es2.elements.dim)) + cmp = true; // both arrays are empty + else if (!es1.elements || !es2.elements) + cmp = false; + else if (es1.elements.dim != es2.elements.dim) + cmp = false; + else + { + cmp = true; + for (size_t i = 0; i < es1.elements.dim; i++) + { + Expression ee1 = cast(Expression)es1.elements.data[i]; + Expression ee2 = cast(Expression)es2.elements.data[i]; + + if (ee1 == ee2) + continue; + if (!ee1 || !ee2) + { + cmp = false; + break; + } + Expression v = Equal(TOK.TOKequal, Type.tint32, ee1, ee2); + if (v == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + long tmp = v.toInteger(); + cmp = (tmp != 0); + if (!cmp) + break; + } + } + } +///static if (false) { +/// else if (e1.op == TOKarrayliteral && e2.op == TOKstring) +/// { +/// } +///} + else if (e1.isConst() != 1 || e2.isConst() != 1) + return EXP_CANT_INTERPRET; + else if (e1.type.isreal()) + { + r1 = e1.toReal(); + r2 = e2.toReal(); + goto L1; + } + else if (e1.type.isimaginary()) + { + r1 = e1.toImaginary(); + r2 = e2.toImaginary(); + L1: + cmp = (r1 == r2); + } + else if (e1.type.iscomplex()) + { + cmp = (e1.toComplex() == e2.toComplex()); + } + else if (e1.type.isintegral()) + { + cmp = (e1.toInteger() == e2.toInteger()); + } + else + return EXP_CANT_INTERPRET; + if (op == TOK.TOKnotequal) + cmp = !cmp; + + e = new IntegerExp(loc, cmp, type); + + return e; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/expression/Identity.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/expression/Identity.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,42 @@ +module dmd.expression.Identity; + +import dmd.Expression; +import dmd.Type; +import dmd.TOK; +import dmd.Loc; +import dmd.SymOffExp; +import dmd.IntegerExp; + +import dmd.expression.Equal; + +Expression Identity(TOK op, Type type, Expression e1, Expression e2) +{ + Expression e; + Loc loc = e1.loc; + int cmp; + + if (e1.op == TOK.TOKnull) + { + cmp = (e2.op == TOK.TOKnull); + } + else if (e2.op == TOK.TOKnull) + { + cmp = 0; + } + else if (e1.op == TOK.TOKsymoff && e2.op == TOK.TOKsymoff) + { + SymOffExp es1 = cast(SymOffExp)e1; + SymOffExp es2 = cast(SymOffExp)e2; + + cmp = (es1.var == es2.var && es1.offset == es2.offset); + } + else if (e1.isConst() == 1 && e2.isConst() == 1) + return Equal((op == TOK.TOKidentity) ? TOK.TOKequal : TOK.TOKnotequal, type, e1, e2); + else + assert(0); + + if (op == TOK.TOKnotidentity) + cmp ^= 1; + + return new IntegerExp(loc, cmp, type); +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/expression/Index.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/expression/Index.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,96 @@ +module dmd.expression.Index; + +import dmd.Type; +import dmd.Loc; +import dmd.StringExp; +import dmd.TOK; +import dmd.Expression; +import dmd.GlobalExpressions; +import dmd.IntegerExp; +import dmd.TY; +import dmd.TypeSArray; +import dmd.ArrayLiteralExp; +import dmd.AssocArrayLiteralExp; + +import dmd.expression.Equal; + +/* Also return EXP_CANT_INTERPRET if this fails + */ +Expression Index(Type type, Expression e1, Expression e2) +{ + Expression e = EXP_CANT_INTERPRET; + Loc loc = e1.loc; + + //printf("Index(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars()); + assert(e1.type); + if (e1.op == TOKstring && e2.op == TOKint64) + { + StringExp es1 = cast(StringExp)e1; + ulong i = e2.toInteger(); + + if (i >= es1.len) + e1.error("string index %ju is out of bounds [0 .. %zu]", i, es1.len); + else + { + uint value = es1.charAt(cast(uint)i); + e = new IntegerExp(loc, value, type); + } + } + else if (e1.type.toBasetype().ty == Tsarray && e2.op == TOKint64) + { + TypeSArray tsa = cast(TypeSArray)e1.type.toBasetype(); + ulong length = tsa.dim.toInteger(); + ulong i = e2.toInteger(); + + if (i >= length) + { + e2.error("array index %ju is out of bounds %s[0 .. %ju]", i, e1.toChars(), length); + } + else if (e1.op == TOKarrayliteral && !e1.checkSideEffect(2)) + { + ArrayLiteralExp ale = cast(ArrayLiteralExp)e1; + e = cast(Expression)ale.elements.data[cast(uint)i]; + e.type = type; + } + } + else if (e1.type.toBasetype().ty == Tarray && e2.op == TOKint64) + { + ulong i = e2.toInteger(); + + if (e1.op == TOKarrayliteral && !e1.checkSideEffect(2)) + { + ArrayLiteralExp ale = cast(ArrayLiteralExp)e1; + if (i >= ale.elements.dim) + { + e2.error("array index %ju is out of bounds %s[0 .. %u]", i, e1.toChars(), ale.elements.dim); + } + else + { + e = cast(Expression)ale.elements.data[cast(uint)i]; + e.type = type; + } + } + } + else if (e1.op == TOKassocarrayliteral && !e1.checkSideEffect(2)) + { + AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e1; + /* Search the keys backwards, in case there are duplicate keys + */ + for (size_t i = ae.keys.dim; i;) + { + i--; + Expression ekey = cast(Expression)ae.keys.data[i]; + Expression ex = Equal(TOKequal, Type.tbool, ekey, e2); + if (ex is EXP_CANT_INTERPRET) + return ex; + if (ex.isBool(true)) + { + e = cast(Expression)ae.values.data[i]; + e.type = type; + break; + } + } + } + + return e; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/expression/Min.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/expression/Min.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,97 @@ +module dmd.expression.Min; + +import dmd.Expression; +import dmd.Type; +import dmd.Loc; +import dmd.RealExp; +import dmd.ComplexExp; +import dmd.IntegerExp; +import dmd.TOK; +import dmd.SymOffExp; +import dmd.Complex; + +Expression Min(Type type, Expression e1, Expression e2) +{ + Expression e; + Loc loc = e1.loc; + + if (type.isreal()) + { + e = new RealExp(loc, e1.toReal() - e2.toReal(), type); + } + else if (type.isimaginary()) + { + e = new RealExp(loc, e1.toImaginary() - e2.toImaginary(), type); + } + else if (type.iscomplex()) + { + // This rigamarole is necessary so that -0.0 doesn't get + // converted to +0.0 by doing an extraneous add with +0.0 + Complex!(real) c1; + real r1; + real i1; + + Complex!(real) c2; + real r2; + real i2; + + Complex!(real) v; + int x; + + if (e1.type.isreal()) + { + r1 = e1.toReal(); + x = 0; + } + else if (e1.type.isimaginary()) + { + i1 = e1.toImaginary(); + x = 3; + } + else + { + c1 = e1.toComplex(); + x = 6; + } + + if (e2.type.isreal()) + { + r2 = e2.toReal(); + } + else if (e2.type.isimaginary()) + { + i2 = e2.toImaginary(); + x += 1; + } + else + { + c2 = e2.toComplex(); + x += 2; + } + + switch (x) + { + case 0+0: v = Complex!(real)(r1 - r2, 0); break; + case 0+1: v = Complex!(real)(r1, -i2); break; + case 0+2: v = Complex!(real)(r1 - c2.re, -c2.im); break; + case 3+0: v = Complex!(real)(-r2, i1); break; + case 3+1: v = Complex!(real)(0, i1 - i2); break; + case 3+2: v = Complex!(real)(c2.re, i1 - c2.im); break; + case 6+0: v = Complex!(real)(c1.re - r2, c1.im); break; + case 6+1: v = Complex!(real)(c1.re, c1.im - i2); break; + case 6+2: v = Complex!(real)(c1.re - c2.re, c1.im - c2.im); break; + } + e = new ComplexExp(loc, v, type); + } + else if (e1.op == TOK.TOKsymoff) + { + SymOffExp soe = cast(SymOffExp)e1; + e = new SymOffExp(loc, soe.var, soe.offset - cast(uint)e2.toInteger()); + e.type = type; + } + else + { + e = new IntegerExp(loc, e1.toInteger() - e2.toInteger(), type); + } + return e; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/expression/Mod.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/expression/Mod.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,67 @@ +module dmd.expression.Mod; + +import dmd.Loc; +import dmd.Type; +import dmd.Expression; +import dmd.IntegerExp; +import dmd.RealExp; +import dmd.ComplexExp; +import dmd.Complex; + +import core.stdc.math; + +Expression Mod(Type type, Expression e1, Expression e2) +{ + Expression e; + Loc loc = e1.loc; + + if (type.isfloating()) + { + Complex!(real) c; + + if (e2.type.isreal()) + { + real r2 = e2.toReal(); + c = Complex!(real)(fmodl(e1.toReal(), r2), fmodl(e1.toImaginary(), r2));; + } + else if (e2.type.isimaginary()) + { + real i2 = e2.toImaginary(); + c = Complex!(real)(fmodl(e1.toReal(), i2), fmodl(e1.toImaginary(), i2)); + } + else + assert(0); + + if (type.isreal()) + e = new RealExp(loc, c.re, type); + else if (type.isimaginary()) + e = new RealExp(loc, c.im, type); + else if (type.iscomplex()) + e = new ComplexExp(loc, c, type); + else + assert(0); + } + else + { + long n1; + long n2; + long n; + + n1 = e1.toInteger(); + n2 = e2.toInteger(); + if (n2 == 0) + { + e2.error("divide by 0"); + e2 = new IntegerExp(loc, 1, e2.type); + n2 = 1; + } + + if (e1.type.isunsigned() || e2.type.isunsigned()) + n = (cast(ulong) n1) % (cast(ulong) n2); + else + n = n1 % n2; + + e = new IntegerExp(loc, n, type); + } + return e; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/expression/Mul.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/expression/Mul.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,66 @@ +module dmd.expression.Mul; + +import dmd.Type; +import dmd.Expression; +import dmd.RealExp; +import dmd.IntegerExp; +import dmd.ComplexExp; +import dmd.Loc; +import dmd.Complex; + +Expression Mul(Type type, Expression e1, Expression e2) +{ + Expression e; + Loc loc = e1.loc; + + if (type.isfloating()) + { + Complex!(real) c; + real r; + + if (e1.type.isreal()) + { + r = e1.toReal(); + c = e2.toComplex(); + c = Complex!(real)(r * c.re, r * c.im); + } + else if (e1.type.isimaginary()) + { + r = e1.toImaginary(); + c = e2.toComplex(); + c = Complex!(real)(-r * c.im, r * c.re); + } + else if (e2.type.isreal()) + { + r = e2.toReal(); + c = e1.toComplex(); + c = Complex!(real)(r * c.re, r * c.im); + } + else if (e2.type.isimaginary()) + { + r = e2.toImaginary(); + c = e1.toComplex(); + c = Complex!(real)(-r * c.im, r * c.re); + } + else + { + Complex!(real) c1 = e1.toComplex(); + Complex!(real) c2 = e2.toComplex(); + c = Complex!(real)(c1.re * c2.re - c1.im * c2.im, c1.re * c2.im + c1.im * c2.re); + } + + if (type.isreal()) + e = new RealExp(loc, c.re, type); + else if (type.isimaginary()) + e = new RealExp(loc, c.im, type); + else if (type.iscomplex()) + e = new ComplexExp(loc, c, type); + else + assert(0); + } + else + { + e = new IntegerExp(loc, e1.toInteger() * e2.toInteger(), type); + } + return e; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/expression/Neg.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/expression/Neg.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,33 @@ +module dmd.expression.Neg; + +import dmd.Type; +import dmd.Loc; +import dmd.RealExp; +import dmd.Expression; +import dmd.ComplexExp; +import dmd.IntegerExp; +import dmd.Complex; + +Expression Neg(Type type, Expression e1) +{ + Expression e; + Loc loc = e1.loc; + + if (e1.type.isreal()) + { + e = new RealExp(loc, -e1.toReal(), type); + } + else if (e1.type.isimaginary()) + { + e = new RealExp(loc, -e1.toImaginary(), type); + } + else if (e1.type.iscomplex()) + { + Complex!(real) c = e1.toComplex(); + e = new ComplexExp(loc, Complex!(real)(-c.re, -c.im), type); + } + else + e = new IntegerExp(loc, -e1.toInteger(), type); + + return e; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/expression/Not.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/expression/Not.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,10 @@ +module dmd.expression.Not; + +import dmd.Type; +import dmd.Expression; +import dmd.IntegerExp; + +Expression Not(Type type, Expression e1) +{ + return new IntegerExp(e1.loc, e1.isBool(false), type); +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/expression/Or.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/expression/Or.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,10 @@ +module dmd.expression.Or; + +import dmd.Type; +import dmd.Expression; +import dmd.IntegerExp; + +Expression Or(Type type, Expression e1, Expression e2) +{ + return new IntegerExp(e1.loc, e1.toInteger() | e2.toInteger(), type); +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/expression/Ptr.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/expression/Ptr.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,35 @@ +module dmd.expression.Ptr; + +import dmd.Expression; +import dmd.Type; +import dmd.TOK; +import dmd.AddrExp; +import dmd.AddExp; +import dmd.StructLiteralExp; +import dmd.GlobalExpressions; + +Expression Ptr(Type type, Expression e1) +{ + //printf("Ptr(e1 = %s)\n", e1->toChars()); + if (e1.op == TOK.TOKadd) + { + AddExp ae = cast(AddExp)e1; + if (ae.e1.op == TOK.TOKaddress && ae.e2.op == TOK.TOKint64) + { + AddrExp ade = cast(AddrExp)ae.e1; + if (ade.e1.op == TOK.TOKstructliteral) + { + StructLiteralExp se = cast(StructLiteralExp)ade.e1; + uint offset = cast(uint)ae.e2.toInteger(); + Expression e = se.getField(type, offset); + if (!e) + e = EXP_CANT_INTERPRET; + + return e; + } + } + } + + return EXP_CANT_INTERPRET; +} + diff -r 000000000000 -r 10317f0c89a5 dmd/expression/Shl.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/expression/Shl.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,10 @@ +module dmd.expression.Shl; + +import dmd.Expression; +import dmd.Type; +import dmd.IntegerExp; + +Expression Shl(Type type, Expression e1, Expression e2) +{ + return new IntegerExp(e1.loc, e1.toInteger() << e2.toInteger(), type); +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/expression/Shr.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/expression/Shr.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,52 @@ +module dmd.expression.Shr; + +import dmd.Expression; +import dmd.Type; +import dmd.Loc; +import dmd.IntegerExp; +import dmd.TY; + +Expression Shr(Type type, Expression e1, Expression e2) +{ + Loc loc = e1.loc; + + long value = e1.toInteger(); + uint count = cast(uint)e2.toInteger(); + + switch (e1.type.toBasetype().ty) + { + case TY.Tint8: + value = cast(byte)(value) >> count; + break; + + case TY.Tuns8: + value = cast(ubyte)(value) >> count; + break; + + case TY.Tint16: + value = cast(short)(value) >> count; + break; + + case TY.Tuns16: + value = cast(ushort)(value) >> count; + break; + + case TY.Tint32: + value = cast(int)(value) >> count; + break; + + case TY.Tuns32: + value = cast(uint)(value) >> count; + break; + + case TY.Tint64: + value = cast(long)(value) >> count; + break; + + case TY.Tuns64: + value = cast(ulong)(value) >> count; + break; + } + + return new IntegerExp(loc, value, type); +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/expression/Slice.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/expression/Slice.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,79 @@ +module dmd.expression.Slice; + +import dmd.Expression; +import dmd.Type; +import dmd.Loc; +import dmd.TOK; +import dmd.StringExp; +import dmd.GlobalExpressions; +import dmd.ArrayLiteralExp; +import dmd.ArrayTypes; + +import core.stdc.stdlib; +import core.stdc.string; + +import std.contracts; + +/* Also return EXP_CANT_INTERPRET if this fails + */ +Expression Slice(Type type, Expression e1, Expression lwr, Expression upr) +{ + Expression e = EXP_CANT_INTERPRET; + Loc loc = e1.loc; + +version (LOG) { + printf("Slice()\n"); + if (lwr) + { + printf("\te1 = %s\n", e1.toChars()); + printf("\tlwr = %s\n", lwr.toChars()); + printf("\tupr = %s\n", upr.toChars()); + } +} + if (e1.op == TOKstring && lwr.op == TOKint64 && upr.op == TOKint64) + { + StringExp es1 = cast(StringExp)e1; + ulong ilwr = lwr.toInteger(); + ulong iupr = upr.toInteger(); + + if (iupr > es1.len || ilwr > iupr) + e1.error("string slice [%ju .. %ju] is out of bounds", ilwr, iupr); + else + { + size_t len = cast(size_t)(iupr - ilwr); + int sz = es1.sz; + + char* s = cast(char*)malloc((len + 1) * sz); + memcpy(s, cast(ubyte*)es1.string_ + ilwr * sz, len * sz); + memset(s + len * sz, 0, sz); + + StringExp es = new StringExp(loc, assumeUnique(s[0..len]), es1.postfix); + es.sz = cast(ubyte)sz; + es.committed = 1; + es.type = type; + e = es; + } + } + else if (e1.op == TOKarrayliteral && + lwr.op == TOKint64 && upr.op == TOKint64 && + !e1.checkSideEffect(2)) + { + ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1; + ulong ilwr = lwr.toInteger(); + ulong iupr = upr.toInteger(); + + if (iupr > es1.elements.dim || ilwr > iupr) + e1.error("array slice [%ju .. %ju] is out of bounds", ilwr, iupr); + else + { + Expressions elements = new Expressions(); + elements.setDim(cast(uint)(iupr - ilwr)); + memcpy(elements.data, + es1.elements.data + ilwr, + cast(uint)(iupr - ilwr) * (*es1.elements.data).sizeof); + e = new ArrayLiteralExp(e1.loc, elements); + e.type = type; + } + } + return e; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/expression/Ushr.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/expression/Ushr.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,50 @@ +module dmd.expression.Ushr; + +import dmd.Type; +import dmd.Expression; +import dmd.Loc; +import dmd.TY; +import dmd.IntegerExp; + +Expression Ushr(Type type, Expression e1, Expression e2) +{ + Expression e; + Loc loc = e1.loc; + uint count; + ulong value; + + value = e1.toInteger(); + count = cast(uint)e2.toInteger(); + + switch (e1.type.toBasetype().ty) + { + case Tint8: + case Tuns8: + assert(0); // no way to trigger this + value = (value & 0xFF) >> count; + break; + + case Tint16: + case Tuns16: + assert(0); // no way to trigger this + value = (value & 0xFFFF) >> count; + break; + + case Tint32: + case Tuns32: + value = (value & 0xFFFFFFFF) >> count; + break; + + case Tint64: + case Tuns64: + value = cast(ulong)(value) >> count; + break; + + default: + assert(0); + } + + e = new IntegerExp(loc, value, type); + + return e; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/expression/Util.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/expression/Util.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,1363 @@ +module dmd.expression.Util; + +import dmd.Expression; +import dmd.Loc; +import dmd.BUILTIN; +import dmd.Scope; +import dmd.FuncExp; +import dmd.DelegateExp; +import dmd.LINK; +import dmd.NullExp; +import dmd.SymOffExp; +import dmd.ExpInitializer; +import dmd.Lexer; +import dmd.TypeSArray; +import dmd.TypeArray; +import dmd.VarDeclaration; +import dmd.VoidInitializer; +import dmd.DeclarationExp; +import dmd.VarExp; +import dmd.NewExp; +import dmd.STC; +import dmd.WANT; +import dmd.IndexExp; +import dmd.AssignExp; +import dmd.CommaExp; +import dmd.Argument; +import dmd.DefaultInitExp; +import dmd.Identifier; +import dmd.Dsymbol; +import dmd.Global; +import dmd.ScopeDsymbol; +import dmd.DotIdExp; +import dmd.DotVarExp; +import dmd.CallExp; +import dmd.TY; +import dmd.MATCH; +import dmd.TypeFunction; +import dmd.declaration.Match; +import dmd.ArrayTypes; +import dmd.Declaration; +import dmd.FuncAliasDeclaration; +import dmd.AliasDeclaration; +import dmd.FuncDeclaration; +import dmd.TemplateDeclaration; +import dmd.AggregateDeclaration; +import dmd.IntegerExp; +import dmd.Type; +import dmd.TOK; +import dmd.TypeExp; +import dmd.TypeTuple; +import dmd.TupleExp; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.ClassDeclaration; +import dmd.TypeClass; +import dmd.StructDeclaration; +import dmd.TypeStruct; +import dmd.MOD; +import dmd.PROT; +import dmd.PREC; +import dmd.Util; +import dmd.TypeAArray; +import dmd.Id; + +import std.stdio : writef; + + +/*********************************** + * Utility to build a function call out of this reference and argument. + */ +Expression build_overload(Loc loc, Scope sc, Expression ethis, Expression earg, Identifier id) +{ + Expression e; + + //printf("build_overload(id = '%s')\n", id.toChars()); + //earg.print(); + //earg.type.print(); + e = new DotIdExp(loc, ethis, id); + + if (earg) + e = new CallExp(loc, e, earg); + else + e = new CallExp(loc, e); + + e = e.semantic(sc); + return e; +} + +/*************************************** + * Search for function funcid in aggregate ad. + */ + +Dsymbol search_function(ScopeDsymbol ad, Identifier funcid) +{ + Dsymbol s; + FuncDeclaration fd; + TemplateDeclaration td; + + s = ad.search(Loc(0), funcid, 0); + if (s) + { + Dsymbol s2; + + //printf("search_function: s = '%s'\n", s.kind()); + s2 = s.toAlias(); + //printf("search_function: s2 = '%s'\n", s2.kind()); + fd = s2.isFuncDeclaration(); + if (fd && fd.type.ty == TY.Tfunction) + return fd; + + td = s2.isTemplateDeclaration(); + if (td) + return td; + } + + return null; +} + +/******************************************** + * Find function in overload list that exactly matches t. + */ + +/*************************************************** + * Visit each overloaded function in turn, and call + * dg(param, f) on it. + * Exit when no more, or dg(param, f) returns 1. + * Returns: + * 0 continue + * 1 done + */ + +int overloadApply(FuncDeclaration fstart, int delegate(FuncDeclaration) dg) +{ + FuncDeclaration f; + Declaration d; + Declaration next; + + for (d = fstart; d; d = next) + { + FuncAliasDeclaration fa = d.isFuncAliasDeclaration(); + + if (fa) + { + if (overloadApply(fa.funcalias, dg)) + return 1; + next = fa.overnext; + } + else + { + AliasDeclaration a = d.isAliasDeclaration(); + + if (a) + { + Dsymbol s = a.toAlias(); + next = s.isDeclaration(); + if (next is a) + break; + if (next is fstart) + break; + } + else + { + f = d.isFuncDeclaration(); + if (f is null) + { + d.error("is aliased to a function"); + break; // BUG: should print error message? + } + if (dg(f)) + return 1; + + next = f.overnext; + } + } + } + return 0; +} + +/******************************************** + * Decide which function matches the arguments best. + */ + +struct Param2 +{ + Match* m; + Expression ethis; + Expressions arguments; + + int fp2(FuncDeclaration f) + { + MATCH match; + + if (f != m.lastf) // skip duplicates + { + m.anyf = f; + TypeFunction tf = cast(TypeFunction)f.type; + match = tf.callMatch(f.needThis() ? ethis : null, arguments); + //printf("match = %d\n", match); + if (match != MATCH.MATCHnomatch) + { + if (match > m.last) + goto LfIsBetter; + + if (match < m.last) + goto LlastIsBetter; + + /* See if one of the matches overrides the other. + */ + if (m.lastf.overrides(f)) + goto LlastIsBetter; + else if (f.overrides(m.lastf)) + goto LfIsBetter; + + /* Try to disambiguate using template-style partial ordering rules. + * In essence, if f() and g() are ambiguous, if f() can call g(), + * but g() cannot call f(), then pick f(). + * This is because f() is "more specialized." + */ + { + MATCH c1 = f.leastAsSpecialized(m.lastf); + MATCH c2 = m.lastf.leastAsSpecialized(f); + //printf("c1 = %d, c2 = %d\n", c1, c2); + if (c1 > c2) + goto LfIsBetter; + if (c1 < c2) + goto LlastIsBetter; + } + + Lambiguous: + m.nextf = f; + m.count++; + return 0; + + LfIsBetter: + m.last = match; + m.lastf = f; + m.count = 1; + return 0; + + LlastIsBetter: + return 0; + } + } + return 0; + } +} + +struct Param1 +{ + Type t; // type to match + FuncDeclaration f; // return value + + int fp1(FuncDeclaration f) + { + if (t.equals(f.type)) + { + this.f = f; + return 1; + } + + version (DMDV2) { + /* Allow covariant matches, if it's just a const conversion + * of the return type + */ + if (t.ty == Tfunction) + { + TypeFunction tf = cast(TypeFunction)f.type; + if (tf.covariant(t) == 1 && + tf.nextOf().implicitConvTo(t.nextOf()) >= MATCHconst) + { + this.f = f; + return 1; + } + } + } + return 0; + } +} + +void overloadResolveX(Match* m, FuncDeclaration fstart, Expression ethis, Expressions arguments) +{ + Param2 p; + p.m = m; + p.ethis = ethis; + p.arguments = arguments; + overloadApply(fstart, &p.fp2); +} + +void templateResolve(Match* m, TemplateDeclaration td, Scope sc, Loc loc, Objects targsi, Expression ethis, Expressions arguments) +{ + FuncDeclaration fd; + + assert(td); + fd = td.deduceFunctionTemplate(sc, loc, targsi, ethis, arguments); + if (!fd) + return; + m.anyf = fd; + if (m.last >= MATCH.MATCHexact) + { + m.nextf = fd; + m.count++; + } + else + { + m.last = MATCH.MATCHexact; + m.lastf = fd; + m.count = 1; + } +} + +/****************************** + * Perform semantic() on an array of Expressions. + */ + +void arrayExpressionSemantic(Expressions exps, Scope sc) +{ + if (exps) + { + for (size_t i = 0; i < exps.dim; i++) + { + Expression e = cast(Expression)exps.data[i]; + + e = e.semantic(sc); + exps.data[i] = cast(void*)e; + } + } +} + +/**************************************** + * Preprocess arguments to function. + */ + +void preFunctionArguments(Loc loc, Scope sc, Expressions exps) +{ + if (exps) + { + expandTuples(exps); + + for (size_t i = 0; i < exps.dim; i++) + { + Expression arg = cast(Expression)exps.data[i]; + + if (!arg.type) + { +debug { + if (!global.gag) + writef("1: \n"); +} + arg.error("%s is not an expression", arg.toChars()); + arg = new IntegerExp(arg.loc, 0, Type.tint32); + } + + arg = resolveProperties(sc, arg); + exps.data[i] = cast(void*) arg; + + //arg.rvalue(); +static if (false) { + if (arg.type.ty == TY.Tfunction) + { + arg = new AddrExp(arg.loc, arg); + arg = arg.semantic(sc); + exps.data[i] = cast(void*) arg; + } +} + } + } +} + +/************************************************************* + * Given var, we need to get the + * right 'this' pointer if var is in an outer class, but our + * existing 'this' pointer is in an inner class. + * Input: + * e1 existing 'this' + * ad struct or class we need the correct 'this' for + * var the specific member of ad we're accessing + */ + +Expression getRightThis(Loc loc, Scope sc, AggregateDeclaration ad, Expression e1, Declaration var) +{ + //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1.toChars(), ad.toChars(), var.toChars()); + L1: + Type t = e1.type.toBasetype(); + //printf("e1.type = %s, var.type = %s\n", e1.type.toChars(), var.type.toChars()); + + /* If e1 is not the 'this' pointer for ad + */ + if (ad && !(t.ty == TY.Tpointer && t.nextOf().ty == TY.Tstruct && (cast(TypeStruct)t.nextOf()).sym == ad) && !(t.ty == TY.Tstruct && (cast(TypeStruct)t).sym == ad)) + { + ClassDeclaration cd = ad.isClassDeclaration(); + ClassDeclaration tcd = t.isClassHandle(); + + /* e1 is the right this if ad is a base class of e1 + */ + if (!cd || !tcd || !(tcd == cd || cd.isBaseOf(tcd, null))) + { + /* Only classes can be inner classes with an 'outer' + * member pointing to the enclosing class instance + */ + if (tcd && tcd.isNested()) + { + /* e1 is the 'this' pointer for an inner class: tcd. + * Rewrite it as the 'this' pointer for the outer class. + */ + + e1 = new DotVarExp(loc, e1, tcd.vthis); + e1.type = tcd.vthis.type; + // Do not call checkNestedRef() + //e1 = e1.semantic(sc); + + // Skip up over nested functions, and get the enclosing + // class type. + int n = 0; + Dsymbol s; + for (s = tcd.toParent(); s && s.isFuncDeclaration(); s = s.toParent()) + { + FuncDeclaration f = s.isFuncDeclaration(); + if (f.vthis) + { + //printf("rewriting e1 to %s's this\n", f.toChars()); + n++; + e1 = new VarExp(loc, f.vthis); + } + } + if (s && s.isClassDeclaration()) + { + e1.type = s.isClassDeclaration().type; + if (n > 1) + e1 = e1.semantic(sc); + } + else + e1 = e1.semantic(sc); + goto L1; + } + /* Can't find a path from e1 to ad + */ + e1.error("this for %s needs to be type %s not type %s", var.toChars(), ad.toChars(), t.toChars()); + } + } + return e1; +} + +/******************************************* + * Given a symbol that could be either a FuncDeclaration or + * a function template, resolve it to a function symbol. + * sc instantiation scope + * loc instantiation location + * targsi initial list of template arguments + * ethis if !null, the 'this' pointer argument + * fargs arguments to function + * flags 1: do not issue error message on no match, just return null + */ + +FuncDeclaration resolveFuncCall(Scope sc, Loc loc, Dsymbol s, + Objects tiargs, + Expression ethis, + Expressions arguments, + int flags) +{ + if (!s) + return null; // no match + FuncDeclaration f = s.isFuncDeclaration(); + if (f) + f = f.overloadResolve(loc, ethis, arguments); + else + { + TemplateDeclaration td = s.isTemplateDeclaration(); + assert(td); + f = td.deduceFunctionTemplate(sc, loc, tiargs, null, arguments, flags); + } + return f; +} + +/**************************************** + * Now that we know the exact type of the function we're calling, + * the arguments[] need to be adjusted: + * 1. implicitly convert argument to the corresponding parameter type + * 2. add default arguments for any missing arguments + * 3. do default promotions on arguments corresponding to ... + * 4. add hidden _arguments[] argument + * 5. call copy constructor for struct value arguments + */ + +void functionArguments(Loc loc, Scope sc, TypeFunction tf, Expressions arguments) +{ + uint n; + + //printf("functionArguments()\n"); + assert(arguments); + size_t nargs = arguments ? arguments.dim : 0; + size_t nparams = Argument.dim(tf.parameters); + + if (nargs > nparams && tf.varargs == 0) + error(loc, "expected %zu arguments, not %zu for non-variadic function type %s", nparams, nargs, tf.toChars()); + + n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams) + + int done = 0; + for (size_t i = 0; i < n; i++) + { + Expression arg; + + if (i < nargs) + arg = cast(Expression)arguments.data[i]; + else + arg = null; + + Type tb; + + if (i < nparams) + { + Argument p = Argument.getNth(tf.parameters, i); + + if (!arg) + { + if (!p.defaultArg) + { + if (tf.varargs == 2 && i + 1 == nparams) + goto L2; + + error(loc, "expected %d function arguments, not %d", nparams, nargs); + break; + } + arg = p.defaultArg; +version (DMDV2) { + if (arg.op == TOK.TOKdefault) + { + DefaultInitExp de = cast(DefaultInitExp)arg; + arg = de.resolve(loc, sc); + } + else + { + arg = arg.copy(); + } +} else { + arg = arg.copy(); +} + arguments.push(cast(void*)arg); + nargs++; + } + + if (tf.varargs == 2 && i + 1 == nparams) + { + //printf("\t\tvarargs == 2, p.type = '%s'\n", p.type.toChars()); + if (arg.implicitConvTo(p.type)) + { + if (nargs != nparams) + error(loc, "expected %zu function arguments, not %zu", nparams, nargs); + goto L1; + } + L2: + tb = p.type.toBasetype(); /// + Type tret = p.isLazyArray(); + switch (tb.ty) + { + case TY.Tsarray: + case TY.Tarray: + { // Create a static array variable v of type arg.type +version (IN_GCC) { + /* GCC 4.0 does not like zero length arrays used like + this; pass a null array value instead. Could also + just make a one-element array. */ + if (nargs - i == 0) + { + arg = new NullExp(loc); + break; + } +} + Identifier id = Lexer.uniqueId("__arrayArg"); + Type t = new TypeSArray((cast(TypeArray)tb).next, new IntegerExp(nargs - i)); + t = t.semantic(loc, sc); + VarDeclaration v = new VarDeclaration(loc, t, id, new VoidInitializer(loc)); + v.semantic(sc); + v.parent = sc.parent; + //sc.insert(v); + + Expression c = new DeclarationExp(Loc(0), v); + c.type = v.type; + + for (size_t u = i; u < nargs; u++) + { + Expression a = cast(Expression)arguments.data[u]; + if (tret && !(cast(TypeArray)tb).next.equals(a.type)) + a = a.toDelegate(sc, tret); + + Expression e = new VarExp(loc, v); + e = new IndexExp(loc, e, new IntegerExp(u + 1 - nparams)); + AssignExp ae = new AssignExp(loc, e, a); + + version (DMDV2) { + ae.op = TOK.TOKconstruct; + } + + if (c) + c = new CommaExp(loc, c, ae); + else + c = ae; + } + + arg = new VarExp(loc, v); + if (c) + arg = new CommaExp(loc, c, arg); + break; + } + + case TY.Tclass: + { /* Set arg to be: + * new Tclass(arg0, arg1, ..., argn) + */ + Expressions args = new Expressions(); + args.setDim(nargs - i); + for (size_t u = i; u < nargs; u++) + args.data[u - i] = arguments.data[u]; + arg = new NewExp(loc, null, null, p.type, args); + break; + } + + default: + if (!arg) + { + error(loc, "not enough arguments"); + return; + } + break; + } + + arg = arg.semantic(sc); + //printf("\targ = '%s'\n", arg.toChars()); + arguments.setDim(i + 1); + done = 1; + } + + L1: + if (!(p.storageClass & STC.STClazy && p.type.ty == TY.Tvoid)) + { + if (p.type != arg.type) + { + //printf("arg.type = %s, p.type = %s\n", arg.type.toChars(), p.type.toChars()); + arg = arg.implicitCastTo(sc, p.type); + arg = arg.optimize(WANT.WANTvalue); + } + } + if (p.storageClass & STC.STCref) + { + arg = arg.toLvalue(sc, arg); + } + else if (p.storageClass & STC.STCout) + { + arg = arg.modifiableLvalue(sc, arg); + } + + // Convert static arrays to pointers + tb = arg.type.toBasetype(); + if (tb.ty == TY.Tsarray) + { + arg = arg.checkToPointer(); + } +version (DMDV2) { + if (tb.ty == TY.Tstruct && !(p.storageClass & (STC.STCref | STC.STCout))) + { + arg = callCpCtor(loc, sc, arg); + } +} + + // Convert lazy argument to a delegate + if (p.storageClass & STC.STClazy) + { + arg = arg.toDelegate(sc, p.type); + } +version (DMDV2) { + /* Look for arguments that cannot 'escape' from the called + * function. + */ + if (!tf.parameterEscapes(p)) + { + /* Function literals can only appear once, so if this + * appearance was scoped, there cannot be any others. + */ + if (arg.op == TOK.TOKfunction) + { + FuncExp fe = cast(FuncExp)arg; + fe.fd.tookAddressOf = 0; + } + + /* For passing a delegate to a scoped parameter, + * this doesn't count as taking the address of it. + * We only worry about 'escaping' references to the function. + */ + else if (arg.op == TOK.TOKdelegate) + { + DelegateExp de = cast(DelegateExp)arg; + if (de.e1.op == TOK.TOKvar) + { + VarExp ve = cast(VarExp)de.e1; + FuncDeclaration f = ve.var.isFuncDeclaration(); + if (f) + { + f.tookAddressOf--; + //printf("tookAddressOf = %d\n", f.tookAddressOf); + } + } + } + } +} + } + else + { + // If not D linkage, do promotions + if (tf.linkage != LINK.LINKd) + { + // Promote bytes, words, etc., to ints + arg = arg.integralPromotions(sc); + + // Promote floats to doubles + switch (arg.type.ty) + { + case TY.Tfloat32: + arg = arg.castTo(sc, Type.tfloat64); + break; + + case TY.Timaginary32: + arg = arg.castTo(sc, Type.timaginary64); + break; + default: + break; + } + } + + // Convert static arrays to dynamic arrays + tb = arg.type.toBasetype(); + if (tb.ty == TY.Tsarray) + { + TypeSArray ts = cast(TypeSArray)tb; + Type ta = ts.next.arrayOf(); + if (ts.size(arg.loc) == 0) + { + arg = new NullExp(arg.loc); + arg.type = ta; + } + else + { + arg = arg.castTo(sc, ta); + } + } +version (DMDV2) { + if (tb.ty == TY.Tstruct) + { + arg = callCpCtor(loc, sc, arg); + } + + // Give error for overloaded function addresses + if (arg.op == TOK.TOKsymoff) + { + SymOffExp se = cast(SymOffExp)arg; + if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique()) + arg.error("function %s is overloaded", arg.toChars()); + } +} + arg.rvalue(); + } + arg = arg.optimize(WANT.WANTvalue); + arguments.data[i] = cast(void*) arg; + if (done) + break; + } + + // If D linkage and variadic, add _arguments[] as first argument + if (tf.linkage == LINK.LINKd && tf.varargs == 1) + { + Expression e = createTypeInfoArray(sc, cast(Expression*)&arguments.data[nparams], arguments.dim - nparams); + arguments.insert(0, cast(void*)e); + } +} + +/**************************************** + * Expand tuples. + */ + +void expandTuples(Expressions exps) +{ + //printf("expandTuples()\n"); + if (exps) + { + for (size_t i = 0; i < exps.dim; i++) + { + Expression arg = cast(Expression)exps.data[i]; + if (!arg) + continue; + + // Look for tuple with 0 members + if (arg.op == TOK.TOKtype) + { + TypeExp e = cast(TypeExp)arg; + if (e.type.toBasetype().ty == TY.Ttuple) + { + TypeTuple tt = cast(TypeTuple)e.type.toBasetype(); + + if (!tt.arguments || tt.arguments.dim == 0) + { + exps.remove(i); + if (i == exps.dim) + return; + i--; + continue; + } + } + } + + // Inline expand all the tuples + while (arg.op == TOK.TOKtuple) + { + TupleExp te = cast(TupleExp)arg; + + exps.remove(i); // remove arg + exps.insert(i, cast(void*)te.exps); // replace with tuple contents + + if (i == exps.dim) + return; // empty tuple, no more arguments + + arg = cast(Expression)exps.data[i]; + } + } + } +} + +/************************************************** + * Write out argument types to buf. + */ + +void argExpTypesToCBuffer(OutBuffer buf, Expressions arguments, HdrGenState* hgs) +{ + if (arguments) + { + scope OutBuffer argbuf = new OutBuffer(); + + for (size_t i = 0; i < arguments.dim; i++) + { + Expression arg = cast(Expression)arguments.data[i]; + + if (i) + buf.writeByte(','); + + argbuf.reset(); + arg.type.toCBuffer2(argbuf, hgs, MOD.MODundefined); + buf.write(argbuf); + } + } +} + +/**************************************** + * Determine if scope sc has package level access to s. + */ + +bool hasPackageAccess(Scope sc, Dsymbol s) +{ +version (LOG) { + printf("hasPackageAccess(s = '%s', sc = '%p')\n", s.toChars(), sc); +} + + for (; s; s = s.parent) + { + if (s.isPackage() && !s.isModule()) + break; + } +version (LOG) { + if (s) + printf("\tthis is in package '%s'\n", s.toChars()); +} + + if (s && s == sc.module_.parent) + { +version (LOG) { + printf("\ts is in same package as sc\n"); +} + return true; + } + + +version (LOG) { + printf("\tno package access\n"); +} + + return false; +} + +/********************************************* + * Call copy constructor for struct value argument. + */ +version (DMDV2) { + Expression callCpCtor(Loc loc, Scope sc, Expression e) + { + Type tb = e.type.toBasetype(); + assert(tb.ty == Tstruct); + StructDeclaration sd = (cast(TypeStruct)tb).sym; + if (sd.cpctor) + { + /* Create a variable tmp, and replace the argument e with: + * (tmp = e),tmp + * and let AssignExp() handle the construction. + * This is not the most efficent, ideally tmp would be constructed + * directly onto the stack. + */ + Identifier idtmp = Lexer.uniqueId("__tmp"); + VarDeclaration tmp = new VarDeclaration(loc, tb, idtmp, new ExpInitializer(Loc(0), e)); + Expression ae = new DeclarationExp(loc, tmp); + e = new CommaExp(loc, ae, new VarExp(loc, tmp)); + e = e.semantic(sc); + } + return e; + } +} + +/*************************************** + * Create a static array of TypeInfo references + * corresponding to an array of Expression's. + * Used to supply hidden _arguments[] value for variadic D functions. + */ + +Expression createTypeInfoArray(Scope sc, Expression* exps, int dim) +{ + assert(false); +} + +/************************************** + * Evaluate builtin function. + * Return result: null if cannot evaluate it. + */ + +Expression eval_builtin(BUILTIN builtin, Expressions arguments) +{ + assert(false); +} + +Expression fromConstInitializer(int result, Expression e1) +{ + //printf("fromConstInitializer(result = %x, %s)\n", result, e1.toChars()); + //static int xx; if (xx++ == 10) assert(0); + Expression e = e1; + if (e1.op == TOK.TOKvar) + { + VarExp ve = cast(VarExp)e1; + VarDeclaration v = ve.var.isVarDeclaration(); + e = expandVar(result, v); + if (e) + { + if (e.type != e1.type) + { + // Type 'paint' operation + e = e.copy(); + e.type = e1.type; + } + } + else + { + e = e1; + } + } + return e; +} + +/************************************* + * If variable has a const initializer, + * return that initializer. + */ + +Expression expandVar(int result, VarDeclaration v) +{ + //printf("expandVar(result = %d, v = %p, %s)\n", result, v, v ? v.toChars() : "null"); + + Expression e = null; + if (!v) + return e; + + if (v.isConst() || v.isInvariant() || v.storage_class & STC.STCmanifest) + { + if (!v.type) + { + //error("ICE"); + return e; + } + + Type tb = v.type.toBasetype(); + if (result & WANT.WANTinterpret || v.storage_class & STC.STCmanifest || (tb.ty != TY.Tsarray && tb.ty != TY.Tstruct)) + { + if (v.init) + { + if (v.inuse) + { + if (v.storage_class & STC.STCmanifest) + v.error("recursive initialization of constant"); + goto L1; + } + Expression ei = v.init.toExpression(); + if (!ei) + goto L1; + if (ei.op == TOK.TOKconstruct || ei.op == TOK.TOKblit) + { + AssignExp ae = cast(AssignExp)ei; + ei = ae.e2; + if (ei.isConst() != 1 && ei.op != TOK.TOKstring) + goto L1; + if (ei.type != v.type) + goto L1; + } + if (v.scope_) + { + v.inuse++; + e = ei.syntaxCopy(); + e = e.semantic(v.scope_); + e = e.implicitCastTo(v.scope_, v.type); + // enabling this line causes test22 in test suite to fail + //ei.type = e.type; + v.scope_ = null; + v.inuse--; + } + else if (!ei.type) + { + goto L1; + } + else + // Should remove the copy() operation by + // making all mods to expressions copy-on-write + e = ei.copy(); + } + else + { +static if (true) { + goto L1; +} else { + // BUG: what if const is initialized in constructor? + e = v.type.defaultInit(); + e.loc = e1.loc; +} + } + if (e.type != v.type) + { + e = e.castTo(null, v.type); + } + v.inuse++; + e = e.optimize(result); + v.inuse--; + } + } +L1: + //if (e) printf("\te = %s, e.type = %s\n", e.toChars(), e.type.toChars()); + return e; +} + +/**************************************** + * Check access to d for expression e.d + */ + +void accessCheck(Loc loc, Scope sc, Expression e, Declaration d) +{ +version (LOG) { + if (e) + { + printf("accessCheck(%s . %s)\n", e.toChars(), d.toChars()); + printf("\te.type = %s\n", e.type.toChars()); + } + else + { + //printf("accessCheck(%s)\n", d.toChars()); + } +} + if (!e) + { + if (d.prot() == PROT.PROTprivate && d.getModule() != sc.module_ || + d.prot() == PROT.PROTpackage && !hasPackageAccess(sc, d)) + + error(loc, "%s %s.%s is not accessible from %s", + d.kind(), d.getModule().toChars(), d.toChars(), sc.module_.toChars()); + } + else if (e.type.ty == TY.Tclass) + { + // Do access check + ClassDeclaration cd; + + cd = cast(ClassDeclaration)((cast(TypeClass)e.type).sym); +static if (true) { + if (e.op == TOK.TOKsuper) + { + ClassDeclaration cd2 = sc.func.toParent().isClassDeclaration(); + if (cd2) + cd = cd2; + } +} + cd.accessCheck(loc, sc, d); + } + else if (e.type.ty == TY.Tstruct) + { + // Do access check + StructDeclaration cd = cast(StructDeclaration)((cast(TypeStruct)e.type).sym); + cd.accessCheck(loc, sc, d); + } +} + +/***************************************** + * Given array of arguments and an aggregate type, + * if any of the argument types are missing, attempt to infer + * them from the aggregate type. + */ + +void inferApplyArgTypes(TOK op, Arguments arguments, Expression aggr) +{ + if (!arguments || !arguments.dim) + return; + + /* Return if no arguments need types. + */ + for (size_t u = 0; 1; u++) + { + if (u == arguments.dim) + return; + + Argument arg = cast(Argument)arguments.data[u]; + if (!arg.type) + break; + } + + AggregateDeclaration ad; + + Argument arg = cast(Argument)arguments.data[0]; + Type taggr = aggr.type; + if (!taggr) + return; + Type tab = taggr.toBasetype(); + switch (tab.ty) + { + case TY.Tarray: + case TY.Tsarray: + case TY.Ttuple: + if (arguments.dim == 2) + { + if (!arg.type) + arg.type = Type.tsize_t; // key type + arg = cast(Argument)arguments.data[1]; + } + if (!arg.type && tab.ty != TY.Ttuple) + arg.type = tab.nextOf(); // value type + break; + + case TY.Taarray: + { + TypeAArray taa = cast(TypeAArray)tab; + + if (arguments.dim == 2) + { + if (!arg.type) + arg.type = taa.index; // key type + arg = cast(Argument)arguments.data[1]; + } + if (!arg.type) + arg.type = taa.next; // value type + break; + } + + case TY.Tclass: + ad = (cast(TypeClass)tab).sym; + goto Laggr; + + case TY.Tstruct: + ad = (cast(TypeStruct)tab).sym; + goto Laggr; + + Laggr: + if (arguments.dim == 1) + { + if (!arg.type) + { + /* Look for a head() or rear() overload + */ + Identifier id = (op == TOK.TOKforeach) ? Id.Fhead : Id.Ftoe; + Dsymbol s = search_function(ad, id); + FuncDeclaration fd = s ? s.isFuncDeclaration() : null; + if (!fd) + { + if (s && s.isTemplateDeclaration()) + break; + goto Lapply; + } + arg.type = fd.type.nextOf(); + } + break; + } + + Lapply: + { /* Look for an + * int opApply(int delegate(ref Type [, ...]) dg); + * overload + */ + Dsymbol s = search_function(ad, (op == TOK.TOKforeach_reverse) ? Id.applyReverse : Id.apply); + if (s) + { + FuncDeclaration fd = s.isFuncDeclaration(); + if (fd) + { + inferApplyArgTypesX(fd, arguments); + break; + } +static if (false) { + TemplateDeclaration td = s.isTemplateDeclaration(); + if (td) + { + inferApplyArgTypesZ(td, arguments); + break; + } +} + } + break; + } + + case TY.Tdelegate: + { + if (0 && aggr.op == TOK.TOKdelegate) + { + DelegateExp de = cast(DelegateExp)aggr; + + FuncDeclaration fd = de.func.isFuncDeclaration(); + if (fd) + inferApplyArgTypesX(fd, arguments); + } + else + { + inferApplyArgTypesY(cast(TypeFunction)tab.nextOf(), arguments); + } + break; + } + + default: + break; // ignore error, caught later + } +} + +struct Param3 +{ + /******************************** + * Recursive helper function, + * analogous to func.overloadResolveX(). + */ + + int fp3(FuncDeclaration f) + { + TypeFunction tf = cast(TypeFunction)f.type; + if (inferApplyArgTypesY(tf, arguments) == 1) + return 0; + + if (arguments.dim == 0) + return 1; + + return 0; + } + + Arguments arguments; +} + +void inferApplyArgTypesX(FuncDeclaration fstart, Arguments arguments) +{ + Param3 p3; + p3.arguments = arguments; + overloadApply(fstart, &p3.fp3); +} + +/****************************** + * Infer arguments from type of function. + * Returns: + * 0 match for this function + * 1 no match for this function + */ + +int inferApplyArgTypesY(TypeFunction tf, Arguments arguments) +{ + size_t nparams; + Argument p; + + if (Argument.dim(tf.parameters) != 1) + goto Lnomatch; + + p = Argument.getNth(tf.parameters, 0); + if (p.type.ty != TY.Tdelegate) + goto Lnomatch; + + tf = cast(TypeFunction)p.type.nextOf(); + assert(tf.ty == TY.Tfunction); + + /* We now have tf, the type of the delegate. Match it against + * the arguments, filling in missing argument types. + */ + nparams = Argument.dim(tf.parameters); + if (nparams == 0 || tf.varargs) + goto Lnomatch; // not enough parameters + if (arguments.dim != nparams) + goto Lnomatch; // not enough parameters + + for (size_t u = 0; u < nparams; u++) + { + Argument arg = cast(Argument)arguments.data[u]; + Argument param = Argument.getNth(tf.parameters, u); + if (arg.type) + { + if (!arg.type.equals(param.type)) + { + /* Cannot resolve argument types. Indicate an + * error by setting the number of arguments to 0. + */ + arguments.dim = 0; + goto Lmatch; + } + continue; + } + arg.type = param.type; + } + + Lmatch: + return 0; + + Lnomatch: + return 1; +} + +/************************************************** + * Write expression out to buf, but wrap it + * in ( ) if its precedence is less than pr. + */ + +void expToCBuffer(OutBuffer buf, HdrGenState* hgs, Expression e, PREC pr) +{ + //if (precedence[e.op] == 0) e.dump(0); + if (precedence[e.op] < pr || + /* Despite precedence, we don't allow a sz) + { + e.error("shift by %jd is outside the range 0..%zu", i2, sz); + e.e2 = new IntegerExp(0); + } + + if (e.e1.isConst() == 1) { + ex = shift(e.type, e.e1, e.e2); + } + } + + return ex; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/expression/util/arrayTypeCompatible.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/expression/util/arrayTypeCompatible.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,34 @@ +module dmd.expression.util.arrayTypeCompatible; + +import dmd.Loc; +import dmd.Type; +import dmd.TY; +import dmd.MATCH; +import dmd.Util; + +/*********************************** + * See if both types are arrays that can be compared + * for equality. Return !=0 if so. + * If they are arrays, but incompatible, issue error. + * This is to enable comparing things like an immutable + * array with a mutable one. + */ +bool arrayTypeCompatible(Loc loc, Type t1, Type t2) +{ + t1 = t1.toBasetype(); + t2 = t2.toBasetype(); + + if ((t1.ty == TY.Tarray || t1.ty == TY.Tsarray || t1.ty == TY.Tpointer) && (t2.ty == TY.Tarray || t2.ty == TY.Tsarray || t2.ty == TY.Tpointer)) + { + if (t1.nextOf().implicitConvTo(t2.nextOf()) < MATCH.MATCHconst && + t2.nextOf().implicitConvTo(t1.nextOf()) < MATCH.MATCHconst && + (t1.nextOf().ty != TY.Tvoid && t2.nextOf().ty != TY.Tvoid)) + { + error(loc, "array equality comparison type mismatch, %s vs %s", t1.toChars(), t2.toChars()); + } + + return true; + } + + return false; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 dmd/type/Util.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/type/Util.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,46 @@ +module dmd.type.Util; + +import dmd.TY; +import dmd.Expression; +import dmd.Scope; +import dmd.Type; +import dmd.TupleDeclaration; +import dmd.TypeTuple; +import dmd.ScopeDsymbol; +import dmd.ArrayScopeSymbol; + +/************************** + * This evaluates exp while setting length to be the number + * of elements in the tuple t. + */ +Expression semanticLength(Scope sc, Type t, Expression exp) +{ + if (t.ty == TY.Ttuple) + { + ScopeDsymbol sym = new ArrayScopeSymbol(sc, cast(TypeTuple)t); + sym.parent = sc.scopesym; + sc = sc.push(sym); + + exp = exp.semantic(sc); + + sc.pop(); + } + else + exp = exp.semantic(sc); + + return exp; +} + +Expression semanticLength(Scope sc, TupleDeclaration s, Expression exp) +{ + assert(false); + + ScopeDsymbol sym = new ArrayScopeSymbol(sc, s); + sym.parent = sc.scopesym; + sc = sc.push(sym); + + exp = exp.semantic(sc); + + sc.pop(); + return exp; +} \ No newline at end of file diff -r 000000000000 -r 10317f0c89a5 main.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,1105 @@ +module main; + +import dmd.Array; +import dmd.Module; +import dmd.Global; +import dmd.VersionCondition; +import dmd.DebugCondition; +import dmd.Loc; +import dmd.Lexer; +import dmd.OutBuffer; +import dmd.FileName; +import dmd.Type; +import dmd.File; +import dmd.Id; +import dmd.Identifier; +import dmd.Library; +import dmd.TOK; +import dmd.String; +import dmd.backend.glue; + +import std.stdarg; +import std.string : toStringz; +import std.contracts; + +import core.stdc.string; +import core.stdc.stdio; +import core.stdc.ctype; +import core.stdc.errno; +import core.stdc.stdlib; +import core.stdc.limits; + +import core.memory; + +import dlib.CrashHandler; +import dbg.ui.CrashWindow; + +import dmd.Util; + +bool loop = true; + +enum ExitCode +{ + EXIT_SUCCESS = 0, +} + +version (Windows) +{ + private import core.stdc.wchar_; +} + +extern (C) void gc_init(); +extern (C) void gc_term(); +extern (C) void _minit(); +extern (C) void _moduleCtor(); +extern (C) void _moduleDtor(); +extern (C) void thread_joinAll(); + +shared bool _d_isHalting = false; + +import win32.windows; + +extern (C) int main(int argc, char **argv) +{ + char[][] args; + int result; + + version (OSX) + { /* OSX does not provide a way to get at the top of the + * stack, except for the magic value 0xC0000000. + * But as far as the gc is concerned, argv is at the top + * of the main thread's stack, so save the address of that. + */ + __osx_stack_end = cast(void*)&argv; + } + + version (Posix) + { + _STI_monitor_staticctor(); + _STI_critical_init(); + } + + version (Windows) + { + wchar_t* wcbuf = GetCommandLineW(); + size_t wclen = wcslen(wcbuf); + int wargc = 0; + wchar_t** wargs = CommandLineToArgvW(wcbuf, &wargc); + assert(wargc == argc); + + char* cargp = null; + size_t cargl = WideCharToMultiByte(65001, 0, wcbuf, wclen, null, 0, null, null); + + cargp = cast(char*) alloca(cargl); + args = ((cast(char[]*) alloca(wargc * (char[]).sizeof)))[0 .. wargc]; + + for (size_t i = 0, p = 0; i < wargc; i++) + { + int wlen = wcslen(wargs[i]); + int clen = WideCharToMultiByte(65001, 0, &wargs[i][0], wlen, null, 0, null, null); + args[i] = cargp[p .. p+clen]; + p += clen; assert(p <= cargl); + WideCharToMultiByte(65001, 0, &wargs[i][0], wlen, &args[i][0], clen, null, null); + } + LocalFree(cast(HANDLE)wargs); + wargs = null; + wargc = 0; + } + else version (Posix) + { + char[]* am = cast(char[]*) malloc(argc * (char[]).sizeof); + scope(exit) free(am); + + for (size_t i = 0; i < argc; i++) + { + auto len = strlen(argv[i]); + am[i] = argv[i][0 .. len]; + } + args = am[0 .. argc]; + } + + gc_init(); + version (Windows) + _minit(); + _moduleCtor(); + + CrashHandlerInit(); + GC.disable(); + + result = main(cast(string[])args); + + thread_joinAll(); + _d_isHalting = true; + _moduleDtor(); + gc_term(); + + version (Posix) + { + _STD_critical_term(); + _STD_monitor_staticdtor(); + } + + return result; +} + +int main(string[] args) +{ + Array files = new Array(); + Array libmodules = new Array(); + Module m; + int status = ExitCode.EXIT_SUCCESS; + int argcstart = args.length; + int setdebuglib = 0; + + global = new Global(); + +/// if (response_expand(&argc,&argv)) // expand response files +/// error("can't open response file"); + + files.reserve(args.length - 1); + + // Set default values + global.params.argv0 = args[0]; + global.params.link = 1; + global.params.useAssert = 1; + global.params.useInvariants = 1; + global.params.useIn = 1; + global.params.useOut = 1; + global.params.useArrayBounds = 1; + global.params.useSwitchError = 1; + global.params.useInline = 0; + global.params.obj = 1; + global.params.Dversion = 2; + global.params.quiet = 1; + + global.params.linkswitches = new Array(); + global.params.libfiles = new Array(); + global.params.objfiles = new Array(); + global.params.ddocfiles = new Array(); + +version (TARGET_WINDOS) { + global.params.defaultlibname = "phobos"; +} else version (XXX) { //#elif TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS + global.params.defaultlibname = "phobos2"; +} else version (TARGET_NET) { +} else { + static assert(false, "fix this"); +} + + // Predefine version identifiers + VersionCondition.addPredefinedGlobalIdent("DigitalMars"); + +version (TARGET_WINDOS) { + VersionCondition.addPredefinedGlobalIdent("Windows"); + global.params.isWindows = 1; +version (TARGET_NET) { + // TARGET_NET macro is NOT mutually-exclusive with TARGET_WINDOS + VersionCondition.addPredefinedGlobalIdent("D_NET"); +} +} else version (TARGET_LINUX) { + VersionCondition.addPredefinedGlobalIdent("Posix"); + VersionCondition.addPredefinedGlobalIdent("linux"); + global.params.isLinux = 1; +} else version (TARGET_OSX) { + VersionCondition.addPredefinedGlobalIdent("Posix"); + VersionCondition.addPredefinedGlobalIdent("OSX"); + global.params.isOSX = 1; + + // For legacy compatibility + VersionCondition.addPredefinedGlobalIdent("darwin"); +} else version (TARGET_FREEBSD) { + VersionCondition.addPredefinedGlobalIdent("Posix"); + VersionCondition.addPredefinedGlobalIdent("FreeBSD"); + global.params.isFreeBSD = 1; +} else version (TARGET_SOLARIS) { + VersionCondition.addPredefinedGlobalIdent("Posix"); + VersionCondition.addPredefinedGlobalIdent("Solaris"); + global.params.isSolaris = 1; +} else { + static assert (false, "fix this"); +} + + VersionCondition.addPredefinedGlobalIdent("LittleEndian"); + //VersionCondition.addPredefinedGlobalIdent("D_Bits"); +version (DMDV2) { + VersionCondition.addPredefinedGlobalIdent("D_Version2"); +} + VersionCondition.addPredefinedGlobalIdent("all"); + +version (_WIN32) { + inifile(args[0], "sc.ini"); +} else version (XXX) {///linux || __APPLE__ || __FreeBSD__ || __sun&&__SVR4 + inifile(argv[0], "dmd.conf"); +} else { + static assert (false, "fix this"); +} + args = getenv_setargv("DFLAGS", args); + +version (disabled) { + for (i = 0; i < argc; i++) + { + writef("argv[%d] = '%s'\n", i, argv[i]); + } +} + + foreach(i; 1..args.length) + { + auto arg = args[i]; + auto p = arg.ptr; + if (*p == '-') + { + arg = arg[1..$]; + if (arg == "d") + global.params.useDeprecated = 1; + else if (arg == "c") + global.params.link = 0; + else if (arg == "cov") + global.params.cov = 1; +///version (XXX) {// TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS +/// else if (arg == "fPIC") +/// global.params.pic = 1; +///} + else if (arg == "multiobj") + global.params.multiobj = 1; + else if (arg == "g") + global.params.symdebug = 1; + else if (arg == "gc") + global.params.symdebug = 2; + else if (arg == "gt") + { error("use -profile instead of -gt\n"); + global.params.trace = 1; + } + else if (arg == "m64") + global.params.isX86_64 = 1; + else if (arg == "profile") + global.params.trace = 1; + else if (arg == "v") + global.params.verbose = 1; +///version (DMDV2) { + else if (arg == "vtls") + global.params.vtls = 1; +///} + else if (arg == "v1") + { +version (DMDV1) { + global.params.Dversion = 1; +} else { + error("use DMD 1.0 series compilers for -v1 switch"); + break; +} + } + else if (arg == "w") + global.params.warnings = 1; + else if (arg == "O") + global.params.optimize = 1; + else if (p[1] == 'o') + { + switch (p[2]) + { + case '-': + global.params.obj = 0; + break; + + case 'd': + if (!p[3]) + goto Lnoarg; + global.params.objdir = arg[(p - arg.ptr) + 3..$]; + break; + + case 'f': + { + if (!p[3]) + goto Lnoarg; + + global.params.objname = arg[(p - arg.ptr) + 3..$]; + break; + } + + case 'p': + if (p[3]) + goto Lerror; + global.params.preservePaths = 1; + break; + + case 0: + error("-o no longer supported, use -of or -od"); + break; + + default: + goto Lerror; + } + } + else if (p[1] == 'D') + { global.params.doDocComments = 1; + switch (p[2]) + { + case 'd': + if (!p[3]) + goto Lnoarg; + global.params.docdir = arg[(p - arg.ptr) + 3..$]; + break; + case 'f': + if (!p[3]) + goto Lnoarg; + global.params.docname = arg[(p - arg.ptr) + 3..$]; + break; + + case 0: + break; + + default: + goto Lerror; + } + } +///version (_DH) { + else if (p[1] == 'H') + { global.params.doHdrGeneration = 1; + switch (p[2]) + { + case 'd': + if (!p[3]) + goto Lnoarg; + global.params.hdrdir = arg[(p - arg.ptr) + 3..$]; + break; + + case 'f': + if (!p[3]) + goto Lnoarg; + global.params.hdrname = arg[(p - arg.ptr) + 3..$]; + break; + + case 0: + break; + + default: + goto Lerror; + } + } +///} + else if (arg == "ignore") + global.params.ignoreUnsupportedPragmas = 1; + else if (arg == "inline") + global.params.useInline = 1; + else if (arg == "lib") + global.params.lib = 1; + else if (arg == "nofloat") + global.params.nofloat = 1; + else if (arg == "quiet") + global.params.quiet = 1; + else if (arg == "release") + global.params.release = 1; +///version (DMDV2) { + else if (arg == "safe") + global.params.safe = 1; +///} + else if (arg == "unittest") + global.params.useUnitTests = 1; + else if (p[1] == 'I') + { + if (!global.params.imppath) + global.params.imppath = new Array(); + global.params.imppath.push(cast(void*)new String(arg[(p - arg.ptr) + 2..$])); /// + } + else if (p[1] == 'J') + { + if (!global.params.fileImppath) + global.params.fileImppath = new Array(); + global.params.fileImppath.push(cast(void*)new String(arg[(p - arg.ptr) + 2..$])); + } + else if (memcmp(p + 1, "debug".ptr, 5) == 0 && p[6] != 'l') + { + // Parse: + // -debug + // -debug=number + // -debug=identifier + if (p[6] == '=') + { + if (isdigit(p[7])) + { long level; + + errno = 0; + level = strtol(p + 7, cast(char**)&p, 10); + if (*p || errno || level > INT_MAX) + goto Lerror; + DebugCondition.setGlobalLevel(cast(int)level); + } + else if (Lexer.isValidIdentifier(arg[(p - arg.ptr) + 7..$])) /// + DebugCondition.addGlobalIdent(p + 7); + else + goto Lerror; + } + else if (p[6]) + goto Lerror; + else + global.params.debuglevel = 1; + } + else if (memcmp(p + 1, "version".ptr, 5) == 0) + { + // Parse: + // -version=number + // -version=identifier + if (p[8] == '=') + { + if (isdigit(p[9])) + { long level; + + errno = 0; + level = strtol(p + 9, cast(char**)&p, 10); /// + if (*p || errno || level > INT_MAX) + goto Lerror; + VersionCondition.setGlobalLevel(cast(int)level); + } + else if (Lexer.isValidIdentifier(arg[(p - arg.ptr) + 9..$])) /// + VersionCondition.addGlobalIdent(arg[(p - arg.ptr) + 9..$]); + else + goto Lerror; + } + else + goto Lerror; + } + else if (arg == "-b") + global.params.debugb = 1; + else if (arg == "-c") + global.params.debugc = 1; + else if (arg == "-f") + global.params.debugf = 1; + else if (arg == "-help") + { usage(); + exit(EXIT_SUCCESS); + } + else if (arg == "-r") + global.params.debugr = 1; + else if (arg == "-x") + global.params.debugx = 1; + else if (arg == "-y") + global.params.debugy = 1; + else if (p[1] == 'L') + { + global.params.linkswitches.push(cast(void*)p + 2); + } + else if (memcmp(p + 1, "defaultlib=".ptr, 11) == 0) + { + global.params.defaultlibname = p + 1 + 11; + } + else if (memcmp(p + 1, "debuglib=".ptr, 9) == 0) + { + setdebuglib = 1; + global.params.debuglibname = p + 1 + 9; + } + else if (memcmp(p + 1, "deps=".ptr, 5) == 0) + { + global.params.moduleDepsFile = arg[(p - arg.ptr) + 1 + 5..$]; + if (!global.params.moduleDepsFile[0]) + goto Lnoarg; + global.params.moduleDeps = new OutBuffer; + } + else if (memcmp(p + 1, "man".ptr, 3) == 0) + { +version (_WIN32) { +version (DMDV1) { + browse("http://www.digitalmars.com/d/1.0/dmd-windows.html"); +} else { + browse("http://www.digitalmars.com/d/2.0/dmd-windows.html"); +} +} +version (linux) { +version (DMDV1) { + browse("http://www.digitalmars.com/d/1.0/dmd-linux.html"); +} else { + browse("http://www.digitalmars.com/d/2.0/dmd-linux.html"); +} +} +version (__APPLE__) { +version (DMDV1) { + browse("http://www.digitalmars.com/d/1.0/dmd-osx.html"); +} else { + browse("http://www.digitalmars.com/d/2.0/dmd-osx.html"); +} +} +version (__FreeBSD__) { +version (DMDV1) { + browse("http://www.digitalmars.com/d/1.0/dmd-freebsd.html"); +} else { + browse("http://www.digitalmars.com/d/2.0/dmd-freebsd.html"); +} +} + exit(EXIT_SUCCESS); + } + else if (arg == "run") + { global.params.run = 1; + global.params.runargs_length = ((i >= argcstart) ? args.length : argcstart) - i - 1; + if (global.params.runargs_length) + { + files.push(cast(void*)args[i + 1].ptr); + global.params.runargs = args[i + 2..$]; + i += global.params.runargs_length; + global.params.runargs_length--; + } + else + { global.params.run = 0; + goto Lnoarg; + } + } + else + { + Lerror: + error("unrecognized switch '%s'", args[i]); + continue; + + Lnoarg: + error("argument expected for switch '%s'", args[i]); + continue; + } + } + else + { +version (TARGET_WINDOS) { + string ext = FileName.ext(p[0..arg.length]); + if (ext != null && FileName.compare(ext, "exe") == 0) + { + global.params.objname = arg[(p - arg.ptr)..$]; + continue; + } +} + files.push(cast(void*)new String(arg[(p - arg.ptr)..$])); + } + } + if (global.errors) + { + fatal(); + } + if (files.dim == 0) + { usage(); + return EXIT_FAILURE; + } + + if (!setdebuglib) + global.params.debuglibname = global.params.defaultlibname; + +version (TARGET_OSX) { + global.params.pic = 1; +} + + if (global.params.release) + { global.params.useInvariants = 0; + global.params.useIn = 0; + global.params.useOut = 0; + global.params.useAssert = 0; + global.params.useArrayBounds = 0; + global.params.useSwitchError = 0; + } + + if (global.params.run) + global.params.quiet = 1; + + if (global.params.useUnitTests) + global.params.useAssert = 1; + + if (!global.params.obj || global.params.lib) + global.params.link = 0; + + if (global.params.link) + { + global.params.exefile = global.params.objname; + global.params.oneobj = 1; + if (global.params.objname) + { + /* Use this to name the one object file with the same + * name as the exe file. + */ + global.params.objname = FileName.forceExt(global.params.objname, global.obj_ext).toChars(); + + /* If output directory is given, use that path rather than + * the exe file path. + */ + if (global.params.objdir) + { + string name = FileName.name(global.params.objname); + global.params.objname = FileName.combine(global.params.objdir, name); + } + } + } + else if (global.params.lib) + { + global.params.libname = global.params.objname; + global.params.objname = null; + + // Haven't investigated handling these options with multiobj + if (!global.params.cov && !global.params.trace) + global.params.multiobj = 1; + } + else if (global.params.run) + { + error("flags conflict with -run"); + fatal(); + } + else + { + if (global.params.objname && files.dim > 1) + { + global.params.oneobj = 1; + //error("multiple source files, but only one .obj name"); + //fatal(); + } + } + if (global.params.isX86_64) + { + VersionCondition.addPredefinedGlobalIdent("D_InlineAsm_X86_64"); + VersionCondition.addPredefinedGlobalIdent("X86_64"); + VersionCondition.addPredefinedGlobalIdent("D_LP64"); +version (TARGET_WINDOS) { + VersionCondition.addPredefinedGlobalIdent("Win64"); +} + } + else + { + VersionCondition.addPredefinedGlobalIdent("D_InlineAsm"); + VersionCondition.addPredefinedGlobalIdent("D_InlineAsm_X86"); + VersionCondition.addPredefinedGlobalIdent("X86"); +version (TARGET_WINDOS) { + VersionCondition.addPredefinedGlobalIdent("Win32"); +} + } + if (global.params.doDocComments) + VersionCondition.addPredefinedGlobalIdent("D_Ddoc"); + if (global.params.cov) + VersionCondition.addPredefinedGlobalIdent("D_Coverage"); + if (global.params.pic) + VersionCondition.addPredefinedGlobalIdent("D_PIC"); +version (DMDV2) { + if (global.params.useUnitTests) + VersionCondition.addPredefinedGlobalIdent("unittest"); +} + + // Initialization + Type.init(); + Id.initialize(); + Module.init(); + initPrecedence(); + + backend_init(); + + //printf("%d source files\n",files.dim); + + // Build import search path + if (global.params.imppath) + { + for (int i = 0; i < global.params.imppath.dim; i++) + { + string path = (cast(String)global.params.imppath.data[i]).str; + string[] a = FileName.splitPath(path); + + global.path ~= a; + } + } + + // Build string import search path + if (global.params.fileImppath) + { + for (int i = 0; i < global.params.fileImppath.dim; i++) + { + string path = (cast(String)global.params.fileImppath.data[i]).str; + string[] a = FileName.splitPath(path); + + global.filePath ~= a; + } + } + + // Create Modules + Array modules = new Array(); + modules.reserve(files.dim); + int firstmodule = 1; + for (int i = 0; i < files.dim; i++) + { + string ext; + string name; + + String s = cast(String) files.data[i]; + string mp = s.str; + +version (_WIN32) { + char[] copy = null; + // Convert / to \ so linker will work + foreach (j, c; mp) + { + if (c == '/') { + if (copy is null) copy = mp.dup; + copy[j] = '\\'; + } + } + + if (copy !is null) mp = assumeUnique(copy); +} + string p = mp; + + p = FileName.name(p); // strip path + ext = FileName.ext(p); + + if (ext.length != 0) + { /* Deduce what to do with a file based on its extension + */ + if (FileName.equals(ext, global.obj_ext)) + { + global.params.objfiles.push(files.data[i]); + libmodules.push(files.data[i]); + continue; + } + + if (FileName.equals(ext, global.lib_ext)) + { + global.params.libfiles.push(files.data[i]); + libmodules.push(files.data[i]); + continue; + } + + if (ext == global.ddoc_ext) + { + global.params.ddocfiles.push(files.data[i]); + continue; + } + +version (TARGET_WINDOS) { + if (FileName.equals(ext, "res")) + { + global.params.resfile = (cast(immutable(char)*)files.data[i])[0..0]; /// !!! + continue; + } + + if (FileName.equals(ext, "def")) + { + global.params.deffile = (cast(immutable(char)*)files.data[i])[0..0]; + continue; + } + + if (FileName.equals(ext, "exe")) + { + assert(0); // should have already been handled + } +} + + /* Examine extension to see if it is a valid + * D source file extension + */ + if (FileName.equals(ext, global.mars_ext) || + FileName.equals(ext, global.hdr_ext) || + FileName.equals(ext, "dd") || + FileName.equals(ext, "htm") || + FileName.equals(ext, "html") || + FileName.equals(ext, "xhtml")) + { + immutable(char)* e = ext.ptr; + e--; // skip onto '.' + assert(*e == '.'); + + immutable(char)* n = p.ptr; + + name = n[0..(e-n)]; // strip extension + + if (name.length == 0 || name == ".." || name == ".") + { + Linvalid: + error("invalid file name '%s'", (cast(String)files.data[i]).str); + fatal(); + } + } + else + { error("unrecognized file extension %s\n", ext); + fatal(); + } + } + else + { + name = p; + if (!*name) + goto Linvalid; + } + + /* At this point, name is the D source file name stripped of + * its path and extension. + */ + + Identifier id = new Identifier(name, TOK.TOKreserved); + m = new Module((cast(String) files.data[i]).str, id, global.params.doDocComments, global.params.doHdrGeneration); + modules.push(cast(void*)m); + + if (firstmodule) + { + global.params.objfiles.push(cast(void*)m.objfile.name); + firstmodule = 0; + } + } + + // Read files +//version = ASYNCREAD; +version (ASYNCREAD) { + // Multi threaded + AsyncRead *aw = AsyncRead.create(modules.dim); + for (i = 0; i < modules.dim; i++) + { + m = cast(Module *)modules.data[i]; + aw.addFile(m.srcfile); + } + aw.start(); +} else { + // Single threaded + for (int i = 0; i < modules.dim; i++) + { + m = cast(Module)modules.data[i]; + m.read(Loc(0)); + } +} + + // Parse files + int anydocfiles = 0; + for (int i = 0; i < modules.dim; i++) + { + m = cast(Module)modules.data[i]; + if (global.params.verbose) + writef("parse %s\n", m.toChars()); + if (!Module.rootModule) + Module.rootModule = m; + m.importedFrom = m; + if (!global.params.oneobj || i == 0 || m.isDocFile) + m.deleteObjFile(); +version (ASYNCREAD) { + if (aw.read(i)) + { + error("cannot read file %s", m.srcfile.name.toChars()); + } +} + + //while (loop) {} + m.parse(); + if (m.isDocFile) + { + anydocfiles = 1; + m.gendocfile(); + + // Remove m from list of modules + modules.remove(i); + i--; + + // Remove m's object file from list of object files + for (int j = 0; j < global.params.objfiles.dim; j++) + { + if (m.objfile.name.str == (cast(FileName)global.params.objfiles.data[j]).str) + { + global.params.objfiles.remove(j); + break; + } + } + + if (global.params.objfiles.dim == 0) + global.params.link = 0; + } + } +version (ASYNCREAD) { + AsyncRead.dispose(aw); +} + + if (anydocfiles && modules.dim && + (global.params.oneobj || global.params.objname)) + { + error("conflicting Ddoc and obj generation options"); + fatal(); + } + if (global.errors) + fatal(); +version (_DH) { + if (global.params.doHdrGeneration) + { + /* Generate 'header' import files. + * Since 'header' import files must be independent of command + * line switches and what else is imported, they are generated + * before any semantic analysis. + */ + for (i = 0; i < modules.dim; i++) + { + m = cast(Module *)modules.data[i]; + if (global.params.verbose) + writef("import %s\n", m.toChars()); + m.genhdrfile(); + } + } + if (global.errors) + fatal(); +} + + // Do semantic analysis + for (int i = 0; i < modules.dim; i++) + { + m = cast(Module)modules.data[i]; + if (global.params.verbose) + writef("semantic %s\n", m.toChars()); + m.semantic(); + } + if (global.errors) + fatal(); + + // Do pass 2 semantic analysis + for (int i = 0; i < modules.dim; i++) + { + m = cast(Module)modules.data[i]; + if (global.params.verbose) + writef("semantic2 %s\n", m.toChars()); + m.semantic2(); + } + if (global.errors) + fatal(); + + // Do pass 3 semantic analysis + for (int i = 0; i < modules.dim; i++) + { + m = cast(Module)modules.data[i]; + if (global.params.verbose) + writef("semantic3 %s\n", m.toChars()); + m.semantic3(); + } + if (global.errors) + fatal(); + + if (global.params.moduleDeps !is null) + { + assert(global.params.moduleDepsFile !is null); + + File deps = new File(global.params.moduleDepsFile); + OutBuffer ob = global.params.moduleDeps; + deps.setbuffer(cast(void*)ob.data, ob.offset); + deps.writev(); + } + + + // Scan for functions to inline + if (global.params.useInline) + { + /* The problem with useArrayBounds and useAssert is that the + * module being linked to may not have generated them, so if + * we inline functions from those modules, the symbols for them will + * not be found at link time. + */ + if (!global.params.useArrayBounds && !global.params.useAssert) + { + // Do pass 3 semantic analysis on all imported modules, + // since otherwise functions in them cannot be inlined + for (int i = 0; i < Module.amodules.dim; i++) + { + m = cast(Module)Module.amodules.data[i]; + if (global.params.verbose) + writef("semantic3 %s\n", m.toChars()); + m.semantic3(); + } + if (global.errors) + fatal(); + } + + for (int i = 0; i < modules.dim; i++) + { + m = cast(Module)modules.data[i]; + if (global.params.verbose) + writef("inline scan %s\n", m.toChars()); + + m.inlineScan(); + } + } + if (global.errors) + fatal(); + + Library library = null; + if (global.params.lib) + { + library = new Library(); + library.setFilename(global.params.objdir, global.params.libname); + + // Add input object and input library files to output library + for (int i = 0; i < libmodules.dim; i++) + { + string p = (cast(String)libmodules.data[i]).str; + library.addObject(p, null, 0); + } + } + + // Generate output files + if (global.params.oneobj) + { + for (int i = 0; i < modules.dim; i++) + { + m = cast(Module)modules.data[i]; + if (global.params.verbose) + writef("code %s\n", m.toChars()); + if (i == 0) + obj_start(cast(char*)toStringz(m.srcfile.toChars())); + m.genobjfile(0); + if (!global.errors && global.params.doDocComments) + m.gendocfile(); + } + if (!global.errors && modules.dim) + { + obj_end(library, (cast(Module)modules.data[0]).objfile); + } + } + else + { + for (int i = 0; i < modules.dim; i++) + { + m = cast(Module)modules.data[i]; + if (global.params.verbose) + writef("code %s\n", m.toChars()); + if (global.params.obj) + { + obj_start(cast(char*)toStringz(m.srcfile.toChars())); + m.genobjfile(global.params.multiobj); + obj_end(library, m.objfile); + obj_write_deferred(library); + } + if (global.errors) + { + if (!global.params.lib) + m.deleteObjFile(); + } + else + { + if (global.params.doDocComments) + m.gendocfile(); + } + } + } + + if (global.params.lib && !global.errors) + library.write(); + + backend_term(); + if (global.errors) + fatal(); + + if (!global.params.objfiles.dim) + { + if (global.params.link) + error("no object files to link"); + } + else + { + if (global.params.link) + status = runLINK(); + + if (global.params.run) + { + if (!status) + { + status = runProgram(); + + /* Delete .obj files and .exe file + */ + for (int i = 0; i < modules.dim; i++) + { + m = cast(Module)modules.data[i]; + m.deleteObjFile(); + if (global.params.oneobj) + break; + } + deleteExeFile(); + } + } + } + + return status; +} \ No newline at end of file