c2nim tool added
This commit is contained in:
parent
c441cdb64c
commit
d10973adb0
28 changed files with 3498 additions and 66 deletions
|
|
@ -155,7 +155,7 @@ underscores ``__`` are not allowed::
|
||||||
|
|
||||||
letter ::= 'A'..'Z' | 'a'..'z' | '\x80'..'\xff'
|
letter ::= 'A'..'Z' | 'a'..'z' | '\x80'..'\xff'
|
||||||
digit ::= '0'..'9'
|
digit ::= '0'..'9'
|
||||||
IDENTIFIER ::= letter ( ['_'] letter | digit )*
|
IDENTIFIER ::= letter ( ['_'] (letter | digit) )*
|
||||||
|
|
||||||
The following `keywords`:idx: are reserved and cannot be used as identifiers:
|
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 ----------- */
|
/* ---------------- casting without correct aliasing rules ----------- */
|
||||||
|
|
||||||
#if defined(__GNUCC__)
|
#if defined(__GNUC__)
|
||||||
# define NIM_CAST(type, ptr) (((union{type __x__;}*)(ptr))->__x__)
|
# define NIM_CAST(type, ptr) (((union{type __x__;}*)(ptr))->__x__)
|
||||||
#else
|
#else
|
||||||
# define NIM_CAST(type, ptr) ((type)(ptr))
|
# define NIM_CAST(type, ptr) ((type)(ptr))
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@ when defined(macosx) or defined(bsd):
|
||||||
|
|
||||||
proc countProcessors*(): int =
|
proc countProcessors*(): int =
|
||||||
## returns the numer of the processors/cores the machine has.
|
## 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):
|
when defined(windows):
|
||||||
var x = getenv("NUMBER_OF_PROCESSORS")
|
var x = getenv("NUMBER_OF_PROCESSORS")
|
||||||
if x.len > 0: result = parseInt(x)
|
if x.len > 0: result = parseInt(x)
|
||||||
|
|
|
||||||
|
|
@ -391,10 +391,13 @@ proc endsWith(s, suffix: string): bool =
|
||||||
var
|
var
|
||||||
i = 0
|
i = 0
|
||||||
j = len(s) - len(suffix)
|
j = len(s) - len(suffix)
|
||||||
while true:
|
while i+j <% s.len:
|
||||||
if suffix[i] == '\0': return true
|
|
||||||
if s[i+j] != suffix[i]: return false
|
if s[i+j] != suffix[i]: return false
|
||||||
inc(i)
|
inc(i)
|
||||||
|
if suffix[i] == '\0': return true
|
||||||
|
|
||||||
|
# 012345
|
||||||
|
# 345
|
||||||
|
|
||||||
when false:
|
when false:
|
||||||
proc abbrev(s: string, possibilities: openarray[string]): int =
|
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 */
|
# sp.status = RangeError; /* if raise; else 0 */
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
|
# excHandler = excHandler->prev; /* deactivate this safe point */
|
||||||
# /* finally: */
|
# /* finally: */
|
||||||
# printf('fin!\n');
|
# printf('fin!\n');
|
||||||
# if (sp.status != 0)
|
# if (sp.status != 0)
|
||||||
# longjmp(excHandler->context, sp.status);
|
# longjmp(excHandler->context, sp.status);
|
||||||
# excHandler = excHandler->prev; /* deactivate this safe point */
|
|
||||||
var
|
|
||||||
i, length, blen: int
|
|
||||||
safePoint, orExpr: PRope
|
|
||||||
genLineDir(p, t)
|
genLineDir(p, t)
|
||||||
safePoint = getTempName()
|
var safePoint = getTempName()
|
||||||
useMagic(p.module, "TSafePoint")
|
useMagic(p.module, "TSafePoint")
|
||||||
useMagic(p.module, "E_Base")
|
useMagic(p.module, "E_Base")
|
||||||
useMagic(p.module, "excHandler")
|
useMagic(p.module, "excHandler")
|
||||||
|
|
@ -600,13 +597,13 @@ proc genTryStmt(p: BProc, t: PNode) =
|
||||||
if optStackTrace in p.Options:
|
if optStackTrace in p.Options:
|
||||||
app(p.s[cpsStmts], "framePtr = (TFrame*)&F;" & tnl)
|
app(p.s[cpsStmts], "framePtr = (TFrame*)&F;" & tnl)
|
||||||
appf(p.s[cpsStmts], "if ($1.status == 0) {$n", [safePoint])
|
appf(p.s[cpsStmts], "if ($1.status == 0) {$n", [safePoint])
|
||||||
length = sonsLen(t)
|
var length = sonsLen(t)
|
||||||
inc(p.nestedTryStmts)
|
inc(p.nestedTryStmts)
|
||||||
genStmts(p, t.sons[0])
|
genStmts(p, t.sons[0])
|
||||||
app(p.s[cpsStmts], "} else {" & tnl)
|
app(p.s[cpsStmts], "} else {" & tnl)
|
||||||
i = 1
|
var i = 1
|
||||||
while (i < length) and (t.sons[i].kind == nkExceptBranch):
|
while (i < length) and (t.sons[i].kind == nkExceptBranch):
|
||||||
blen = sonsLen(t.sons[i])
|
var blen = sonsLen(t.sons[i])
|
||||||
if blen == 1:
|
if blen == 1:
|
||||||
# general except section:
|
# general except section:
|
||||||
if i > 1: app(p.s[cpsStmts], "else {" & tnl)
|
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])
|
appf(p.s[cpsStmts], "$1.status = 0;$n", [safePoint])
|
||||||
if i > 1: app(p.s[cpsStmts], '}' & tnl)
|
if i > 1: app(p.s[cpsStmts], '}' & tnl)
|
||||||
else:
|
else:
|
||||||
orExpr = nil
|
var orExpr: PRope = nil
|
||||||
for j in countup(0, blen - 2):
|
for j in countup(0, blen - 2):
|
||||||
assert(t.sons[i].sons[j].kind == nkType)
|
assert(t.sons[i].sons[j].kind == nkType)
|
||||||
if orExpr != nil: app(orExpr, "||")
|
if orExpr != nil: app(orExpr, "||")
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ const
|
||||||
compilerExe: "gcc",
|
compilerExe: "gcc",
|
||||||
compileTmpl: "-c $options $include -o $objfile $file",
|
compileTmpl: "-c $options $include -o $objfile $file",
|
||||||
buildGui: " -mwindows",
|
buildGui: " -mwindows",
|
||||||
buildDll: " -mdll",
|
buildDll: " -shared",
|
||||||
linkerExe: "gcc",
|
linkerExe: "gcc",
|
||||||
linkTmpl: "$options $buildgui $builddll -o $exefile $objfiles",
|
linkTmpl: "$options $buildgui $builddll -o $exefile $objfiles",
|
||||||
includeCmd: " -I",
|
includeCmd: " -I",
|
||||||
|
|
@ -65,7 +65,7 @@ const
|
||||||
compilerExe: "llvm-gcc",
|
compilerExe: "llvm-gcc",
|
||||||
compileTmpl: "-c $options $include -o $objfile $file",
|
compileTmpl: "-c $options $include -o $objfile $file",
|
||||||
buildGui: " -mwindows",
|
buildGui: " -mwindows",
|
||||||
buildDll: " -mdll",
|
buildDll: " -shared",
|
||||||
linkerExe: "llvm-gcc",
|
linkerExe: "llvm-gcc",
|
||||||
linkTmpl: "$options $buildgui $builddll -o $exefile $objfiles",
|
linkTmpl: "$options $buildgui $builddll -o $exefile $objfiles",
|
||||||
includeCmd: " -I",
|
includeCmd: " -I",
|
||||||
|
|
@ -225,7 +225,7 @@ const
|
||||||
|
|
||||||
var ccompiler*: TSystemCC = ccGcc
|
var ccompiler*: TSystemCC = ccGcc
|
||||||
|
|
||||||
const # the used compiler
|
const # the used compiler
|
||||||
hExt* = "h"
|
hExt* = "h"
|
||||||
|
|
||||||
var cExt*: string = "c" # extension of generated C/C++ files
|
var cExt*: string = "c" # extension of generated C/C++ files
|
||||||
|
|
@ -490,7 +490,6 @@ proc CallCCompiler(projectfile: string) =
|
||||||
generateScript(projectFile, script)
|
generateScript(projectFile, script)
|
||||||
|
|
||||||
proc genMappingFiles(list: TLinkedList): PRope =
|
proc genMappingFiles(list: TLinkedList): PRope =
|
||||||
result = nil
|
|
||||||
var it = PStrEntry(list.head)
|
var it = PStrEntry(list.head)
|
||||||
while it != nil:
|
while it != nil:
|
||||||
appf(result, "--file:r\"$1\"$n", [toRope(AddFileExt(it.data, cExt))])
|
appf(result, "--file:r\"$1\"$n", [toRope(AddFileExt(it.data, cExt))])
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nimrod Compiler
|
||||||
# (c) Copyright 2009 Andreas Rumpf
|
# (c) Copyright 2010 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
|
|
@ -37,7 +37,7 @@ const
|
||||||
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
||||||
wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, wPure, wDeprecated}
|
wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, wPure, wDeprecated}
|
||||||
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
|
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
|
||||||
wPure, wHeader, wCompilerProc, wFinal}
|
wPure, wHeader, wCompilerProc, wFinal, wSize}
|
||||||
fieldPragmas* = {wImportc, wExportc, wDeprecated}
|
fieldPragmas* = {wImportc, wExportc, wDeprecated}
|
||||||
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
|
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
|
||||||
wMagic, wHeader, wDeprecated, wCompilerProc, wDynLib}
|
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)
|
sym.typ.align = expectIntLit(c, it)
|
||||||
if not IsPowerOfTwo(sym.typ.align) and (sym.typ.align != 0):
|
if not IsPowerOfTwo(sym.typ.align) and (sym.typ.align != 0):
|
||||||
liMessage(it.info, errPowerOfTwoExpected)
|
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:
|
of wNodecl:
|
||||||
noVal(it)
|
noVal(it)
|
||||||
incl(sym.loc.Flags, lfNoDecl)
|
incl(sym.loc.Flags, lfNoDecl)
|
||||||
|
|
|
||||||
|
|
@ -615,13 +615,19 @@ proc gproc(g: var TSrcGen, n: PNode) =
|
||||||
proc gblock(g: var TSrcGen, n: PNode) =
|
proc gblock(g: var TSrcGen, n: PNode) =
|
||||||
var c: TContext
|
var c: TContext
|
||||||
initContext(c)
|
initContext(c)
|
||||||
putWithSpace(g, tkBlock, "block")
|
if n.sons[0] != nil:
|
||||||
gsub(g, n.sons[0])
|
putWithSpace(g, tkBlock, "block")
|
||||||
|
gsub(g, n.sons[0])
|
||||||
|
else:
|
||||||
|
put(g, tkBlock, "block")
|
||||||
putWithSpace(g, tkColon, ":")
|
putWithSpace(g, tkColon, ":")
|
||||||
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > maxLineLen):
|
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > maxLineLen):
|
||||||
incl(c.flags, rfLongMode)
|
incl(c.flags, rfLongMode)
|
||||||
gcoms(g)
|
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)
|
gstmts(g, n.sons[1], c)
|
||||||
|
dedent(g)
|
||||||
|
|
||||||
proc gasm(g: var TSrcGen, n: PNode) =
|
proc gasm(g: var TSrcGen, n: PNode) =
|
||||||
putWithSpace(g, tkAsm, "asm")
|
putWithSpace(g, tkAsm, "asm")
|
||||||
|
|
|
||||||
|
|
@ -427,7 +427,7 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) =
|
||||||
case L.buf[L.bufpos]
|
case L.buf[L.bufpos]
|
||||||
of 'n', 'N':
|
of 'n', 'N':
|
||||||
if tok.toktype == tkCharLit: lexMessage(L, errNnotAllowedInCharacter)
|
if tok.toktype == tkCharLit: lexMessage(L, errNnotAllowedInCharacter)
|
||||||
tok.literal = tok.literal & tnl
|
add(tok.literal, tnl)
|
||||||
Inc(L.bufpos)
|
Inc(L.bufpos)
|
||||||
of 'r', 'R', 'c', 'C':
|
of 'r', 'R', 'c', 'C':
|
||||||
add(tok.literal, CR)
|
add(tok.literal, CR)
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nimrod Compiler
|
||||||
# (c) Copyright 2009 Andreas Rumpf
|
# (c) Copyright 2010 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
# This implements the first pass over the generic body; it resolves some
|
# 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
|
# symbols. Thus for generics there is a two-phase symbol lookup just like
|
||||||
# in C++.
|
# in C++.
|
||||||
|
|
@ -155,8 +156,8 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode
|
||||||
if (a.kind != nkIdentDefs): IllFormedAst(a)
|
if (a.kind != nkIdentDefs): IllFormedAst(a)
|
||||||
checkMinSonsLen(a, 3)
|
checkMinSonsLen(a, 3)
|
||||||
L = sonsLen(a)
|
L = sonsLen(a)
|
||||||
a.sons[L - 2] = semGenericStmt(c, a.sons[L - 2], {withinTypeDesc}) # do not perform symbol lookup for default
|
a.sons[L - 2] = semGenericStmt(c, a.sons[L - 2], {withinTypeDesc})
|
||||||
# expressions
|
# do not perform symbol lookup for default expressions
|
||||||
for j in countup(0, L - 3):
|
for j in countup(0, L - 3):
|
||||||
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
|
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
|
||||||
of nkConstSection:
|
of nkConstSection:
|
||||||
|
|
@ -196,8 +197,7 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode
|
||||||
of nkEnumFieldDef: a = n.sons[i].sons[0]
|
of nkEnumFieldDef: a = n.sons[i].sons[0]
|
||||||
of nkIdent: a = n.sons[i]
|
of nkIdent: a = n.sons[i]
|
||||||
else: illFormedAst(n)
|
else: illFormedAst(n)
|
||||||
addDeclAt(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c), c.tab.tos -
|
addDeclAt(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c), c.tab.tos-1)
|
||||||
1)
|
|
||||||
of nkObjectTy, nkTupleTy:
|
of nkObjectTy, nkTupleTy:
|
||||||
nil
|
nil
|
||||||
of nkFormalParams:
|
of nkFormalParams:
|
||||||
|
|
|
||||||
|
|
@ -92,18 +92,15 @@ proc getNotFoundError(c: PContext, n: PNode): string =
|
||||||
# Gives a detailed error message; this is seperated from semDirectCall,
|
# Gives a detailed error message; this is seperated from semDirectCall,
|
||||||
# as semDirectCall is already pretty slow (and we need this information only
|
# as semDirectCall is already pretty slow (and we need this information only
|
||||||
# in case of an error).
|
# in case of an error).
|
||||||
var
|
|
||||||
sym: PSym
|
|
||||||
o: TOverloadIter
|
|
||||||
candidates: string
|
|
||||||
result = msgKindToString(errTypeMismatch)
|
result = msgKindToString(errTypeMismatch)
|
||||||
for i in countup(1, sonsLen(n) - 1):
|
for i in countup(1, sonsLen(n) - 1):
|
||||||
#debug(n.sons[i].typ);
|
#debug(n.sons[i].typ);
|
||||||
add(result, typeToString(n.sons[i].typ))
|
add(result, typeToString(n.sons[i].typ))
|
||||||
if i != sonsLen(n) - 1: add(result, ", ")
|
if i != sonsLen(n) - 1: add(result, ", ")
|
||||||
add(result, ')')
|
add(result, ')')
|
||||||
candidates = ""
|
var candidates = ""
|
||||||
sym = initOverloadIter(o, c, n.sons[0])
|
var o: TOverloadIter
|
||||||
|
var sym = initOverloadIter(o, c, n.sons[0])
|
||||||
while sym != nil:
|
while sym != nil:
|
||||||
if sym.kind in {skProc, skMethod, skIterator, skConverter}:
|
if sym.kind in {skProc, skMethod, skIterator, skConverter}:
|
||||||
add(candidates, getProcHeader(sym))
|
add(candidates, getProcHeader(sym))
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ proc parseAll*(p: var TParsers): PNode
|
||||||
proc parseTopLevelStmt*(p: var TParsers): PNode
|
proc parseTopLevelStmt*(p: var TParsers): PNode
|
||||||
# implements an iterator. Returns the next top-level statement or nil if end
|
# implements an iterator. Returns the next top-level statement or nil if end
|
||||||
# of stream.
|
# of stream.
|
||||||
|
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
proc ParseFile(filename: string): PNode =
|
proc ParseFile(filename: string): PNode =
|
||||||
|
|
@ -57,7 +58,8 @@ proc parseAll(p: var TParsers): PNode =
|
||||||
of skinBraces:
|
of skinBraces:
|
||||||
result = pbraces.parseAll(p.parser)
|
result = pbraces.parseAll(p.parser)
|
||||||
of skinEndX:
|
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 =
|
proc parseTopLevelStmt(p: var TParsers): PNode =
|
||||||
case p.skin
|
case p.skin
|
||||||
|
|
@ -66,39 +68,33 @@ proc parseTopLevelStmt(p: var TParsers): PNode =
|
||||||
of skinBraces:
|
of skinBraces:
|
||||||
result = pbraces.parseTopLevelStmt(p.parser)
|
result = pbraces.parseTopLevelStmt(p.parser)
|
||||||
of skinEndX:
|
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 =
|
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
|
result = 3
|
||||||
else:
|
else:
|
||||||
result = 0
|
result = 0
|
||||||
|
|
||||||
proc containsShebang(s: string, i: int): bool =
|
proc containsShebang(s: string, i: int): bool =
|
||||||
var j: int
|
|
||||||
result = false
|
|
||||||
if (s[i] == '#') and (s[i + 1] == '!'):
|
if (s[i] == '#') and (s[i + 1] == '!'):
|
||||||
j = i + 2
|
var j = i + 2
|
||||||
while s[j] in WhiteSpace: inc(j)
|
while s[j] in WhiteSpace: inc(j)
|
||||||
result = s[j] == '/'
|
result = s[j] == '/'
|
||||||
|
|
||||||
proc parsePipe(filename: string, inputStream: PLLStream): PNode =
|
proc parsePipe(filename: string, inputStream: PLLStream): PNode =
|
||||||
var
|
var s = LLStreamOpen(filename, fmRead)
|
||||||
line: string
|
|
||||||
s: PLLStream
|
|
||||||
i: int
|
|
||||||
q: TParser
|
|
||||||
result = nil
|
|
||||||
s = LLStreamOpen(filename, fmRead)
|
|
||||||
if s != nil:
|
if s != nil:
|
||||||
line = LLStreamReadLine(s)
|
var line = LLStreamReadLine(s)
|
||||||
i = UTF8_Bom(line) + 0
|
var i = UTF8_Bom(line)
|
||||||
if containsShebang(line, i):
|
if containsShebang(line, i):
|
||||||
line = LLStreamReadLine(s)
|
line = LLStreamReadLine(s)
|
||||||
i = 0
|
i = 0
|
||||||
if (line[i] == '#') and (line[i + 1] == '!'):
|
if (line[i] == '#') and (line[i + 1] == '!'):
|
||||||
inc(i, 2)
|
inc(i, 2)
|
||||||
while line[i] in WhiteSpace: inc(i)
|
while line[i] in WhiteSpace: inc(i)
|
||||||
|
var q: TParser
|
||||||
OpenParser(q, filename, LLStreamOpen(copy(line, i)))
|
OpenParser(q, filename, LLStreamOpen(copy(line, i)))
|
||||||
result = pnimsyn.parseAll(q)
|
result = pnimsyn.parseAll(q)
|
||||||
CloseParser(q)
|
CloseParser(q)
|
||||||
|
|
@ -124,12 +120,10 @@ proc getCallee(n: PNode): PIdent =
|
||||||
else:
|
else:
|
||||||
rawMessage(errXNotAllowedHere, renderTree(n))
|
rawMessage(errXNotAllowedHere, renderTree(n))
|
||||||
|
|
||||||
proc applyFilter(p: var TParsers, n: PNode, filename: string, stdin: PLLStream): PLLStream =
|
proc applyFilter(p: var TParsers, n: PNode, filename: string,
|
||||||
var
|
stdin: PLLStream): PLLStream =
|
||||||
ident: PIdent
|
var ident = getCallee(n)
|
||||||
f: TFilterKind
|
var f = getFilter(ident)
|
||||||
ident = getCallee(n)
|
|
||||||
f = getFilter(ident)
|
|
||||||
case f
|
case f
|
||||||
of filtNone:
|
of filtNone:
|
||||||
p.skin = getParser(ident)
|
p.skin = getParser(ident)
|
||||||
|
|
@ -146,7 +140,8 @@ proc applyFilter(p: var TParsers, n: PNode, filename: string, stdin: PLLStream):
|
||||||
messageOut(result.s)
|
messageOut(result.s)
|
||||||
rawMessage(hintCodeEnd, [])
|
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
|
result = start
|
||||||
if n == nil: return
|
if n == nil: return
|
||||||
if (n.kind == nkInfix) and (n.sons[0].kind == nkIdent) and
|
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)
|
result = applyFilter(p, n, filename, result)
|
||||||
|
|
||||||
proc openParsers(p: var TParsers, filename: string, inputstream: PLLStream) =
|
proc openParsers(p: var TParsers, filename: string, inputstream: PLLStream) =
|
||||||
var
|
var s: PLLStream
|
||||||
pipe: PNode
|
|
||||||
s: PLLStream
|
|
||||||
p.skin = skinStandard
|
p.skin = skinStandard
|
||||||
pipe = parsePipe(filename, inputStream)
|
var pipe = parsePipe(filename, inputStream)
|
||||||
if pipe != nil: s = evalPipe(p, pipe, filename, inputStream)
|
if pipe != nil: s = evalPipe(p, pipe, filename, inputStream)
|
||||||
else: s = inputStream
|
else: s = inputStream
|
||||||
case p.skin
|
case p.skin
|
||||||
of skinStandard, skinBraces, skinEndX: pnimsyn.openParser(p.parser, filename,
|
of skinStandard, skinBraces, skinEndX:
|
||||||
s)
|
pnimsyn.openParser(p.parser, filename, s)
|
||||||
|
|
||||||
proc closeParsers(p: var TParsers) =
|
proc closeParsers(p: var TParsers) =
|
||||||
pnimsyn.closeParser(p.parser)
|
pnimsyn.closeParser(p.parser)
|
||||||
|
|
|
||||||
|
|
@ -502,7 +502,7 @@ proc base(t: PType): PType =
|
||||||
|
|
||||||
proc firstOrd(t: PType): biggestInt =
|
proc firstOrd(t: PType): biggestInt =
|
||||||
case t.kind
|
case t.kind
|
||||||
of tyBool, tyChar, tySequence, tyOpenArray:
|
of tyBool, tyChar, tySequence, tyOpenArray, tyString:
|
||||||
result = 0
|
result = 0
|
||||||
of tySet, tyVar:
|
of tySet, tyVar:
|
||||||
result = firstOrd(t.sons[0])
|
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;
|
tambsys.nim;
|
||||||
tarray.nim;10012
|
tarray.nim;10012
|
||||||
tarray2.nim;[16, 25, 36]
|
tarray2.nim;[16, 25, 36]
|
||||||
|
tarray3.nim;3
|
||||||
tassert.nim;assertion failure!this shall be always written
|
tassert.nim;assertion failure!this shall be always written
|
||||||
tbind1.nim;3
|
tbind1.nim;3
|
||||||
tbind3.nim;1
|
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" ;;
|
mycpu="amd64" ;;
|
||||||
*sparc*|*sun* )
|
*sparc*|*sun* )
|
||||||
mycpu="sparc" ;;
|
mycpu="sparc" ;;
|
||||||
*power* )
|
*power*|*Power* )
|
||||||
mycpu="powerpc" ;;
|
mycpu="powerpc" ;;
|
||||||
*mips* )
|
*mips* )
|
||||||
mycpu="mips" ;;
|
mycpu="mips" ;;
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ Bugfixes
|
||||||
- Bugfix: ``dialogs.ChooseFileToSave`` uses ``STOCK_SAVE`` instead of
|
- Bugfix: ``dialogs.ChooseFileToSave`` uses ``STOCK_SAVE`` instead of
|
||||||
``STOCK_OPEN`` for the GTK backend.
|
``STOCK_OPEN`` for the GTK backend.
|
||||||
- Bugfix: ``raise`` within an exception handler did not work.
|
- 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
|
Changes affecting backwards compatibility
|
||||||
|
|
@ -37,6 +39,8 @@ Additions
|
||||||
- Added ``times.epochTime`` and ``times.cpuTime``.
|
- Added ``times.epochTime`` and ``times.cpuTime``.
|
||||||
- Implemented explicit type arguments for generics.
|
- Implemented explicit type arguments for generics.
|
||||||
- Implemented implicit 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
|
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.
|
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
|
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)
|
Execution of GCC fails (Windows)
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue