ADDED .poseidon Index: .poseidon ================================================================== --- .poseidon +++ .poseidon @@ -0,0 +1,55 @@ + + + + Polemy + bin\polemy + + *.d + 0 + + 0 + main.d + + + -g -unittest + + + + + + 0 + 0 + 0 + 0 + 0 + + + + + + + d2stacktrace\dbghelp.d + d2stacktrace\stacktrace.d + main.d + polemy\_common.d + polemy\ast.d + polemy\eval.d + polemy\lex.d + polemy\parse.d + polemy\runtime.d + polemy\tricks.d + + + + + + build.bat + build.sh + readme.txt + + + + + + + ADDED build.bat Index: build.bat ================================================================== --- build.bat +++ build.bat @@ -0,0 +1,6 @@ +@setlocal ENABLEDELAYEDEXPANSION +@set ARGS= +@for %%I in (main.d polemy\*.d d2stacktrace\*.d) do @set ARGS=!ARGS! %%I +@if not exist bin mkdir bin +@echo dmd -ofbin\polemy.exe -O -release -inline %ARGS% +@dmd -ofbin\polemy.exe -O -release -inline %ARGS% ADDED d2stacktrace/dbghelp.d Index: d2stacktrace/dbghelp.d ================================================================== --- d2stacktrace/dbghelp.d +++ d2stacktrace/dbghelp.d @@ -0,0 +1,236 @@ +/************************************************************* +Copyright (c) 2010 + +Benjamin Thaut. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted +provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions + and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY BENJAMIN THAUT "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, +OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +web: http://3d.benjamin-thaut.de +*************************************************************/ +module dbghelp; + +version (Windows){ + +import std.c.windows.windows; +import core.runtime; + +class Dbghelp { +public: + typedef char TCHAR; + typedef ulong DWORD64; + typedef char* CTSTR; + typedef char* PTSTR; + typedef const(char)* PCSTR; + + enum ADDRESS_MODE : DWORD { + AddrMode1616 = 0, + AddrMode1632 = 1, + AddrModeReal = 2, + AddrModeFlat = 3 + }; + + enum : DWORD { + SYMOPT_FAIL_CRITICAL_ERRORS = 0x00000200, + SYMOPT_LOAD_LINES = 0x00000010 + }; + + struct GUID { + uint Data1; + ushort Data2; + ushort Data3; + ubyte[8] Data4; + }; + + struct ADDRESS64 { + DWORD64 Offset; + WORD Segment; + ADDRESS_MODE Mode; + }; + + struct KDHELP64 { + DWORD64 Thread; + DWORD ThCallbackStack; + DWORD ThCallbackBStore; + DWORD NextCallback; + DWORD FramePointer; + DWORD64 KiCallUserMode; + DWORD64 KeUserCallbackDispatcher; + DWORD64 SystemRangeStart; + DWORD64 KiUserExceptionDispatcher; + DWORD64[7] Reserved; + }; + + struct STACKFRAME64 { + ADDRESS64 AddrPC; + ADDRESS64 AddrReturn; + ADDRESS64 AddrFrame; + ADDRESS64 AddrStack; + ADDRESS64 AddrBStore; + PVOID FuncTableEntry; + DWORD64[4] Params; + BOOL Far; + BOOL Virtual; + DWORD64[3] Reserved; + KDHELP64 KdHelp; + }; + + enum : DWORD { + IMAGE_FILE_MACHINE_I386 = 0x014c, + IMGAE_FILE_MACHINE_IA64 = 0x0200, + IMAGE_FILE_MACHINE_AMD64 = 0x8664 + }; + + struct IMAGEHLP_LINE64 { + DWORD SizeOfStruct; + PVOID Key; + DWORD LineNumber; + PTSTR FileName; + DWORD64 Address; + }; + + enum SYM_TYPE : int { + SymNone = 0, + SymCoff, + SymCv, + SymPdb, + SymExport, + SymDeferred, + SymSym, + SymDia, + SymVirtual, + NumSymTypes + }; + + struct IMAGEHLP_MODULE64 { + DWORD SizeOfStruct; + DWORD64 BaseOfImage; + DWORD ImageSize; + DWORD TimeDateStamp; + DWORD CheckSum; + DWORD NumSyms; + SYM_TYPE SymType; + TCHAR[32] ModuleName; + TCHAR[256] ImageName; + TCHAR[256] LoadedImageName; + TCHAR[256] LoadedPdbName; + DWORD CVSig; + TCHAR[MAX_PATH*3] CVData; + DWORD PdbSig; + GUID PdbSig70; + DWORD PdbAge; + BOOL PdbUnmatched; + BOOL DbgUnmachted; + BOOL LineNumbers; + BOOL GlobalSymbols; + BOOL TypeInfo; + BOOL SourceIndexed; + BOOL Publics; + }; + + struct IMAGEHLP_SYMBOL64 { + DWORD SizeOfStruct; + DWORD64 Address; + DWORD Size; + DWORD Flags; + DWORD MaxNameLength; + TCHAR[1] Name; + }; + + extern(System){ + typedef BOOL function(HANDLE hProcess, DWORD64 lpBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead) ReadProcessMemoryProc64; + typedef PVOID function(HANDLE hProcess, DWORD64 AddrBase) FunctionTableAccessProc64; + typedef DWORD64 function(HANDLE hProcess, DWORD64 Address) GetModuleBaseProc64; + typedef DWORD64 function(HANDLE hProcess, HANDLE hThread, ADDRESS64 *lpaddr) TranslateAddressProc64; + + typedef BOOL function(HANDLE hProcess, PCSTR UserSearchPath, bool fInvadeProcess) SymInitializeFunc; + typedef BOOL function(HANDLE hProcess) SymCleanupFunc; + typedef DWORD function(DWORD SymOptions) SymSetOptionsFunc; + typedef DWORD function() SymGetOptionsFunc; + typedef PVOID function(HANDLE hProcess, DWORD64 AddrBase) SymFunctionTableAccess64Func; + typedef BOOL function(DWORD MachineType, HANDLE hProcess, HANDLE hThread, STACKFRAME64 *StackFrame, PVOID ContextRecord, + ReadProcessMemoryProc64 ReadMemoryRoutine, FunctionTableAccessProc64 FunctoinTableAccess, + GetModuleBaseProc64 GetModuleBaseRoutine, TranslateAddressProc64 TranslateAddress) StackWalk64Func; + typedef BOOL function(HANDLE hProcess, DWORD64 dwAddr, PDWORD pdwDisplacement, IMAGEHLP_LINE64 *line) SymGetLineFromAddr64Func; + typedef DWORD64 function(HANDLE hProcess, DWORD64 dwAddr) SymGetModuleBase64Func; + typedef BOOL function(HANDLE hProcess, DWORD64 dwAddr, IMAGEHLP_MODULE64 *ModuleInfo) SymGetModuleInfo64Func; + typedef BOOL function(HANDLE hProcess, DWORD64 Address, DWORD64 *Displacement, IMAGEHLP_SYMBOL64 *Symbol) SymGetSymFromAddr64Func; + typedef DWORD function(CTSTR *DecoratedName, PTSTR UnDecoratedName, DWORD UndecoratedLength, DWORD Flags) UnDecorateSymbolNameFunc; + typedef DWORD64 function(HANDLE hProcess, HANDLE hFile, PCSTR ImageName, PCSTR ModuleName, DWORD64 BaseOfDll, DWORD SizeOfDll) SymLoadModule64Func; + typedef BOOL function(HANDLE HProcess, PTSTR SearchPath, DWORD SearchPathLength) SymGetSearchPathFunc; + typedef BOOL function(HANDLE hProcess, DWORD64 Address) SymUnloadModule64Func; + } + + private static bool isInit = false; + private static HANDLE dbghelp_lib = cast(HANDLE)null; + static SymInitializeFunc SymInitialize; + static SymCleanupFunc SymCleanup; + static StackWalk64Func StackWalk64; + static SymGetOptionsFunc SymGetOptions; + static SymSetOptionsFunc SymSetOptions; + static SymFunctionTableAccess64Func SymFunctionTableAccess64; + static SymGetLineFromAddr64Func SymGetLineFromAddr64; + static SymGetModuleBase64Func SymGetModuleBase64; + static SymGetModuleInfo64Func SymGetModuleInfo64; + static SymGetSymFromAddr64Func SymGetSymFromAddr64; + static UnDecorateSymbolNameFunc UnDecorateSymbolName; + static SymLoadModule64Func SymLoadModule64; + static SymGetSearchPathFunc SymGetSearchPath; + static SymUnloadModule64Func SymUnloadModule64; + + static bool Init(){ + if(isInit) + return true; + + dbghelp_lib = cast(HANDLE)Runtime.loadLibrary("dbghelp.dll"); + if(dbghelp_lib == null) + return false; + + SymInitialize = cast(SymInitializeFunc) GetProcAddress(dbghelp_lib,"SymInitialize"); + SymCleanup = cast(SymCleanupFunc) GetProcAddress(dbghelp_lib,"SymCleanup"); + StackWalk64 = cast(StackWalk64Func) GetProcAddress(dbghelp_lib,"StackWalk64"); + SymGetOptions = cast(SymGetOptionsFunc) GetProcAddress(dbghelp_lib,"SymGetOptions"); + SymSetOptions = cast(SymSetOptionsFunc) GetProcAddress(dbghelp_lib,"SymSetOptions"); + SymFunctionTableAccess64 = cast(SymFunctionTableAccess64Func) GetProcAddress(dbghelp_lib,"SymFunctionTableAccess64"); + SymGetLineFromAddr64 = cast(SymGetLineFromAddr64Func) GetProcAddress(dbghelp_lib,"SymGetLineFromAddr64"); + SymGetModuleBase64 = cast(SymGetModuleBase64Func) GetProcAddress(dbghelp_lib,"SymGetModuleBase64"); + SymGetModuleInfo64 = cast(SymGetModuleInfo64Func) GetProcAddress(dbghelp_lib,"SymGetModuleInfo64"); + SymGetSymFromAddr64 = cast(SymGetSymFromAddr64Func) GetProcAddress(dbghelp_lib,"SymGetSymFromAddr64"); + SymLoadModule64 = cast(SymLoadModule64Func) GetProcAddress(dbghelp_lib,"SymLoadModule64"); + SymGetSearchPath = cast(SymGetSearchPathFunc) GetProcAddress(dbghelp_lib,"SymGetSearchPath"); + SymUnloadModule64 = cast(SymUnloadModule64Func) GetProcAddress(dbghelp_lib,"SymUnloadModule64"); + + if(!SymInitialize || !SymCleanup || !StackWalk64 || !SymGetOptions || !SymSetOptions || !SymFunctionTableAccess64 + || !SymGetLineFromAddr64 || !SymGetModuleBase64 || !SymGetModuleInfo64 || !SymGetSymFromAddr64 + || !SymLoadModule64 || !SymGetSearchPath || !SymUnloadModule64){ + return false; + } + + isInit = true; + return true; + + } + + void DeInit(){ + if(isInit){ + Runtime.unloadLibrary(dbghelp_lib); + isInit = false; + } + } +}; + +} ADDED d2stacktrace/licence.txt Index: d2stacktrace/licence.txt ================================================================== --- d2stacktrace/licence.txt +++ d2stacktrace/licence.txt @@ -0,0 +1,22 @@ +Copyright (c) 2010 + +Benjamin Thaut. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted +provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions + and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY BENJAMIN THAUT "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, +OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +web: http://3d.benjamin-thaut.de ADDED d2stacktrace/readme.txt Index: d2stacktrace/readme.txt ================================================================== --- d2stacktrace/readme.txt +++ d2stacktrace/readme.txt @@ -0,0 +1,31 @@ +I wrote a small piece of sourcecode that generates stacktraces in D 2.0 under windows. It works both with the pdb and cv debug symbol format. For Exceptions that are derived from the Error class the trace information is automatically appended, this causes all builtin D errors to get a stacktrace information. The only point where this does not work is the Access Vioaltion error, as it does not call the stacktrace callback function for some reason. + + +It is very easy to use, just copy the two files from the zip archive to your root source directory and import the stacktrace module inside your main file. + +import stacktrace; + +void main(string[] argv){ +... +} + +Now all Errors will get trace information. +If you need a backtrace at a certain point in your code just do the following: + +module foo; + +import stacktrace; + +void blup(){ +... +StackTrace trace = new StackTrace(); +auto stack = trace.GetCallstack(); +foreach(char[] s;stack) +writefln("%s",s); +... +} + +It is released under the BSD license. If this licence causes any problems for you, feel free to contact me and we will fix the problem. + +XP Users: +If you get a stacktrace with numbers only download a new version of dbghelp.dll and put it into your project root directory. That should fix it. ADDED d2stacktrace/stacktrace.d Index: d2stacktrace/stacktrace.d ================================================================== --- d2stacktrace/stacktrace.d +++ d2stacktrace/stacktrace.d @@ -0,0 +1,366 @@ +/************************************************************* +Copyright (c) 2010 + +Benjamin Thaut. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted +provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions + and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY BENJAMIN THAUT "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, +OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +web: http://3d.benjamin-thaut.de +*************************************************************/ +module stacktrace; + +import std.c.windows.windows; +import std.c.string; +import std.string; +import dbghelp; +import core.runtime; +import std.stdio; +import std.c.stdlib; +import std.demangle; +import std.conv; + +extern(Windows){ + DWORD GetEnvironmentVariableA(LPCSTR lpName, LPSTR pBuffer, DWORD nSize); + void RtlCaptureContext(CONTEXT* ContextRecord); + typedef LONG function(void*) UnhandeledExceptionFilterFunc; + void* SetUnhandledExceptionFilter(void* handler); +} + +class StackTrace { +private: + enum : uint { + MAX_MODULE_NAME32 = 255, + TH32CS_SNAPMODULE = 0x00000008, + MAX_NAMELEN = 1024 + }; + + struct MODULEENTRY32 { + DWORD dwSize; + DWORD th32ModuleID; + DWORD th32ProcessID; + DWORD GlblcntUsage; + DWORD ProccntUsage; + BYTE* modBaseAddr; + DWORD modBaseSize; + HMODULE hModule; + CHAR[MAX_MODULE_NAME32 + 1] szModule; + CHAR[MAX_PATH] szExePath; + }; + + string m_UserSymPath; + static bool isInit = false; + static bool modulesLoaded = false; + + extern(System){ + typedef HANDLE function(DWORD dwFlags, DWORD th32ProcessID) CreateToolhelp32SnapshotFunc; + typedef BOOL function(HANDLE hSnapshot, MODULEENTRY32 *lpme) Module32FirstFunc; + typedef BOOL function(HANDLE hSnapshot, MODULEENTRY32 *lpme) Module32NextFunc; + } + + extern(Windows) static LONG UnhandeledExceptionFilterHandler(void* info){ + printStackTrace(); + return 0; + } + + static void printStackTrace(){ + auto stack = TraceHandler(null); + foreach(char[] s;stack){ + writefln("%s",s); + } + } + + bool LoadModules(HANDLE hProcess, DWORD pid){ + if(modulesLoaded) + return true; + + CreateToolhelp32SnapshotFunc CreateToolhelp32Snapshot = null; + Module32FirstFunc Module32First = null; + Module32NextFunc Module32Next = null; + + HMODULE hDll = null; + + string[] searchDlls = [ "kernel32.dll", "tlhelp32.dll" ]; + foreach(dll;searchDlls){ + hDll = cast(HMODULE)Runtime.loadLibrary(dll); + if(hDll == null) + break; + CreateToolhelp32Snapshot = cast(CreateToolhelp32SnapshotFunc) GetProcAddress(hDll,"CreateToolhelp32Snapshot"); + Module32First = cast(Module32FirstFunc) GetProcAddress(hDll,"Module32First"); + Module32Next = cast(Module32NextFunc) GetProcAddress(hDll,"Module32Next"); + if(CreateToolhelp32Snapshot != null && Module32First != null && Module32Next != null) + break; + Runtime.unloadLibrary(hDll); + hDll = null; + } + + if(hDll == null){ + return false; + } + + HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid); + if(hSnap == cast(HANDLE) -1) + return false; + + MODULEENTRY32 ModuleEntry; + memset(&ModuleEntry,0,MODULEENTRY32.sizeof); + ModuleEntry.dwSize = MODULEENTRY32.sizeof; + + bool more = cast(bool)Module32First(hSnap,&ModuleEntry); + int count = 0; + while(more){ + LoadModule(hProcess, ModuleEntry.szExePath.ptr, ModuleEntry.szModule.ptr, cast(Dbghelp.DWORD64)ModuleEntry.modBaseAddr, ModuleEntry.modBaseSize); + count++; + more = cast(bool)Module32Next(hSnap,&ModuleEntry); + } + + CloseHandle(hSnap); + Runtime.unloadLibrary(hDll); + + if(count <= 0) + return false; + + modulesLoaded = true; + return true; + } + + void LoadModule(HANDLE hProcess, LPCSTR img, LPCSTR mod, Dbghelp.DWORD64 baseAddr, DWORD size){ + char[] szImg = new char[strlen(img)]; + char[] szMod = new char[strlen(mod)]; + szImg[0..szImg.length] = img[0..(strlen(img))]; + szMod[0..szMod.length] = mod[0..(strlen(mod))]; + + Dbghelp.DWORD64 moduleAddr = Dbghelp.SymLoadModule64(hProcess,HANDLE.init,cast(Dbghelp.PCSTR)toStringz(szImg),cast(Dbghelp.PCSTR)toStringz(szMod),baseAddr,size); + if(moduleAddr == 0) + return; + + Dbghelp.IMAGEHLP_MODULE64 ModuleInfo; + memset(&ModuleInfo,0,typeof(ModuleInfo).sizeof); + ModuleInfo.SizeOfStruct = typeof(ModuleInfo).sizeof; + if(Dbghelp.SymGetModuleInfo64(hProcess,moduleAddr,&ModuleInfo) == TRUE){ + if(ModuleInfo.SymType == Dbghelp.SYM_TYPE.SymNone){ + Dbghelp.SymUnloadModule64(hProcess,moduleAddr); + moduleAddr = Dbghelp.SymLoadModule64(hProcess,HANDLE.init,cast(Dbghelp.PCSTR)toStringz(szImg),null,cast(Dbghelp.DWORD64)0,0); + if(moduleAddr == 0) + return; + } + } + + //writefln("Successfully loaded module %s",szImg); + } + + string GenereateSearchPath(){ + string path; + if(m_UserSymPath.length){ + path = m_UserSymPath ~ ";"; + } + + char[1024] temp; + if(GetCurrentDirectoryA(temp.length,temp.ptr) > 0){ + temp[temp.length-1] = 0; + path ~= temp ~ ";"; + } + + if(GetModuleFileNameA(null,temp.ptr,temp.length) > 0){ + temp[temp.length-1] = 0; + foreach_reverse(ref char e;temp){ + if(e == '\\' || e == '/' || e == ':'){ + e = 0; + break; + } + } + if(strlen(temp.ptr) > 0){ + path ~= temp ~ ";"; + } + } + + string[] systemVars = [ "_NT_SYMBOL_PATH", "_NT_ALTERNATE_SYMBOL_PATH", "SYSTEMROOT" ]; + + foreach(e;systemVars){ + if(GetEnvironmentVariableA(toStringz(e),temp.ptr,temp.length) > 0){ + temp[temp.length-1] = 0; + path ~= temp ~ ";"; + } + } + + return path; + } + + static class Callstack : Throwable.TraceInfo { + private: + string[] info = null; + public: + int opApply(scope int delegate(ref char[]) dg){ + int result = 0; + foreach(e;info){ + char[] temp = to!(char[])(e); + result = dg(temp); + if(result) + break; + } + return result; + } + + override string toString(){ + string result = ""; + foreach(e;info){ + result ~= e ~ "\n"; + } + return result; + } + + void append(string str){ + if(info is null){ + info = new string[1]; + info[0] = str; + } + else { + info.length = info.length + 1; + info[info.length-1] = str; + } + } + } + + static Throwable.TraceInfo TraceHandler(void* ptr){ + StackTrace trace = new StackTrace(); + return trace.GetCallstack(); + } + +public: + static this(){ + Runtime.traceHandler(&TraceHandler); + SetUnhandledExceptionFilter(&UnhandeledExceptionFilterHandler); + } + + this(){ + if(isInit) + return; + HANDLE hProcess = GetCurrentProcess(); + DWORD pid = GetCurrentProcessId(); + + Dbghelp.Init(); + string symPath = GenereateSearchPath(); + if(Dbghelp.SymInitialize(hProcess,cast(Dbghelp.PCSTR)toStringz(symPath),FALSE) != FALSE){ + isInit = true; + + DWORD symOptions = Dbghelp.SymGetOptions(); + symOptions |= Dbghelp.SYMOPT_LOAD_LINES; + symOptions |= Dbghelp.SYMOPT_FAIL_CRITICAL_ERRORS; + symOptions = Dbghelp.SymSetOptions(symOptions); + + LoadModules(hProcess,pid); + } + } + + Throwable.TraceInfo GetCallstack(){ + if(!isInit){ + writefln("Is not init!"); + return null; + } + + HANDLE hThread = GetCurrentThread(); + HANDLE hProcess = GetCurrentProcess(); + + //Capture the current context + CONTEXT c; + memset(&c, 0, CONTEXT.sizeof); + c.ContextFlags = CONTEXT_FULL; + RtlCaptureContext(&c); + + Dbghelp.STACKFRAME64 stackframe; + memset(&stackframe,0,typeof(stackframe).sizeof); + DWORD imageType; + //x86 + imageType = Dbghelp.IMAGE_FILE_MACHINE_I386; + stackframe.AddrPC.Offset = cast(Dbghelp.DWORD64)c.Eip; + stackframe.AddrPC.Mode = Dbghelp.ADDRESS_MODE.AddrModeFlat; + stackframe.AddrFrame.Offset = cast(Dbghelp.DWORD64)c.Ebp; + stackframe.AddrFrame.Mode = Dbghelp.ADDRESS_MODE.AddrModeFlat; + stackframe.AddrStack.Offset = cast(Dbghelp.DWORD64)c.Esp; + stackframe.AddrStack.Mode = Dbghelp.ADDRESS_MODE.AddrModeFlat; + + size_t SymbolSize = Dbghelp.IMAGEHLP_SYMBOL64.sizeof + MAX_NAMELEN; + Dbghelp.IMAGEHLP_SYMBOL64 *Symbol = cast(Dbghelp.IMAGEHLP_SYMBOL64*) malloc(SymbolSize); + memset(Symbol,0,SymbolSize); + Symbol.SizeOfStruct = SymbolSize; + Symbol.MaxNameLength = MAX_NAMELEN; + + Dbghelp.IMAGEHLP_LINE64 Line; + memset(&Line,0,typeof(Line).sizeof); + Line.SizeOfStruct = typeof(Line).sizeof; + + Dbghelp.IMAGEHLP_MODULE64 Module; + memset(&Module,0,typeof(Module).sizeof); + Module.SizeOfStruct = typeof(Module).sizeof; + + auto stack = new Callstack(); + + //writefln("Callstack:"); + for(int frameNum=0;;frameNum++){ + if(Dbghelp.StackWalk64(imageType, hProcess, hThread, + &stackframe, &c, + null, + cast(Dbghelp.FunctionTableAccessProc64)Dbghelp.SymFunctionTableAccess64, + cast(Dbghelp.GetModuleBaseProc64)Dbghelp.SymGetModuleBase64, + null) != TRUE ) + { + //writefln("End of Callstack"); + break; + } + + if(stackframe.AddrPC.Offset == stackframe.AddrReturn.Offset){ + //writefln("Endless callstack"); + stack.append("Endless callstack"); + break; + } + + if(stackframe.AddrPC.Offset != 0){ + string lineStr = ""; + Dbghelp.DWORD64 offsetFromSymbol = cast(Dbghelp.DWORD64)0; + if( Dbghelp.SymGetSymFromAddr64(hProcess,stackframe.AddrPC.Offset,&offsetFromSymbol,Symbol) == TRUE){ + char[] symName = new char[strlen(cast(const(char)*)Symbol.Name.ptr)+1]; + memcpy(symName.ptr,Symbol.Name.ptr,symName.length); + string symString = ""; + if(symName[0] == 'D') + symString = "_"; + symString ~= symName; + + string demangeledName = demangle(symString); + lineStr ~= demangeledName; + + DWORD zeichen = 0; + if(Dbghelp.SymGetLineFromAddr64(hProcess,stackframe.AddrPC.Offset,&zeichen,&Line) == TRUE){ + char[] fileName = new char[strlen(Line.FileName)]; + fileName[] = Line.FileName[0..fileName.length]; + lineStr = to!string(fileName ~ "::" ~ to!string(Line.LineNumber) ~ "(" ~ to!string(zeichen) ~ ") " ~ lineStr); + } + } + else { + lineStr = to!string(cast(ulong)stackframe.AddrPC.Offset); + } + lineStr = to!string(frameNum-2) ~ " " ~ lineStr; + if(frameNum-2 < 10) + lineStr = "0" ~ lineStr; + if(frameNum >= 2) + stack.append(lineStr); + } + } + + free(Symbol); + return stack; + } + }; ADDED main.d Index: main.d ================================================================== --- main.d +++ main.d @@ -0,0 +1,16 @@ +/* + * Author: k.inaba + * License: NYSL 0.9982 (http://www.kmonos.net/nysl/ + * Entry point for the polemy interpreter + */ + +import std.stdio; +import polemy.lex; +import polemy.parse; + +static ~this() { readln(); } // workaround for enabling "pause" under Poseidon + +void main() +{ + writeln( "test ok" ); +} ADDED polemy/_common.d Index: polemy/_common.d ================================================================== --- polemy/_common.d +++ polemy/_common.d @@ -0,0 +1,13 @@ +module polemy._common; +/* + * Author: k.inaba + * License: NYSL 0.9982 (http://www.kmonos.net/nysl/ + * "Always-opend" modules inside polemy + */ + +public import std.array; +public import std.range; +public import std.algorithm; +public import std.conv : to; +public import std.bigint; +public import polemy.tricks; ADDED polemy/ast.d Index: polemy/ast.d ================================================================== --- polemy/ast.d +++ polemy/ast.d @@ -0,0 +1,69 @@ +module polemy.ast; +import polemy._common; +/* + * Author: k.inaba + * License: NYSL 0.9982 (http://www.kmonos.net/nysl/ + * Syntax tree for the polemy programming language + */ + +import polemy.lex : LexPosition; + +alias Statement[] Program; + +abstract class Statement +{ + immutable LexPosition pos; + mixin SimpleConstructor; +} + +class DeclStatement : Statement +{ + string var; + Expression expr; + mixin SimpleConstructor; + mixin SimpleCompare; // do not take "pos" into account +} + +class ExprStatement : Statement +{ + Expression expr; + mixin SimpleConstructor; + mixin SimpleCompare; // do not take "pos" into account +} + +abstract class Expression +{ + immutable LexPosition pos; + mixin SimpleConstructor; + mixin SimpleCompare; // do not take "pos" into account +} + +class StrLiteralExpression : Expression +{ + string data; + mixin SimpleConstructor; + mixin SimpleCompare; // do not take "pos" into account +} + +class IntLiteralExpression : Expression +{ + BigInt data; + mixin SimpleConstructor; + mixin SimpleCompare; // do not take "pos" into account +} + +class VarExpression : Expression +{ + string var; + mixin SimpleConstructor; + mixin SimpleCompare; // do not take "pos" into account +} + +class BinOpExpression : Expression +{ + string op; + Expression lhs; + Expression rhs; + mixin SimpleConstructor; + mixin SimpleCompare; // do not take "pos" into account +} ADDED polemy/eval.d Index: polemy/eval.d ================================================================== --- polemy/eval.d +++ polemy/eval.d @@ -0,0 +1,113 @@ +module polemy.eval; +import polemy._common; +/* + * Author: k.inaba + * License: NYSL 0.9982 (http://www.kmonos.net/nysl/ + * Evaluator for the polemy programming language + */ +import polemy.ast; +import polemy.runtime; + +Context eval(Program prog) +{ + return eval(prog, new Context); +} + +Context eval(Program prog, Context ctx) +{ + foreach(s; prog) + ctx = eval(s, ctx); + return ctx; +} + +Context eval(Statement _s, Context ctx) +{ + if( auto s = cast(DeclStatement)_s ) + { + auto v = eval(s.expr, ctx); + ctx.add(s.var, v); + return ctx; + } + else + if( auto s = cast(ExprStatement)_s ) + { + eval(s.expr, ctx); + return ctx; + } + throw new PolemyRuntimeException(sprintf!"Unknown Kind of Statement %s at [%s]"(typeid(_s), _s.pos)); +} + +Value eval(Expression _e, Context ctx) +{ + if( auto e = cast(StrLiteralExpression)_e ) + { + return new StrValue(e.data); + } + else + if( auto e = cast(IntLiteralExpression)_e ) + { + return new IntValue(e.data); + } + else + if( auto e = cast(VarExpression)_e ) + { + return ctx[e.var]; + } + else + if( auto e = cast(BinOpExpression)_e ) + { + if( e.op == "=" ) + { + if( auto ev = cast(VarExpression)e.lhs ) + { + Value r = eval(e.rhs, ctx); + ctx[ev.var] = r; + return r; + } + throw new PolemyRuntimeException(sprintf!"Lhs of assignment must be a variable: %s"(e.pos)); + } + + Value l = eval(e.lhs, ctx); + Value r = eval(e.rhs, ctx); + if( auto lv = cast(IntValue)l ) + if( auto rv = cast(IntValue)r ) + final switch(e.op) + { + case "+": return new IntValue(lv.data+rv.data); + case "-": return new IntValue(lv.data-rv.data); + case "*": return new IntValue(lv.data*rv.data); + case "/": return new IntValue(lv.data/rv.data); + } + else + throw new PolemyRuntimeException(sprintf!"rhs of %s must be an integer but was %s at [%s]"(e.op, typeid(r), e.rhs.pos)); + else + throw new PolemyRuntimeException(sprintf!"lhs of %s must be an integer but was %s at [%s]"(e.op, typeid(l), e.lhs.pos)); + } + throw new PolemyRuntimeException(sprintf!"Unknown Kind of Expression %s at [%s]"(typeid(_e), _e.pos)); +} + + +version(unittest) import polemy.parse; +version(unittest) import std.stdio; +version(unittest) import std.exception; +unittest +{ + auto parser = parserFromString(`var x = 21; x = x + x*x;`); + auto prog = parser.parseProgram(); + auto ctx = eval(prog); + assert( ctx["x"] == new IntValue(BigInt(21+21*21)) ); + assert( !collectException(ctx["x"]) ); + assert( collectException(ctx["y"]) ); +} +unittest +{ + auto parser = parserFromString(`var x = 21; x = x + x*y;`); + auto prog = parser.parseProgram(); + assert( collectException(eval(prog)) ); +} +unittest +{ + auto parser = parserFromString(`var x = 21; y = x + x*x;`); + auto prog = parser.parseProgram(); + assert( collectException(eval(prog)) ); +} ADDED polemy/lex.d Index: polemy/lex.d ================================================================== --- polemy/lex.d +++ polemy/lex.d @@ -0,0 +1,389 @@ +module polemy.lex; +import polemy._common; +/* + * Author: k.inaba + * License: NYSL 0.9982 (http://www.kmonos.net/nysl/ + * Lexer for the polemy programming language + */ + +import std.file : readText; +import std.string : munch; +import std.ctype; + +/// Represents a position in a source code + +class LexPosition +{ + immutable string filename; ///< name of the source file + immutable int lineno; ///< line number: 1, 2, ... + immutable int column; ///< column: 1, 2, ... + + override string toString() const + { return sprintf!"%s:%d:%d"(filename, lineno, column); } + + mixin SimpleConstructor; + mixin SimpleCompare; +} + +unittest +{ + auto p = new LexPosition("hello.cpp", 123, 45); + auto q = new LexPosition("hello.cpp", 123, 46); + + assert( p.filename == "hello.cpp" ); + assert( p.lineno == 123 ); + assert( p.column == 45 ); + assert( to!string(p) == "hello.cpp:123:45" ); + assert( p < q ); + assert( p != q ); + + assert( !__traits(compiles, new LexPosition) ); + assert( !__traits(compiles, p.filename="foo") ); + assert( !__traits(compiles, p.lineno =789) ); + assert( !__traits(compiles, p.column =222) ); +} + +/// Represents a lexer token + +class Token +{ + enum Kind {identifier, stringLiteral, number}; + immutable LexPosition pos; ///< position where the token occurred in the source + immutable string str; ///< the token string itself + immutable Kind kind; ///< which kind of token? + + mixin SimpleConstructor; + mixin SimpleCompare; +} + +unittest +{ + auto p = new immutable(LexPosition)("hello.cpp", 123, 45); + auto t = new Token(p, "class", Token.Kind.identifier); + + assert( t.pos == p ); + assert( t.str == "class" ); + assert( t == new Token(p, "class", Token.Kind.identifier) ); + assert( t < new Token(p, "struct", Token.Kind.identifier) ); + + assert( !__traits(compiles, new Token) ); + assert( !__traits(compiles, t.pos=p) ); + assert( !__traits(compiles, t.str=789) ); +} + +/// Named Construtor for Lexer + +Lexer lexerFromFile(T...)( string filename, T rest ) +{ + return lexerFromString( std.file.readText(filename), filename, rest ); +} + +/// Named Construtor for Lexer + +Lexer lexerFromString( string str, string filename="", int lineno=1, int column=1 ) +{ + return new Lexer(str, filename, lineno, column); +} + +/// Lexer is a forward range of Tokens + +class Lexer +{ + bool empty() /*@property*/ + { + return current is null; + } + + Token front() /*@property*/ + { + return std.exception.enforce(current, "Lexer has already reached the end"); + } + + void popFront() /*@property*/ + { + std.exception.enforce(current, "Lexer has already reached the end"); + current = readNext(); + } + + Lexer save() /*@property*/ + { + return new Lexer(buffer, filename, lineno, column, current); + } + +private: // implementation + + string buffer; + string filename; + int lineno; + int column; + Token current; + + invariant() + { + assert( buffer.empty || !std.ctype.isspace(buffer[0]) ); + } + + this( string buffer, string filename, int lineno, int column, Token current=null ) + { + this.buffer = buffer; + this.filename = filename; + this.lineno = lineno; + this.column = column; + skipws(); + this.current = (current is null ? readNext() : current); + } + + void skipws() + { + bool progress = false; + do + { + string ws = buffer.munch(" \t"); + column += ws.length; + progress = !ws.empty; + while( !buffer.empty && (buffer[0]=='\r' || buffer[0]=='\n') ) + { + progress = true; + if( buffer[0] == '\n' ) + buffer = buffer[1..$]; + else // if( buffer.front == '\r' ) + { + buffer = buffer[1..$]; + if( !buffer.empty && buffer[0]=='\n' ) + buffer = buffer[1..$]; + } + lineno ++; + column = 1; + } + }while( progress ); + } + + char readChar() + { + scope(exit) { + buffer = buffer[1..$]; + column ++; + } + return buffer[0]; + } + + /// This is the main lexing routine + Token readNext() + { + if( buffer.empty ) + return null; + scope(exit) + skipws(); + + if( isSymbol(buffer[0]) ) + { + if( buffer[0] == '#' ) + { + // skip comment + while( !buffer.empty && (buffer[0]!='\n' && buffer[0]!='\r') ) + readChar(); + skipws(); + return readNext(); + } + else if( buffer[0] == '"' ) + { + // string literal + auto pos = currentPosition(); + string lit; + readChar(); + while( !buffer.empty && buffer[0]!='"' ) + { + // read one char + char c = readChar(); + if( c == '\\' ) + { + if( !buffer.empty && (buffer[0]=='\\' || buffer[0]=='"') ) + lit ~= readChar(); + else + lit ~= c; + } + else if( c == '\n' ) + { + lit ~= c; + lineno++; + column = 1; + } + else if( c == '\r' ) + { + if( !buffer.empty && buffer[0]=='\n' ) + readChar(); + lit ~= '\n'; + lineno++; + column = 1; + } + else + lit ~= c; + } + if( !buffer.empty ) + readChar(); + return new Token(pos, lit, Token.Kind.stringLiteral); + } + else + { + // normal symbol + auto pos = currentPosition(); + auto str = ""~readChar(); + return new Token(pos, str, Token.Kind.identifier); + } + } + else + { + auto pos = currentPosition(); + int i = 0; + while( i new Temp(1,"bar") ); + assert( new Temp(1,"foo") < new Temp(2,"bar") ); +} ADDED readme.txt Index: readme.txt ================================================================== --- readme.txt +++ readme.txt @@ -0,0 +1,45 @@ +----------------------------------------------------------------------------- + Polemy 0.1.0 + by k.inaba (www.kmonos.net) + Nov 7, 2010 +----------------------------------------------------------------------------- + + + +<> + + - Install DMD + http://www.digitalmars.com/d/2.0/changelog.html + Version 2.050 is recommended. Older and/or newer version may not work. + + - Build + (for Poseidon IDE users) Open the project and build + (for Windows) Run build.bat + (for Unix) Run build.sh + or use your favorite build tools upon main.d and polemy/*.d. + + Then you will get the executable "polemy" in the "bin" directory. + + + +<> + + d2stacktrace/* + + is written by Benjamin Thaut and licensed under 2-clause BSD License. + See http://3d.benjamin-thaut.de/?p=15 for the detail. + + (this package is used only for enabling stack-traces during printing exceptions; + if it is not needed, please just simply remove the sources from your build) + + polemy/* + main.d + + All the other parts are written by Kazuhiro Inaba and + licensed under NYSL 0.9982 ( http://www.kmonos.net/nysl/ ). + + + +<> + + I don't know.