mirror of
https://github.com/nim-lang/Nim.git
synced 2026-07-21 16:31:39 +00:00
c2nim tool added
This commit is contained in:
@@ -155,7 +155,7 @@ underscores ``__`` are not allowed::
|
||||
|
||||
letter ::= 'A'..'Z' | 'a'..'z' | '\x80'..'\xff'
|
||||
digit ::= '0'..'9'
|
||||
IDENTIFIER ::= letter ( ['_'] letter | digit )*
|
||||
IDENTIFIER ::= letter ( ['_'] (letter | digit) )*
|
||||
|
||||
The following `keywords`:idx: are reserved and cannot be used as identifiers:
|
||||
|
||||
|
||||
68
lib/impure/osinfo_posix.nim
Executable file
68
lib/impure/osinfo_posix.nim
Executable file
@@ -0,0 +1,68 @@
|
||||
import posix, strutils, os
|
||||
|
||||
type
|
||||
Tstatfs {.importc: "struct statfs64",
|
||||
header: "<sys/statfs.h>", final, pure.} = object
|
||||
f_type: int
|
||||
f_bsize: int
|
||||
f_blocks: int
|
||||
f_bfree: int
|
||||
f_bavail: int
|
||||
f_files: int
|
||||
f_ffree: int
|
||||
f_fsid: int
|
||||
f_namelen: int
|
||||
|
||||
proc statfs(path: string, buf: var Tstatfs): int {.
|
||||
importc, header: "<sys/vfs.h>".}
|
||||
|
||||
|
||||
proc getSystemVersion*(): string =
|
||||
result = ""
|
||||
|
||||
var unix_info: TUtsname
|
||||
|
||||
if uname(unix_info) != 0:
|
||||
os.OSError()
|
||||
|
||||
if $unix_info.sysname == "Linux":
|
||||
# Linux
|
||||
result.add("Linux ")
|
||||
|
||||
result.add($unix_info.release & " ")
|
||||
result.add($unix_info.machine)
|
||||
elif $unix_info.sysname == "Darwin":
|
||||
# Darwin
|
||||
result.add("Mac OS X ")
|
||||
if "10" in $unix_info.release:
|
||||
result.add("v10.6 Snow Leopard")
|
||||
elif "9" in $unix_info.release:
|
||||
result.add("v10.5 Leopard")
|
||||
elif "8" in $unix_info.release:
|
||||
result.add("v10.4 Tiger")
|
||||
elif "7" in $unix_info.release:
|
||||
result.add("v10.3 Panther")
|
||||
elif "6" in $unix_info.release:
|
||||
result.add("v10.2 Jaguar")
|
||||
elif "1.4" in $unix_info.release:
|
||||
result.add("v10.1 Puma")
|
||||
elif "1.3" in $unix_info.release:
|
||||
result.add("v10.0 Cheetah")
|
||||
elif "0" in $unix_info.release:
|
||||
result.add("Server 1.0 Hera")
|
||||
else:
|
||||
result.add($unix_info.sysname & " " & $unix_info.release)
|
||||
|
||||
|
||||
when false:
|
||||
var unix_info: TUtsname
|
||||
echo(uname(unix_info))
|
||||
echo(unix_info.sysname)
|
||||
echo("8" in $unix_info.release)
|
||||
|
||||
echo(getSystemVersion())
|
||||
|
||||
var stfs: TStatfs
|
||||
echo(statfs("sysinfo_posix.nim", stfs))
|
||||
echo(stfs.f_files)
|
||||
|
||||
399
lib/impure/osinfo_win.nim
Executable file
399
lib/impure/osinfo_win.nim
Executable file
@@ -0,0 +1,399 @@
|
||||
# XXX clean up this mess!
|
||||
|
||||
import winlean
|
||||
|
||||
const
|
||||
INVALID_HANDLE_VALUE = int(- 1) # GetStockObject
|
||||
|
||||
type
|
||||
TMEMORYSTATUSEX {.final, pure.} = object
|
||||
dwLength: int32
|
||||
dwMemoryLoad: int32
|
||||
ullTotalPhys: int64
|
||||
ullAvailPhys: int64
|
||||
ullTotalPageFile: int64
|
||||
ullAvailPageFile: int64
|
||||
ullTotalVirtual: int64
|
||||
ullAvailVirtual: int64
|
||||
ullAvailExtendedVirtual: int64
|
||||
|
||||
SYSTEM_INFO* {.final, pure.} = object
|
||||
wProcessorArchitecture*: int16
|
||||
wReserved*: int16
|
||||
dwPageSize*: int32
|
||||
lpMinimumApplicationAddress*: pointer
|
||||
lpMaximumApplicationAddress*: pointer
|
||||
dwActiveProcessorMask*: int32
|
||||
dwNumberOfProcessors*: int32
|
||||
dwProcessorType*: int32
|
||||
dwAllocationGranularity*: int32
|
||||
wProcessorLevel*: int16
|
||||
wProcessorRevision*: int16
|
||||
|
||||
LPSYSTEM_INFO* = ptr SYSTEM_INFO
|
||||
TSYSTEMINFO* = SYSTEM_INFO
|
||||
|
||||
TMemoryInfo* = object
|
||||
MemoryLoad*: int ## occupied memory, in percent
|
||||
TotalPhysMem*: int64 ## Total Physical memory, in bytes
|
||||
AvailablePhysMem*: int64 ## Available physical memory, in bytes
|
||||
TotalPageFile*: int64 ## The current committed memory limit
|
||||
## for the system or the current process, whichever is smaller, in bytes.
|
||||
AvailablePageFile*: int64 ## The maximum amount of memory the current process can commit, in bytes.
|
||||
TotalVirtualMem*: int64 ## Total virtual memory, in bytes
|
||||
AvailableVirtualMem*: int64 ## Available virtual memory, in bytes
|
||||
|
||||
TOSVERSIONINFOEX {.final, pure.} = object
|
||||
dwOSVersionInfoSize: int32
|
||||
dwMajorVersion: int32
|
||||
dwMinorVersion: int32
|
||||
dwBuildNumber: int32
|
||||
dwPlatformId: int32
|
||||
szCSDVersion: array[0..127, char]
|
||||
wServicePackMajor: int16
|
||||
wServicePackMinor: int16
|
||||
wSuiteMask: int16
|
||||
wProductType: int8
|
||||
wReserved: char
|
||||
|
||||
TVersionInfo* = object
|
||||
majorVersion*: int
|
||||
minorVersion*: int
|
||||
buildNumber*: int
|
||||
platformID*: int
|
||||
SPVersion*: string ## Full Service pack version string
|
||||
SPMajor*: int ## Major service pack version
|
||||
SPMinor*: int ## Minor service pack version
|
||||
SuiteMask*: int
|
||||
ProductType*: int
|
||||
|
||||
TPartitionInfo* = tuple[FreeSpace, TotalSpace: filetime]
|
||||
|
||||
const
|
||||
# SuiteMask - VersionInfo.SuiteMask
|
||||
VER_SUITE_BACKOFFICE* = 0x00000004
|
||||
VER_SUITE_BLADE* = 0x00000400
|
||||
VER_SUITE_COMPUTE_SERVER* = 0x00004000
|
||||
VER_SUITE_DATACENTER* = 0x00000080
|
||||
VER_SUITE_ENTERPRISE* = 0x00000002
|
||||
VER_SUITE_EMBEDDEDNT* = 0x00000040
|
||||
VER_SUITE_PERSONAL* = 0x00000200
|
||||
VER_SUITE_SINGLEUSERTS* = 0x00000100
|
||||
VER_SUITE_SMALLBUSINESS* = 0x00000001
|
||||
VER_SUITE_SMALLBUSINESS_RESTRICTED* = 0x00000020
|
||||
VER_SUITE_STORAGE_SERVER* = 0x00002000
|
||||
VER_SUITE_TERMINAL* = 0x00000010
|
||||
VER_SUITE_WH_SERVER* = 0x00008000
|
||||
|
||||
# ProductType - VersionInfo.ProductType
|
||||
VER_NT_DOMAIN_CONTROLLER* = 0x0000002
|
||||
VER_NT_SERVER* = 0x0000003
|
||||
VER_NT_WORKSTATION* = 0x0000001
|
||||
|
||||
VER_PLATFORM_WIN32_NT* = 2
|
||||
|
||||
# Product Info - getProductInfo() - (Remove unused ones ?)
|
||||
PRODUCT_BUSINESS* = 0x00000006
|
||||
PRODUCT_BUSINESS_N* = 0x00000010
|
||||
PRODUCT_CLUSTER_SERVER* = 0x00000012
|
||||
PRODUCT_DATACENTER_SERVER* = 0x00000008
|
||||
PRODUCT_DATACENTER_SERVER_CORE* = 0x0000000C
|
||||
PRODUCT_DATACENTER_SERVER_CORE_V* = 0x00000027
|
||||
PRODUCT_DATACENTER_SERVER_V* = 0x00000025
|
||||
PRODUCT_ENTERPRISE* = 0x00000004
|
||||
PRODUCT_ENTERPRISE_E* = 0x00000046
|
||||
PRODUCT_ENTERPRISE_N* = 0x0000001B
|
||||
PRODUCT_ENTERPRISE_SERVER* = 0x0000000A
|
||||
PRODUCT_ENTERPRISE_SERVER_CORE* = 0x0000000E
|
||||
PRODUCT_ENTERPRISE_SERVER_CORE_V* = 0x00000029
|
||||
PRODUCT_ENTERPRISE_SERVER_IA64* = 0x0000000F
|
||||
PRODUCT_ENTERPRISE_SERVER_V* = 0x00000026
|
||||
PRODUCT_HOME_BASIC* = 0x00000002
|
||||
PRODUCT_HOME_BASIC_E* = 0x00000043
|
||||
PRODUCT_HOME_BASIC_N* = 0x00000005
|
||||
PRODUCT_HOME_PREMIUM* = 0x00000003
|
||||
PRODUCT_HOME_PREMIUM_E* = 0x00000044
|
||||
PRODUCT_HOME_PREMIUM_N* = 0x0000001A
|
||||
PRODUCT_HYPERV* = 0x0000002A
|
||||
PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT* = 0x0000001E
|
||||
PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING* = 0x00000020
|
||||
PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY* = 0x0000001F
|
||||
PRODUCT_PROFESSIONAL* = 0x00000030
|
||||
PRODUCT_PROFESSIONAL_E* = 0x00000045
|
||||
PRODUCT_PROFESSIONAL_N* = 0x00000031
|
||||
PRODUCT_SERVER_FOR_SMALLBUSINESS* = 0x00000018
|
||||
PRODUCT_SERVER_FOR_SMALLBUSINESS_V* = 0x00000023
|
||||
PRODUCT_SERVER_FOUNDATION* = 0x00000021
|
||||
PRODUCT_SMALLBUSINESS_SERVER* = 0x00000009
|
||||
PRODUCT_STANDARD_SERVER* = 0x00000007
|
||||
PRODUCT_STANDARD_SERVER_CORE * = 0x0000000D
|
||||
PRODUCT_STANDARD_SERVER_CORE_V* = 0x00000028
|
||||
PRODUCT_STANDARD_SERVER_V* = 0x00000024
|
||||
PRODUCT_STARTER* = 0x0000000B
|
||||
PRODUCT_STARTER_E* = 0x00000042
|
||||
PRODUCT_STARTER_N* = 0x0000002F
|
||||
PRODUCT_STORAGE_ENTERPRISE_SERVER* = 0x00000017
|
||||
PRODUCT_STORAGE_EXPRESS_SERVER* = 0x00000014
|
||||
PRODUCT_STORAGE_STANDARD_SERVER* = 0x00000015
|
||||
PRODUCT_STORAGE_WORKGROUP_SERVER* = 0x00000016
|
||||
PRODUCT_UNDEFINED* = 0x00000000
|
||||
PRODUCT_ULTIMATE* = 0x00000001
|
||||
PRODUCT_ULTIMATE_E* = 0x00000047
|
||||
PRODUCT_ULTIMATE_N* = 0x0000001C
|
||||
PRODUCT_WEB_SERVER* = 0x00000011
|
||||
PRODUCT_WEB_SERVER_CORE* = 0x0000001D
|
||||
|
||||
PROCESSOR_ARCHITECTURE_AMD64* = 9 ## x64 (AMD or Intel)
|
||||
PROCESSOR_ARCHITECTURE_IA64* = 6 ## Intel Itanium Processor Family (IPF)
|
||||
PROCESSOR_ARCHITECTURE_INTEL* = 0 ## x86
|
||||
PROCESSOR_ARCHITECTURE_UNKNOWN* = 0xffff ## Unknown architecture.
|
||||
|
||||
# GetSystemMetrics
|
||||
SM_SERVERR2 = 89
|
||||
|
||||
proc GlobalMemoryStatusEx*(lpBuffer: var TMEMORYSTATUSEX){.stdcall, dynlib: "kernel32",
|
||||
importc: "GlobalMemoryStatusEx".}
|
||||
|
||||
proc getMemoryInfo*(): TMemoryInfo =
|
||||
## Retrieves memory info
|
||||
var statex: TMEMORYSTATUSEX
|
||||
statex.dwLength = sizeof(statex)
|
||||
|
||||
GlobalMemoryStatusEx(statex)
|
||||
result.MemoryLoad = statex.dwMemoryLoad
|
||||
result.TotalPhysMem = statex.ullTotalPhys
|
||||
result.AvailablePhysMem = statex.ullAvailPhys
|
||||
result.TotalPageFile = statex.ullTotalPageFile
|
||||
result.AvailablePageFile = statex.ullAvailPageFile
|
||||
result.TotalVirtualMem = statex.ullTotalVirtual
|
||||
result.AvailableVirtualMem = statex.ullAvailExtendedVirtual
|
||||
|
||||
proc GetVersionEx*(lpVersionInformation: var TOSVERSIONINFOEX): WINBOOL{.stdcall,
|
||||
dynlib: "kernel32", importc: "GetVersionExA".}
|
||||
|
||||
proc GetProcAddress*(hModule: int, lpProcName: cstring): pointer{.stdcall,
|
||||
dynlib: "kernel32", importc: "GetProcAddress".}
|
||||
|
||||
proc GetModuleHandleA*(lpModuleName: cstring): int{.stdcall,
|
||||
dynlib: "kernel32", importc.}
|
||||
|
||||
proc getVersionInfo*(): TVersionInfo =
|
||||
## Retrieves operating system info
|
||||
var osvi: TOSVERSIONINFOEX
|
||||
osvi.dwOSVersionInfoSize = sizeof(osvi)
|
||||
discard GetVersionEx(osvi)
|
||||
result.majorVersion = osvi.dwMajorVersion
|
||||
result.minorVersion = osvi.dwMinorVersion
|
||||
result.buildNumber = osvi.dwBuildNumber
|
||||
result.platformID = osvi.dwPlatformId
|
||||
result.SPVersion = $osvi.szCSDVersion
|
||||
result.SPMajor = osvi.wServicePackMajor
|
||||
result.SPMinor = osvi.wServicePackMinor
|
||||
result.SuiteMask = osvi.wSuiteMask
|
||||
result.ProductType = osvi.wProductType
|
||||
|
||||
proc getProductInfo*(majorVersion, minorVersion, SPMajorVersion,
|
||||
SPMinorVersion: int): int =
|
||||
## Retrieves Windows' ProductInfo, this function only works in Vista and 7
|
||||
|
||||
var pGPI = cast[proc (dwOSMajorVersion, dwOSMinorVersion,
|
||||
dwSpMajorVersion, dwSpMinorVersion: int32, outValue: Pint32)](GetProcAddress(
|
||||
GetModuleHandleA("kernel32.dll"), "GetProductInfo"))
|
||||
|
||||
if pGPI != nil:
|
||||
var dwType: int32
|
||||
pGPI(int32(majorVersion), int32(minorVersion), int32(SPMajorVersion), int32(SPMinorVersion), addr(dwType))
|
||||
result = int(dwType)
|
||||
else:
|
||||
return PRODUCT_UNDEFINED
|
||||
|
||||
proc GetSystemInfo*(lpSystemInfo: LPSYSTEM_INFO){.stdcall, dynlib: "kernel32",
|
||||
importc: "GetSystemInfo".}
|
||||
|
||||
proc getSystemInfo*(): TSYSTEM_INFO =
|
||||
## Returns the SystemInfo
|
||||
|
||||
# Use GetNativeSystemInfo if it's available
|
||||
var pGNSI = cast[proc (lpSystemInfo: LPSYSTEM_INFO)](GetProcAddress(
|
||||
GetModuleHandleA("kernel32.dll"), "GetNativeSystemInfo"))
|
||||
|
||||
var systemi: TSYSTEM_INFO
|
||||
if pGNSI != nil:
|
||||
pGNSI(addr(systemi))
|
||||
else:
|
||||
GetSystemInfo(addr(systemi))
|
||||
|
||||
return systemi
|
||||
|
||||
proc GetSystemMetrics*(nIndex: int32): int32{.stdcall, dynlib: "user32",
|
||||
importc: "GetSystemMetrics".}
|
||||
|
||||
proc `$`*(osvi: TVersionInfo): string =
|
||||
## Turns a VersionInfo object, into a string
|
||||
|
||||
if osvi.platformID == VER_PLATFORM_WIN32_NT and osvi.majorVersion > 4:
|
||||
result = "Microsoft "
|
||||
|
||||
var si = getSystemInfo()
|
||||
# Test for the specific product
|
||||
if osvi.majorVersion == 6:
|
||||
if osvi.minorVersion == 0:
|
||||
if osvi.ProductType == VER_NT_WORKSTATION:
|
||||
result.add("Windows Vista ")
|
||||
else: result.add("Windows Server 2008 ")
|
||||
elif osvi.minorVersion == 1:
|
||||
if osvi.ProductType == VER_NT_WORKSTATION:
|
||||
result.add("Windows 7 ")
|
||||
else: result.add("Windows Server 2008 R2 ")
|
||||
|
||||
var dwType = getProductInfo(osvi.majorVersion, osvi.minorVersion, 0, 0)
|
||||
case dwType
|
||||
of PRODUCT_ULTIMATE:
|
||||
result.add("Ultimate Edition")
|
||||
of PRODUCT_PROFESSIONAL:
|
||||
result.add("Professional")
|
||||
of PRODUCT_HOME_PREMIUM:
|
||||
result.add("Home Premium Edition")
|
||||
of PRODUCT_HOME_BASIC:
|
||||
result.add("Home Basic Edition")
|
||||
of PRODUCT_ENTERPRISE:
|
||||
result.add("Enterprise Edition")
|
||||
of PRODUCT_BUSINESS:
|
||||
result.add("Business Edition")
|
||||
of PRODUCT_STARTER:
|
||||
result.add("Starter Edition")
|
||||
of PRODUCT_CLUSTER_SERVER:
|
||||
result.add("Cluster Server Edition")
|
||||
of PRODUCT_DATACENTER_SERVER:
|
||||
result.add("Datacenter Edition")
|
||||
of PRODUCT_DATACENTER_SERVER_CORE:
|
||||
result.add("Datacenter Edition (core installation)")
|
||||
of PRODUCT_ENTERPRISE_SERVER:
|
||||
result.add("Enterprise Edition")
|
||||
of PRODUCT_ENTERPRISE_SERVER_CORE:
|
||||
result.add("Enterprise Edition (core installation)")
|
||||
of PRODUCT_ENTERPRISE_SERVER_IA64:
|
||||
result.add("Enterprise Edition for Itanium-based Systems")
|
||||
of PRODUCT_SMALLBUSINESS_SERVER:
|
||||
result.add("Small Business Server")
|
||||
of PRODUCT_STANDARD_SERVER:
|
||||
result.add("Standard Edition")
|
||||
of PRODUCT_STANDARD_SERVER_CORE:
|
||||
result.add("Standard Edition (core installation)")
|
||||
of PRODUCT_WEB_SERVER:
|
||||
result.add("Web Server Edition")
|
||||
else:
|
||||
nil
|
||||
# End of Windows 6.*
|
||||
|
||||
if osvi.majorVersion == 5 and osvi.minorVersion == 2:
|
||||
if GetSystemMetrics(SM_SERVERR2) != 0:
|
||||
result.add("Windows Server 2003 R2, ")
|
||||
elif (osvi.SuiteMask and VER_SUITE_PERSONAL) != 0: # Not sure if this will work
|
||||
result.add("Windows Storage Server 2003")
|
||||
elif (osvi.SuiteMask and VER_SUITE_WH_SERVER) != 0:
|
||||
result.add("Windows Home Server")
|
||||
elif osvi.ProductType == VER_NT_WORKSTATION and
|
||||
si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64:
|
||||
result.add("Windows XP Professional x64 Edition")
|
||||
else:
|
||||
result.add("Windows Server 2003, ")
|
||||
|
||||
# Test for the specific product
|
||||
if osvi.ProductType != VER_NT_WORKSTATION:
|
||||
if ze(si.wProcessorArchitecture) == PROCESSOR_ARCHITECTURE_IA64:
|
||||
if (osvi.SuiteMask and VER_SUITE_DATACENTER) != 0:
|
||||
result.add("Datacenter Edition for Itanium-based Systems")
|
||||
elif (osvi.SuiteMask and VER_SUITE_ENTERPRISE) != 0:
|
||||
result.add("Enterprise Edition for Itanium-based Systems")
|
||||
elif ze(si.wProcessorArchitecture) == PROCESSOR_ARCHITECTURE_AMD64:
|
||||
if (osvi.SuiteMask and VER_SUITE_DATACENTER) != 0:
|
||||
result.add("Datacenter x64 Edition")
|
||||
elif (osvi.SuiteMask and VER_SUITE_ENTERPRISE) != 0:
|
||||
result.add("Enterprise x64 Edition")
|
||||
else:
|
||||
result.add("Standard x64 Edition")
|
||||
else:
|
||||
if (osvi.SuiteMask and VER_SUITE_COMPUTE_SERVER) != 0:
|
||||
result.add("Compute Cluster Edition")
|
||||
elif (osvi.SuiteMask and VER_SUITE_DATACENTER) != 0:
|
||||
result.add("Datacenter Edition")
|
||||
elif (osvi.SuiteMask and VER_SUITE_ENTERPRISE) != 0:
|
||||
result.add("Enterprise Edition")
|
||||
elif (osvi.SuiteMask and VER_SUITE_BLADE) != 0:
|
||||
result.add("Web Edition")
|
||||
else:
|
||||
result.add("Standard Edition")
|
||||
# End of 5.2
|
||||
|
||||
if osvi.majorVersion == 5 and osvi.minorVersion == 1:
|
||||
result.add("Windows XP ")
|
||||
if (osvi.SuiteMask and VER_SUITE_PERSONAL) != 0:
|
||||
result.add("Home Edition")
|
||||
else:
|
||||
result.add("Professional")
|
||||
# End of 5.1
|
||||
|
||||
if osvi.majorVersion == 5 and osvi.minorVersion == 0:
|
||||
result.add("Windows 2000 ")
|
||||
if osvi.ProductType == VER_NT_WORKSTATION:
|
||||
result.add("Professional")
|
||||
else:
|
||||
if (osvi.SuiteMask and VER_SUITE_DATACENTER) != 0:
|
||||
result.add("Datacenter Server")
|
||||
elif (osvi.SuiteMask and VER_SUITE_ENTERPRISE) != 0:
|
||||
result.add("Advanced Server")
|
||||
else:
|
||||
result.add("Server")
|
||||
# End of 5.0
|
||||
|
||||
# Include service pack (if any) and build number.
|
||||
if len(osvi.SPVersion) > 0:
|
||||
result.add(" ")
|
||||
result.add(osvi.SPVersion)
|
||||
|
||||
result.add(" (build " & $osvi.buildNumber & ")")
|
||||
|
||||
if osvi.majorVersion >= 6:
|
||||
if ze(si.wProcessorArchitecture) == PROCESSOR_ARCHITECTURE_AMD64:
|
||||
result.add(", 64-bit")
|
||||
elif ze(si.wProcessorArchitecture) == PROCESSOR_ARCHITECTURE_INTEL:
|
||||
result.add(", 32-bit")
|
||||
|
||||
else:
|
||||
# Windows 98 etc...
|
||||
result = "Unknown version of windows[Kernel version <= 4]"
|
||||
|
||||
|
||||
proc getFileSize*(file: string): biggestInt =
|
||||
var fileData: TWIN32_FIND_DATA
|
||||
var hFile = FindFirstFileA(file, fileData)
|
||||
|
||||
if hFile == INVALID_HANDLE_VALUE:
|
||||
raise newException(EIO, $GetLastError())
|
||||
|
||||
return fileData.nFileSizeLow
|
||||
|
||||
proc GetDiskFreeSpaceEx*(lpDirectoryName: cstring, lpFreeBytesAvailableToCaller,
|
||||
lpTotalNumberOfBytes,
|
||||
lpTotalNumberOfFreeBytes: var filetime): WINBOOL{.
|
||||
stdcall, dynlib: "kernel32", importc: "GetDiskFreeSpaceExA".}
|
||||
|
||||
proc getPartitionInfo*(partition: string): TPartitionInfo =
|
||||
## Retrieves partition info, for example ``partition`` may be ``"C:\"``
|
||||
var FreeBytes, TotalBytes, TotalFreeBytes: filetime
|
||||
var res = GetDiskFreeSpaceEx(r"C:\", FreeBytes, TotalBytes,
|
||||
TotalFreeBytes)
|
||||
return (FreeBytes, TotalBytes)
|
||||
|
||||
when isMainModule:
|
||||
var r = getMemoryInfo()
|
||||
echo("Memory load: ", r.MemoryLoad, "%")
|
||||
|
||||
var osvi = getVersionInfo()
|
||||
|
||||
echo($osvi)
|
||||
|
||||
echo(getFileSize(r"osinfo_win.nim") div 1024 div 1024)
|
||||
|
||||
echo(rdFileTime(getPartitionInfo(r"C:\")[0]))
|
||||
@@ -80,7 +80,7 @@ __TINYC__
|
||||
|
||||
/* ---------------- casting without correct aliasing rules ----------- */
|
||||
|
||||
#if defined(__GNUCC__)
|
||||
#if defined(__GNUC__)
|
||||
# define NIM_CAST(type, ptr) (((union{type __x__;}*)(ptr))->__x__)
|
||||
#else
|
||||
# define NIM_CAST(type, ptr) ((type)(ptr))
|
||||
|
||||
@@ -117,7 +117,7 @@ when defined(macosx) or defined(bsd):
|
||||
|
||||
proc countProcessors*(): int =
|
||||
## returns the numer of the processors/cores the machine has.
|
||||
## Returns 0 if it cannot be determined.
|
||||
## Returns 0 if it cannot be detected.
|
||||
when defined(windows):
|
||||
var x = getenv("NUMBER_OF_PROCESSORS")
|
||||
if x.len > 0: result = parseInt(x)
|
||||
|
||||
@@ -391,10 +391,13 @@ proc endsWith(s, suffix: string): bool =
|
||||
var
|
||||
i = 0
|
||||
j = len(s) - len(suffix)
|
||||
while true:
|
||||
if suffix[i] == '\0': return true
|
||||
while i+j <% s.len:
|
||||
if s[i+j] != suffix[i]: return false
|
||||
inc(i)
|
||||
if suffix[i] == '\0': return true
|
||||
|
||||
# 012345
|
||||
# 345
|
||||
|
||||
when false:
|
||||
proc abbrev(s: string, possibilities: openarray[string]): int =
|
||||
|
||||
74
rod/c2nim/c2nim.nim
Executable file
74
rod/c2nim/c2nim.nim
Executable file
@@ -0,0 +1,74 @@
|
||||
#
|
||||
#
|
||||
# c2nim - C to Nimrod source converter
|
||||
# (c) Copyright 2010 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
import
|
||||
strutils, os, times, parseopt, llstream, ast, rnimsyn, options, msgs,
|
||||
clex, cparse
|
||||
|
||||
const
|
||||
Version = "0.8.10"
|
||||
Usage = """
|
||||
c2nim - C to Nimrod source converter
|
||||
(c) 2010 Andreas Rumpf
|
||||
Usage: c2nim [options] inputfile [options]
|
||||
Options:
|
||||
-o, --out:FILE set output filename
|
||||
--dynlib:SYMBOL import from dynlib: SYMBOL will be used for the import
|
||||
--header:HEADER_FILE import from a HEADER_FILE (discouraged!)
|
||||
--cdecl annotate procs with ``{.cdecl.}``
|
||||
--stdcall annotate procs with ``{.stdcall.}``
|
||||
--ref convert typ* to ref typ (default: ptr typ)
|
||||
--prefix:PREFIX strip prefix for the generated Nimrod identifiers
|
||||
(multiple --prefix options are supported)
|
||||
--suffix:SUFFIX strip suffix for the generated Nimrod identifiers
|
||||
(multiple --suffix options are supported)
|
||||
--skip:IDENT skip IDENT in the input file
|
||||
-v, --version write c2nim's version
|
||||
-h, --help show this help
|
||||
"""
|
||||
|
||||
proc main(infile, outfile: string, options: PParserOptions) =
|
||||
var start = getTime()
|
||||
var stream = LLStreamOpen(infile, fmRead)
|
||||
if stream == nil: rawMessage(errCannotOpenFile, infile)
|
||||
var p: TParser
|
||||
openParser(p, infile, stream, options)
|
||||
var module = parseUnit(p)
|
||||
closeParser(p)
|
||||
renderModule(module, outfile)
|
||||
rawMessage(hintSuccessX, [$gLinesCompiled, $(getTime() - start)])
|
||||
|
||||
var
|
||||
infile = ""
|
||||
outfile = ""
|
||||
parserOptions = newParserOptions()
|
||||
for kind, key, val in getopt():
|
||||
case kind
|
||||
of cmdArgument: infile = key
|
||||
of cmdLongOption, cmdShortOption:
|
||||
case key.toLower
|
||||
of "help", "h":
|
||||
stdout.write(Usage)
|
||||
quit(0)
|
||||
of "version", "v":
|
||||
stdout.write(Version & "\n")
|
||||
quit(0)
|
||||
of "o", "out": outfile = key
|
||||
else:
|
||||
if not parserOptions.setOption(key, val):
|
||||
stdout.write("[Error] unknown option: " & key)
|
||||
of cmdEnd: assert(false)
|
||||
if infile.len == 0:
|
||||
# no filename has been given, so we show the help:
|
||||
stdout.write(Usage)
|
||||
else:
|
||||
if outfile.len == 0:
|
||||
outfile = changeFileExt(infile, "nim")
|
||||
infile = addFileExt(infile, "h")
|
||||
main(infile, outfile, parserOptions)
|
||||
751
rod/c2nim/clex.nim
Executable file
751
rod/c2nim/clex.nim
Executable file
@@ -0,0 +1,751 @@
|
||||
#
|
||||
#
|
||||
# c2nim - C to Nimrod source converter
|
||||
# (c) Copyright 2010 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# This module implements an Ansi C scanner. This is an adaption from
|
||||
# the scanner module. Keywords are not handled here, but in the parser to make
|
||||
# it more flexible.
|
||||
|
||||
|
||||
import
|
||||
options, msgs, strutils, platform, lexbase, llstream
|
||||
|
||||
const
|
||||
MaxLineLength* = 80 # lines longer than this lead to a warning
|
||||
numChars*: TCharSet = {'0'..'9', 'a'..'z', 'A'..'Z'}
|
||||
SymChars*: TCharSet = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\x80'..'\xFF'}
|
||||
SymStartChars*: TCharSet = {'a'..'z', 'A'..'Z', '_', '\x80'..'\xFF'}
|
||||
|
||||
type
|
||||
TTokKind* = enum
|
||||
pxInvalid, pxEof,
|
||||
pxStarComment, # /* */ comment
|
||||
pxLineComment, # // comment
|
||||
pxDirective, # #define, etc.
|
||||
pxDirectiveParLe, # #define m( with parle (yes, C is that ugly!)
|
||||
pxDirConc, # ##
|
||||
pxNewLine, # newline: end of directive
|
||||
pxAmp, # &
|
||||
pxAmpAmp, # &&
|
||||
pxAmpAsgn, # &=
|
||||
pxAmpAmpAsgn, # &&=
|
||||
pxBar, # |
|
||||
pxBarBar, # ||
|
||||
pxBarAsgn, # |=
|
||||
pxBarBarAsgn, # ||=
|
||||
pxNot, # !
|
||||
pxPlusPlus, # ++
|
||||
pxMinusMinus, # --
|
||||
pxPlus, # +
|
||||
pxPlusAsgn, # +=
|
||||
pxMinus, # -
|
||||
pxMinusAsgn, # -=
|
||||
pxMod, # %
|
||||
pxModAsgn, # %=
|
||||
pxSlash, # /
|
||||
pxSlashAsgn, # /=
|
||||
pxStar, # *
|
||||
pxStarAsgn, # *=
|
||||
pxHat, # ^
|
||||
pxHatAsgn, # ^=
|
||||
pxAsgn, # =
|
||||
pxEquals, # ==
|
||||
pxDot, # .
|
||||
pxDotDotDot, # ...
|
||||
pxLe, # <=
|
||||
pxLt, # <
|
||||
pxGe, # >=
|
||||
pxGt, # >
|
||||
pxNeq, # !=
|
||||
pxConditional, # ?
|
||||
pxShl, # <<
|
||||
pxShlAsgn, # <<=
|
||||
pxShr, # >>
|
||||
pxShrAsgn, # >>=
|
||||
pxTilde, # ~
|
||||
pxTildeAsgn, # ~=
|
||||
pxArrow, # ->
|
||||
pxScope, # ::
|
||||
|
||||
pxStrLit,
|
||||
pxCharLit,
|
||||
pxSymbol, # a symbol
|
||||
pxIntLit,
|
||||
pxInt64Lit, # long constant like 0x70fffffff or out of int range
|
||||
pxFloatLit,
|
||||
pxParLe, pxParRi,
|
||||
pxBracketLe, pxBracketRi,
|
||||
pxComma, pxSemiColon, pxColon,
|
||||
pxCurlyLe, pxCurlyRi
|
||||
TTokKinds* = set[TTokKind]
|
||||
|
||||
type
|
||||
TNumericalBase* = enum base10, base2, base8, base16
|
||||
TToken* = object
|
||||
xkind*: TTokKind # the type of the token
|
||||
s*: string # parsed symbol, char or string literal
|
||||
iNumber*: BiggestInt # the parsed integer literal
|
||||
fNumber*: BiggestFloat # the parsed floating point literal
|
||||
base*: TNumericalBase # the numerical base; only valid for int
|
||||
# or float literals
|
||||
next*: ref TToken # for C we need arbitrary look-ahead :-(
|
||||
|
||||
TLexer* = object of TBaseLexer
|
||||
filename*: string
|
||||
inDirective: bool
|
||||
|
||||
|
||||
proc getTok*(L: var TLexer, tok: var TToken)
|
||||
proc PrintTok*(tok: TToken)
|
||||
proc `$`*(tok: TToken): string
|
||||
# implementation
|
||||
|
||||
var
|
||||
gLinesCompiled*: int
|
||||
|
||||
proc fillToken(L: var TToken) =
|
||||
L.xkind = pxInvalid
|
||||
L.iNumber = 0
|
||||
L.s = ""
|
||||
L.fNumber = 0.0
|
||||
L.base = base10
|
||||
|
||||
proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream) =
|
||||
openBaseLexer(lex, inputstream)
|
||||
lex.filename = filename
|
||||
|
||||
proc closeLexer*(lex: var TLexer) =
|
||||
inc(gLinesCompiled, lex.LineNumber)
|
||||
closeBaseLexer(lex)
|
||||
|
||||
proc getColumn*(L: TLexer): int =
|
||||
result = getColNumber(L, L.bufPos)
|
||||
|
||||
proc getLineInfo*(L: TLexer): TLineInfo =
|
||||
result = newLineInfo(L.filename, L.linenumber, getColNumber(L, L.bufpos))
|
||||
|
||||
proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "") =
|
||||
msgs.liMessage(getLineInfo(L), msg, arg)
|
||||
|
||||
proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
|
||||
var info = newLineInfo(L.filename, L.linenumber, pos - L.lineStart)
|
||||
msgs.liMessage(info, msg, arg)
|
||||
|
||||
proc TokKindToStr*(k: TTokKind): string =
|
||||
case k
|
||||
of pxEof: result = "[EOF]"
|
||||
of pxInvalid: result = "[invalid]"
|
||||
of pxStarComment, pxLineComment: result = "[comment]"
|
||||
of pxStrLit: result = "[string literal]"
|
||||
of pxCharLit: result = "[char literal]"
|
||||
|
||||
of pxDirective, pxDirectiveParLe: result = "#" # #define, etc.
|
||||
of pxDirConc: result = "##"
|
||||
of pxNewLine: result = "[NewLine]"
|
||||
of pxAmp: result = "&" # &
|
||||
of pxAmpAmp: result = "&&" # &&
|
||||
of pxAmpAsgn: result = "&=" # &=
|
||||
of pxAmpAmpAsgn: result = "&&=" # &&=
|
||||
of pxBar: result = "|" # |
|
||||
of pxBarBar: result = "||" # ||
|
||||
of pxBarAsgn: result = "|=" # |=
|
||||
of pxBarBarAsgn: result = "||=" # ||=
|
||||
of pxNot: result = "!" # !
|
||||
of pxPlusPlus: result = "++" # ++
|
||||
of pxMinusMinus: result = "--" # --
|
||||
of pxPlus: result = "+" # +
|
||||
of pxPlusAsgn: result = "+=" # +=
|
||||
of pxMinus: result = "-" # -
|
||||
of pxMinusAsgn: result = "-=" # -=
|
||||
of pxMod: result = "%" # %
|
||||
of pxModAsgn: result = "%=" # %=
|
||||
of pxSlash: result = "/" # /
|
||||
of pxSlashAsgn: result = "/=" # /=
|
||||
of pxStar: result = "*" # *
|
||||
of pxStarAsgn: result = "*=" # *=
|
||||
of pxHat: result = "^" # ^
|
||||
of pxHatAsgn: result = "^=" # ^=
|
||||
of pxAsgn: result = "=" # =
|
||||
of pxEquals: result = "==" # ==
|
||||
of pxDot: result = "." # .
|
||||
of pxDotDotDot: result = "..." # ...
|
||||
of pxLe: result = "<=" # <=
|
||||
of pxLt: result = "<" # <
|
||||
of pxGe: result = ">=" # >=
|
||||
of pxGt: result = ">" # >
|
||||
of pxNeq: result = "!=" # !=
|
||||
of pxConditional: result = "?"
|
||||
of pxShl: result = "<<"
|
||||
of pxShlAsgn: result = "<<="
|
||||
of pxShr: result = ">>"
|
||||
of pxShrAsgn: result = ">>="
|
||||
of pxTilde: result = "~"
|
||||
of pxTildeAsgn: result = "~="
|
||||
of pxArrow: result = "->"
|
||||
of pxScope: result = "::"
|
||||
|
||||
of pxSymbol: result = "[identifier]"
|
||||
of pxIntLit, pxInt64Lit: result = "[integer literal]"
|
||||
of pxFloatLit: result = "[floating point literal]"
|
||||
of pxParLe: result = "("
|
||||
of pxParRi: result = ")"
|
||||
of pxBracketLe: result = "["
|
||||
of pxBracketRi: result = "]"
|
||||
of pxComma: result = ","
|
||||
of pxSemiColon: result = ";"
|
||||
of pxColon: result = ":"
|
||||
of pxCurlyLe: result = "{"
|
||||
of pxCurlyRi: result = "}"
|
||||
|
||||
proc `$`(tok: TToken): string =
|
||||
case tok.xkind
|
||||
of pxSymbol, pxInvalid, pxStarComment, pxLineComment, pxStrLit: result = tok.s
|
||||
of pxIntLit, pxInt64Lit: result = $tok.iNumber
|
||||
of pxFloatLit: result = $tok.fNumber
|
||||
else: result = TokKindToStr(tok.xkind)
|
||||
|
||||
proc PrintTok(tok: TToken) =
|
||||
writeln(stdout, $tok)
|
||||
|
||||
proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
|
||||
# matches ([chars]_)*
|
||||
var pos = L.bufpos # use registers for pos, buf
|
||||
var buf = L.buf
|
||||
while true:
|
||||
if buf[pos] in chars:
|
||||
add(tok.s, buf[pos])
|
||||
Inc(pos)
|
||||
else:
|
||||
break
|
||||
if buf[pos] == '_':
|
||||
add(tok.s, '_')
|
||||
Inc(pos)
|
||||
L.bufPos = pos
|
||||
|
||||
proc isFloatLiteral(s: string): bool =
|
||||
for i in countup(0, len(s)-1):
|
||||
if s[i] in {'.', 'e', 'E'}:
|
||||
return true
|
||||
|
||||
proc getNumber2(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos + 2 # skip 0b
|
||||
tok.base = base2
|
||||
var xi: biggestInt = 0
|
||||
var bits = 0
|
||||
while true:
|
||||
case L.buf[pos]
|
||||
of 'A'..'Z', 'a'..'z':
|
||||
# ignore type suffix:
|
||||
inc(pos)
|
||||
of '2'..'9', '.':
|
||||
lexMessage(L, errInvalidNumber)
|
||||
inc(pos)
|
||||
of '_':
|
||||
inc(pos)
|
||||
of '0', '1':
|
||||
xi = `shl`(xi, 1) or (ord(L.buf[pos]) - ord('0'))
|
||||
inc(pos)
|
||||
inc(bits)
|
||||
else: break
|
||||
tok.iNumber = xi
|
||||
if (bits > 32): tok.xkind = pxInt64Lit
|
||||
else: tok.xkind = pxIntLit
|
||||
L.bufpos = pos
|
||||
|
||||
proc getNumber8(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos + 2 # skip 0b
|
||||
tok.base = base8
|
||||
var xi: biggestInt = 0
|
||||
var bits = 0
|
||||
while true:
|
||||
case L.buf[pos]
|
||||
of 'A'..'Z', 'a'..'z':
|
||||
# ignore type suffix:
|
||||
inc(pos)
|
||||
of '8'..'9', '.':
|
||||
lexMessage(L, errInvalidNumber)
|
||||
inc(pos)
|
||||
of '_':
|
||||
inc(pos)
|
||||
of '0'..'7':
|
||||
xi = `shl`(xi, 3) or (ord(L.buf[pos]) - ord('0'))
|
||||
inc(pos)
|
||||
inc(bits)
|
||||
else: break
|
||||
tok.iNumber = xi
|
||||
if (bits > 12): tok.xkind = pxInt64Lit
|
||||
else: tok.xkind = pxIntLit
|
||||
L.bufpos = pos
|
||||
|
||||
proc getNumber16(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos + 2 # skip 0x
|
||||
tok.base = base16
|
||||
var xi: biggestInt = 0
|
||||
var bits = 0
|
||||
while true:
|
||||
case L.buf[pos]
|
||||
of 'G'..'Z', 'g'..'z':
|
||||
# ignore type suffix:
|
||||
inc(pos)
|
||||
of '_': inc(pos)
|
||||
of '0'..'9':
|
||||
xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('0'))
|
||||
inc(pos)
|
||||
inc(bits, 4)
|
||||
of 'a'..'f':
|
||||
xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('a') + 10)
|
||||
inc(pos)
|
||||
inc(bits, 4)
|
||||
of 'A'..'F':
|
||||
xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('A') + 10)
|
||||
inc(pos)
|
||||
inc(bits, 4)
|
||||
else: break
|
||||
tok.iNumber = xi
|
||||
if bits > 32: tok.xkind = pxInt64Lit
|
||||
else: tok.xkind = pxIntLit
|
||||
L.bufpos = pos
|
||||
|
||||
proc getNumber(L: var TLexer, tok: var TToken) =
|
||||
tok.base = base10
|
||||
matchUnderscoreChars(L, tok, {'0'..'9'})
|
||||
if (L.buf[L.bufpos] == '.') and (L.buf[L.bufpos + 1] in {'0'..'9'}):
|
||||
add(tok.s, '.')
|
||||
inc(L.bufpos)
|
||||
matchUnderscoreChars(L, tok, {'e', 'E', '+', '-', '0'..'9'})
|
||||
try:
|
||||
if isFloatLiteral(tok.s):
|
||||
tok.fnumber = parseFloat(tok.s)
|
||||
tok.xkind = pxFloatLit
|
||||
else:
|
||||
tok.iNumber = ParseInt(tok.s)
|
||||
if (tok.iNumber < low(int32)) or (tok.iNumber > high(int32)):
|
||||
tok.xkind = pxInt64Lit
|
||||
else:
|
||||
tok.xkind = pxIntLit
|
||||
except EInvalidValue:
|
||||
lexMessage(L, errInvalidNumber, tok.s)
|
||||
except EOverflow:
|
||||
lexMessage(L, errNumberOutOfRange, tok.s)
|
||||
# ignore type suffix:
|
||||
while L.buf[L.bufpos] in {'A'..'Z', 'a'..'z'}: inc(L.bufpos)
|
||||
|
||||
proc HandleCRLF(L: var TLexer, pos: int): int =
|
||||
case L.buf[pos]
|
||||
of CR: result = lexbase.HandleCR(L, pos)
|
||||
of LF: result = lexbase.HandleLF(L, pos)
|
||||
else: result = pos
|
||||
|
||||
proc escape(L: var TLexer, tok: var TToken, allowEmpty=false) =
|
||||
inc(L.bufpos) # skip \
|
||||
case L.buf[L.bufpos]
|
||||
of 'b', 'B':
|
||||
add(tok.s, '\b')
|
||||
inc(L.bufpos)
|
||||
of 't', 'T':
|
||||
add(tok.s, '\t')
|
||||
inc(L.bufpos)
|
||||
of 'n', 'N':
|
||||
add(tok.s, '\L')
|
||||
inc(L.bufpos)
|
||||
of 'f', 'F':
|
||||
add(tok.s, '\f')
|
||||
inc(L.bufpos)
|
||||
of 'r', 'R':
|
||||
add(tok.s, '\r')
|
||||
inc(L.bufpos)
|
||||
of '\'':
|
||||
add(tok.s, '\'')
|
||||
inc(L.bufpos)
|
||||
of '"':
|
||||
add(tok.s, '"')
|
||||
inc(L.bufpos)
|
||||
of '\\':
|
||||
add(tok.s, '\b')
|
||||
inc(L.bufpos)
|
||||
of '0'..'7':
|
||||
var xi = ord(L.buf[L.bufpos]) - ord('0')
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] in {'0'..'7'}:
|
||||
xi = (xi shl 3) or (ord(L.buf[L.bufpos]) - ord('0'))
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] in {'0'..'7'}:
|
||||
xi = (xi shl 3) or (ord(L.buf[L.bufpos]) - ord('0'))
|
||||
inc(L.bufpos)
|
||||
add(tok.s, chr(xi))
|
||||
elif not allowEmpty:
|
||||
lexMessage(L, errInvalidCharacterConstant)
|
||||
|
||||
proc getCharLit(L: var TLexer, tok: var TToken) =
|
||||
inc(L.bufpos) # skip '
|
||||
if L.buf[L.bufpos] == '\\':
|
||||
escape(L, tok)
|
||||
else:
|
||||
add(tok.s, L.buf[L.bufpos])
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '\'':
|
||||
inc(L.bufpos)
|
||||
else:
|
||||
lexMessage(L, errMissingFinalQuote)
|
||||
tok.xkind = pxCharLit
|
||||
|
||||
proc getString(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufPos + 1 # skip "
|
||||
var buf = L.buf # put `buf` in a register
|
||||
var line = L.linenumber # save linenumber for better error message
|
||||
while true:
|
||||
case buf[pos]
|
||||
of '\"':
|
||||
Inc(pos)
|
||||
break
|
||||
of CR:
|
||||
pos = lexbase.HandleCR(L, pos)
|
||||
buf = L.buf
|
||||
of LF:
|
||||
pos = lexbase.HandleLF(L, pos)
|
||||
buf = L.buf
|
||||
of lexbase.EndOfFile:
|
||||
var line2 = L.linenumber
|
||||
L.LineNumber = line
|
||||
lexMessagePos(L, errClosingQuoteExpected, L.lineStart)
|
||||
L.LineNumber = line2
|
||||
break
|
||||
of '\\':
|
||||
# we allow an empty \ for line concatenation, but we don't require it
|
||||
# for line concatenation
|
||||
L.bufpos = pos
|
||||
escape(L, tok, allowEmpty=true)
|
||||
pos = L.bufpos
|
||||
else:
|
||||
add(tok.s, buf[pos])
|
||||
Inc(pos)
|
||||
L.bufpos = pos
|
||||
tok.xkind = pxStrLit
|
||||
|
||||
proc getSymbol(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
while true:
|
||||
var c = buf[pos]
|
||||
if c notin SymChars: break
|
||||
add(tok.s, c)
|
||||
Inc(pos)
|
||||
L.bufpos = pos
|
||||
tok.xkind = pxSymbol
|
||||
|
||||
proc scanLineComment(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
# a comment ends if the next line does not start with the // on the same
|
||||
# column after only whitespace
|
||||
tok.xkind = pxLineComment
|
||||
var col = getColNumber(L, pos)
|
||||
while true:
|
||||
inc(pos, 2) # skip //
|
||||
add(tok.s, '#')
|
||||
while not (buf[pos] in {CR, LF, lexbase.EndOfFile}):
|
||||
add(tok.s, buf[pos])
|
||||
inc(pos)
|
||||
pos = handleCRLF(L, pos)
|
||||
buf = L.buf
|
||||
var indent = 0
|
||||
while buf[pos] == ' ':
|
||||
inc(pos)
|
||||
inc(indent)
|
||||
if (col == indent) and (buf[pos] == '/') and (buf[pos + 1] == '/'):
|
||||
add(tok.s, "\n")
|
||||
else:
|
||||
break
|
||||
L.bufpos = pos
|
||||
|
||||
proc scanStarComment(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
tok.s = "#"
|
||||
tok.xkind = pxStarComment
|
||||
while true:
|
||||
case buf[pos]
|
||||
of CR, LF:
|
||||
pos = HandleCRLF(L, pos)
|
||||
buf = L.buf
|
||||
add(tok.s, "\n#")
|
||||
# skip annoying stars as line prefix: (eg.
|
||||
# /*
|
||||
# * ugly comment <-- this star
|
||||
# */
|
||||
while buf[pos] in {' ', '\t'}:
|
||||
add(tok.s, ' ')
|
||||
inc(pos)
|
||||
if buf[pos] == '*' and buf[pos+1] != '/': inc(pos)
|
||||
of '*':
|
||||
inc(pos)
|
||||
if buf[pos] == '/':
|
||||
inc(pos)
|
||||
break
|
||||
else:
|
||||
add(tok.s, '*')
|
||||
of lexbase.EndOfFile:
|
||||
lexMessage(L, errTokenExpected, "*/")
|
||||
else:
|
||||
add(tok.s, buf[pos])
|
||||
inc(pos)
|
||||
L.bufpos = pos
|
||||
|
||||
proc skip(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
while true:
|
||||
case buf[pos]
|
||||
of '\\':
|
||||
# Ignore \ line continuation characters when not inDirective
|
||||
inc(pos)
|
||||
if L.inDirective:
|
||||
while buf[pos] in {' ', '\t'}: inc(pos)
|
||||
if buf[pos] in {CR, LF}:
|
||||
pos = HandleCRLF(L, pos)
|
||||
buf = L.buf
|
||||
of ' ', Tabulator:
|
||||
Inc(pos) # newline is special:
|
||||
of CR, LF:
|
||||
pos = HandleCRLF(L, pos)
|
||||
buf = L.buf
|
||||
if L.inDirective:
|
||||
tok.xkind = pxNewLine
|
||||
L.inDirective = false
|
||||
else:
|
||||
break # EndOfFile also leaves the loop
|
||||
L.bufpos = pos
|
||||
|
||||
proc getDirective(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos + 1
|
||||
var buf = L.buf
|
||||
while buf[pos] in {' ', '\t'}: inc(pos)
|
||||
while buf[pos] in SymChars:
|
||||
add(tok.s, buf[pos])
|
||||
inc(pos)
|
||||
# a HACK: we need to distinguish
|
||||
# #define x (...)
|
||||
# from:
|
||||
# #define x(...)
|
||||
#
|
||||
L.bufpos = pos
|
||||
# look ahead:
|
||||
while buf[pos] in {' ', '\t'}: inc(pos)
|
||||
while buf[pos] in SymChars: inc(pos)
|
||||
if buf[pos] == '(': tok.xkind = pxDirectiveParLe
|
||||
else: tok.xkind = pxDirective
|
||||
L.inDirective = true
|
||||
|
||||
proc getTok(L: var TLexer, tok: var TToken) =
|
||||
tok.xkind = pxInvalid
|
||||
fillToken(tok)
|
||||
skip(L, tok)
|
||||
if tok.xkind == pxNewLine: return
|
||||
var c = L.buf[L.bufpos]
|
||||
if c in SymStartChars:
|
||||
getSymbol(L, tok)
|
||||
elif c == '0':
|
||||
case L.buf[L.bufpos+1]
|
||||
of 'x', 'X': getNumber16(L, tok)
|
||||
of 'b', 'B': getNumber2(L, tok)
|
||||
of '1'..'7': getNumber8(L, tok)
|
||||
else: getNumber(L, tok)
|
||||
elif c in {'1'..'9'}:
|
||||
getNumber(L, tok)
|
||||
else:
|
||||
case c
|
||||
of ';':
|
||||
tok.xkind = pxSemicolon
|
||||
Inc(L.bufpos)
|
||||
of '/':
|
||||
if L.buf[L.bufpos + 1] == '/':
|
||||
scanLineComment(L, tok)
|
||||
elif L.buf[L.bufpos+1] == '*':
|
||||
inc(L.bufpos, 2)
|
||||
scanStarComment(L, tok)
|
||||
elif L.buf[L.bufpos+1] == '=':
|
||||
inc(L.bufpos, 2)
|
||||
tok.xkind = pxSlashAsgn
|
||||
else:
|
||||
tok.xkind = pxSlash
|
||||
inc(L.bufpos)
|
||||
of ',':
|
||||
tok.xkind = pxComma
|
||||
Inc(L.bufpos)
|
||||
of '(':
|
||||
Inc(L.bufpos)
|
||||
tok.xkind = pxParLe
|
||||
of '*':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxStarAsgn
|
||||
else:
|
||||
tok.xkind = pxStar
|
||||
of ')':
|
||||
Inc(L.bufpos)
|
||||
tok.xkind = pxParRi
|
||||
of '[':
|
||||
Inc(L.bufpos)
|
||||
tok.xkind = pxBracketLe
|
||||
of ']':
|
||||
Inc(L.bufpos)
|
||||
tok.xkind = pxBracketRi
|
||||
of '.':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '.' and L.buf[L.bufpos+1] == '.':
|
||||
tok.xkind = pxDotDotDot
|
||||
inc(L.bufpos, 2)
|
||||
else:
|
||||
tok.xkind = pxDot
|
||||
of '{':
|
||||
Inc(L.bufpos)
|
||||
tok.xkind = pxCurlyLe
|
||||
of '}':
|
||||
Inc(L.bufpos)
|
||||
tok.xkind = pxCurlyRi
|
||||
of '+':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
tok.xkind = pxPlusAsgn
|
||||
inc(L.bufpos)
|
||||
elif L.buf[L.bufpos] == '+':
|
||||
tok.xkind = pxPlusPlus
|
||||
inc(L.bufpos)
|
||||
else:
|
||||
tok.xkind = pxPlus
|
||||
of '-':
|
||||
inc(L.bufpos)
|
||||
case L.buf[L.bufpos]
|
||||
of '>':
|
||||
tok.xkind = pxArrow
|
||||
inc(L.bufpos)
|
||||
of '=':
|
||||
tok.xkind = pxMinusAsgn
|
||||
inc(L.bufpos)
|
||||
of '-':
|
||||
tok.xkind = pxMinusMinus
|
||||
inc(L.bufpos)
|
||||
else:
|
||||
tok.xkind = pxMinus
|
||||
of '?':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxConditional
|
||||
of ':':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == ':':
|
||||
tok.xkind = pxScope
|
||||
inc(L.bufpos)
|
||||
else:
|
||||
tok.xkind = pxColon
|
||||
of '!':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
tok.xkind = pxNeq
|
||||
inc(L.bufpos)
|
||||
else:
|
||||
tok.xkind = pxNot
|
||||
of '<':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxLe
|
||||
elif L.buf[L.bufpos] == '<':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxShlAsgn
|
||||
else:
|
||||
tok.xkind = pxShl
|
||||
else:
|
||||
tok.xkind = pxLt
|
||||
of '>':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxGe
|
||||
elif L.buf[L.bufpos] == '>':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxShrAsgn
|
||||
else:
|
||||
tok.xkind = pxShr
|
||||
else:
|
||||
tok.xkind = pxGt
|
||||
of '=':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
tok.xkind = pxEquals
|
||||
inc(L.bufpos)
|
||||
else:
|
||||
tok.xkind = pxAsgn
|
||||
of '&':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
tok.xkind = pxAmpAsgn
|
||||
inc(L.bufpos)
|
||||
elif L.buf[L.bufpos] == '&':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxAmpAmpAsgn
|
||||
else:
|
||||
tok.xkind = pxAmpAmp
|
||||
else:
|
||||
tok.xkind = pxAmp
|
||||
of '|':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
tok.xkind = pxBarAsgn
|
||||
inc(L.bufpos)
|
||||
elif L.buf[L.bufpos] == '|':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxBarBarAsgn
|
||||
else:
|
||||
tok.xkind = pxBarBar
|
||||
else:
|
||||
tok.xkind = pxBar
|
||||
of '^':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
tok.xkind = pxHatAsgn
|
||||
inc(L.bufpos)
|
||||
else:
|
||||
tok.xkind = pxHat
|
||||
of '%':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
tok.xkind = pxModAsgn
|
||||
inc(L.bufpos)
|
||||
else:
|
||||
tok.xkind = pxMod
|
||||
of '~':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
tok.xkind = pxTildeAsgn
|
||||
inc(L.bufpos)
|
||||
else:
|
||||
tok.xkind = pxTilde
|
||||
of '#':
|
||||
if L.buf[L.bufpos+1] == '#':
|
||||
inc(L.bufpos, 2)
|
||||
tok.xkind = pxDirConc
|
||||
else:
|
||||
getDirective(L, tok)
|
||||
of '"': getString(L, tok)
|
||||
of '\'': getCharLit(L, tok)
|
||||
of lexbase.EndOfFile:
|
||||
tok.xkind = pxEof
|
||||
else:
|
||||
tok.s = $c
|
||||
tok.xkind = pxInvalid
|
||||
lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
|
||||
Inc(L.bufpos)
|
||||
1469
rod/c2nim/cparse.nim
Executable file
1469
rod/c2nim/cparse.nim
Executable file
File diff suppressed because it is too large
Load Diff
231
rod/c2nim/cpp.nim
Executable file
231
rod/c2nim/cpp.nim
Executable file
@@ -0,0 +1,231 @@
|
||||
# Preprocessor support
|
||||
|
||||
const
|
||||
c2nimSymbol = "C2NIM"
|
||||
|
||||
proc eatNewLine(p: var TParser, n: PNode) =
|
||||
if p.tok.xkind == pxLineComment:
|
||||
skipCom(p, n)
|
||||
if p.tok.xkind == pxNewLine: getTok(p)
|
||||
else:
|
||||
eat(p, pxNewLine)
|
||||
|
||||
proc parseDefineBody(p: var TParser, tmplDef: PNode): string =
|
||||
if p.tok.xkind == pxCurlyLe or
|
||||
(p.tok.xkind == pxSymbol and (declKeyword(p.tok.s) or stmtKeyword(p.tok.s))):
|
||||
addSon(tmplDef, statement(p))
|
||||
result = "stmt"
|
||||
elif p.tok.xkind in {pxLineComment, pxNewLine}:
|
||||
addSon(tmplDef, buildStmtList(newNodeP(nkNilLit, p)))
|
||||
result = "stmt"
|
||||
else:
|
||||
addSon(tmplDef, buildStmtList(expression(p)))
|
||||
result = "expr"
|
||||
|
||||
proc parseDefine(p: var TParser): PNode =
|
||||
if p.tok.xkind == pxDirectiveParLe:
|
||||
# a macro with parameters:
|
||||
result = newNodeP(nkTemplateDef, p)
|
||||
getTok(p)
|
||||
addSon(result, skipIdent(p))
|
||||
eat(p, pxParLe)
|
||||
var params = newNodeP(nkFormalParams, p)
|
||||
# return type; not known yet:
|
||||
addSon(params, nil)
|
||||
var identDefs = newNodeP(nkIdentDefs, p)
|
||||
while p.tok.xkind != pxParRi:
|
||||
addSon(identDefs, skipIdent(p))
|
||||
skipStarCom(p, nil)
|
||||
if p.tok.xkind != pxComma: break
|
||||
getTok(p)
|
||||
addSon(identDefs, newIdentNodeP("expr", p))
|
||||
addSon(identDefs, nil)
|
||||
addSon(params, identDefs)
|
||||
eat(p, pxParRi)
|
||||
|
||||
addSon(result, nil) # no generic parameters
|
||||
addSon(result, params)
|
||||
addSon(result, nil) # no pragmas
|
||||
var kind = parseDefineBody(p, result)
|
||||
params.sons[0] = newIdentNodeP(kind, p)
|
||||
eatNewLine(p, result)
|
||||
else:
|
||||
# a macro without parameters:
|
||||
result = newNodeP(nkConstSection, p)
|
||||
while p.tok.xkind == pxDirective and p.tok.s == "define":
|
||||
getTok(p) # skip #define
|
||||
var c = newNodeP(nkConstDef, p)
|
||||
addSon(c, skipIdent(p))
|
||||
addSon(c, nil)
|
||||
skipStarCom(p, c)
|
||||
if p.tok.xkind in {pxLineComment, pxNewLine, pxEof}:
|
||||
addSon(c, newIdentNodeP("true", p))
|
||||
else:
|
||||
addSon(c, expression(p))
|
||||
addSon(result, c)
|
||||
eatNewLine(p, c)
|
||||
|
||||
proc isDir(p: TParser, dir: string): bool =
|
||||
result = p.tok.xkind in {pxDirectiveParLe, pxDirective} and p.tok.s == dir
|
||||
|
||||
proc parseInclude(p: var TParser): PNode =
|
||||
result = newNodeP(nkImportStmt, p)
|
||||
while isDir(p, "include"):
|
||||
getTok(p) # skip "include"
|
||||
if p.tok.xkind == pxStrLit:
|
||||
var file = newStrNodeP(nkStrLit, p.tok.s, p)
|
||||
addSon(result, file)
|
||||
getTok(p)
|
||||
skipStarCom(p, file)
|
||||
elif p.tok.xkind == pxLt:
|
||||
while p.tok.xkind notin {pxEof, pxNewLine, pxLineComment}: getTok(p)
|
||||
else:
|
||||
parMessage(p, errXExpected, "string literal")
|
||||
eatNewLine(p, nil)
|
||||
if sonsLen(result) == 0:
|
||||
# we only parsed includes that we chose to ignore:
|
||||
result = nil
|
||||
|
||||
proc definedExprAux(p: var TParser): PNode =
|
||||
result = newNodeP(nkCall, p)
|
||||
addSon(result, newIdentNodeP("defined", p))
|
||||
addSon(result, skipIdent(p))
|
||||
|
||||
proc parseStmtList(p: var TParser): PNode =
|
||||
result = newNodeP(nkStmtList, p)
|
||||
while true:
|
||||
case p.tok.xkind
|
||||
of pxEof: break
|
||||
of pxDirectiveParLe, pxDirective:
|
||||
case p.tok.s
|
||||
of "else", "endif", "elif": break
|
||||
else: nil
|
||||
addSon(result, statement(p))
|
||||
|
||||
proc parseIfDirAux(p: var TParser, result: PNode) =
|
||||
addSon(result.sons[0], parseStmtList(p))
|
||||
while isDir(p, "elif"):
|
||||
var b = newNodeP(nkElifBranch, p)
|
||||
getTok(p)
|
||||
addSon(b, expression(p))
|
||||
eatNewLine(p, nil)
|
||||
addSon(b, parseStmtList(p))
|
||||
addSon(result, b)
|
||||
if isDir(p, "else"):
|
||||
var s = newNodeP(nkElse, p)
|
||||
while p.tok.xkind notin {pxEof, pxNewLine, pxLineComment}: getTok(p)
|
||||
eatNewLine(p, nil)
|
||||
addSon(s, parseStmtList(p))
|
||||
addSon(result, s)
|
||||
if isDir(p, "endif"):
|
||||
while p.tok.xkind notin {pxEof, pxNewLine, pxLineComment}: getTok(p)
|
||||
eatNewLine(p, nil)
|
||||
else:
|
||||
parMessage(p, errXExpected, "#endif")
|
||||
|
||||
proc specialIf(p: TParser): bool =
|
||||
ExpectIdent(p)
|
||||
result = p.tok.s == c2nimSymbol
|
||||
|
||||
proc chooseBranch(whenStmt: PNode, branch: int): PNode =
|
||||
var L = sonsLen(whenStmt)
|
||||
if branch < L:
|
||||
if L == 2 and whenStmt[1].kind == nkElse or branch == 0:
|
||||
result = lastSon(whenStmt[branch])
|
||||
else:
|
||||
var b = whenStmt[branch]
|
||||
assert(b.kind == nkElifBranch)
|
||||
result = newNodeI(nkWhenStmt, whenStmt.info)
|
||||
for i in branch .. L-1:
|
||||
addSon(result, whenStmt[i])
|
||||
|
||||
proc skipIfdefCPlusPlus(p: var TParser): PNode =
|
||||
while p.tok.xkind != pxEof:
|
||||
if isDir(p, "endif"):
|
||||
while p.tok.xkind notin {pxEof, pxNewLine, pxLineComment}: getTok(p)
|
||||
eatNewLine(p, nil)
|
||||
return
|
||||
getTok(p)
|
||||
parMessage(p, errXExpected, "#endif")
|
||||
|
||||
proc parseIfdefDir(p: var TParser): PNode =
|
||||
result = newNodeP(nkWhenStmt, p)
|
||||
addSon(result, newNodeP(nkElifBranch, p))
|
||||
getTok(p)
|
||||
var special = specialIf(p)
|
||||
if p.tok.s == "__cplusplus":
|
||||
return skipIfdefCPlusPlus(p)
|
||||
addSon(result.sons[0], definedExprAux(p))
|
||||
eatNewLine(p, nil)
|
||||
parseIfDirAux(p, result)
|
||||
if special:
|
||||
result = chooseBranch(result, 0)
|
||||
|
||||
proc parseIfndefDir(p: var TParser): PNode =
|
||||
result = newNodeP(nkWhenStmt, p)
|
||||
addSon(result, newNodeP(nkElifBranch, p))
|
||||
getTok(p)
|
||||
var special = specialIf(p)
|
||||
var e = newNodeP(nkCall, p)
|
||||
addSon(e, newIdentNodeP("not", p))
|
||||
addSon(e, definedExprAux(p))
|
||||
eatNewLine(p, nil)
|
||||
addSon(result.sons[0], e)
|
||||
parseIfDirAux(p, result)
|
||||
if special:
|
||||
result = chooseBranch(result, 1)
|
||||
|
||||
proc parseIfDir(p: var TParser): PNode =
|
||||
result = newNodeP(nkWhenStmt, p)
|
||||
addSon(result, newNodeP(nkElifBranch, p))
|
||||
getTok(p)
|
||||
addSon(result.sons[0], expression(p))
|
||||
eatNewLine(p, nil)
|
||||
parseIfDirAux(p, result)
|
||||
|
||||
proc parseMangleDir(p: var TParser) =
|
||||
var col = getColumn(p.lex) + 2
|
||||
getTok(p)
|
||||
if p.tok.xkind != pxStrLit: ExpectIdent(p)
|
||||
try:
|
||||
var pattern = parsePeg(
|
||||
input = p.tok.s,
|
||||
filename = p.lex.filename,
|
||||
line = p.lex.linenumber,
|
||||
col = col)
|
||||
getTok(p)
|
||||
if p.tok.xkind != pxStrLit: ExpectIdent(p)
|
||||
p.options.mangleRules.add((pattern, p.tok.s))
|
||||
getTok(p)
|
||||
except EInvalidPeg:
|
||||
parMessage(p, errUser, getCurrentExceptionMsg())
|
||||
eatNewLine(p, nil)
|
||||
|
||||
proc parseDir(p: var TParser): PNode =
|
||||
assert(p.tok.xkind in {pxDirective, pxDirectiveParLe})
|
||||
case p.tok.s
|
||||
of "define": result = parseDefine(p)
|
||||
of "include": result = parseInclude(p)
|
||||
of "ifdef": result = parseIfdefDir(p)
|
||||
of "ifndef": result = parseIfndefDir(p)
|
||||
of "if": result = parseIfDir(p)
|
||||
of "cdecl", "stdcall", "ref":
|
||||
discard setOption(p.options, p.tok.s)
|
||||
getTok(p)
|
||||
eatNewLine(p, nil)
|
||||
of "dynlib", "header", "prefix", "suffix", "skip":
|
||||
var key = p.tok.s
|
||||
getTok(p)
|
||||
if p.tok.xkind != pxStrLit: ExpectIdent(p)
|
||||
discard setOption(p.options, key, p.tok.s)
|
||||
getTok(p)
|
||||
eatNewLine(p, nil)
|
||||
of "mangle":
|
||||
parseMangleDir(p)
|
||||
else:
|
||||
# ignore unimportant/unknown directive ("undef", "pragma", "error")
|
||||
while true:
|
||||
getTok(p)
|
||||
if p.tok.xkind in {pxEof, pxNewLine, pxLineComment}: break
|
||||
eatNewLine(p, nil)
|
||||
|
||||
235
rod/c2nim/manual.txt
Normal file
235
rod/c2nim/manual.txt
Normal file
@@ -0,0 +1,235 @@
|
||||
=================================
|
||||
c2nim User's manual
|
||||
=================================
|
||||
|
||||
:Author: Andreas Rumpf
|
||||
:Version: 0.8.10
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
c2nim is a tool to translate Ansi C code to Nimrod. The output is
|
||||
human-readable Nimrod code that is meant to be tweaked by hand after the
|
||||
translation process. c2nim is no real compiler!
|
||||
|
||||
c2nim is preliminary meant to translate C header files. Because of this, the
|
||||
preprocessor is part of the parser. For example:
|
||||
|
||||
.. code-block:: C
|
||||
#define abc 123
|
||||
#define xyz 789
|
||||
|
||||
Is translated into:
|
||||
|
||||
.. code-block:: Nimrod
|
||||
const
|
||||
abc* = 123
|
||||
xyz* = 789
|
||||
|
||||
|
||||
c2nim is meant to translate fragments of C code and thus does not follow
|
||||
include files. c2nim cannot parse all of Ansi C and many constructs cannot
|
||||
be represented in Nimrod: for example `duff's device`:idx: cannot be translated
|
||||
to Nimrod.
|
||||
|
||||
|
||||
Preprocessor support
|
||||
====================
|
||||
|
||||
Even though the translation process is not perfect, it is often the case that
|
||||
the translated Nimrod code does not need any tweaking by hand. In other cases
|
||||
it may be preferable to modify the input file instead of the generated Nimrod
|
||||
code so that c2nim can parse it properly. c2nim's preprocessor defines the
|
||||
symbol ``C2NIM`` that can be used to mark code sections:
|
||||
|
||||
.. code-block:: C
|
||||
#ifndef C2NIM
|
||||
// C2NIM should ignore this prototype:
|
||||
int fprintf(FILE* f, const char* frmt, ...);
|
||||
#endif
|
||||
|
||||
The ``C2NIM`` symbol is only recognized in ``#ifdef`` and ``#ifndef``
|
||||
constructs! ``#if defined(C2NIM)`` does **not** work.
|
||||
|
||||
c2nim *processes* ``#ifdef C2NIM`` and ``#ifndef C2NIM`` directives, but other
|
||||
``#if[def]`` directives are *translated* into Nimrod's ``when`` construct:
|
||||
|
||||
.. code-block:: C
|
||||
#ifdef DEBUG
|
||||
# define OUT(x) printf("%s\n", x)
|
||||
#else
|
||||
# define OUT(x)
|
||||
#endif
|
||||
|
||||
Is translated into:
|
||||
|
||||
.. code-block:: Nimrod
|
||||
when defined(debug):
|
||||
template OUT(x: expr): expr =
|
||||
printf("%s\x0A", x)
|
||||
else:
|
||||
template OUT(x: expr): stmt =
|
||||
nil
|
||||
|
||||
As can been seen from the example, C's macros with parameters are mapped
|
||||
to Nimrod's templates. This mapping is the best one can do, but it is of course
|
||||
not accurate: Nimrod's templates operate on syntax trees whereas C's
|
||||
macros work on the token level. c2nim cannot translate any macro that contains
|
||||
the ``##`` token concatenation operator.
|
||||
|
||||
c2nim's preprocessor supports special directives that affect how the output
|
||||
is generated. They should be put into a ``#ifdef C2NIM`` section so that
|
||||
ordinary C compilers ignore them.
|
||||
|
||||
|
||||
``#stdcall`` and ``#cdecl`` directives
|
||||
--------------------------------------
|
||||
**Note**: There are also ``--stdcall`` and ``--cdecl`` command line options
|
||||
that can be used for the same purpose.
|
||||
|
||||
These directives tell c2nim that it should annotate every proc (or proc type)
|
||||
with the ``stdcall`` / ``cdecl`` calling convention.
|
||||
|
||||
|
||||
``#dynlib`` directive
|
||||
---------------------
|
||||
**Note**: There is also a ``--dynlib`` command line option that can be used for
|
||||
the same purpose.
|
||||
|
||||
This directive tells c2nim that it should annotate every proc that resulted
|
||||
from a C function prototype with the ``dynlib`` pragma:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
#ifdef C2NIM
|
||||
# dynlib iupdll
|
||||
# cdecl
|
||||
# if defined(windows)
|
||||
# define iupdll "iup.dll"
|
||||
# elif defined(macosx)
|
||||
# define iupdll "libiup.dynlib"
|
||||
# else
|
||||
# define iupdll "libiup.so"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
int IupConvertXYToPos(PIhandle ih, int x, int y);
|
||||
|
||||
Is translated to:
|
||||
|
||||
.. code-block:: Nimrod
|
||||
when defined(windows):
|
||||
const iupdll* = "iup.dll"
|
||||
elif defined(macosx):
|
||||
const iupdll* = "libiup.dynlib"
|
||||
else:
|
||||
const iupdll* = "libiup.so"
|
||||
|
||||
proc IupConvertXYToPos*(ih: PIhandle, x: cint, y: cint): cint {.
|
||||
importc: "IupConvertXYToPos", cdecl, dynlib: iupdll.}
|
||||
|
||||
Note how the example contains extra C code to declare the ``iupdll`` symbol
|
||||
in the generated Nimrod code.
|
||||
|
||||
|
||||
``#header`` directive
|
||||
---------------------
|
||||
**Note**: There is also a ``--header`` command line option that can be used for
|
||||
the same purpose.
|
||||
|
||||
The ``#header`` directive tells c2nim that it should annotate every proc that
|
||||
resulted from a C function prototype and every exported variable and type with
|
||||
the ``header`` pragma:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
#ifdef C2NIM
|
||||
# header "iup.h"
|
||||
#endif
|
||||
|
||||
int IupConvertXYToPos(PIhandle ih, int x, int y);
|
||||
|
||||
Is translated to:
|
||||
|
||||
.. code-block:: Nimrod
|
||||
proc IupConvertXYToPos*(ih: PIhandle, x: cint, y: cint): cint {.
|
||||
importc: "IupConvertXYToPos", header: "iup.h".}
|
||||
|
||||
The ``#header`` and the ``#dynlib`` directives are mutually exclusive.
|
||||
A binding that uses ``dynlib`` is much more preferable over one that uses
|
||||
``header``! The Nimrod compiler might drop support for the ``header`` pragma
|
||||
in the future as it cannot work for backends that do not generate C code.
|
||||
|
||||
|
||||
``#prefix`` and ``#suffix`` directives
|
||||
--------------------------------------
|
||||
|
||||
**Note**: There are also ``--prefix`` and ``--suffix`` command line options
|
||||
that can be used for the same purpose.
|
||||
|
||||
c2nim does not do any name mangling by default. However the
|
||||
``#prefix`` and ``#suffix`` directives can be used to strip prefixes and
|
||||
suffixes from the identifiers in the C code:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
#ifdef C2NIM
|
||||
# prefix Iup
|
||||
# dynlib dllname
|
||||
# cdecl
|
||||
#endif
|
||||
|
||||
int IupConvertXYToPos(PIhandle ih, int x, int y);
|
||||
|
||||
Is translated to:
|
||||
|
||||
.. code-block:: Nimrod
|
||||
|
||||
proc ConvertXYToPos*(ih: PIhandle, x: cint, y: cint): cint {.
|
||||
importc: "IupConvertXYToPos", cdecl, dynlib: dllname.}
|
||||
|
||||
|
||||
``#mangle`` directive
|
||||
---------------------
|
||||
|
||||
Even more sophisticated name mangling can be achieved by the ``#mangle``
|
||||
directive: It takes a PEG pattern and format string that specify how the
|
||||
identifier should be converted:
|
||||
|
||||
.. code-block:: C
|
||||
#mangle "'GTK_'{.*}" "TGtk$1"
|
||||
|
||||
|
||||
``#skip`` directive
|
||||
-------------------
|
||||
**Note**: There is also ``--skip`` command line option that can be used for the
|
||||
same purpose.
|
||||
|
||||
Often C code contains special macros that affect the declaration of a function
|
||||
prototype but confuse c2nim's parser:
|
||||
|
||||
.. code-block:: C
|
||||
// does not parse!
|
||||
EXPORT int f(void);
|
||||
EXPORT int g(void);
|
||||
|
||||
Instead of to remove ``EXPORT`` from the input source file, one can tell c2nim
|
||||
to skip special identifiers:
|
||||
|
||||
.. code-block:: C
|
||||
#skip EXPORT
|
||||
// does parse now!
|
||||
EXPORT int f(void);
|
||||
EXPORT int g(void);
|
||||
|
||||
|
||||
Limitations
|
||||
===========
|
||||
|
||||
* C's ``,`` operator (comma operator) is not supported.
|
||||
* C's ``union`` has no equivalent in Nimrod.
|
||||
* Standalone ``struct x {}`` declarations are not implemented. Put them into
|
||||
a ``typedef``.
|
||||
* The condition in a ``do while(condition)`` statement must be ``0``.
|
||||
* Lots of other small issues...
|
||||
|
||||
@@ -581,16 +581,13 @@ proc genTryStmt(p: BProc, t: PNode) =
|
||||
# sp.status = RangeError; /* if raise; else 0 */
|
||||
# }
|
||||
# }
|
||||
# excHandler = excHandler->prev; /* deactivate this safe point */
|
||||
# /* finally: */
|
||||
# printf('fin!\n');
|
||||
# if (sp.status != 0)
|
||||
# longjmp(excHandler->context, sp.status);
|
||||
# excHandler = excHandler->prev; /* deactivate this safe point */
|
||||
var
|
||||
i, length, blen: int
|
||||
safePoint, orExpr: PRope
|
||||
genLineDir(p, t)
|
||||
safePoint = getTempName()
|
||||
var safePoint = getTempName()
|
||||
useMagic(p.module, "TSafePoint")
|
||||
useMagic(p.module, "E_Base")
|
||||
useMagic(p.module, "excHandler")
|
||||
@@ -600,13 +597,13 @@ proc genTryStmt(p: BProc, t: PNode) =
|
||||
if optStackTrace in p.Options:
|
||||
app(p.s[cpsStmts], "framePtr = (TFrame*)&F;" & tnl)
|
||||
appf(p.s[cpsStmts], "if ($1.status == 0) {$n", [safePoint])
|
||||
length = sonsLen(t)
|
||||
var length = sonsLen(t)
|
||||
inc(p.nestedTryStmts)
|
||||
genStmts(p, t.sons[0])
|
||||
app(p.s[cpsStmts], "} else {" & tnl)
|
||||
i = 1
|
||||
var i = 1
|
||||
while (i < length) and (t.sons[i].kind == nkExceptBranch):
|
||||
blen = sonsLen(t.sons[i])
|
||||
var blen = sonsLen(t.sons[i])
|
||||
if blen == 1:
|
||||
# general except section:
|
||||
if i > 1: app(p.s[cpsStmts], "else {" & tnl)
|
||||
@@ -614,7 +611,7 @@ proc genTryStmt(p: BProc, t: PNode) =
|
||||
appf(p.s[cpsStmts], "$1.status = 0;$n", [safePoint])
|
||||
if i > 1: app(p.s[cpsStmts], '}' & tnl)
|
||||
else:
|
||||
orExpr = nil
|
||||
var orExpr: PRope = nil
|
||||
for j in countup(0, blen - 2):
|
||||
assert(t.sons[i].sons[j].kind == nkType)
|
||||
if orExpr != nil: app(orExpr, "||")
|
||||
|
||||
@@ -50,7 +50,7 @@ const
|
||||
compilerExe: "gcc",
|
||||
compileTmpl: "-c $options $include -o $objfile $file",
|
||||
buildGui: " -mwindows",
|
||||
buildDll: " -mdll",
|
||||
buildDll: " -shared",
|
||||
linkerExe: "gcc",
|
||||
linkTmpl: "$options $buildgui $builddll -o $exefile $objfiles",
|
||||
includeCmd: " -I",
|
||||
@@ -65,7 +65,7 @@ const
|
||||
compilerExe: "llvm-gcc",
|
||||
compileTmpl: "-c $options $include -o $objfile $file",
|
||||
buildGui: " -mwindows",
|
||||
buildDll: " -mdll",
|
||||
buildDll: " -shared",
|
||||
linkerExe: "llvm-gcc",
|
||||
linkTmpl: "$options $buildgui $builddll -o $exefile $objfiles",
|
||||
includeCmd: " -I",
|
||||
@@ -225,7 +225,7 @@ const
|
||||
|
||||
var ccompiler*: TSystemCC = ccGcc
|
||||
|
||||
const # the used compiler
|
||||
const # the used compiler
|
||||
hExt* = "h"
|
||||
|
||||
var cExt*: string = "c" # extension of generated C/C++ files
|
||||
@@ -490,7 +490,6 @@ proc CallCCompiler(projectfile: string) =
|
||||
generateScript(projectFile, script)
|
||||
|
||||
proc genMappingFiles(list: TLinkedList): PRope =
|
||||
result = nil
|
||||
var it = PStrEntry(list.head)
|
||||
while it != nil:
|
||||
appf(result, "--file:r\"$1\"$n", [toRope(AddFileExt(it.data, cExt))])
|
||||
|
||||
@@ -408,7 +408,7 @@ proc toColumn(info: TLineInfo): int =
|
||||
proc MessageOut(s: string) =
|
||||
# change only this proc to put it elsewhere
|
||||
Writeln(stdout, s)
|
||||
|
||||
|
||||
proc coordToStr(coord: int): string =
|
||||
if coord == - 1: result = "???"
|
||||
else: result = $(coord)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2009 Andreas Rumpf
|
||||
# (c) Copyright 2010 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
@@ -37,7 +37,7 @@ const
|
||||
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
||||
wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, wPure, wDeprecated}
|
||||
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
|
||||
wPure, wHeader, wCompilerProc, wFinal}
|
||||
wPure, wHeader, wCompilerProc, wFinal, wSize}
|
||||
fieldPragmas* = {wImportc, wExportc, wDeprecated}
|
||||
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
|
||||
wMagic, wHeader, wDeprecated, wCompilerProc, wDynLib}
|
||||
@@ -344,6 +344,13 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
|
||||
sym.typ.align = expectIntLit(c, it)
|
||||
if not IsPowerOfTwo(sym.typ.align) and (sym.typ.align != 0):
|
||||
liMessage(it.info, errPowerOfTwoExpected)
|
||||
of wSize:
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
var size = expectIntLit(c, it)
|
||||
if not IsPowerOfTwo(size) or size <= 0 or size > 8:
|
||||
liMessage(it.info, errPowerOfTwoExpected)
|
||||
else:
|
||||
sym.typ.size = size
|
||||
of wNodecl:
|
||||
noVal(it)
|
||||
incl(sym.loc.Flags, lfNoDecl)
|
||||
|
||||
@@ -615,13 +615,19 @@ proc gproc(g: var TSrcGen, n: PNode) =
|
||||
proc gblock(g: var TSrcGen, n: PNode) =
|
||||
var c: TContext
|
||||
initContext(c)
|
||||
putWithSpace(g, tkBlock, "block")
|
||||
gsub(g, n.sons[0])
|
||||
if n.sons[0] != nil:
|
||||
putWithSpace(g, tkBlock, "block")
|
||||
gsub(g, n.sons[0])
|
||||
else:
|
||||
put(g, tkBlock, "block")
|
||||
putWithSpace(g, tkColon, ":")
|
||||
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > maxLineLen):
|
||||
incl(c.flags, rfLongMode)
|
||||
gcoms(g)
|
||||
# XXX I don't get why this is needed here! gstmts should already handle this!
|
||||
indentNL(g)
|
||||
gstmts(g, n.sons[1], c)
|
||||
dedent(g)
|
||||
|
||||
proc gasm(g: var TSrcGen, n: PNode) =
|
||||
putWithSpace(g, tkAsm, "asm")
|
||||
|
||||
@@ -427,7 +427,7 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) =
|
||||
case L.buf[L.bufpos]
|
||||
of 'n', 'N':
|
||||
if tok.toktype == tkCharLit: lexMessage(L, errNnotAllowedInCharacter)
|
||||
tok.literal = tok.literal & tnl
|
||||
add(tok.literal, tnl)
|
||||
Inc(L.bufpos)
|
||||
of 'r', 'R', 'c', 'C':
|
||||
add(tok.literal, CR)
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2009 Andreas Rumpf
|
||||
# (c) Copyright 2010 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# This implements the first pass over the generic body; it resolves some
|
||||
# symbols. Thus for generics there is a two-phase symbol lookup just like
|
||||
# in C++.
|
||||
@@ -155,8 +156,8 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode
|
||||
if (a.kind != nkIdentDefs): IllFormedAst(a)
|
||||
checkMinSonsLen(a, 3)
|
||||
L = sonsLen(a)
|
||||
a.sons[L - 2] = semGenericStmt(c, a.sons[L - 2], {withinTypeDesc}) # do not perform symbol lookup for default
|
||||
# expressions
|
||||
a.sons[L - 2] = semGenericStmt(c, a.sons[L - 2], {withinTypeDesc})
|
||||
# do not perform symbol lookup for default expressions
|
||||
for j in countup(0, L - 3):
|
||||
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
|
||||
of nkConstSection:
|
||||
@@ -196,8 +197,7 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode
|
||||
of nkEnumFieldDef: a = n.sons[i].sons[0]
|
||||
of nkIdent: a = n.sons[i]
|
||||
else: illFormedAst(n)
|
||||
addDeclAt(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c), c.tab.tos -
|
||||
1)
|
||||
addDeclAt(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c), c.tab.tos-1)
|
||||
of nkObjectTy, nkTupleTy:
|
||||
nil
|
||||
of nkFormalParams:
|
||||
@@ -229,4 +229,4 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode
|
||||
else:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
result.sons[i] = semGenericStmt(c, n.sons[i], flags)
|
||||
|
||||
|
||||
|
||||
@@ -92,18 +92,15 @@ proc getNotFoundError(c: PContext, n: PNode): string =
|
||||
# Gives a detailed error message; this is seperated from semDirectCall,
|
||||
# as semDirectCall is already pretty slow (and we need this information only
|
||||
# in case of an error).
|
||||
var
|
||||
sym: PSym
|
||||
o: TOverloadIter
|
||||
candidates: string
|
||||
result = msgKindToString(errTypeMismatch)
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
#debug(n.sons[i].typ);
|
||||
add(result, typeToString(n.sons[i].typ))
|
||||
if i != sonsLen(n) - 1: add(result, ", ")
|
||||
add(result, ')')
|
||||
candidates = ""
|
||||
sym = initOverloadIter(o, c, n.sons[0])
|
||||
var candidates = ""
|
||||
var o: TOverloadIter
|
||||
var sym = initOverloadIter(o, c, n.sons[0])
|
||||
while sym != nil:
|
||||
if sym.kind in {skProc, skMethod, skIterator, skConverter}:
|
||||
add(candidates, getProcHeader(sym))
|
||||
|
||||
@@ -37,6 +37,7 @@ proc parseAll*(p: var TParsers): PNode
|
||||
proc parseTopLevelStmt*(p: var TParsers): PNode
|
||||
# implements an iterator. Returns the next top-level statement or nil if end
|
||||
# of stream.
|
||||
|
||||
# implementation
|
||||
|
||||
proc ParseFile(filename: string): PNode =
|
||||
@@ -57,7 +58,8 @@ proc parseAll(p: var TParsers): PNode =
|
||||
of skinBraces:
|
||||
result = pbraces.parseAll(p.parser)
|
||||
of skinEndX:
|
||||
InternalError("parser to implement") # skinEndX: result := pendx.parseAll(p.parser);
|
||||
InternalError("parser to implement")
|
||||
# skinEndX: result := pendx.parseAll(p.parser);
|
||||
|
||||
proc parseTopLevelStmt(p: var TParsers): PNode =
|
||||
case p.skin
|
||||
@@ -66,39 +68,33 @@ proc parseTopLevelStmt(p: var TParsers): PNode =
|
||||
of skinBraces:
|
||||
result = pbraces.parseTopLevelStmt(p.parser)
|
||||
of skinEndX:
|
||||
InternalError("parser to implement") #skinEndX: result := pendx.parseTopLevelStmt(p.parser);
|
||||
InternalError("parser to implement")
|
||||
#skinEndX: result := pendx.parseTopLevelStmt(p.parser);
|
||||
|
||||
proc UTF8_BOM(s: string): int =
|
||||
if (s[0] == '\xEF') and (s[0 + 1] == '\xBB') and (s[0 + 2] == '\xBF'):
|
||||
if (s[0] == '\xEF') and (s[1] == '\xBB') and (s[2] == '\xBF'):
|
||||
result = 3
|
||||
else:
|
||||
result = 0
|
||||
|
||||
proc containsShebang(s: string, i: int): bool =
|
||||
var j: int
|
||||
result = false
|
||||
if (s[i] == '#') and (s[i + 1] == '!'):
|
||||
j = i + 2
|
||||
var j = i + 2
|
||||
while s[j] in WhiteSpace: inc(j)
|
||||
result = s[j] == '/'
|
||||
|
||||
proc parsePipe(filename: string, inputStream: PLLStream): PNode =
|
||||
var
|
||||
line: string
|
||||
s: PLLStream
|
||||
i: int
|
||||
q: TParser
|
||||
result = nil
|
||||
s = LLStreamOpen(filename, fmRead)
|
||||
var s = LLStreamOpen(filename, fmRead)
|
||||
if s != nil:
|
||||
line = LLStreamReadLine(s)
|
||||
i = UTF8_Bom(line) + 0
|
||||
var line = LLStreamReadLine(s)
|
||||
var i = UTF8_Bom(line)
|
||||
if containsShebang(line, i):
|
||||
line = LLStreamReadLine(s)
|
||||
i = 0
|
||||
if (line[i] == '#') and (line[i + 1] == '!'):
|
||||
inc(i, 2)
|
||||
while line[i] in WhiteSpace: inc(i)
|
||||
var q: TParser
|
||||
OpenParser(q, filename, LLStreamOpen(copy(line, i)))
|
||||
result = pnimsyn.parseAll(q)
|
||||
CloseParser(q)
|
||||
@@ -124,12 +120,10 @@ proc getCallee(n: PNode): PIdent =
|
||||
else:
|
||||
rawMessage(errXNotAllowedHere, renderTree(n))
|
||||
|
||||
proc applyFilter(p: var TParsers, n: PNode, filename: string, stdin: PLLStream): PLLStream =
|
||||
var
|
||||
ident: PIdent
|
||||
f: TFilterKind
|
||||
ident = getCallee(n)
|
||||
f = getFilter(ident)
|
||||
proc applyFilter(p: var TParsers, n: PNode, filename: string,
|
||||
stdin: PLLStream): PLLStream =
|
||||
var ident = getCallee(n)
|
||||
var f = getFilter(ident)
|
||||
case f
|
||||
of filtNone:
|
||||
p.skin = getParser(ident)
|
||||
@@ -146,7 +140,8 @@ proc applyFilter(p: var TParsers, n: PNode, filename: string, stdin: PLLStream):
|
||||
messageOut(result.s)
|
||||
rawMessage(hintCodeEnd, [])
|
||||
|
||||
proc evalPipe(p: var TParsers, n: PNode, filename: string, start: PLLStream): PLLStream =
|
||||
proc evalPipe(p: var TParsers, n: PNode, filename: string,
|
||||
start: PLLStream): PLLStream =
|
||||
result = start
|
||||
if n == nil: return
|
||||
if (n.kind == nkInfix) and (n.sons[0].kind == nkIdent) and
|
||||
@@ -162,16 +157,14 @@ proc evalPipe(p: var TParsers, n: PNode, filename: string, start: PLLStream): PL
|
||||
result = applyFilter(p, n, filename, result)
|
||||
|
||||
proc openParsers(p: var TParsers, filename: string, inputstream: PLLStream) =
|
||||
var
|
||||
pipe: PNode
|
||||
s: PLLStream
|
||||
var s: PLLStream
|
||||
p.skin = skinStandard
|
||||
pipe = parsePipe(filename, inputStream)
|
||||
var pipe = parsePipe(filename, inputStream)
|
||||
if pipe != nil: s = evalPipe(p, pipe, filename, inputStream)
|
||||
else: s = inputStream
|
||||
case p.skin
|
||||
of skinStandard, skinBraces, skinEndX: pnimsyn.openParser(p.parser, filename,
|
||||
s)
|
||||
of skinStandard, skinBraces, skinEndX:
|
||||
pnimsyn.openParser(p.parser, filename, s)
|
||||
|
||||
proc closeParsers(p: var TParsers) =
|
||||
pnimsyn.closeParser(p.parser)
|
||||
|
||||
@@ -502,7 +502,7 @@ proc base(t: PType): PType =
|
||||
|
||||
proc firstOrd(t: PType): biggestInt =
|
||||
case t.kind
|
||||
of tyBool, tyChar, tySequence, tyOpenArray:
|
||||
of tyBool, tyChar, tySequence, tyOpenArray, tyString:
|
||||
result = 0
|
||||
of tySet, tyVar:
|
||||
result = firstOrd(t.sons[0])
|
||||
|
||||
16
tests/accept/compile/tenum3.nim
Normal file
16
tests/accept/compile/tenum3.nim
Normal file
@@ -0,0 +1,16 @@
|
||||
# Test enum with explicit size
|
||||
|
||||
type
|
||||
TEnumHole {.size: sizeof(int).} = enum
|
||||
eA = 0,
|
||||
eB = 4,
|
||||
eC = 5
|
||||
|
||||
var
|
||||
e: TEnumHole = eB
|
||||
|
||||
case e
|
||||
of eA: echo "A"
|
||||
of eB: echo "B"
|
||||
of eC: echo "C"
|
||||
|
||||
@@ -3,6 +3,7 @@ tambsym2.nim;7
|
||||
tambsys.nim;
|
||||
tarray.nim;10012
|
||||
tarray2.nim;[16, 25, 36]
|
||||
tarray3.nim;3
|
||||
tassert.nim;assertion failure!this shall be always written
|
||||
tbind1.nim;3
|
||||
tbind3.nim;1
|
||||
|
||||
|
7
tests/accept/run/tarray3.nim
Normal file
7
tests/accept/run/tarray3.nim
Normal file
@@ -0,0 +1,7 @@
|
||||
# simple check for two dimensional arrays
|
||||
|
||||
const
|
||||
myData = [[1,2,3], [4, 5, 6]]
|
||||
|
||||
echo myData[0][2] #OUT 3
|
||||
|
||||
155
todo.txt
Executable file
155
todo.txt
Executable file
@@ -0,0 +1,155 @@
|
||||
For version 0.8.10
|
||||
==================
|
||||
|
||||
- fix exception handling
|
||||
- fix implicit generic routines
|
||||
- fix the streams implementation so that they use methods
|
||||
|
||||
|
||||
TO IMPLEMENT
|
||||
============
|
||||
|
||||
* fix overloading resolution
|
||||
* wrong co-/contravariance
|
||||
* startsWith `=^`
|
||||
* endsWith `=$`
|
||||
* ignore case `=?` --> `=$?`
|
||||
|
||||
Bugs
|
||||
----
|
||||
- proc (x: int) is passable to proc (x: var int) !?
|
||||
- detected by pegs module 64bit: p(result, result) should use a temporary!
|
||||
- seq[TLoc] in C code generator always failed --> probably some reference
|
||||
counting is wrong; try to reproduce this in the GC test
|
||||
- the parser allows empty object case branches
|
||||
- SDL event handling
|
||||
- accurate file/line information
|
||||
|
||||
|
||||
To implement
|
||||
------------
|
||||
|
||||
* icon installation for the Windows installer
|
||||
* sort routine
|
||||
* hash tables and sets
|
||||
* the two other parsers
|
||||
* distinct types for array/seq indexes
|
||||
* constant sequences
|
||||
* IMPLEMENT GENERIC TYPES!
|
||||
- implement expr parameters
|
||||
- document generic types better
|
||||
|
||||
* implement closures for the C code generator
|
||||
|
||||
|
||||
|
||||
Low priority
|
||||
------------
|
||||
- resizing of strings/sequences could take into account the memory that
|
||||
is allocated
|
||||
- implicit conversions from ``ptr/ref T`` to ``var T`` (from
|
||||
``ptr/ref T`` to ``T``)?
|
||||
- documentation: type converters
|
||||
- typeAllowed() for parameters...
|
||||
- find a way to reintroduce the cleanup() pass for C code generation: this
|
||||
is hard because of partial evaluation --> symbol files will fix this as
|
||||
a side effect
|
||||
- implement better error handling: errornous top level statements are ignored
|
||||
and not part of the symbal table --> for REPL
|
||||
--> this needs deletion operation for symbol table!
|
||||
- floating point checks for EcmaScript
|
||||
- enhance `` notation for identifier concatenation: `concat` a `these`
|
||||
- prefer proc in current module over other procs with same overloading result?
|
||||
- real types for template results
|
||||
- generalized case statement (requires better transf)
|
||||
- normalize for the DOM
|
||||
- script layer!
|
||||
- tlastmod returns wrong results on BSD (Linux, MacOS X: works)
|
||||
- nested tuple unpacking
|
||||
|
||||
|
||||
Library
|
||||
-------
|
||||
|
||||
- float formatting
|
||||
- locale support
|
||||
- conversion between character sets
|
||||
- bignums
|
||||
- ftp, smtp (and other internet protocols)
|
||||
|
||||
- finish json module: use coroutines for this!
|
||||
|
||||
- pdcurses bindings
|
||||
- automate module: expect-like module for Nimrod
|
||||
|
||||
- for system:
|
||||
proc `@` [T](a: openArray[T]): seq[T] =
|
||||
newSeq(result, a.len)
|
||||
for i in 0..a.len-1: result[i] = a[i]
|
||||
|
||||
--> ensure @[] calls the array version!
|
||||
|
||||
|
||||
For the next versions
|
||||
=====================
|
||||
|
||||
- support for generation of dynamic libraries
|
||||
|
||||
|
||||
Further ideas/nice to have
|
||||
==========================
|
||||
|
||||
- queues additional to streams: have two positions (read/write) instead of one
|
||||
|
||||
|
||||
Version 2
|
||||
---------
|
||||
|
||||
- language change: inheritance should only work with reference types, so that
|
||||
the ``type`` field is not needed for objects! --> zero overhead aggregation
|
||||
BETTER: ``is`` and safe object conversions only work with ref objects. Same
|
||||
for multi methods.
|
||||
|
||||
- explicit nil types?
|
||||
* nil seq[int]
|
||||
* nil string
|
||||
* nil ref int
|
||||
* nil ptr THallo
|
||||
* nil proc
|
||||
|
||||
.. code-block:: nimrod
|
||||
var
|
||||
x: string = nil # initialized with invalid value!
|
||||
if not isNil(x):
|
||||
# now x
|
||||
|
||||
- better for backwards compatibility: default nilable, but ``not nil``
|
||||
notation::
|
||||
|
||||
type
|
||||
PWindow = ref TWindow not nil
|
||||
|
||||
|
||||
Low priority
|
||||
------------
|
||||
|
||||
- ``when T is int`` for generic code
|
||||
- ``when validCode( proc () )`` for generic code
|
||||
|
||||
|
||||
when compiles:
|
||||
|
||||
elif compiles:
|
||||
|
||||
|
||||
- macros: ``typecheck`` pragma; this allows transformations based on types!
|
||||
- find a way for easy constructors and destructors; (destructors are much more
|
||||
important than constructors)
|
||||
- code generated for type information is wasteful
|
||||
|
||||
|
||||
RST
|
||||
---
|
||||
- footnotes; prefix :i: whitespace before :i:, _reference, `reference`__
|
||||
__ anonymous: www.nimrod.org
|
||||
|
||||
@@ -55,7 +55,7 @@ case $ucpu in
|
||||
mycpu="amd64" ;;
|
||||
*sparc*|*sun* )
|
||||
mycpu="sparc" ;;
|
||||
*power* )
|
||||
*power*|*Power* )
|
||||
mycpu="powerpc" ;;
|
||||
*mips* )
|
||||
mycpu="mips" ;;
|
||||
|
||||
@@ -16,6 +16,8 @@ Bugfixes
|
||||
- Bugfix: ``dialogs.ChooseFileToSave`` uses ``STOCK_SAVE`` instead of
|
||||
``STOCK_OPEN`` for the GTK backend.
|
||||
- Bugfix: ``raise`` within an exception handler did not work.
|
||||
- Bugfix: ``low(somestring)`` crashed the compiler.
|
||||
- Bugfix: ``strutils.endsWith`` lacked range checking.
|
||||
|
||||
|
||||
Changes affecting backwards compatibility
|
||||
@@ -37,6 +39,8 @@ Additions
|
||||
- Added ``times.epochTime`` and ``times.cpuTime``.
|
||||
- Implemented explicit type arguments for generics.
|
||||
- Implemented implicit type arguments for generics.
|
||||
- Implemented ``{.size: sizeof(cint).}`` pragma for enum types. This is useful
|
||||
for interfacing with C.
|
||||
|
||||
|
||||
2010-03-14 Version 0.8.8 released
|
||||
|
||||
@@ -58,9 +58,29 @@ to write as low-level Nimrod code as C requires you to do. That said the only
|
||||
overhead Nimrod has over C is the GC which has been tuned for years.
|
||||
|
||||
|
||||
What about JVM/CLR backends?
|
||||
----------------------------
|
||||
|
||||
A JVM backend is almost impossible. The JVM is not expressive enough. It has
|
||||
never been designed as a general purpose VM anyway. A CLR backend is possible
|
||||
but would require much work.
|
||||
|
||||
|
||||
Compilation
|
||||
===========
|
||||
|
||||
Which option to use for the fastest executable?
|
||||
-----------------------------------------------
|
||||
|
||||
For the standard configuration file, ``-d:release`` does the trick.
|
||||
|
||||
|
||||
Which option to use for the smallest executable?
|
||||
------------------------------------------------
|
||||
|
||||
For the standard configuration file, ``-d:quick --opt:size`` does the trick.
|
||||
|
||||
|
||||
Execution of GCC fails (Windows)
|
||||
--------------------------------
|
||||
|
||||
|
||||
Reference in New Issue
Block a user