# 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
+
+
+
+
\ 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