too many changes to list

This commit is contained in:
Andreas Rumpf 2008-08-23 11:16:44 +02:00
commit 07d5a8085b
200 changed files with 24344 additions and 17809 deletions

View file

@ -2,6 +2,10 @@
# (c) 2008 Andreas Rumpf
# Feel free to edit the templates as you need.
split.item.toc = "25"
# too long entries in the table of contents get truncated
# after this number of characters
doc.section = """
<div class="section" id="$sectionID">
<h1><a class="toc-backref" href="#$sectionTitleID">$sectionTitle</a></h1>
@ -52,10 +56,10 @@ $content
"""
doc.file = """<?xml version="1.0" encoding="utf-8" ?>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- This file is generated by Nimrod. -->
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>$title</title>
@ -88,7 +92,7 @@ span.Command, span.Rule, span.Hyperlink, span.Label, span.Reference,
span.Other {color: black}
div.navigation {
float: left; width: 20em;
float: left; width: 25em;
margin: 0; padding: 0; /*
border: 1px dashed gold; */
outline: 3px outset #99ff99; //gold;
@ -109,7 +113,7 @@ div.navigation ul li a:hover {
}
div.content {
margin-left: 20em;
margin-left: 25em;
padding: 0 1em;
border: 1px dashed gold;
min-width: 16em;
@ -285,4 +289,3 @@ $content
</html>
"""
@write "used doctempl.cfg"

View file

@ -9,7 +9,7 @@
# Environment variables cannot be used in the options, however!
# Just call the compiler with several options:
cc = @if unix: gcc @else: llvm_gcc @end
cc = @if unix: gcc @else: vcc @end
lib="$nimrod/lib"
path="$lib/base"
path="$lib/base/gtk"
@ -17,13 +17,22 @@ path="$lib/base/cairo"
path="$lib/base/x11"
path="$lib/windows"
path="$lib/posix"
path="$lib/ecmas"
path="$lib/extra"
@if release:
checks:off
stacktrace:off
debugger:off
line_dir:off
@end
# additional defines:
#define=""
# additional options always passed to the compiler:
force_build
line_dir=off
cfilecache=on
hint[LineTooLong]=off
hint[XDeclaredButNotUsed]=off
@ -40,7 +49,7 @@ hint[XDeclaredButNotUsed]=off
# Configuration for the LLVM GCC compiler:
@if windows:
llvm_gcc.path = r"dist\llvm-gcc4.2\bin"
llvm_gcc.path = r"$nimrod\dist\llvm-gcc4.2\bin"
@end
llvm_gcc.options.debug = "-g"
llvm_gcc.options.always = "-w"
@ -59,14 +68,15 @@ bcc.options.size = "-O1 -6"
# Configuration for the Visual C/C++ compiler:
@if vcc:
@prepend_env path r"C:\Eigenes\compiler\vcc2005\Common7\IDE;"
@prepend_env INCLUDE r"C:\Eigenes\compiler\vcc2005\VC\include;C:\Eigenes\compiler\vcc2005\VC\ATLMFC\INCLUDE;"
@prepend_env LIB r"C:\Eigenes\compiler\vcc2005\VC\lib;C:\Eigenes\compiler\vcc2005\SDK\v2.0\Lib;"
@prepend_env path r"C:\Programme\Microsoft Visual Studio 9.0\Common7\IDE;"
@prepend_env INCLUDE r"C:\Programme\Microsoft Visual Studio 9.0\VC\include;C:\Programme\Microsoft Visual Studio 9.0\VC\ATLMFC\INCLUDE;C:\Programme\Microsoft SDKs\Windows\v6.0A\Include;"
@prepend_env LIB r"C:\Programme\Microsoft Visual Studio 9.0\VC\lib;C:\Programme\Microsoft Visual Studio 9.0\SDK\v2.0\Lib;C:\Programme\Microsoft SDKs\Windows\v6.0A\Lib;"
passl: r"/F33554432" # set the stack size to 8 MB
@end
@if windows:
vcc.path = r"C:\Eigenes\compiler\vcc2005\VC\bin"
vcc.path = r"C:\Programme\Microsoft Visual Studio 9.0\VC\bin"
@end
vcc.options.debug = "/GZ /ZI"
vcc.options.debug = "/RTC1 /ZI"
vcc.options.always = "/nologo"
vcc.options.speed = "/Ogityb2 /G7 /arch:SSE2"
vcc.options.size = "/O1 /G7"
@ -113,10 +123,11 @@ lcc.options.size = "-O -p6"
# Configuration for the Tiny C Compiler:
@if windows:
tcc.path = r"C:\eigenes\compiler\tcc\bin"
tcc.path = r"C:\Eigenes\compiler\tcc-0.9.23\tcc"
tcc.options.always = r"-IC:\Eigenes\compiler\tcc-0.9.23\include " &
r"-IC:\Eigenes\compiler\tcc-0.9.23\include\winapi"
@end
tcc.options.debug = "-b"
tcc.options.always = ""
tcc.options.debug = ""
tcc.options.speed = ""
tcc.options.size = ""
@ -137,4 +148,9 @@ icc.options.always = "-w"
icc.options.speed = "-O3 -ffast-math"
icc.options.size = "-Os -ffast-math"
@write "used default config file"
@write "used special config file"
@if ecmascript:
@write "Target is ECMAScript! No unsafe features are allowed!"
@end

View file

@ -9,7 +9,7 @@
{
'SymFlag': [ # already 32 flags!
'sfGeneric', # whether an operator, proc or type is generic
'sfTypeCheck', # wether macro parameters should be type checked
'sfForward', # symbol is forward directed
'sfImportc', # symbol is external; imported
'sfExportc', # symbol is exported (under a specified name)
@ -26,7 +26,7 @@
'sfMainModule', # module is the main module
'sfSystemModule', # module is the system module
'sfNoReturn', # proc never returns (an exit proc)
'sfReturnsNew', # proc returns new allocated thing (allows optimizations)
'sfAddrTaken', # the variable's address is taken (ex- or implicitely)
'sfInInterface', # symbol is in interface section declared
'sfNoStatic', # symbol is used within an iterator (needed for codegen)
# so it cannot be 'static' in the C code
@ -56,32 +56,40 @@
# is used to speed up semantic checking a bit
'tfEnumHasWholes', # enum cannot be mapped into a range
'tfVarargs', # procedure has C styled varargs
'tfAssignable' # can the type be assigned to?
'tfFinal' # is the object final?
],
'TypeKind': [ # order is important!
# Don't forget to change hti.nim if you make a change here
'tyNone', 'tyBool', 'tyChar',
'tyEmptySet', 'tyArrayConstr', 'tyNil', 'tyRecordConstr',
'tyGeneric',
'tyGenericInst', # instantiated generic type
'tyGenericParam',
'tyEnum', 'tyAnyEnum',
'tyArray',
'tyRecord',
'tyObject',
'tyTuple',
'tySet',
'tyRange',
'tyPtr', 'tyRef',
'tyVar',
'tySequence',
'tyProc',
'tyPointer', 'tyOpenArray',
'tyString', 'tyCString', 'tyForward',
# numerical types:
'tyInt', 'tyInt8', 'tyInt16', 'tyInt32', 'tyInt64', # signed integers
'tyFloat', 'tyFloat32', 'tyFloat64', 'tyFloat128'
'tyNone', 'tyBool', 'tyChar',
'tyEmptySet', 'tyArrayConstr', 'tyNil',
'tyGeneric',
'tyGenericInst', # instantiated generic type
'tyGenericParam',
'tyEnum',
'tyAnyEnum',
'tyArray',
'tyObject',
'tyTuple',
'tySet',
'tyRange',
'tyPtr', 'tyRef',
'tyVar',
'tySequence',
'tyProc',
'tyPointer', 'tyOpenArray',
'tyString', 'tyCString', 'tyForward',
# numerical types:
'tyInt', 'tyInt8', 'tyInt16', 'tyInt32', 'tyInt64', # signed integers
'tyFloat', 'tyFloat32', 'tyFloat64', 'tyFloat128'
],
'NodeFlag': [ # keep this number under 16 for performance reasons!
'nfNone',
'nfBase2', # nfBase10 is default, so not needed
'nfBase8',
'nfBase16',
'nfAllConst' # used to mark complex expressions constant
],
'NodeKind': [ # these are pure nodes
@ -97,7 +105,6 @@
'nkType', # node is used for its typ field
'nkCharLit', # a character literal ''
'nkRCharLit', # a raw character literal r''
'nkIntLit', # an integer literal
'nkInt8Lit',
@ -110,6 +117,8 @@
'nkStrLit', # a string literal ""
'nkRStrLit', # a raw string literal r""
'nkTripleStrLit', # a triple string literal """
'nkMetaNode', # difficult to explan; represents itself
# (used for macros)
'nkNilLit', # the nil literal
# end of atoms
'nkDotCall', # used to temporarily flag a nkCall node; this is used
@ -126,7 +135,7 @@
'nkInfix', # a call like (a + b)
'nkPrefix', # a call like !a
'nkPostfix', # something like a! (also used for visibility)
'nkPar', # syntactic ()
'nkPar', # syntactic (); may be a tuple constructor
'nkCurly', # syntactic {}
'nkBracket', # syntactic []
'nkBracketExpr', # an expression like a[i..j, k]
@ -142,14 +151,7 @@
'nkAccQuoted', # `a` as a node
'nkHeaderQuoted', # `a(x: int)` as a node
'nkSetConstr', # a set constructor {}
'nkConstSetConstr', # a set constructor with only constant expressions
'nkArrayConstr', # an array constructor []
'nkConstArrayConstr', # an array constructor with only constant expressions
'nkRecordConstr', # a record constructor []
'nkConstRecordConstr', # a record constructor with only constant expressions
'nkTableConstr', # a table constructor {expr: expr}
'nkConstTableConstr', # a table constructor with only constant expressions
'nkQualified', # describes a.b for qualified identifiers
'nkHiddenStdConv', # an implicit standard type conversion
'nkHiddenSubConv', # an implicit type conversion from a subtype
@ -158,6 +160,16 @@
'nkConv', # a type conversion
'nkCast', # a type cast
'nkAddr', # a addr expression
'nkHiddenAddr', # implicit address operator
'nkHiddenDeref', # implicit ^ operator
'nkObjDownConv', # down conversion between object types
'nkObjUpConv', # up conversion between object types
'nkChckRangeF', # range check for floats
'nkChckRange64', # range check for 64 bit ints
'nkChckRange', # range check for ints
'nkStringToCString', # string to cstring
'nkCStringToString', # cstring to string
'nkPassAsOpenArray', # thing is passed as an open array
# end of expressions
'nkAsgn', # a = b
@ -198,8 +210,6 @@
'nkBreakStmt', # a break statement
'nkContinueStmt', # a continue statement
'nkBlockStmt', # a block statement
'nkGotoStmt', # used by the transformation pass; first son is a sym
# node containing a label
'nkDiscardStmt', # a discard statement
'nkStmtList', # a list of statements
'nkImportStmt', # an import statement
@ -218,8 +228,8 @@
# types as syntactic trees:
'nkTypeOfExpr',
'nkRecordTy',
'nkObjectTy',
'nkTupleTy',
'nkRecList', # list of record/object parts
'nkRecCase', # case section of record/object
'nkRecWhen', # when section of record/object
@ -228,7 +238,8 @@
'nkVarTy',
'nkProcTy',
'nkEnumTy',
'nkEnumFieldDef' # `ident = expr` in an enumeration
'nkEnumFieldDef', # `ident = expr` in an enumeration
'nkReturnToken', # token used for interpretation
],
'SymKind': [

View file

@ -4,6 +4,7 @@ Command::
compile compile project with default code generator (C)
compile_to_c compile project with C code generator
compile_to_cpp compile project with C++ code generator
compile_to_ecmascript compile project to ECMAScript code (experimental)
doc generate the documentation for inputfile;
with --run switch opens it with $BROWSER
Arguments:
@ -18,6 +19,8 @@ Options:
--line_trace:on|off code generation for line trace ON|OFF
--debugger:on|off turn Embedded Nimrod Debugger ON|OFF
-x, --checks:on|off code generation for all runtime checks ON|OFF
--obj_checks:on|off code generation for obj conversion checks ON|OFF
--field_checks:on|off code generation for case record fields ON|OFF
--range_checks:on|off code generation for range checks ON|OFF
--bound_checks:on|off code generation for bound checks ON|OFF
--overflow_checks:on|off code generation for over-/underflow checks ON|OFF

View file

@ -10,9 +10,9 @@ macro method mod
nil not notin
object of or out
proc ptr
raise record ref return
raise ref return
shl shr
template try type
template try tuple type
var
when where while with without
xor

View file

@ -113,8 +113,13 @@
'UnaryPlusF64',
'UnaryMinusF64',
'AbsF64',
'Ze',
'Ze64',
'Ze8ToI',
'Ze8ToI64',
'Ze16ToI',
'Ze16ToI64',
'Ze32ToI64',
'ZeIToI64',
'ToU8',
'ToU16',
'ToU32',
@ -123,6 +128,14 @@
'ToInt',
'ToBiggestInt',
'CharToStr',
'BoolToStr',
'IntToStr', # $ for ints
'Int64ToStr',
'FloatToStr',
'CStrToStr',
'StrToStr',
# special ones:
'And',
'Or',
@ -156,12 +169,12 @@
'SetLengthSeq',
'Assert',
'Swap',
'IsNil',
# magic type constructors:
'Array',
'OpenArray',
'Range',
'Tuple',
'Set',
'Seq',
@ -172,5 +185,38 @@
'NimrodMajor',
'NimrodMinor',
'NimrodPatch',
'CpuEndian'
'CpuEndian',
'NaN',
'Inf',
'NegInf',
# magics for modifying the AST (macro support)
'NLen',
'NChild',
'NSetChild',
'NAdd',
'NAddMultiple',
'NDel',
'NKind',
'NIntVal',
'NFloatVal',
'NSymbol',
'NIdent',
'NGetType',
'NStrVal',
'NSetIntVal',
'NSetFloatVal',
'NSetSymbol',
'NSetIdent',
'NSetType',
'NSetStrVal',
'NNewNimNode',
'NCopyNimNode',
'NCopyNimTree',
'StrToIdent',
'IdentToStr',
'EqIdent',
'NHint',
'NWarning',
'NError'
]

View file

@ -23,7 +23,7 @@
{'errInvalidToken': 'invalid token: $1'},
{'errLineTooLong': 'line too long'},
{'errInvalidNumber': '$1 is not a valid number'},
{'errNumberOutOfRange': '$1 is too large or too small'},
{'errNumberOutOfRange': 'number $1 out of valid range'},
{'errNnotAllowedInCharacter': '\\n not allowed in character literal'},
{'errClosingBracketExpected': "closing ']' expected, but end of file reached"},
{'errMissingFinalQuote': "missing final '"},
@ -32,10 +32,6 @@
{'errTokenExpected': "'$1' expected"},
{'errStringAfterIncludeExpected': "string after 'include' expected"},
{'errRecursiveInclude': "recursive include file: '$1'"},
{'errAtIfExpected': "'@if' expected"},
{'errAtIfExpectedBeforeElse': "'@if' expected before '@else'"},
{'errAtIfExpectedBeforeElif': "'@if' expected before '@elif'"},
{'errAtEndExpected': "'@end' expected"},
{'errOnOrOffExpected': "'on' or 'off' expected"},
{'errNoneSpeedOrSizeExpected': "'none', 'speed' or 'size' expected"},
{'errInvalidPragma': 'invalid pragma'},
@ -157,13 +153,13 @@
{'errSizeTooBig': "computing the type's size produced an overflow"},
{'errSetTooBig': 'set is too large'},
{'errBaseTypeMustBeOrdinal': 'base type of a set must be an ordinal'},
{'errInheritanceOnlyWithObjects': 'inheritance only works with an object'},
{'errInheritanceOnlyWithNonFinalObjects': 'inheritance only works non-final objects'},
{'errInheritanceOnlyWithEnums': 'inheritance only works with an enum'},
{'errIllegalRecursionInTypeX': "illegal recursion in type '$1'"},
{'errCannotInstantiateX': "cannot instantiate: '$1'"},
{'errExprHasNoAddress': 'expression has no address'},
{'errExprHasNoAddress': "expression has no address"},
{'errVarForOutParamNeeded':
'to an out parameter a variable needs to be passed'},
"for a 'var' type a variable needs to be passed"},
{'errPureTypeMismatch': 'type mismatch'},
{'errTypeMismatch': 'type mismatch: got ('},
{'errButExpected': 'but expected one of: '},
@ -243,6 +239,20 @@
{'errWhitespaceExpected': "whitespace expected, got '$1'"},
{'errXisNoValidIndexFile': "'$1' is no valid index file"},
{'errCannotRenderX': "cannot render reStructuredText element '$1'"},
{'errVarVarTypeNotAllowed': "type 'var var' is not allowed"},
{'errIsExpectsTwoArguments': "'is' expects two arguments"},
{'errIsExpectsObjectTypes': "'is' expects object types"},
{'errXcanNeverBeOfThisSubtype': "'$1' can never be of this subtype"},
{'errTooManyIterations': "interpretation requires too many iterations"},
{'errCannotInterpretNodeX': "cannot interpret node kind '$1'"},
{'errFieldXNotFound': "field '$1' cannot be found"},
{'errInvalidConversionFromTypeX': "invalid conversion from type '$1'"},
{'errAssertionFailed': "assertion failed"},
{'errCannotGenerateCodeForX': "cannot generate code for '$1'"},
{'errXNeedsReturnType': "converter needs return type"},
{'errXRequiresOneArgument': "converter requires one parameter"},
{'errUnhandledExceptionX': "unhandled exception: $1"},
{'errCyclicTree': "macro returned a cyclic abstract syntax tree"},
# user error message:
{'errUser': '$1'},
@ -276,6 +286,8 @@
{'hintMo2FileInvalid': "mo2 file '$1' is invalid"},
{'hintModuleHasChanged': "module '$1' has been changed"},
{'hintCannotOpenMo2File': "mo2 file '$1' does not exist"},
{'hintQuitCalled': "quit() called"},
{'hintProcessing': "processing"},
# user hint message:
{'hintUser': '$1'}

View file

@ -3,6 +3,9 @@
The documentation consists of several documents:
- | `First steps after installation <steps.html>`_
| Read this after installation for a quick introduction.
- | `Nimrod manual <manual.html>`_
| Read this to get to know the Nimrod programming system.
@ -23,4 +26,3 @@ The documentation consists of several documents:
- | `Index <theindex.html>`_
| The generated index. Often the quickest way to find the piece of
information you need.

View file

@ -78,6 +78,7 @@ typeDescK ::= VAR typeDesc
| REF typeDesc
| PTR typeDesc
| TYPE expr
| TUPLE tupleDesc
| PROC paramList [pragma]
typeDesc ::= typeDescK | primary
@ -157,23 +158,23 @@ colonAndEquals ::= [COLON typeDesc] EQUALS expr
constDecl ::= symbol ["*"] [pragma] colonAndEquals [COMMENT | IND COMMENT]
| COMMENT
constSection ::= CONST indPush constDecl (SAD constDecl)* DED
typeDef ::= typeDesc | recordDef | objectDef | enumDef
typeDef ::= typeDesc | objectDef | enumDef
recordIdentPart ::=
objectIdentPart ::=
(symbol ["*" | "-"] [pragma] optComma)+ COLON typeDesc [COMMENT | IND COMMENT]
recordWhen ::= WHEN expr COLON [COMMENT] recordPart
(ELIF expr COLON [COMMENT] recordPart)*
[ELSE COLON [COMMENT] recordPart]
recordCase ::= CASE expr COLON typeDesc [COMMENT]
(OF sliceList COLON [COMMENT] recordPart)*
[ELSE COLON [COMMENT] recordPart]
objectWhen ::= WHEN expr COLON [COMMENT] objectPart
(ELIF expr COLON [COMMENT] objectPart)*
[ELSE COLON [COMMENT] objectPart]
objectCase ::= CASE expr COLON typeDesc [COMMENT]
(OF sliceList COLON [COMMENT] objectPart)*
[ELSE COLON [COMMENT] objectPart]
recordPart ::= recordWhen | recordCase | recordIdentPart
| indPush recordPart (SAD recordPart)* DED
recordDef ::= RECORD [pragma] recordPart
objectPart ::= objectWhen | objectCase | objectIdentPart
| indPush objectPart (SAD objectPart)* DED
tupleDesc ::= BRACKET_LE optInd ((symbol optComma)+ COLON typeDesc optComma)* BRACKET_RI
objectDef ::= OBJECT [pragma] [OF typeDesc] recordPart
objectDef ::= OBJECT [pragma] [OF typeDesc] objectPart
enumDef ::= ENUM [OF typeDesc] (symbol [EQUALS expr] optComma [COMMENT | IND COMMENT])+
typeDecl ::= COMMENT

View file

@ -13,36 +13,119 @@ Advanced libraries are in the ``lib/base`` directory.
Basic libraries
===============
* `System <system.html>`_
* `system <system.html>`_
Basic procs and operators that every program needs. It also provides IO
facilities for reading and writing text and binary files. It is imported
implicitly by the compiler. Do not import it directly. It relies on compiler
magic to work.
* `Strutils <strutils.html>`_
* `strutils <strutils.html>`_
This module contains common string handling operations like converting a
string into uppercase, splitting a string into substrings, searching for
substrings, replacing substrings.
* `OS <os.html>`_
* `os <os.html>`_
Basic operating system facilities like retrieving environment variables,
reading command line arguments, working with directories, running shell
commands, etc. This module is -- like any other basic library --
platform independant.
* `Math <math.html>`_
* `math <math.html>`_
Mathematical operations like cosine, square root.
* `Complex <complex.html>`_
* `complex <complex.html>`_
This module implements complex numbers and their mathematical operations.
* `Times <times.html>`_
* `times <times.html>`_
The ``times`` module contains basic support for working with time.
* `parseopt <parseopt.html>`_
The ``parseopt`` module implements a command line option parser. This
supports long and short command options with optional values and command line
arguments.
* `parsecfg <parsecfg.html>`_
The ``parsecfg`` module implements a high performance configuration file
parser. The configuration file's syntax is similar to the Windows ``.ini``
format, but much more powerful, as it is not a line based parser. String
literals, raw string literals and triple quote string literals are supported
as in the Nimrod programming language.
* `strtabs <strtabs.html>`_
The ``strtabs`` module implements an efficient hash table that is a mapping
from strings to strings. Supports a case-sensitive, case-insensitive and
style-insensitive mode. An efficient string substitution operator ``%``
for the string table is also provided.
* `hashes <hashes.html>`_
This module implements efficient computations of hash values for diverse
Nimrod types.
* `lexbase <lexbase.html>`_
This is a low leve module that implements an extremely efficent buffering
scheme for lexers and parsers. This is used by the ``parsecfg`` module.
Advanced libaries
=================
* `Regexprs <regexprs.html>`_
* `regexprs <regexprs.html>`_
This module contains procedures and operators for handling regular
expressions.
* `dialogs <dialogs.html>`_
This module implements portable dialogs for Nimrod; the implementation
builds on the GTK interface. On Windows, native dialogs are shown if
appropriate.
Wrappers
========
Note that the generated HTML for some of these wrappers is so huge, that it is
not contained in the distribution. You can then find them on the website.
* `posix <posix.html>`_
Contains a wrapper for the POSIX standard.
* `windows <windows.html>`_
Contains a wrapper for the Win32 API.
* `shellapi <shellapi.html>`_
Contains a wrapper for the ``shellapi.h`` header.
* `shfolder <shfolder.html>`_
Contains a wrapper for the ``shfolder.h`` header.
* `mmsystem <mmsystem.html>`_
Contains a wrapper for the ``mmsystem.h`` header.
* `ole2 <ole2.html>`_
Contains GUIDs for OLE2 automation support.
* `nb30 <nb30.html>`_
This module contains the definitions for portable NetBIOS 3.0 support.
* `cairo <cairo.html>`_
Wrapper for the cairo library.
* `cairoft <cairoft.html>`_
Wrapper for the cairoft library.
* `cairowin32 <cairowin32.html>`_
Wrapper for the cairowin32 library.
* `cairoxlib <cairoxlib.html>`_
Wrapper for the cairoxlib library.
* `atk <atk.html>`_
Wrapper for the atk library.
* `gdk2 <gdk2.html>`_
Wrapper for the gdk2 library.
* `gdk2pixbuf <gdk2pixbuf.html>`_
Wrapper for the gdk2pixbuf library.
* `gdkglext <gdkglext.html>`_
Wrapper for the gdkglext library.
* `glib2 <glib2.html>`_
Wrapper for the glib2 library.
* `gtk2 <gtk2.html>`_
Wrapper for the gtk2 library.
* `gtkglext <gtkglext.html>`_
Wrapper for the gtkglext library.
* `gtkhtml <gtkhtml.html>`_
Wrapper for the gtkhtml library.
* `libglade2 <libglade2.html>`_
Wrapper for the libglade2 library.
* `pango <pango.html>`_
Wrapper for the pango library.
* `pangoutils <pangoutils.html>`_
Wrapper for the pangoutils library.

View file

@ -593,7 +593,7 @@ Structured types
~~~~~~~~~~~~~~~~
A variable of a `structured type`:idx: can hold multiple values at the same
time. Stuctured types can be nested to unlimited levels. Arrays, sequences,
records, objects and sets belong to the structured types.
tuples, objects and sets belong to the structured types.
Array and sequence types
~~~~~~~~~~~~~~~~~~~~~~~~
@ -638,42 +638,47 @@ checks can be disabled via pragmas or invoking the compiler with the
``--bound_checks:off`` command line switch.
Tuples, record and object types
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A variable of a `record`:idx: or `object`:idx: type is a heterogenous storage
Tuples and object types
~~~~~~~~~~~~~~~~~~~~~~~
A variable of a `tuple`:idx: or `object`:idx: type is a heterogenous storage
container.
A record or object defines various named *fields* of a type. The assignment
operator for records and objects always copies the whole record/object. The
constructor ``()`` can be used to initialize records/objects. A field may
be given a default value. Fields with default values do not have to be listed
in a record construction, all other fields have to be listed.
A tuple or object defines various named *fields* of a type. A tuple defines an
*order* of the fields additionally. Tuples are meant for heterogenous storage
types with no overhead and few abstraction possibilities. The constructor ``()``
can be used to construct tuples. The order of the fields in the constructor
must match the order of the tuple's definition. Different tuple-types are
*equivalent* if they specify the same fields of the same type in the same
order.
The assignment operator for tuples copies each component.
The default assignment operator for objects is not defined. The programmer may
provide one, however.
.. code-block:: nimrod
type
TPerson = record # type representing a person
name: string # a person consists of a name
age: int = 30 # and an age which default value is 30
TPerson = tuple[name: string, age: int] # type representing a person
# a person consists of a name
# and an age
var
person: TPerson
person = (name: "Peter") # person.age is its default value (30)
person = (name: "Peter", age: 30)
# the same, but less readable:
person = ("Peter", 30)
The implementation aligns the fields for best access performance. The alignment
is done in a way that is compatible the way the C compiler does it.
The difference between records and objects is that objects allow inheritance.
Objects have access to their type at runtime, so that the ``is`` operator
can be used to determine the object's type. Assignment from an object to its
parents' object leads to a static or runtime error (the
`EInvalidObjectAssignment`:idx: exception is raised).
Objects provide many features that tuples do not. Object provide inheritance
and information hiding. Objects have access to their type at runtime, so that
the ``is`` operator can be used to determine the object's type.
.. code-block:: nimrod
type
TPerson = object
name: string
age: int
name*: string # the * means that `name` is accessible from the outside
age: int # no * means that the field is hidden
TStudent = object of TPerson # a student is a person
id: int # with an id field
@ -681,10 +686,11 @@ parents' object leads to a static or runtime error (the
var
student: TStudent
person: TPerson
student = (name: "Peter", age: 89, id: 3)
person = (name: "Mary", age: 17)
assert(student is TStudent) # is true
person = student # this is an error; person has no storage for id.
Object fields that should be visible outside from the defining module, have to
marked by ``*``. In contrast to tuples, different object types are
never *equivalent*.
Set type
@ -743,15 +749,15 @@ The ``^`` operator can be used to derefer a reference, the ``addr`` procedure
returns the address of an item. An address is always an untraced reference.
Thus the usage of ``addr`` is an *unsafe* feature.
The ``.`` (access a record field operator) and ``[]`` (array/string/sequence
index operator) operators perform implicit dereferencing operations for
reference types:
The ``.`` (access a tuple/object field operator)
and ``[]`` (array/string/sequence index operator) operators perform implicit
dereferencing operations for reference types:
.. code-block:: nimrod
type
PNode = ref TNode
TNode = record
TNode = object
le, ri: PNode
data: int
@ -938,8 +944,8 @@ ref or pointer type nil
procedural type nil
sequence nil
string nil (**not** "")
tuple[A, B, ...] (default(A), default(B), ...)
(analogous for objects and records)
tuple[x: A, y: B, ...] (default(A), default(B), ...)
(analogous for objects)
array[0..., T] [default(T), ...]
range[T] default(T); this may be out of the valid range
T = enum cast[T](0); this may be an invalid value
@ -1065,7 +1071,7 @@ exceptions:
The ``when`` statement enables conditional compilation techniques. As
a special syntatic extension, the ``when`` construct is also available
within ``record`` or ``object`` definitions.
within ``object`` definitions.
Raise statement
@ -1117,7 +1123,7 @@ Example:
echo("sum: " & $(parseInt(a) + parseInt(b)))
except EOverflow:
echo("overflow!")
except EValue:
except EInvalidValue:
echo("could not convert string to integer")
except EIO:
echo("IO error!")
@ -1411,7 +1417,7 @@ Type sections
Syntax::
typeDef ::= typeDesc | recordDef | objectDef | enumDef
typeDef ::= typeDesc | objectDef | enumDef
genericParams ::= BRACKET_LE (symbol [EQUALS typeDesc] )* BRACKET_RI
typeDecl ::= TYPE
@ -1425,11 +1431,11 @@ Example:
.. code-block:: nimrod
type # example demonstrates mutually recursive types
PNode = ref TNode # a traced pointer to a TNode
TNode = record
TNode = object
le, ri: PNode # left and right subtrees
sym: ref TSym # leaves contain a reference to a TSym
TSym = record # a symbol
TSym = object # a symbol
name: string # the symbol's name
line: int # the line the symbol was declared in
code: PNode # the symbol's abstract syntax tree
@ -1447,7 +1453,7 @@ Example:
.. code-block:: nimrod
type
TBinaryTree[T] = record # TBinaryTree is a generic type with
TBinaryTree[T] = object # TBinaryTree is a generic type with
# with generic param ``T``
le, ri: ref TBinaryTree[T] # left and right subtrees; may be nil
data: T # the data stored in a node
@ -1537,7 +1543,8 @@ Modules make separate compilation possible. Each module needs to be in its
own file. Modules enable `information hiding`:idx: and
`separate compilation`:idx:. A module may gain access to symbols of another
module by the `import`:idx: statement. `Recursive module dependancies`:idx: are
allowed, but slightly subtle.
allowed, but slightly subtle. Only top-level symbols that are marked with an
asterisk (``*``) are exported.
The algorithm for compiling modules is:
@ -1587,13 +1594,13 @@ identifier cannot be redefined in the same block, except if valid for
procedure or iterator overloading purposes.
Record or object scope
Tuple or object scope
~~~~~~~~~~~~~~~~~~~~~~
The field identifiers inside a record or object definition are valid in the
The field identifiers inside a tuple or object definition are valid in the
following places:
* To the end of the record definition
* Field designators of a variable of the given record type.
* To the end of the tuple/object definition
* Field designators of a variable of the given tuple/object type.
* In all descendent types of the object type.
Module scope

View file

@ -86,8 +86,8 @@ the C code. Thus it makes the following possible, for example:
.. code-block:: Nimrod
var
EOF {.import: "EOF", no_decl.}: cint # pretend EOF was a variable, as
# Nimrod does not know its value
EOF {.importc: "EOF", no_decl.}: cint # pretend EOF was a variable, as
# Nimrod does not know its value
Varargs Pragma
~~~~~~~~~~~~~~
@ -110,7 +110,7 @@ declared but also that it leads to the inclusion of a given header file:
.. code-block:: Nimrod
type
PFile {.import: "FILE*", header: "<stdio.h>".} = pointer
PFile {.importc: "FILE*", header: "<stdio.h>".} = pointer
# import C's FILE* type; Nimrod will treat it as a new pointer type
The ``header`` pragma expects always a string constant. The string contant
@ -239,3 +239,28 @@ However it is not efficient to do:
String case statements are optimized too. A hashing scheme is used for them
if several different string constants are used. This is likely to be more
efficient than any hand-coded scheme.
The ECMAScript code generator
=============================
Note: I use the term `ECMAScript`:idx: here instead of `JavaScript`:idx:, since
it is the proper term.
Nimrod targets ECMAScript 1.5 which is supported by any widely used browser.
Since ECMAScript does not have a portable means to include another module,
Nimrod just generate a long ``.js`` file.
Features or modules that the ECMAScript platform does not support are not
available. This includes:
* manual memory management (``alloc``, etc.)
* casting and other unsafe operations (``cast`` operator, ``zeroMem``, etc.)
* file management (``openfile``, etc.)
* most modules of the Standard library
* proper 64 bit integer arithmetic
* proper unsigned integer arithmetic
However, the modules `strutils`:idx:, `math`:idx:, and `times`:idx: are
available! To access the DOM, use the `dom`:idx: module that is only available
for the ECMAScript platform.

View file

@ -1,220 +0,0 @@
Function POSIX Description
access Tests for file accessibility
alarm Schedules an alarm
asctime Converts a time structure to a string
cfgetispeed Reads terminal input baud rate
cfgetospeed Reads terminal output baud rate
cfsetispeed Sets terminal input baud rate
cfsetospeed Sets terminal output baud rate
chdir Changes current working directory
chmod Changes file mode
chown Changes owner and/or group of a file
close Closes a file
closedir Ends directory read operation
creat Creates a new file or rewrites an existing one
ctermid Generates terminal pathname
cuserid Gets user name
dup Duplicates an open file descriptor
dup2 Duplicates an open file descriptor
execl Executes a file
execle Executes a file
execlp Executes a file
execv Executes a file
execve Executes a file
execvp Executes a file
_exit Terminates a process
fcntl Manipulates an open file descriptor
fdopen Opens a stream on a file descriptor
fork Creates a process
fpathconf Gets configuration variable for an open file
fstat Gets file status
getcwd Gets current working directory
getegid Gets effective group ID
getenv Gets environment variable
geteuid Gets effective user ID
getgid Gets real group ID
getgrgid Reads groups database based on group ID
getgrnam Reads groups database based on group name
getgroups Gets supplementary group IDs
getlogin Gets user name
getpgrp Gets process group ID
getpid Gets process ID
getppid Gets parent process ID
getpwnam Reads user database based on user name
getpwuid Reads user database based on user ID
getuid Gets real user ID
isatty Determines if a file descriptor is associated with a terminal
kill Sends a kill signal to a process
link Creates a link to a file
longjmp Restores the calling environment
lseek Repositions read/write file offset
mkdir Makes a directory
mkfifo Makes a FIFO special file
open Opens a file
opendir Opens a directory
pathconf Gets configuration variables for a path
pause Suspends a process execution
pipe Creates an interprocess channel
read Reads from a file
readdir Reads a directory
rename Renames a file
rewinddir Resets the readdir() pointer
rmdir Removes a directory
setgid Sets group ID
setjmp Saves the calling environment for use by longjmp()
setlocale Sets or queries a program's locale
setpgid Sets a process group ID for job control
setuid Sets the user ID
sigaction Examines and changes signal action
sigaddset Adds a signal to a signal set
sigdelset Removes a signal to a signal set
sigemptyset Creates an empty signal set
sigfillset Creates a full set of signals
sigismember Tests a signal for a selected member
siglongjmp Goes to and restores signal mask
sigpending Examines pending signals
sigprocmask Examines and changes blocked signals
sigsetjmp Saves state for siglongjmp()
sigsuspend Waits for a signal
sleep Delays process execution
stat Gets information about a file
sysconf Gets system configuration information
tcdrain Waits for all output to be transmitted to the terminal
tcflow Suspends/restarts terminal output
tcflush Discards terminal data
tcgetattr Gets terminal attributes
tcgetpgrp Gets foreground process group ID
tcsendbreak Sends a break to a terminal
tcsetattr Sets terminal attributes
tcsetpgrp Sets foreground process group ID
time Determines the current calendar time
times Gets process times
ttyname Determines a terminal pathname
tzset Sets the timezone from environment variables
umask Sets the file creation mask
uname Gets system name
unlink Removes a directory entry
utime Sets file access and modification times
waitpid Waits for process termination
write Writes to a file
POSIX.1b function calls Function POSIX Description
aio_cancel Tries to cancel an asynchronous operation
aio_error Retrieves the error status for an asynchronous operation
aio_read Asynchronously reads from a file
aio_return Retrieves the return status for an asynchronous operation
aio_suspend Waits for an asynchronous operation to complete
aio_write Asynchronously writes to a file
clock_getres Gets resolution of a POSIX.1b clock
clock_gettime Gets the time according to a particular POSIX.1b clock
clock_settime Sets the time according to a particular POSIX.1b clock
fdatasync Synchronizes at least the data part of a file with the underlying media
fsync Synchronizes a file with the underlying media
kill, sigqueue Sends signals to a process
lio_listio Performs a list of I/O operations, synchronously or asynchronously
mlock Locks a range of memory
mlockall Locks the entire memory space down
mmap Maps a shared memory object (or possibly another file) into process's address space
mprotect Changes memory protection on a mapped area
mq_close Terminates access to a POSIX.1b message queue
mq_getattr Gets POSIX.1b message queue attributes
mq_notify Registers a request to be notified when a message arrives on an empty message queue
mq_open Creates/accesses a POSIX.1b message queue
mq_receive Receives a message from a POSIX.1b message queue
mq_send Sends a message on a POSIX.1b message queue
mq_setattr Sets a subset of POSIX.1b message queue attributes
msync Makes a mapping consistent with the underlying object
munlock Unlocks a range of memory
munlockall Unlocks the entire address space
munmap Undo mapping established by mmap
nanosleep Pauses execution for a number of nanoseconds
sched_get_priority_max Gets maximum priority value for a scheduler
sched_get_priority_min Gets minimum priority value for a scheduler
sched_getparam Retrieves scheduling parameters for a particular process
sched_getscheduler Retrieves scheduling algorithm for a particular purpose
sched_rr_get_interval Gets the SCHED_RR interval for the named process
sched_setparam Sets scheduling parameters for a process
sched_setscheduler Sets scheduling algorithm/parameters for a process
sched_yield Yields the processor
sem_close Terminates access to a POSIX.1b semaphore
sem_destroy De-initializes a POSIX.1b unnamed semaphore
sem_getvalue Gets the value of a POSIX.1b semaphore
sem_open Creates/accesses a POSIX.1b named semaphore
sem_post Posts (signal) a POSIX.1b named or unnamed semaphore
sem_unlink Destroys a POSIX.1b named semaphore
sem_wait, sem_trywait Waits on a POSIX.1b named or unnamed semaphore
shm_open Creates/accesses a POSIX.1b shared memory object
shm_unlink Destroys a POSIX.1b shared memory object
sigwaitinfosigtimedwait Synchronously awaits signal arrival; avoid calling handler
timer_create Creates a POSIX.1b timer based on a particular clock
timer_delete Deletes a POSIX.1b timer
timer_gettime Time remaining on a POSIX.1b timer before expiration
timer_settime Sets expiration time/interval for a POSIX.1b timer
wait, waitpid Retrieves status of a terminated process and clean up corpse
POSIX.1c function calls Function POSIX Description
pthread_atfork Declares procedures to be called before and after a fork
pthread_attr_destroy Destroys a thread attribute object
pthread_attr_getdetachstate Obtains the setting of the detached state of a thread
pthread_attr_getinheritsched Obtains the setting of the scheduling inheritance of a thread
pthread_attr_getschedparam Obtains the parameters associated with the scheduling policy attribute of a thread
pthread_attr_getschedpolicy Obtains the setting of the scheduling policy of a thread
pthread_attr_getscope Obtains the setting of the scheduling scope of a thread
pthread_attr_getstackaddr Obtains the stack address of a thread
pthread_attr_getstacksize Obtains the stack size of a thread
pthread_attr_init Initializes a thread attribute object
pthread_attr_setdetachstate Adjusts the detached state of a thread
pthread_attr_setinheritsched Adjusts the scheduling inheritance of a thread
pthread_attr_setschedparam Adjusts the parameters associated with the scheduling policy of a thread
pthread_attr_setschedpolicy Adjusts the scheduling policy of a thread
pthread_attr_setscope Adjusts the scheduling scope of a thread
pthread_attr_setstackaddr Adjusts the stack address of a thread
pthread_attr_setstacksize Adjusts the stack size of a thread
pthread_cancel Cancels the specific thread
pthread_cleanup_pop Removes the routine from the top of a thread's cleanup stack, and if execute is nonzero, runs it
pthread_cleanup_push Places a routine on the top of a thread's cleanup stack
pthread_condattr_destroy Destroys a condition variable attribute object
pthread_condattr_getpshared Obtains the process-shared setting of a condition variable attribute object
pthread_condattr_init Initializes a condition variable attribute object
pthread_condattr_setpshared Sets the process-shared attribute in a condition variable attribute object to either PTHREAD_PROCESS_SHARED or PTHREAD_PROCESS_PRIVATE
pthread_cond_broadcast Unblocks all threads that are waiting on a condition variable
pthread_cond_destroy Destroys a condition variable
pthread_cond_init Initializes a condition variable with the attributes specified in the specified condition variable attribute object
pthread_cond_signal Unblocks at least one thread waiting on a condition variable
pthread_cond_timedwait Automatically unlocks the specified mutex, and places the calling thread into a wait state
pthread_cond_wait Automatically unlocks the specified mutex, and places the calling thread into a wait state
pthread_create Creates a thread with the attributes specified in attr
pthread_detach Marks a threads internal data structures for deletion
pthread_equal Compares one thread handle to another thread handle
pthread_exit Terminates the calling thread
pthread_getschedparam Obtains both scheduling policy and scheduling parameters of an existing thread
pthread_getspecific Obtains the thread specific data value associated with the specific key in the calling thread
pthread_join Causes the calling thread to wait for the specific thread’s termination
pthread_key_create Generates a unique thread-specific key that's visible to all threads in a process
pthread_key_delete Deletes a thread specific key
pthread_kill Delivers a signal to the specified thread
pthread_mutexattr_destroy Destroys a mutex attribute object
pthread_mutexattr_getprioceiling Obtains the priority ceiling of a mutex attribute object
pthread_mutexattr_getprotocol Obtains protocol of a mutex attribute object
pthread_mutexattr_getpshared Obtains a process-shared setting of a mutex attribute object
pthread_mutexattr_init Initializes a mutex attribute object
pthread_mutexattr_setprioceiling Sets the priority ceiling attribute of a mutex attribute object
pthread_mutexattr_setprotocol Sets the protocol attribute of a mutex attribute object
pthread_mutexattr_setpshared Sets the process-shared attribute of a mutex attribute object to either PTHREAD_PROCESS_SHARED or PTHREAD_PROCESS_PRIVATE
pthread_mutex_destroy Destroys a mutex
pthread_mutex_init Initializes a mutex with the attributes specified in the specified mutex attribute object
pthread_mutex_lock Locks an unlocked mutex
pthread_mutex_trylock Tries to lock a not tested
pthread_mutex_unlock Unlocks a mutex
pthread_once Ensures that init_routine will run just once regardless of how many threads in the process call it
pthread_self Obtains a thread handle of a calling thread
pthread_setcancelstate Sets a thread's cancelability state
pthread_setcanceltype Sets a thread's cancelability type
pthread_setschedparam Adjusts the scheduling policy and scheduling parameters of an existing thread
pthread_setspecific Sets the thread-specific data value associated with the specific key in the calling thread
pthread_sigmask Examines or changes the calling thread's signal mask
pthread_testcancel Requests that any pending cancellation request be delivered to the calling thread

View file

@ -4,8 +4,4 @@ Nimrod's documenation system
This folder contains Nimrod's documentation. The documentation
is written in a format called *reStructuredText*, a markup language that reads
like ASCII and can be converted to HTML, Tex and other formats automatically!
Unfortunately reStructuredText does not allow to colorize source code in the
HTML page. Therefore a postprocessor runs over the generated HTML code, looking
for Nimrod code fragments and colorizing them.
like ASCII and can be converted to HTML automatically!

View file

@ -272,25 +272,3 @@ end of the subject string, whatever options are set.
The difference between ``\Z`` and ``\z`` is that ``\Z`` matches before
a newline that is the last character of the string as well as at the end
of the string, whereas ``\z`` matches only at the end.
..
Regular expressions in Nimrod itself!
-------------------------------------
'a' -- matches the character a
'a'-'z' -- range operator '-'
'A' | 'B' -- alternative operator |
* 'a' -- prefix * is needed
+ 'a' -- prefix + is needed
? 'a' -- prefix ? is needed
letter -- character classes with real names!
letters
white
whites
any -- any character
() -- are Nimrod syntax
! 'a'-'z'
-- concatentation via proc call:
re('A' 'Z' word * )

File diff suppressed because it is too large Load diff

View file

@ -85,13 +85,13 @@ We start the tour with a modified "hallo world" program:
Save this code to the file "greeting.nim". Now compile and run it::
nimrod run greeting.nim
nimrod compile --run greeting.nim
As you see, with the ``run`` command Nimrod executes the file automatically
As you see, with the ``--run`` switch Nimrod executes the file automatically
after compilation. You can even give your program command line arguments by
appending them after the filename that is to be compiled and run::
nimrod run greeting.nim arg1 arg2
nimrod compile --run greeting.nim arg1 arg2
Though it should be pretty obvious what the program does, I will explain the
syntax: Statements which are not indented are executed when the program
@ -198,7 +198,7 @@ An example showing the most common statement types:
.. code-block:: Nimrod
type
TMyRecord = record
TMyRecord = object
x, y: int

View file

@ -1,60 +1,35 @@
import glib2, gtk2, libglade2
import glib2, gtk2, libglade2, dialogs
proc on_window_destroy(obj: PGtkObject, data: pointer) {.exportc, cdecl.} =
proc on_window_destroy(obj: PGtkObject, data: pointer) {.cdecl.} =
gtk_main_quit()
const
GuiTemplate = "/media/hda4/nimrod/ide/nimide.glade"
type
TMyTextEditor = record
TTab = object of TObject
textview: PGtkTextView
filename: string
untitled: bool
TMyTextEditor = object of TObject
window: PGtkWindow
statusbar: PGtkStatusBar
textview: PGtkTextview
statusbarContextId: int
filename: string
proc error_message(msg: string) =
var
dialog: PGtkDialog
dialog = GTK_DIALOG(gtk_message_dialog_new(nil,
GTK_DIALOG_MODAL or GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, msg))
gtk_window_set_title(dialog, "Error!")
gtk_dialog_run(dialog)
gtk_widget_destroy(dialog)
proc get_open_filename(e: TMyTextEditor): string =
var
chooser: PGtkDialog
chooser = gtk_file_chooser_dialog_new("Open File...", e.window,
GTK_FILE_CHOOSER_ACTION_OPEN,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_OK, nil)
if gtk_dialog_run(chooser) == GTK_RESPONSE_OK:
result = $gtk_file_chooser_get_filename(chooser)
else:
result = ""
gtk_widget_destroy(chooser)
proc get_save_filename(e: TMyTextEditor): string =
var
chooser: PGtkDialog
chooser = gtk_file_chooser_dialog_new("Save File...", e.window,
GTK_FILE_CHOOSER_ACTION_SAVE,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_OK, nil)
if gtk_dialog_run(chooser) == GTK_RESPONSE_OK:
result = $gtk_file_chooser_get_filename(chooser)
else:
result = ""
gtk_widget_destroy(chooser)
proc on_about_menu_item_activate(menuItem: PGtkMenuItem,
e: var TMyTextEditor) {.cdecl.} =
gtk_show_about_dialog(e.window,
"comments", "A fast and leight-weight IDE for Nimrod",
"copyright", "Copyright \xc2\xa9 2008 Andreas Rumpf",
"version", "0.1",
"website", "http://nimrod.ethexor.com",
"program-name", "Nimrod IDE",
nil)
proc load_file(e: var TMyTextEditor, filename: string) =
var
@ -119,6 +94,21 @@ proc write_file(e: var TMyTextEditor, filename: string) =
reset_default_status(editor)
proc check_for_save(e: var TMyTextEditor): bool =
GtkTextBuffer *buffer;
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->text_view));
if gtk_text_buffer_get_modified(buffer):
GtkWidget *dialog;
const gchar *msg = "Do you want to save the changes you have made?";
dialog = gtk_message_dialog_new (nil,
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_QUESTION,
GTK_BUTTONS_YES_NO,
msg);
gtk_window_set_title (GTK_WINDOW (dialog), "Save?");
result = gtk_dialog_run(dialog) != GTK_RESPONSE_NO
gtk_widget_destroy(dialog)
proc initApp(e: var TMyTextEditor) =
var
builder: PGladeXML
@ -136,7 +126,7 @@ proc initApp(e: var TMyTextEditor) =
# connect the signal handlers:
glade_xml_signal_connect(builder, "on_window_destroy",
cast[TGCallback](on_window_destroy))
GCallback(on_window_destroy))
font_desc = pango_font_description_from_string("monospace 10")
gtk_widget_modify_font(e.textview, font_desc)
@ -162,208 +152,82 @@ proc main() =
main()
proc reset_default_status(e: var TMyTextEditor)
gchar *file;
gchar *status;
if e.filename == "":
file = g_strdup("(UNTITLED)")
else:
file = g_path_get_basename(editor->filename)
proc on_window_delete_event(widget: PGtkWidget, event: PGdkEvent,
e: TMyTextEditor): bool {.cdecl.} =
if check_for_save(editor):
on_save_menu_item_activate(nil, editor)
result = false
status = g_strdup_printf("File: %s", file)
gtk_statusbar_pop(e.statusbar,
e.statusbar_context_id)
gtk_statusbar_push(e.statusbar,
e.statusbar_context_id, status)
g_free(status)
g_free(file)
gboolean
check_for_save(e: var TMyTextEditor)
gboolean ret = FALSE;
proc on_new_menu_item_activate(GtkMenuItem *menuitem, TutorialTextEditor *editor)
GtkTextBuffer *buffer;
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->text_view));
if (gtk_text_buffer_get_modified (buffer) == TRUE)
if check_for_save(editor):
on_save_menu_item_activate(nil, editor)
/* clear editor for a new file */
editor->filename = nil;
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW (editor->text_view));
gtk_text_buffer_set_text(buffer, "", -1);
gtk_text_buffer_set_modified(buffer, FALSE);
reset_default_status(editor);
proc on_open_menu_item_activate(menuItem: PGtkMenuItem,
TutorialTextEditor *editor) =
gchar *filename;
if check_for_save(editor):
on_save_menu_item_activate(nil, editor)
filename = get_open_filename(editor)
if filename != nil: load_file(editor, filename)
proc on_save_menu_item_activate(menuItem: PGtkMenuItem, TutorialTextEditor *editor) =
gchar *filename;
if (editor->filename == nil)
{
GtkWidget *dialog;
const gchar *msg = "Do you want to save the changes you have made?";
dialog = gtk_message_dialog_new (NULL,
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_QUESTION,
GTK_BUTTONS_YES_NO,
msg);
gtk_window_set_title (GTK_WINDOW (dialog), "Save?");
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_NO)
{
ret = FALSE;
} else ret = TRUE;
gtk_widget_destroy (dialog);
filename = get_save_filename(editor);
if (filename != nil) write_file(editor, filename);
}
return ret;
else write_file(editor, nil);
proc on_save_as_menu_item_activate(GtkMenuItem *menuitem,
TutorialTextEditor *editor) =
gchar *filename;
filename = get_save_filename(editor)
if filename != nil: write_file(editor, filename)
proc on_quit_menu_item_activate(GtkMenuItem *menuitem, TutorialTextEditor *editor)
if check_for_save(editor):
on_save_menu_item_activate(nil, editor)
gtk_main_quit()
proc on_cut_menu_item_activate(GtkMenuItem *menuitem, TutorialTextEditor *editor) =
GtkTextBuffer *buffer;
GtkClipboard *clipboard;
clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
buffer = gtk_text_view_get_buffer(editor->text_view)
gtk_text_buffer_cut_clipboard(buffer, clipboard, TRUE)
proc on_copy_menu_item_activate(GtkMenuItem *menuitem, TutorialTextEditor *editor) =
GtkTextBuffer *buffer;
GtkClipboard *clipboard;
clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD)
buffer = gtk_text_view_get_buffer(editor->text_view)
gtk_text_buffer_copy_clipboard(buffer, clipboard)
/*
When the window is requested to be closed, we need to check if they have
unsaved work. We use this callback to prompt the user to save their work before
they exit the application. From the "delete-event" signal, we can choose to
effectively cancel the close based on the value we return.
*/
gboolean
on_window_delete_event(GtkWidget *widget, GdkEvent *event,
TutorialTextEditor *editor)
{
if (check_for_save (editor) == TRUE)
on_save_menu_item_activate (NULL, editor);
return FALSE; /* propogate event */
}
proc on_paste_menu_item_activate(GtkMenuItem *menuitem, TutorialTextEditor *editor)
GtkTextBuffer *buffer;
GtkClipboard *clipboard;
clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD)
buffer = gtk_text_view_get_buffer(editor->text_view)
gtk_text_buffer_paste_clipboard(buffer, clipboard, nil, TRUE)
/*
Called when the user clicks the 'New' menu. We need to prompt for save if the
file has been modified, and then delete the buffer and clear the modified flag.
*/
void on_new_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
{
GtkTextBuffer *buffer;
if (check_for_save (editor) == TRUE)
{
on_save_menu_item_activate (NULL, editor);
}
/* clear editor for a new file */
editor->filename = NULL;
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->text_view));
gtk_text_buffer_set_text (buffer, "", -1);
gtk_text_buffer_set_modified (buffer, FALSE);
reset_default_status (editor);
}
/*
Called when the user clicks the 'Open' menu. We need to prompt for save if the
file has been modified, allow the user to choose a file to open, and then call
load_file() on that file.
*/
void on_open_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
{
gchar *filename;
if (check_for_save (editor) == TRUE)
{
on_save_menu_item_activate (NULL, editor);
}
filename = get_open_filename (editor);
if (filename != NULL) load_file (editor, filename);
}
/*
Called when the user clicks the 'Save' menu. We need to allow the user to choose
a file to save if it's an untitled document, and then call write_file() on that
file.
*/
void on_save_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
{
gchar *filename;
if (editor->filename == NULL)
{
filename = get_save_filename (editor);
if (filename != NULL) write_file (editor, filename);
}
else write_file (editor, NULL);
}
/*
Called when the user clicks the 'Save As' menu. We need to allow the user to
choose a file to save and then call write_file() on that file.
*/
void on_save_as_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
{
gchar *filename;
filename = get_save_filename (editor);
if (filename != NULL) write_file (editor, filename);
}
/*
Called when the user clicks the 'Quit' menu. We need to prompt for save if the
file has been modified and then break out of the GTK+ main loop.
*/
void on_quit_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
{
if (check_for_save (editor) == TRUE)
{
on_save_menu_item_activate (NULL, editor);
}
gtk_main_quit();
}
/*
Called when the user clicks the 'Cut' menu.
*/
void on_cut_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
{
GtkTextBuffer *buffer;
GtkClipboard *clipboard;
clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->text_view));
gtk_text_buffer_cut_clipboard (buffer, clipboard, TRUE);
}
/*
Called when the user clicks the 'Copy' menu.
*/
void on_copy_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
{
GtkTextBuffer *buffer;
GtkClipboard *clipboard;
clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->text_view));
gtk_text_buffer_copy_clipboard (buffer, clipboard);
}
/*
Called when the user clicks the 'Paste' menu.
*/
void on_paste_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
{
GtkTextBuffer *buffer;
GtkClipboard *clipboard;
clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->text_view));
gtk_text_buffer_paste_clipboard (buffer, clipboard, NULL, TRUE);
}
/*
Called when the user clicks the 'Delete' menu.
*/
void on_delete_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
{
GtkTextBuffer *buffer;
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->text_view));
gtk_text_buffer_delete_selection (buffer, FALSE, TRUE);
}
void on_about_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
{
static const gchar * const authors[] = {
"Micah Carrick <email@micahcarrick.com>",
NULL
};
static const gchar copyright[] = "Copyright \xc2\xa9 2008 Andreas Rumpf";
static const gchar comments[] = "GTK+ and Glade3 GUI Programming Tutorial";
gtk_show_about_dialog (e.window,
"authors", authors,
"comments", comments,
"copyright", copyright,
"version", "0.1",
"website", "http://www.micahcarrick.com",
"program-name", "GTK+ Text Editor",
"logo-icon-name", GTK_STOCK_EDIT, nil)
}
proc on_delete_menu_item_activate(GtkMenuItem *menuitem, TutorialTextEditor *editor)
GtkTextBuffer *buffer;
buffer = gtk_text_view_get_buffer(editor->text_view);
gtk_text_buffer_delete_selection(buffer, FALSE, TRUE);

View file

@ -1,175 +1,224 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!--Generated with glade3 3.4.2 on Sat Jun 21 14:12:42 2008 -->
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
<glade-interface>
<widget class="GtkWindow" id="window">
<property name="extension_events">GDK_EXTENSION_EVENTS_ALL</property>
<signal name="destroy" handler="on_window_destroy" object="destroy"/>
<child>
<widget class="GtkVBox" id="mainvbox">
<property name="visible">True</property>
<child>
<widget class="GtkMenuBar" id="menubar">
<property name="visible">True</property>
<child>
<widget class="GtkMenuItem" id="menuitem1">
<property name="visible">True</property>
<property name="label" translatable="yes">_Datei</property>
<property name="use_underline">True</property>
<child>
<widget class="GtkMenu" id="menu1">
<property name="visible">True</property>
<child>
<widget class="GtkImageMenuItem" id="new_menu_item">
<property name="visible">True</property>
<property name="label" translatable="yes">gtk-new</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="open_menu_item">
<property name="visible">True</property>
<property name="label" translatable="yes">gtk-open</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="save_menu_item">
<property name="visible">True</property>
<property name="label" translatable="yes">gtk-save</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="save_as_menu_item">
<property name="visible">True</property>
<property name="label" translatable="yes">gtk-save-as</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</widget>
</child>
<child>
<widget class="GtkSeparatorMenuItem" id="separatormenuitem1">
<property name="visible">True</property>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="quit_menu_item">
<property name="visible">True</property>
<property name="label" translatable="yes">gtk-quit</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</widget>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkMenuItem" id="menuitem2">
<property name="visible">True</property>
<property name="label" translatable="yes">_Bearbeiten</property>
<property name="use_underline">True</property>
<child>
<widget class="GtkMenu" id="menu2">
<property name="visible">True</property>
<child>
<widget class="GtkImageMenuItem" id="cut_menu_item">
<property name="visible">True</property>
<property name="label" translatable="yes">gtk-cut</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="copy_menu_item">
<property name="visible">True</property>
<property name="label" translatable="yes">gtk-copy</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="paste_menu_item">
<property name="visible">True</property>
<property name="label" translatable="yes">gtk-paste</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="delete_menu_item">
<property name="visible">True</property>
<property name="label" translatable="yes">gtk-delete</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</widget>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkMenuItem" id="menuitem4">
<property name="visible">True</property>
<property name="label" translatable="yes">_Hilfe</property>
<property name="use_underline">True</property>
<child>
<widget class="GtkMenu" id="menu3">
<property name="visible">True</property>
<child>
<widget class="GtkImageMenuItem" id="about_menu_item">
<property name="visible">True</property>
<property name="label" translatable="yes">gtk-about</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</widget>
</child>
</widget>
</child>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
</packing>
</child>
<child>
<widget class="GtkScrolledWindow" id="scrolledwindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="extension_events">GDK_EXTENSION_EVENTS_ALL</property>
<property name="border_width">1</property>
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
<child>
<widget class="GtkTextView" id="textview">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="left_margin">2</property>
<property name="right_margin">2</property>
</widget>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkStatusbar" id="statusbar">
<property name="visible">True</property>
<property name="spacing">2</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">2</property>
</packing>
</child>
</widget>
</child>
</widget>
<widget class="GtkWindow" id="window">
<property name="extension_events">GDK_EXTENSION_EVENTS_ALL</property>
<property name="title" translatable="yes"></property>
<property name="type">GTK_WINDOW_TOPLEVEL</property>
<property name="window_position">GTK_WIN_POS_NONE</property>
<property name="modal">False</property>
<property name="resizable">True</property>
<property name="destroy_with_parent">False</property>
<property name="decorated">True</property>
<property name="skip_taskbar_hint">False</property>
<property name="skip_pager_hint">False</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
<property name="focus_on_map">True</property>
<property name="urgency_hint">False</property>
<signal name="destroy" handler="on_window_destroy" object="destroy"/>
<child>
<widget class="GtkVBox" id="mainvbox">
<property name="width_request">600</property>
<property name="height_request">400</property>
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child>
<widget class="GtkMenuBar" id="menubar">
<property name="visible">True</property>
<property name="pack_direction">GTK_PACK_DIRECTION_LTR</property>
<property name="child_pack_direction">GTK_PACK_DIRECTION_LTR</property>
<child>
<widget class="GtkMenuItem" id="menuitem1">
<property name="visible">True</property>
<property name="label" translatable="yes">_Datei</property>
<property name="use_underline">True</property>
<child>
<widget class="GtkMenu" id="menu1">
<property name="visible">True</property>
<child>
<widget class="GtkImageMenuItem" id="new_menu_item">
<property name="visible">True</property>
<property name="label">gtk-new</property>
<property name="use_stock">True</property>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="open_menu_item">
<property name="visible">True</property>
<property name="label">gtk-open</property>
<property name="use_stock">True</property>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="save_menu_item">
<property name="visible">True</property>
<property name="label">gtk-save</property>
<property name="use_stock">True</property>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="save_as_menu_item">
<property name="visible">True</property>
<property name="label">gtk-save-as</property>
<property name="use_stock">True</property>
</widget>
</child>
<child>
<widget class="GtkSeparatorMenuItem" id="separatormenuitem1">
<property name="visible">True</property>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="quit_menu_item">
<property name="visible">True</property>
<property name="label">gtk-quit</property>
<property name="use_stock">True</property>
</widget>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkMenuItem" id="menuitem2">
<property name="visible">True</property>
<property name="label" translatable="yes">_Bearbeiten</property>
<property name="use_underline">True</property>
<child>
<widget class="GtkMenu" id="menu2">
<property name="visible">True</property>
<child>
<widget class="GtkImageMenuItem" id="cut_menu_item">
<property name="visible">True</property>
<property name="label">gtk-cut</property>
<property name="use_stock">True</property>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="copy_menu_item">
<property name="visible">True</property>
<property name="label">gtk-copy</property>
<property name="use_stock">True</property>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="paste_menu_item">
<property name="visible">True</property>
<property name="label">gtk-paste</property>
<property name="use_stock">True</property>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="delete_menu_item">
<property name="visible">True</property>
<property name="label">gtk-delete</property>
<property name="use_stock">True</property>
</widget>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkMenuItem" id="menuitem4">
<property name="visible">True</property>
<property name="label" translatable="yes">_Hilfe</property>
<property name="use_underline">True</property>
<child>
<widget class="GtkMenu" id="menu3">
<property name="visible">True</property>
<child>
<widget class="GtkImageMenuItem" id="about_menu_item">
<property name="visible">True</property>
<property name="label">gtk-about</property>
<property name="use_stock">True</property>
</widget>
</child>
</widget>
</child>
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkScrolledWindow" id="scrolledwindow">
<property name="border_width">1</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
<child>
<widget class="GtkTextView" id="textview">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">True</property>
<property name="overwrite">False</property>
<property name="accepts_tab">True</property>
<property name="justification">GTK_JUSTIFY_LEFT</property>
<property name="wrap_mode">GTK_WRAP_NONE</property>
<property name="cursor_visible">True</property>
<property name="pixels_above_lines">0</property>
<property name="pixels_below_lines">0</property>
<property name="pixels_inside_wrap">0</property>
<property name="left_margin">2</property>
<property name="right_margin">2</property>
<property name="indent">0</property>
<property name="text" translatable="yes"></property>
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkStatusbar" id="statusbar">
<property name="visible">True</property>
<property name="has_resize_grip">True</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">True</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface>

View file

@ -1,38 +1,17 @@
Installation
============
Installation on Windows - the easy way
--------------------------------------
Install Nimrod by downloading the appropriate .zip file and extracting it to a
directory of your choice. The Nimrod Compiler will stay in this directory;
do not use a temporary one! You should add the ``bin`` directory of Nimrod to
your ``$PATH`` environment variable.
Installation on UNIX
--------------------
Installation on Linux/UNIX
--------------------------
Note:
A C compiler is required - knowledge of C is not!
**Note: Installation under UNIX does not work yet** - you have to bootstrap.
Play with the ``koch.py`` script to compile the compiler. Under Windows the
``nim.exe`` is provided, so you don't need to do anything. Under UNIX you need
to install the `FreePascal <www.freepascal.org>`_ compiler.
Compile the compiler::
python koch.py nim
To bootstrap (does not work yet)::
python koch.py boot
The GNU C Compiler is fully supported, other compilers may work. The C compiler
should be in your ``$PATH`` (most likely the case). Note that some Linux
distributions do not ship with a C compiler preinstalled - then you have to
install one.
distributions do not ship with a GCC compiler preinstalled - then you have to
install it.
After you have made sure that a C compiler is available, install Nimrod
by downloading the appropriate ``.zip`` file and extracting it to a
@ -46,7 +25,7 @@ Then run the following command::
Unlike other software, Nimrod does not distribute its files over the whole file
hierarchy. This has the advantage that you can deinstall it by just deleting
its folder. The disadvantage is that you have to add it to your ``PATH``
manually. The alternative is to create a symbolic link in ``/usr/bin``::
manually. An alternative is to create a symbolic link in ``/usr/bin``::
[sudo] ln -s $your_install_dir/bin/nimrod /usr/bin/nimrod
@ -55,35 +34,43 @@ Installation on the Macintosh
-----------------------------
Only MacOS X is supported.
Since MacOS X is UNIX based too, it works like the installation on UNIX. You
Since MacOS X is UNIX based too, it works like the installation on Linux. You
need to install Apple's developer's tools for the GNU Compiler Collection
though.
Installation on Windows - the easy way
--------------------------------------
Install Nimrod by downloading and running
the ``nimrod_windows_$version.exe`` file. The installation procedure detects
which C compilers are installed and writes the ``config/nimrod.cfg`` file
for you. If no installed C compiler is found, the ``LLVM-GCC`` compiler is
used that is bundled with this installer. So it should just work.
Installation on Windows - the hard way
--------------------------------------
Windows does not ship with a C compiler; you have to install one. The
following C compilers are supported under Windows:
- | Digital Mars C++
| http://www.digitalmars.com/download/freecompiler.html
- | Watcom C++
| http://www.openwatcom.org/ftp/
- | Borland C++ (5.5 or above; including Borland C++Builder)
| http://www.borland.com/downloads/download_cbuilder.html
| (Download the package under "compiler" - this requires registration though.)
- | Microsoft's Visual C++
| http://msdn.microsoft.com/visualc
| (You may need the SDK too - but not the full one: Essential are only
the win32api header files and import libraries.)
- | Borland C++ (5.5 or above; including Borland C++Builder)
| http://www.borland.com/downloads/download_cbuilder.html
| (Download the package under "compiler" - this requires registration though.)
- | Gnu C Compiler (the mingw version; the cygwin version has not been tested!)
| http://www.mingw.org/download.shtml
- | LLVM with GNU C/C++ frontend
| http://llvm.org/releases/download.html#2.2
- | Pelles C Compiler
- | Digital Mars C++
| http://www.digitalmars.com/download/freecompiler.html
- | Pelles C Compiler (bootstrapping does not work with PCC!)
| http://www.smorgasbordet.com/pellesc
- | Lcc-win32
- | Lcc-win32 (bootstrapping does not work with LCC!)
| http://www.cs.virginia.edu/~lcc-win32
All of the above compilers are available for free!
@ -96,10 +83,4 @@ After you have made sure that a C compiler is available, install
Nimrod by downloading the appropriate .zip file and extracting it to a
directory of your choice. The Nimrod Compiler will stay in this
directory; do not use a temporary one! Then adapt the ``config/nimrod.cfg``
file appropriately. Choose your C compiler and press ``OK``. You should
add Nimrod to your ``$PATH``.
Alternatively, you can install Nimrod with the ``koch.py`` script just like
in the UNIX installation instructions.
Nimrod does not use the Registry and can be removed by just deleting its folder.
file appropriately. You should add Nimrod to your ``$PATH``.

1111
koch.py

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,7 @@
# For further documentation see koch.txt or koch.html.
# (c) 2007 Andreas Rumpf
VERSION = "1.0.3"
VERSION = "1.0.4"
import os, os.path, inspect, re, shutil, glob, cPickle, zlib, string, \
getopt, sys
@ -18,6 +18,25 @@ _FINGERPRINTS_FILE = "koch.dat"
# has changed. This works reliably, which cannot be said from just taking
# filetime-stamps.
# -----------------------------------------------------------------------------
def FileCmp(filenameA, filenameB):
SIZE = 4096*2
result = True
a = file(filenameA, "rb")
b = file(filenameB, "rb")
while True:
x = a.read(SIZE)
y = b.read(SIZE)
if x != y:
result = False
break
elif len(x) < SIZE: # EOF?
break
a.close()
b.close()
return result
# ---------------- C Compilers ------------------------------------------------
# We support the following C compilers:
@ -185,6 +204,9 @@ def Subs(frmt, **substitution):
else:
return tuple([string.Template(x).substitute(substitution) for x in frmt])
def SafeSubs(frmt, **substitution):
return string.Template(frmt).safe_substitute(substitution)
_baseDir = os.getcwd()
BaseDir = _baseDir

View file

@ -17,9 +17,9 @@ proc c_memcpy(a, b: CString, size: cint) {.nodecl, importc: "memcpy".}
proc c_strlen(a: CString): cint {.nodecl, importc: "strlen".}
type
C_TextFile {.importc: "FILE", nodecl.} = record # empty record for
# data hiding
C_BinaryFile {.importc: "FILE", nodecl.} = record
C_TextFile {.importc: "FILE", nodecl, final.} = object # empty record for
# data hiding
C_BinaryFile {.importc: "FILE", nodecl, final.} = object
C_TextFileStar = ptr CTextFile
C_BinaryFileStar = ptr CBinaryFile

View file

@ -18,13 +18,13 @@ proc raiseDivByZero {.exportc: "raiseDivByZero".} =
raise newException(EDivByZero, "divison by zero")
proc addInt64(a, b: int64): int64 {.compilerProc, inline.} =
result = a + b
result = a +% b
if (result xor a) >= int64(0) or (result xor b) >= int64(0):
return result
raiseOverflow()
proc subInt64(a, b: int64): int64 {.compilerProc, inline.} =
result = a - b
result = a -% b
if (result xor a) >= int64(0) or (result xor not b) >= int64(0):
return result
raiseOverflow()
@ -74,7 +74,7 @@ proc modInt64(a, b: int64): int64 {.compilerProc, inline.} =
proc mulInt64(a, b: int64): int64 {.compilerproc.} =
var
resAsFloat, floatProd: float64
result = a * b
result = a *% b
floatProd = float64(a) # conversion
floatProd = floatProd * float64(b)
resAsFloat = float64(result)
@ -276,13 +276,13 @@ else:
# Platform independant versions of the above (slower!)
proc addInt(a, b: int): int =
result = a + b
result = a +% b
if (result xor a) >= 0 or (result xor b) >= 0:
return result
raiseOverflow()
proc subInt(a, b: int): int =
result = a - b
result = a -% b
if (result xor a) >= 0 or (result xor not b) >= 0:
return result
raiseOverflow()
@ -327,7 +327,7 @@ else:
var
resAsFloat, floatProd: float
result = a * b
result = a *% b
floatProd = toFloat(a) * toFloat(b)
resAsFloat = toFloat(result)

View file

@ -55,7 +55,8 @@ proc genericAssign(dest, src: Pointer, mt: PNimType) =
var dstseq = cast[PGenericSeq](dst)
dstseq.len = seq.len
dstseq.space = seq.len
of tyRecord, tyObject, tyTuple:
of tyObject, tyTuple, tyPureObject:
# we don't need to copy m_type field for tyObject, as they are equal anyway
genericAssignAux(dest, src, mt.node)
of tyArray, tyArrayConstr:
for i in 0..(mt.size div mt.base.size)-1:
@ -75,6 +76,7 @@ proc genericAssign(dest, src: Pointer, mt: PNimType) =
copyMem(dest, src, mt.size) # copy raw bits
proc genericSeqAssign(dest, src: Pointer, mt: PNimType) {.compilerProc.} =
var src = src # ugly, but I like to stress the parser sometimes :-)
genericAssign(dest, addr(src), mt)
proc genericAssignOpenArray(dest, src: pointer, len: int,
@ -110,7 +112,7 @@ proc objectInit(dest: Pointer, typ: PNimType) =
var pint = cast[ptr PNimType](dest)
pint^ = typ
objectInitAux(dest, typ.node)
of tyRecord:
of tyTuple, tyPureObject:
objectInitAux(dest, typ.node)
of tyArray, tyArrayConstr:
for i in 0..(typ.size div typ.base.size)-1:

View file

@ -149,13 +149,13 @@ type
cdecl.}
cairo_read_func_t* = proc (closure: Pointer, data: PByte, len: int32): cairo_status_t{.
cdecl.}
cairo_t* = record #OPAQUE
cairo_surface_t* = record #OPAQUE
cairo_pattern_t* = record #OPAQUE
cairo_scaled_font_t* = record #OPAQUE
cairo_font_face_t* = record #OPAQUE
cairo_font_options_t* = record #OPAQUE
cairo_matrix_t* = record
cairo_t* {.final.} = object #OPAQUE
cairo_surface_t* {.final.} = object #OPAQUE
cairo_pattern_t* {.final.} = object #OPAQUE
cairo_scaled_font_t* {.final.} = object #OPAQUE
cairo_font_face_t* {.final.} = object #OPAQUE
cairo_font_options_t* {.final.} = object #OPAQUE
cairo_matrix_t* {.final.} = object
xx: float64
yx: float64
xy: float64
@ -163,15 +163,15 @@ type
x0: float64
y0: float64
cairo_user_data_key_t* = record
cairo_user_data_key_t* {.final.} = object
unused: int32
cairo_glyph_t* = record
cairo_glyph_t* {.final.} = object
index: int32
x: float64
y: float64
cairo_text_extents_t* = record
cairo_text_extents_t* {.final.} = object
x_bearing: float64
y_bearing: float64
width: float64
@ -179,28 +179,28 @@ type
x_advance: float64
y_advance: float64
cairo_font_extents_t* = record
cairo_font_extents_t* {.final.} = object
ascent: float64
descent: float64
height: float64
max_x_advance: float64
max_y_advance: float64
cairo_path_data_t* = record #* _type : cairo_path_data_type_t;
# length : LongInt;
# end
cairo_path_data_t* {.final.} = object #* _type : cairo_path_data_type_t;
# length : LongInt;
# end
x: float64
y: float64
cairo_path_t* = record
cairo_path_t* {.final.} = object
status: cairo_status_t
data: Pcairo_path_data_t
num_data: int32
cairo_rectangle_t* = record
cairo_rectangle_t* {.final.} = object
x, y, width, height: float64
cairo_rectangle_list_t* = record
cairo_rectangle_list_t* {.final.} = object
status: cairo_status_t
rectangles: Pcairo_rectangle_t
num_rectangles: int32

View file

@ -56,7 +56,7 @@ type
ATK_LAYER_INVALID, ATK_LAYER_BACKGROUND, ATK_LAYER_CANVAS, ATK_LAYER_WIDGET,
ATK_LAYER_MDI, ATK_LAYER_POPUP, ATK_LAYER_OVERLAY
PAtkPropertyValues* = ptr TAtkPropertyValues
TAtkPropertyValues* = record
TAtkPropertyValues* {.final.} = object
property_name*: cstring
old_value*: TGValue
new_value*: TGValue
@ -379,7 +379,7 @@ type
TAtkAttributeSet* = TGSList
PAtkAttribute* = ptr TAtkAttribute
TAtkAttribute* = record
TAtkAttribute* {.final.} = object
name*: cstring
value*: cstring
@ -453,7 +453,7 @@ type
TAtkEventListenerInitProc* = proc ()
TAtkEventListenerInit* = proc (para1: TAtkEventListenerInitProc){.cdecl.}
PAtkKeyEventStruct* = ptr TAtkKeyEventStruct
TAtkKeyEventStruct* = record
TAtkKeyEventStruct* {.final.} = object
`type`*: gint
state*: guint
keyval*: guint

View file

@ -32,7 +32,7 @@ type
TGdkVisualClass* = object of TGObjectClass
PGdkColor* = ptr TGdkColor
TGdkColor* = record
TGdkColor* {.final.} = object
pixel*: guint32
red*: guint16
green*: guint16
@ -52,7 +52,7 @@ type
TGdkFontType* = enum
GDK_FONT_FONT, GDK_FONT_FONTSET
PGdkFont* = ptr TGdkFont
TGdkFont* = record
TGdkFont* {.final.} = object
`type`*: TGdkFontType
ascent*: gint
descent*: gint
@ -79,7 +79,7 @@ type
PGdkGCValuesMask* = ptr TGdkGCValuesMask
TGdkGCValuesMask* = int32
PGdkGCValues* = ptr TGdkGCValues
TGdkGCValues* = record
TGdkGCValues* {.final.} = object
foreground*: TGdkColor
background*: TGdkColor
font*: PGdkFont
@ -125,7 +125,7 @@ type
TGdkInputCondition* = int32
PGdkStatus* = ptr TGdkStatus
TGdkStatus* = int32
TGdkPoint* = record
TGdkPoint* {.final.} = object
x*: gint
y*: gint
@ -135,14 +135,14 @@ type
PGdkWChar* = ptr TGdkWChar
TGdkWChar* = guint32
PGdkSegment* = ptr TGdkSegment
TGdkSegment* = record
TGdkSegment* {.final.} = object
x1*: gint
y1*: gint
x2*: gint
y2*: gint
PGdkRectangle* = ptr TGdkRectangle
TGdkRectangle* = record
TGdkRectangle* {.final.} = object
x*: gint
y*: gint
width*: gint
@ -190,7 +190,7 @@ type
PGdkCursorType* = ptr TGdkCursorType
TGdkCursorType* = gint
PGdkCursor* = ptr TGdkCursor
TGdkCursor* = record
TGdkCursor* {.final.} = object
`type`*: TGdkCursorType
ref_count*: guint
@ -220,14 +220,14 @@ type
PGdkRegionBox* = ptr TGdkRegionBox
TGdkRegionBox* = TGdkSegment
PGdkRegion* = ptr TGdkRegion
TGdkRegion* = record
TGdkRegion* {.final.} = object
size*: int32
numRects*: int32
rects*: PGdkRegionBox
extents*: TGdkRegionBox
PPOINTBLOCK* = ptr TPOINTBLOCK
TPOINTBLOCK* = record
TPOINTBLOCK* {.final.} = object
pts*: array[0..(NUMPTSTOBUFFER) - 1, TGdkPoint]
next*: PPOINTBLOCK
@ -336,13 +336,13 @@ type
GDK_SETTING_ACTION_NEW, GDK_SETTING_ACTION_CHANGED,
GDK_SETTING_ACTION_DELETED
PGdkEventAny* = ptr TGdkEventAny
TGdkEventAny* = record
TGdkEventAny* {.final.} = object
`type`*: TGdkEventType
window*: PGdkWindow
send_event*: gint8
PGdkEventExpose* = ptr TGdkEventExpose
TGdkEventExpose* = record
TGdkEventExpose* {.final.} = object
`type`*: TGdkEventType
window*: PGdkWindow
send_event*: gint8
@ -351,20 +351,20 @@ type
count*: gint
PGdkEventNoExpose* = ptr TGdkEventNoExpose
TGdkEventNoExpose* = record
TGdkEventNoExpose* {.final.} = object
`type`*: TGdkEventType
window*: PGdkWindow
send_event*: gint8
PGdkEventVisibility* = ptr TGdkEventVisibility
TGdkEventVisibility* = record
TGdkEventVisibility* {.final.} = object
`type`*: TGdkEventType
window*: PGdkWindow
send_event*: gint8
state*: TGdkVisibilityState
PGdkEventMotion* = ptr TGdkEventMotion
TGdkEventMotion* = record
TGdkEventMotion* {.final.} = object
`type`*: TGdkEventType
window*: PGdkWindow
send_event*: gint8
@ -379,7 +379,7 @@ type
y_root*: gdouble
PGdkEventButton* = ptr TGdkEventButton
TGdkEventButton* = record
TGdkEventButton* {.final.} = object
`type`*: TGdkEventType
window*: PGdkWindow
send_event*: gint8
@ -394,7 +394,7 @@ type
y_root*: gdouble
PGdkEventScroll* = ptr TGdkEventScroll
TGdkEventScroll* = record
TGdkEventScroll* {.final.} = object
`type`*: TGdkEventType
window*: PGdkWindow
send_event*: gint8
@ -408,7 +408,7 @@ type
y_root*: gdouble
PGdkEventKey* = ptr TGdkEventKey
TGdkEventKey* = record
TGdkEventKey* {.final.} = object
`type`*: TGdkEventType
window*: PGdkWindow
send_event*: gint8
@ -421,7 +421,7 @@ type
group*: guint8
PGdkEventCrossing* = ptr TGdkEventCrossing
TGdkEventCrossing* = record
TGdkEventCrossing* {.final.} = object
`type`*: TGdkEventType
window*: PGdkWindow
send_event*: gint8
@ -437,14 +437,14 @@ type
state*: guint
PGdkEventFocus* = ptr TGdkEventFocus
TGdkEventFocus* = record
TGdkEventFocus* {.final.} = object
`type`*: TGdkEventType
window*: PGdkWindow
send_event*: gint8
`in`*: gint16
PGdkEventConfigure* = ptr TGdkEventConfigure
TGdkEventConfigure* = record
TGdkEventConfigure* {.final.} = object
`type`*: TGdkEventType
window*: PGdkWindow
send_event*: gint8
@ -454,7 +454,7 @@ type
height*: gint
PGdkEventProperty* = ptr TGdkEventProperty
TGdkEventProperty* = record
TGdkEventProperty* {.final.} = object
`type`*: TGdkEventType
window*: PGdkWindow
send_event*: gint8
@ -464,7 +464,7 @@ type
TGdkNativeWindow* = pointer
PGdkEventSelection* = ptr TGdkEventSelection
TGdkEventSelection* = record
TGdkEventSelection* {.final.} = object
`type`*: TGdkEventType
window*: PGdkWindow
send_event*: gint8
@ -475,7 +475,7 @@ type
requestor*: TGdkNativeWindow
PGdkEventProximity* = ptr TGdkEventProximity
TGdkEventProximity* = record
TGdkEventProximity* {.final.} = object
`type`*: TGdkEventType
window*: PGdkWindow
send_event*: gint8
@ -483,11 +483,11 @@ type
device*: PGdkDevice
PmatDUMMY* = ptr TmatDUMMY
TmatDUMMY* = record
TmatDUMMY* {.final.} = object
b*: array[0..19, char]
PGdkEventClient* = ptr TGdkEventClient
TGdkEventClient* = record
TGdkEventClient* {.final.} = object
`type`*: TGdkEventType
window*: PGdkWindow
send_event*: gint8
@ -496,7 +496,7 @@ type
b*: array[0..19, char]
PGdkEventSetting* = ptr TGdkEventSetting
TGdkEventSetting* = record
TGdkEventSetting* {.final.} = object
`type`*: TGdkEventType
window*: PGdkWindow
send_event*: gint8
@ -504,7 +504,7 @@ type
name*: cstring
PGdkEventWindowState* = ptr TGdkEventWindowState
TGdkEventWindowState* = record
TGdkEventWindowState* {.final.} = object
`type`*: TGdkEventType
window*: PGdkWindow
send_event*: gint8
@ -512,7 +512,7 @@ type
new_window_state*: TGdkWindowState
PGdkEventDND* = ptr TGdkEventDND
TGdkEventDND* = record
TGdkEventDND* {.final.} = object
`type`*: TGdkEventType
window*: PGdkWindow
send_event*: gint8
@ -521,7 +521,7 @@ type
x_root*: gshort
y_root*: gshort
TGdkEvent* = record
TGdkEvent* {.final.} = object
data*: array[0..255, char] # union of
# `type`: TGdkEventType
# any: TGdkEventAny
@ -585,12 +585,12 @@ type
PGdkAxisUse* = ptr TGdkAxisUse
TGdkAxisUse* = int32
PGdkDeviceKey* = ptr TGdkDeviceKey
TGdkDeviceKey* = record
TGdkDeviceKey* {.final.} = object
keyval*: guint
modifiers*: TGdkModifierType
PGdkDeviceAxis* = ptr TGdkDeviceAxis
TGdkDeviceAxis* = record
TGdkDeviceAxis* {.final.} = object
use*: TGdkAxisUse
min*: gdouble
max*: gdouble
@ -605,12 +605,12 @@ type
num_keys*: gint
keys*: PGdkDeviceKey
TGdkTimeCoord* = record
TGdkTimeCoord* {.final.} = object
time*: guint32
axes*: array[0..(GDK_MAX_TIMECOORD_AXES) - 1, gdouble]
PGdkKeymapKey* = ptr TGdkKeymapKey
TGdkKeymapKey* = record
TGdkKeymapKey* {.final.} = object
keycode*: guint
group*: gint
level*: gint
@ -624,12 +624,12 @@ type
direction_changed*: proc (keymap: PGdkKeymap){.cdecl.}
PGdkPangoAttrStipple* = ptr TGdkPangoAttrStipple
TGdkPangoAttrStipple* = record
TGdkPangoAttrStipple* {.final.} = object
attr*: TPangoAttribute
stipple*: PGdkBitmap
PGdkPangoAttrEmbossed* = ptr TGdkPangoAttrEmbossed
TGdkPangoAttrEmbossed* = record
TGdkPangoAttrEmbossed* {.final.} = object
attr*: TPangoAttribute
embossed*: gboolean
@ -653,7 +653,7 @@ type
GDK_OVERLAP_RECTANGLE_PART
TGdkSpanFunc* = proc (span: PGdkSpan, data: gpointer){.cdecl.}
PGdkRgbCmap* = ptr TGdkRgbCmap
TGdkRgbCmap* = record
TGdkRgbCmap* {.final.} = object
colors*: array[0..255, guint32]
n_colors*: gint
info_list*: PGSList
@ -698,7 +698,7 @@ type
TGdkInputFunction* = proc (data: gpointer, source: gint,
condition: TGdkInputCondition){.cdecl.}
TGdkDestroyNotify* = proc (data: gpointer){.cdecl.}
TGdkSpan* = record
TGdkSpan* {.final.} = object
x*: gint
y*: gint
width*: gint
@ -731,7 +731,7 @@ type
GDK_WINDOW_EDGE_SOUTH_WEST, GDK_WINDOW_EDGE_SOUTH,
GDK_WINDOW_EDGE_SOUTH_EAST
PGdkWindowAttr* = ptr TGdkWindowAttr
TGdkWindowAttr* = record
TGdkWindowAttr* {.final.} = object
title*: cstring
event_mask*: gint
x*: gint
@ -748,7 +748,7 @@ type
override_redirect*: gboolean
PGdkGeometry* = ptr TGdkGeometry
TGdkGeometry* = record
TGdkGeometry* {.final.} = object
min_width*: gint
min_height*: gint
max_width*: gint
@ -762,7 +762,7 @@ type
win_gravity*: TGdkGravity
PGdkPointerHooks* = ptr TGdkPointerHooks
TGdkPointerHooks* = record
TGdkPointerHooks* {.final.} = object
get_pointer*: proc (window: PGdkWindow, x: Pgint, y: Pgint,
mask: PGdkModifierType): PGdkWindow{.cdecl.}
window_at_pointer*: proc (screen: PGdkScreen, win_x: Pgint, win_y: Pgint): PGdkWindow{.

View file

@ -191,12 +191,12 @@ proc gdk_pixbuf_get_option*(pixbuf: PGdkPixbuf, key: cstring): cstring{.cdecl,
dynlib: gdkpixbuflib, importc: "gdk_pixbuf_get_option".}
type
PGdkPixbufLoader* = ptr TGdkPixbufLoader
TGdkPixbufLoader* = record
TGdkPixbufLoader* {.final.} = object
parent_instance*: TGObject
priv*: gpointer
PGdkPixbufLoaderClass* = ptr TGdkPixbufLoaderClass
TGdkPixbufLoaderClass* = record
TGdkPixbufLoaderClass* {.final.} = object
parent_class*: TGObjectClass
area_prepared*: proc (loader: PGdkPixbufLoader){.cdecl.}
area_updated*: proc (loader: PGdkPixbufLoader, x: int32, y: int32,

View file

@ -61,7 +61,7 @@ type
TGHFunc* = proc (key, value, user_data: gpointer){.cdecl.}
PGFreeFunc* = proc (data: gpointer){.cdecl.}
PGTimeVal* = ptr TGTimeVal
TGTimeVal* = record
TGTimeVal* {.final.} = object
tv_sec*: glong
tv_usec*: glong
@ -88,17 +88,17 @@ type
TGQuark* = guint32
PGQuark* = ptr TGQuark
PGTypeCValue* = ptr TGTypeCValue
TGTypeCValue* = record
TGTypeCValue* {.final.} = object
v_double*: gdouble
GType* = gulong
PGType* = ptr GType
PGTypeClass* = ptr TGTypeClass
TGTypeClass* = record
TGTypeClass* {.final.} = object
g_type*: GType
PGTypeInstance* = ptr TGTypeInstance
TGTypeInstance* = record
TGTypeInstance* {.final.} = object
g_class*: PGTypeClass
PGTypeInterface* = ptr TGTypeInterface
@ -107,14 +107,14 @@ type
g_instance_type*: GType
PGTypeQuery* = ptr TGTypeQuery
TGTypeQuery* = record
TGTypeQuery* {.final.} = object
theType*: GType
type_name*: cstring
class_size*: guint
instance_size*: guint
PGValue* = ptr TGValue
TGValue* = record
TGValue* {.final.} = object
g_type*: GType
data*: array[0..1, gdouble]
@ -122,12 +122,12 @@ type
PGData* = pointer
PGSList* = ptr TGSList
PPGSList* = ptr PGSList
TGSList* = record
TGSList* {.final.} = object
data*: gpointer
next*: PGSList
PGList* = ptr TGList
TGList* = record
TGList* {.final.} = object
data*: gpointer
next*: PGList
prev*: PGList
@ -136,7 +136,7 @@ type
TGParamFlags* = int32
PGParamSpec* = ptr TGParamSpec
PPGParamSpec* = ptr PGParamSpec
TGParamSpec* = record
TGParamSpec* {.final.} = object
g_type_instance*: TGTypeInstance
name*: cstring
flags*: TGParamFlags
@ -149,7 +149,7 @@ type
param_id*: guint
PGParamSpecClass* = ptr TGParamSpecClass
TGParamSpecClass* = record
TGParamSpecClass* {.final.} = object
g_type_class*: TGTypeClass
value_type*: GType
finalize*: proc (pspec: PGParamSpec){.cdecl.}
@ -160,7 +160,7 @@ type
dummy*: array[0..3, gpointer]
PGParameter* = ptr TGParameter
TGParameter* = record
TGParameter* {.final.} = object
name*: cstring
value*: TGValue
@ -305,7 +305,7 @@ const
type
PGTypeValueTable* = ptr TGTypeValueTable
TGTypeValueTable* = record
TGTypeValueTable* {.final.} = object
value_init*: proc (value: PGValue){.cdecl.}
value_free*: proc (value: PGValue){.cdecl.}
value_copy*: proc (src_value: PGValue, dest_value: PGValue){.cdecl.}
@ -320,7 +320,7 @@ type
cdecl.}
PGTypeInfo* = ptr TGTypeInfo
TGTypeInfo* = record
TGTypeInfo* {.final.} = object
class_size*: guint16
base_init*: TGBaseInitFunc
base_finalize*: TGBaseFinalizeFunc
@ -333,11 +333,11 @@ type
value_table*: PGTypeValueTable
PGTypeFundamentalInfo* = ptr TGTypeFundamentalInfo
TGTypeFundamentalInfo* = record
TGTypeFundamentalInfo* {.final.} = object
type_flags*: TGTypeFundamentalFlags
PGInterfaceInfo* = ptr TGInterfaceInfo
TGInterfaceInfo* = record
TGInterfaceInfo* {.final.} = object
interface_init*: TGInterfaceInitFunc
interface_finalize*: TGInterfaceFinalizeFunc
interface_data*: gpointer
@ -449,7 +449,7 @@ const
type
PGValueArray* = ptr TGValueArray
TGValueArray* = record
TGValueArray* {.final.} = object
n_values*: guint
values*: PGValue
n_prealloced*: guint
@ -628,7 +628,7 @@ proc g_value_set_param_take_ownership*(value: PGValue, param: PGParamSpec){.
cdecl, dynlib: gliblib, importc: "g_value_set_param_take_ownership".}
type
PGParamSpecTypeInfo* = ptr TGParamSpecTypeInfo
TGParamSpecTypeInfo* = record
TGParamSpecTypeInfo* {.final.} = object
instance_size*: guint16
n_preallocs*: guint16
instance_init*: proc (pspec: PGParamSpec){.cdecl.}
@ -668,7 +668,7 @@ type
PGClosure* = ptr TGClosure
PGClosureNotifyData* = ptr TGClosureNotifyData
TGClosureNotify* = proc (data: gpointer, closure: PGClosure){.cdecl.}
TGClosure* = record
TGClosure* {.final.} = object
flag0*: int32
marshal*: proc (closure: PGClosure, return_value: PGValue,
n_param_values: guint, param_values: PGValue,
@ -682,7 +682,7 @@ type
n_param_values: guint, param_values: PGValue,
invocation_hint: gpointer, marshal_data: gpointer){.
cdecl.}
TGClosureNotifyData* = record
TGClosureNotifyData* {.final.} = object
data*: gpointer
notify*: TGClosureNotify
@ -734,7 +734,7 @@ proc is_invalid*(a: var TGClosure): guint
proc set_is_invalid*(a: var TGClosure, is_invalid: guint)
type
PGCClosure* = ptr TGCClosure
TGCClosure* = record
TGCClosure* {.final.} = object
closure*: TGClosure
callback*: gpointer
@ -797,13 +797,13 @@ type
data: gpointer): gboolean{.cdecl.}
PGSignalFlags* = ptr TGSignalFlags
TGSignalFlags* = int32
TGSignalInvocationHint* = record
TGSignalInvocationHint* {.final.} = object
signal_id*: guint
detail*: TGQuark
run_type*: TGSignalFlags
PGSignalQuery* = ptr TGSignalQuery
TGSignalQuery* = record
TGSignalQuery* {.final.} = object
signal_id*: guint
signal_name*: cstring
itype*: GType
@ -952,7 +952,7 @@ type
TGTypePluginCompleteInterfaceInfo* = proc (plugin: PGTypePlugin,
instance_type: GType, interface_type: GType, info: PGInterfaceInfo){.cdecl.}
PGTypePluginClass* = ptr TGTypePluginClass
TGTypePluginClass* = record
TGTypePluginClass* {.final.} = object
base_iface*: TGTypeInterface
use_plugin*: TGTypePluginUse
unuse_plugin*: TGTypePluginUnuse
@ -1011,7 +1011,7 @@ type
notify*: proc (anObject: PGObject, pspec: PGParamSpec){.cdecl.}
pdummy*: array[0..7, gpointer]
TGObjectConstructParam* = record
TGObjectConstructParam* {.final.} = object
pspec*: PGParamSpec
value*: PGValue
@ -1125,27 +1125,27 @@ proc GUINT32_SWAP_LE_BE_CONSTANT*(val: guint32): guint32
type
PGEnumClass* = ptr TGEnumClass
PGEnumValue* = ptr TGEnumValue
TGEnumClass* = record
TGEnumClass* {.final.} = object
g_type_class*: TGTypeClass
minimum*: gint
maximum*: gint
n_values*: guint
values*: PGEnumValue
TGEnumValue* = record
TGEnumValue* {.final.} = object
value*: gint
value_name*: cstring
value_nick*: cstring
PGFlagsClass* = ptr TGFlagsClass
PGFlagsValue* = ptr TGFlagsValue
TGFlagsClass* = record
TGFlagsClass* {.final.} = object
g_type_class*: TGTypeClass
mask*: guint
n_values*: guint
values*: PGFlagsValue
TGFlagsValue* = record
TGFlagsValue* {.final.} = object
value*: guint
value_name*: cstring
value_nick*: cstring
@ -1203,7 +1203,7 @@ const
G_MAXUSHORT* = 2 * G_MAXSHORT + 1
G_MAXINT* = 2147483647
G_MININT* = - G_MAXINT - 1
G_MAXUINT* = 4294967295
G_MAXUINT* = -1
G_MINLONG* = G_MININT
G_MAXLONG* = G_MAXINT
G_MAXULONG* = G_MAXUINT
@ -1224,7 +1224,7 @@ const
type
PGSystemThread* = ptr TGSystemThread
TGSystemThread* = record
TGSystemThread* {.final.} = object
data*: array[0..3, char]
dummy_double*: float64
dummy_pointer*: pointer
@ -1350,7 +1350,7 @@ proc g_set_prgname*(prgname: cstring){.cdecl, dynlib: gliblib,
importc: "g_set_prgname".}
type
PGDebugKey* = ptr TGDebugKey
TGDebugKey* = record
TGDebugKey* {.final.} = object
key*: cstring
value*: guint
@ -1390,7 +1390,7 @@ proc g_bit_storage*(number: gulong): guint{.cdecl, dynlib: gliblib,
type
PPGTrashStack* = ptr PGTrashStack
PGTrashStack* = ptr TGTrashStack
TGTrashStack* = record
TGTrashStack* {.final.} = object
next*: PGTrashStack
@ -1466,7 +1466,7 @@ const
type
PGMemVTable* = ptr TGMemVTable
TGMemVTable* = record
TGMemVTable* {.final.} = object
malloc*: proc (n_bytes: gsize): gpointer{.cdecl.}
realloc*: proc (mem: gpointer, n_bytes: gsize): gpointer{.cdecl.}
free*: proc (mem: gpointer){.cdecl.}
@ -1679,7 +1679,7 @@ type
TGCompletionStrncmpFunc* = proc (s1: cstring, s2: cstring, n: gsize): gint{.
cdecl.}
PGCompletion* = ptr TGCompletion
TGCompletion* = record
TGCompletion* {.final.} = object
items*: PGList
func*: TGCompletionFunc
prefix*: cstring
@ -1809,7 +1809,7 @@ type
PGDateDay* = ptr TGDateDay
TGDateDay* = guint8
Ptm* = ptr Ttm
Ttm* = record
Ttm* {.final.} = object
tm_sec*: gint
tm_min*: gint
tm_hour*: gint
@ -1872,7 +1872,7 @@ const
type
PGDate* = ptr TGDate
TGDate* = record
TGDate* {.final.} = object
flag0*: int32
flag1*: int32
@ -2028,7 +2028,7 @@ proc g_file_open_tmp*(tmpl: cstring, name_used: PPchar, error: pointer): int32{.
cdecl, dynlib: gliblib, importc: "g_file_open_tmp".}
type
PGHook* = ptr TGHook
TGHook* = record
TGHook* {.final.} = object
data*: gpointer
next*: PGHook
prev*: PGHook
@ -2047,7 +2047,7 @@ type
TGHookFunc* = proc (data: gpointer){.cdecl.}
TGHookCheckFunc* = proc (data: gpointer): gboolean{.cdecl.}
TGHookFinalizeFunc* = proc (hook_list: PGHookList, hook: PGHook){.cdecl.}
TGHookList* = record
TGHookList* {.final.} = object
seq_id*: gulong
flag0*: int32
hooks*: PGHook
@ -2138,7 +2138,7 @@ proc g_hook_list_marshal_check*(hook_list: PGHookList, may_recurse: gboolean,
importc: "g_hook_list_marshal_check".}
type
PGThreadPool* = ptr TGThreadPool
TGThreadPool* = record
TGThreadPool* {.final.} = object
func*: TGFunc
user_data*: gpointer
exclusive*: gboolean
@ -2352,7 +2352,7 @@ proc g_utf8_collate_key*(str: cstring, len: gssize): cstring{.cdecl,
dynlib: gliblib, importc: "g_utf8_collate_key".}
type
PGString* = ptr TGString
TGString* = record
TGString* {.final.} = object
str*: cstring
len*: gsize
allocated_len*: gsize
@ -2468,7 +2468,7 @@ type
TGIOFunc* = proc (source: PGIOChannel, condition: TGIOCondition,
data: gpointer): gboolean{.cdecl.}
PGIOFuncs* = ptr TGIOFuncs
TGIOFuncs* = record
TGIOFuncs* {.final.} = object
io_read*: proc (channel: PGIOChannel, buf: cstring, count: gsize,
bytes_read: Pgsize, err: pointer): TGIOStatus{.cdecl.}
io_write*: proc (channel: PGIOChannel, buf: cstring, count: gsize,
@ -2483,7 +2483,7 @@ type
cdecl.}
io_get_flags*: proc (channel: PGIOChannel): TGIOFlags{.cdecl.}
TGIOChannel* = record
TGIOChannel* {.final.} = object
ref_count*: guint
funcs*: PGIOFuncs
encoding*: cstring
@ -2699,7 +2699,7 @@ type
PGMarkupParseContext* = ptr TGMarkupParseContext
TGMarkupParseContext* = pointer
PGMarkupParser* = ptr TGMarkupParser
TGMarkupParser* = record
TGMarkupParser* {.final.} = object
start_element*: proc (context: PGMarkupParseContext, element_name: cstring,
attribute_names: PPgchar, attribute_values: PPgchar,
user_data: gpointer, error: pointer){.cdecl.}
@ -2733,7 +2733,7 @@ proc g_markup_escape_text*(text: cstring, length: gssize): cstring{.cdecl,
dynlib: gliblib, importc: "g_markup_escape_text".}
type
PGNode* = ptr TGNode
TGNode* = record
TGNode* {.final.} = object
data*: gpointer
next*: PGNode
prev*: PGNode
@ -2886,7 +2886,7 @@ proc g_qsort_with_data*(pbase: gconstpointer, total_elems: gint, size: gsize,
cdecl, dynlib: gliblib, importc: "g_qsort_with_data".}
type
PGQueue* = ptr TGQueue
TGQueue* = record
TGQueue* {.final.} = object
head*: PGList
tail*: PGList
length*: guint
@ -2947,7 +2947,7 @@ proc g_random_double_range*(`begin`: gdouble, `end`: gdouble): gdouble{.cdecl,
dynlib: gliblib, importc: "g_random_double_range".}
type
PGTuples* = ptr TGTuples
TGTuples* = record
TGTuples* {.final.} = object
len*: guint
PGRelation* = pointer
@ -3003,12 +3003,12 @@ type
PGScanner* = ptr TGScanner
PGScannerConfig* = ptr TGScannerConfig
PGTokenValue* = ptr TGTokenValue
TGTokenValue* = record
TGTokenValue* {.final.} = object
v_float*: gdouble
TGScannerMsgFunc* = proc (scanner: PGScanner, message: cstring,
error: gboolean){.cdecl.}
TGScanner* = record
TGScanner* {.final.} = object
user_data*: gpointer
max_parse_errors*: guint
parse_errors*: guint
@ -3031,7 +3031,7 @@ type
scope_id*: guint
msg_handler*: TGScannerMsgFunc
TGScannerConfig* = record
TGScannerConfig* {.final.} = object
cset_skip_characters*: cstring
cset_identifier_first*: cstring
cset_identifier_nth*: cstring

View file

@ -155,17 +155,17 @@ type
TGtkSignalFunc* = proc (para1: TGtkSignalFuncProc){.cdecl.}
PGtkSignalMarshaller* = ptr TGtkSignalMarshaller
TGtkSignalMarshaller* = TGSignalCMarshaller
TGtkArgSignalData* = record
TGtkArgSignalData* {.final.} = object
f*: TGtkSignalFunc
d*: gpointer
TGtkArg* = record
TGtkArg* {.final.} = object
`type`*: TGtkType
name*: cstring
d*: gdouble # was a union type
PGtkTypeInfo* = ptr TGtkTypeInfo
TGtkTypeInfo* = record
TGtkTypeInfo* {.final.} = object
type_name*: cstring
object_size*: guint
class_size*: guint
@ -188,7 +188,7 @@ type
TGtkAllocation* = TGdkRectangle
TGtkCallback* = proc (widget: PGtkWidget, data: gpointer){.cdecl.}
PGtkRequisition* = ptr TGtkRequisition
TGtkRequisition* = record
TGtkRequisition* {.final.} = object
width*: gint
height*: gint
@ -323,7 +323,7 @@ type
gtk_reserved8*: proc (){.cdecl.}
PGtkWidgetAuxInfo* = ptr TGtkWidgetAuxInfo
TGtkWidgetAuxInfo* = record
TGtkWidgetAuxInfo* {.final.} = object
x*: gint
y*: gint
width*: gint
@ -331,7 +331,7 @@ type
flag0*: guint16
PGtkWidgetShapeInfo* = ptr TGtkWidgetShapeInfo
TGtkWidgetShapeInfo* = record
TGtkWidgetShapeInfo* {.final.} = object
offset_x*: gint16
offset_y*: gint16
shape_mask*: PGdkBitmap
@ -370,12 +370,12 @@ type
gtk_reserved4: proc (){.cdecl.}
PGtkAccelKey* = ptr TGtkAccelKey
TGtkAccelKey* = record
TGtkAccelKey* {.final.} = object
accel_key*: guint
accel_mods*: TGdkModifierType
flag0*: guint16
TGtkAccelGroupEntry* = record
TGtkAccelGroupEntry* {.final.} = object
key*: TGtkAccelKey
closure*: PGClosure
accel_path_quark*: TGQuark
@ -595,7 +595,7 @@ type
PGtkBindingSignal* = ptr TGtkBindingSignal
PGtkBindingArg* = ptr TGtkBindingArg
PGtkBindingSet* = ptr TGtkBindingSet
TGtkBindingSet* = record
TGtkBindingSet* {.final.} = object
set_name*: cstring
priority*: gint
widget_path_pspecs*: PGSList
@ -605,7 +605,7 @@ type
current*: PGtkBindingEntry
flag0*: guint16
TGtkBindingEntry* = record
TGtkBindingEntry* {.final.} = object
keyval*: guint
modifiers*: TGdkModifierType
binding_set*: PGtkBindingSet
@ -614,13 +614,13 @@ type
hash_next*: PGtkBindingEntry
signals*: PGtkBindingSignal
TGtkBindingSignal* = record
TGtkBindingSignal* {.final.} = object
next*: PGtkBindingSignal
signal_name*: cstring
n_args*: guint
args*: PGtkBindingArg
TGtkBindingArg* = record
TGtkBindingArg* {.final.} = object
arg_type*: TGtkType
d*: gdouble
@ -634,7 +634,7 @@ type
TGtkBoxClass* = object of TGtkContainerClass
PGtkBoxChild* = ptr TGtkBoxChild
TGtkBoxChild* = record
TGtkBoxChild* {.final.} = object
widget*: PGtkWidget
padding*: guint16
flag0*: guint16
@ -906,12 +906,12 @@ type
TGtkCListCompareFunc* = proc (clist: PGtkCList, ptr1: gconstpointer,
ptr2: gconstpointer): gint{.cdecl.}
PGtkCListCellInfo* = ptr TGtkCListCellInfo
TGtkCListCellInfo* = record
TGtkCListCellInfo* {.final.} = object
row*: gint
column*: gint
PGtkCListDestInfo* = ptr TGtkCListDestInfo
TGtkCListDestInfo* = record
TGtkCListDestInfo* {.final.} = object
cell*: TGtkCListCellInfo
insert_pos*: TGtkCListDragPos
@ -1014,7 +1014,7 @@ type
PGPtrArray = pointer
PGArray = pointer
TGtkCListColumn* = record
TGtkCListColumn* {.final.} = object
title*: cstring
area*: TGdkRectangle
button*: PGtkWidget
@ -1025,7 +1025,7 @@ type
justification*: TGtkJustification
flag0*: guint16
TGtkCListRow* = record
TGtkCListRow* {.final.} = object
cell*: PGtkCell
state*: TGtkStateType
foreground*: TGdkColor
@ -1036,7 +1036,7 @@ type
flag0*: guint16
PGtkCellText* = ptr TGtkCellText
TGtkCellText* = record
TGtkCellText* {.final.} = object
`type`*: TGtkCellType
vertical*: gint16
horizontal*: gint16
@ -1044,7 +1044,7 @@ type
text*: cstring
PGtkCellPixmap* = ptr TGtkCellPixmap
TGtkCellPixmap* = record
TGtkCellPixmap* {.final.} = object
`type`*: TGtkCellType
vertical*: gint16
horizontal*: gint16
@ -1053,7 +1053,7 @@ type
mask*: PGdkBitmap
PGtkCellPixText* = ptr TGtkCellPixText
TGtkCellPixText* = record
TGtkCellPixText* {.final.} = object
`type`*: TGtkCellType
vertical*: gint16
horizontal*: gint16
@ -1064,14 +1064,14 @@ type
mask*: PGdkBitmap
PGtkCellWidget* = ptr TGtkCellWidget
TGtkCellWidget* = record
TGtkCellWidget* {.final.} = object
`type`*: TGtkCellType
vertical*: gint16
horizontal*: gint16
style*: PGtkStyle
widget*: PGtkWidget
TGtkCell* = record
TGtkCell* {.final.} = object
`type`*: TGtkCellType
vertical*: gint16
horizontal*: gint16
@ -1212,7 +1212,7 @@ type
action: TGtkCTreeExpansionType){.cdecl.}
PGtkCTreeRow* = ptr TGtkCTreeRow
TGtkCTreeRow* = record
TGtkCTreeRow* {.final.} = object
row*: TGtkCListRow
parent*: PGtkCTreeNode
sibling*: PGtkCTreeNode
@ -1224,7 +1224,7 @@ type
level*: guint16
GtkCTreeRow_flag0*: guint16
TGtkCTreeNode* = record
TGtkCTreeNode* {.final.} = object
list*: TGList
PGtkDrawingArea* = ptr TGtkDrawingArea
@ -1479,7 +1479,7 @@ type
TGtkFixedClass* = object of TGtkContainerClass
PGtkFixedChild* = ptr TGtkFixedChild
TGtkFixedChild* = record
TGtkFixedChild* {.final.} = object
widget*: PGtkWidget
x*: gint
y*: gint
@ -1632,7 +1632,7 @@ type
gtk_reserved363: proc (){.cdecl.}
gtk_reserved364: proc (){.cdecl.}
TGtkRulerMetric* = record
TGtkRulerMetric* {.final.} = object
metric_name*: cstring
abbrev*: cstring
pixels_per_unit*: gdouble
@ -1657,7 +1657,7 @@ type
TGtkSettingsClass* = object of TGObjectClass
PGtkSettingsValue* = ptr TGtkSettingsValue
TGtkSettingsValue* = record
TGtkSettingsValue* {.final.} = object
origin*: cstring
value*: TGValue
@ -1708,7 +1708,7 @@ type
GTK_RC_TOKEN_IM_MODULE_FILE, GTK_RC_TOKEN_STOCK, GTK_RC_TOKEN_LTR,
GTK_RC_TOKEN_RTL, GTK_RC_TOKEN_LAST
PGtkRcProperty* = ptr TGtkRcProperty
TGtkRcProperty* = record
TGtkRcProperty* {.final.} = object
type_name*: TGQuark
property_name*: TGQuark
origin*: cstring
@ -1877,7 +1877,7 @@ type
gtk_reserved3812: proc (){.cdecl.}
PGtkBorder* = ptr TGtkBorder
TGtkBorder* = record
TGtkBorder* {.final.} = object
left*: gint
right*: gint
top*: gint
@ -1978,27 +1978,27 @@ type
PGtkIconSet* = pointer
PGtkImagePixmapData* = ptr TGtkImagePixmapData
TGtkImagePixmapData* = record
TGtkImagePixmapData* {.final.} = object
pixmap*: PGdkPixmap
PGtkImageImageData* = ptr TGtkImageImageData
TGtkImageImageData* = record
TGtkImageImageData* {.final.} = object
image*: PGdkImage
PGtkImagePixbufData* = ptr TGtkImagePixbufData
TGtkImagePixbufData* = record
TGtkImagePixbufData* {.final.} = object
pixbuf*: PGdkPixbuf
PGtkImageStockData* = ptr TGtkImageStockData
TGtkImageStockData* = record
TGtkImageStockData* {.final.} = object
stock_id*: cstring
PGtkImageIconSetData* = ptr TGtkImageIconSetData
TGtkImageIconSetData* = record
TGtkImageIconSetData* {.final.} = object
icon_set*: PGtkIconSet
PGtkImageAnimationData* = ptr TGtkImageAnimationData
TGtkImageAnimationData* = record
TGtkImageAnimationData* {.final.} = object
anim*: PGdkPixbufAnimation
iter*: PGdkPixbufAnimationIter
frame_timeout*: guint
@ -2111,7 +2111,7 @@ type
gtk_reserved474: proc (){.cdecl.}
PGtkItemFactoryEntry* = ptr TGtkItemFactoryEntry
TGtkItemFactoryEntry* = record
TGtkItemFactoryEntry* {.final.} = object
path*: cstring
accelerator*: cstring
callback*: TGtkItemFactoryCallback
@ -2120,7 +2120,7 @@ type
extra_data*: gconstpointer
PGtkItemFactoryItem* = ptr TGtkItemFactoryItem
TGtkItemFactoryItem* = record
TGtkItemFactoryItem* {.final.} = object
path*: cstring
widgets*: PGSList
@ -2173,7 +2173,7 @@ type
cdecl.}
PGtkTreeModelFlags* = ptr TGtkTreeModelFlags
TGtkTreeModelFlags* = int32
TGtkTreeIter* = record
TGtkTreeIter* {.final.} = object
stamp*: gint
user_data*: gpointer
user_data2*: gpointer
@ -2435,12 +2435,12 @@ type
GtkPreview_flag0*: guint16
PGtkPreviewInfo* = ptr TGtkPreviewInfo
TGtkPreviewInfo* = record
TGtkPreviewInfo* {.final.} = object
lookup*: Pguchar
gamma*: gdouble
PGtkDitherInfo* = ptr TGtkDitherInfo
TGtkDitherInfo* = record
TGtkDitherInfo* {.final.} = object
c*: array[0..3, guchar]
PGtkPreviewClass* = ptr TGtkPreviewClass
@ -2533,7 +2533,7 @@ type
gtk_reserved603: proc (){.cdecl.}
gtk_reserved604: proc (){.cdecl.}
TGtkSelectionData* = record
TGtkSelectionData* {.final.} = object
selection*: TGdkAtom
target*: TGdkAtom
thetype*: TGdkAtom
@ -2543,18 +2543,18 @@ type
display*: PGdkDisplay
PGtkTargetEntry* = ptr TGtkTargetEntry
TGtkTargetEntry* = record
TGtkTargetEntry* {.final.} = object
target*: cstring
flags*: guint
info*: guint
PGtkTargetList* = ptr TGtkTargetList
TGtkTargetList* = record
TGtkTargetList* {.final.} = object
list*: PGList
ref_count*: guint
PGtkTargetPair* = ptr TGtkTargetPair
TGtkTargetPair* = record
TGtkTargetPair* {.final.} = object
target*: TGdkAtom
flags*: guint
info*: guint
@ -2635,7 +2635,7 @@ type
gtk_reserved634: proc (){.cdecl.}
PGtkStockItem* = ptr TGtkStockItem
TGtkStockItem* = record
TGtkStockItem* {.final.} = object
stock_id*: cstring
label*: cstring
modifier*: TGdkModifierType
@ -2681,7 +2681,7 @@ type
TGtkTableClass* = object of TGtkContainerClass
PGtkTableChild* = ptr TGtkTableChild
TGtkTableChild* = record
TGtkTableChild* {.final.} = object
widget*: PGtkWidget
left_attach*: guint16
right_attach*: guint16
@ -2691,7 +2691,7 @@ type
ypadding*: guint16
GtkTableChild_flag0*: guint16
TGtkTableRowCol* = record
TGtkTableRowCol* {.final.} = object
requisition*: guint16
allocation*: guint16
spacing*: guint16
@ -2710,7 +2710,7 @@ type
PGtkTextFont* = pointer
PGtkPropertyMark* = ptr TGtkPropertyMark
TGtkPropertyMark* = record
TGtkPropertyMark* {.final.} = object
`property`*: PGList
offset*: guint
index*: guint
@ -2764,7 +2764,7 @@ type
PGtkTextSearchFlags* = ptr TGtkTextSearchFlags
TGtkTextSearchFlags* = int32
PGtkTextIter* = ptr TGtkTextIter
TGtkTextIter* = record
TGtkTextIter* {.final.} = object
dummy1*: gpointer
dummy2*: gpointer
dummy3*: gint
@ -2802,7 +2802,7 @@ type
gtk_reserved664: proc (){.cdecl.}
PGtkTextAppearance* = ptr TGtkTextAppearance
TGtkTextAppearance* = record
TGtkTextAppearance* {.final.} = object
bg_color*: TGdkColor
fg_color*: TGdkColor
bg_stipple*: PGdkBitmap
@ -2811,7 +2811,7 @@ type
padding1*: gpointer
flag0*: guint16
TGtkTextAttributes* = record
TGtkTextAttributes* {.final.} = object
refcount*: guint
appearance*: TGtkTextAppearance
justification*: TGtkJustification
@ -2860,7 +2860,7 @@ type
gtk_reserved4: proc (){.cdecl.}
PGtkTextMarkBody* = ptr TGtkTextMarkBody
TGtkTextMarkBody* = record
TGtkTextMarkBody* {.final.} = object
obj*: PGtkTextMark
name*: cstring
tree*: PGtkTextBTree
@ -2879,11 +2879,11 @@ type
gtk_reserved4: proc (){.cdecl.}
PGtkTextPixbuf* = ptr TGtkTextPixbuf
TGtkTextPixbuf* = record
TGtkTextPixbuf* {.final.} = object
pixbuf*: PGdkPixbuf
PGtkTextChildBody* = ptr TGtkTextChildBody
TGtkTextChildBody* = record
TGtkTextChildBody* {.final.} = object
obj*: PGtkTextChildAnchor
widgets*: PGSList
tree*: PGtkTextBTree
@ -2892,17 +2892,17 @@ type
PGtkTextLineSegment* = ptr TGtkTextLineSegment
PGtkTextLineSegmentClass* = ptr TGtkTextLineSegmentClass
PGtkTextTagInfo* = ptr TGtkTextTagInfo
TGtkTextTagInfo* = record
TGtkTextTagInfo* {.final.} = object
tag*: PGtkTextTag
tag_root*: PGtkTextBTreeNode
toggle_count*: gint
PGtkTextToggleBody* = ptr TGtkTextToggleBody
TGtkTextToggleBody* = record
TGtkTextToggleBody* {.final.} = object
info*: PGtkTextTagInfo
inNodeCounts*: gboolean
TGtkTextLineSegment* = record
TGtkTextLineSegment* {.final.} = object
`type`*: PGtkTextLineSegmentClass
next*: PGtkTextLineSegment
char_count*: int32
@ -2919,7 +2919,7 @@ type
line: PGtkTextLine){.cdecl.}
TGtkTextSegCheckFunc* = proc (seg: PGtkTextLineSegment, line: PGtkTextLine){.
cdecl.}
TGtkTextLineSegmentClass* = record
TGtkTextLineSegmentClass* {.final.} = object
name*: cstring
leftGravity*: gboolean
splitFunc*: TGtkTextSegSplitFunc
@ -2929,13 +2929,13 @@ type
checkFunc*: TGtkTextSegCheckFunc
PGtkTextLineData* = ptr TGtkTextLineData
TGtkTextLineData* = record
TGtkTextLineData* {.final.} = object
view_id*: gpointer
next*: PGtkTextLineData
height*: gint
flag0*: int32
TGtkTextLine* = record
TGtkTextLine* {.final.} = object
parent*: PGtkTextBTreeNode
next*: PGtkTextLine
segments*: PGtkTextLineSegment
@ -3020,18 +3020,18 @@ type
gtk_reserved4: proc (){.cdecl.}
PGtkTextAttrAppearance* = ptr TGtkTextAttrAppearance
TGtkTextAttrAppearance* = record
TGtkTextAttrAppearance* {.final.} = object
attr*: TPangoAttribute
appearance*: TGtkTextAppearance
PGtkTextCursorDisplay* = ptr TGtkTextCursorDisplay
TGtkTextCursorDisplay* = record
TGtkTextCursorDisplay* {.final.} = object
x*: gint
y*: gint
height*: gint
flag0*: guint16
TGtkTextLineDisplay* = record
TGtkTextLineDisplay* {.final.} = object
layout*: PPangoLayout
cursors*: PGSList
shaped_objects*: PGSList
@ -3152,7 +3152,7 @@ type
PGtkTooltips* = ptr TGtkTooltips
PGtkTooltipsData* = ptr TGtkTooltipsData
TGtkTooltipsData* = record
TGtkTooltipsData* {.final.} = object
tooltips*: PGtkTooltips
widget*: PGtkWidget
tip_text*: cstring
@ -3184,7 +3184,7 @@ type
TGtkToolbarSpaceStyle* = enum
GTK_TOOLBAR_SPACE_EMPTY, GTK_TOOLBAR_SPACE_LINE
PGtkToolbarChild* = ptr TGtkToolbarChild
TGtkToolbarChild* = record
TGtkToolbarChild* {.final.} = object
`type`*: TGtkToolbarChildType
widget*: PGtkWidget
icon*: PGtkWidget
@ -3365,13 +3365,13 @@ type
PGtkRBNode* = ptr TGtkRBNode
TGtkRBTreeTraverseFunc* = proc (tree: PGtkRBTree, node: PGtkRBNode,
data: gpointer){.cdecl.}
TGtkRBTree* = record
TGtkRBTree* {.final.} = object
root*: PGtkRBNode
`nil`*: PGtkRBNode
parent_tree*: PGtkRBTree
parent_node*: PGtkRBNode
TGtkRBNode* = record
TGtkRBNode* {.final.} = object
flag0*: guint16
left*: PGtkRBNode
right*: PGtkRBNode
@ -3386,14 +3386,14 @@ type
TGtkTreeViewSearchDialogPositionFunc* = proc (tree_view: PGtkTreeView,
search_dialog: PGtkWidget){.cdecl.}
PGtkTreeViewColumnReorder* = ptr TGtkTreeViewColumnReorder
TGtkTreeViewColumnReorder* = record
TGtkTreeViewColumnReorder* {.final.} = object
left_align*: gint
right_align*: gint
left_column*: PGtkTreeViewColumn
right_column*: PGtkTreeViewColumn
PGtkTreeViewPrivate* = ptr TGtkTreeViewPrivate
TGtkTreeViewPrivate* = record
TGtkTreeViewPrivate* {.final.} = object
model*: PGtkTreeModel
flags*: guint
tree*: PGtkRBTree
@ -11304,96 +11304,127 @@ proc GTK_FUNDAMENTAL_TYPE*(thetype: GType): GType =
result = G_TYPE_FUNDAMENTAL(thetype)
proc GTK_VALUE_CHAR*(a: TGtkArg): gchar =
var a = a
Result = cast[ptr gchar](addr(a.d))^
proc GTK_VALUE_UCHAR*(a: TGtkArg): guchar =
var a = a
Result = cast[ptr guchar](addr(a.d))^
proc GTK_VALUE_BOOL*(a: TGtkArg): gboolean =
var a = a
Result = cast[ptr gboolean](addr(a.d))^
proc GTK_VALUE_INT*(a: TGtkArg): gint =
var a = a
Result = cast[ptr gint](addr(a.d))^
proc GTK_VALUE_UINT*(a: TGtkArg): guint =
var a = a
Result = cast[ptr guint](addr(a.d))^
proc GTK_VALUE_LONG*(a: TGtkArg): glong =
var a = a
Result = cast[ptr glong](addr(a.d))^
proc GTK_VALUE_ULONG*(a: TGtkArg): gulong =
var a = a
Result = cast[ptr gulong](addr(a.d))^
proc GTK_VALUE_FLOAT*(a: TGtkArg): gfloat =
var a = a
Result = cast[ptr gfloat](addr(a.d))^
proc GTK_VALUE_DOUBLE*(a: TGtkArg): gdouble =
var a = a
Result = cast[ptr gdouble](addr(a.d))^
proc GTK_VALUE_STRING*(a: TGtkArg): cstring =
var a = a
Result = cast[ptr cstring](addr(a.d))^
proc GTK_VALUE_ENUM*(a: TGtkArg): gint =
var a = a
Result = cast[ptr gint](addr(a.d))^
proc GTK_VALUE_FLAGS*(a: TGtkArg): guint =
var a = a
Result = cast[ptr guint](addr(a.d))^
proc GTK_VALUE_BOXED*(a: TGtkArg): gpointer =
var a = a
Result = cast[ptr gpointer](addr(a.d))^
proc GTK_VALUE_OBJECT*(a: TGtkArg): PGtkObject =
var a = a
Result = cast[ptr PGtkObject](addr(a.d))^
proc GTK_VALUE_POINTER*(a: TGtkArg): GPointer =
var a = a
Result = cast[ptr gpointer](addr(a.d))^
proc GTK_VALUE_SIGNAL*(a: TGtkArg): TGtkArgSignalData =
var a = a
Result = cast[ptr TGtkArgSignalData](addr(a.d))^
proc GTK_RETLOC_CHAR*(a: TGtkArg): cstring =
var a = a
Result = cast[ptr cstring](addr(a.d))^
proc GTK_RETLOC_UCHAR*(a: TGtkArg): Pguchar =
var a = a
Result = cast[ptr pguchar](addr(a.d))^
proc GTK_RETLOC_BOOL*(a: TGtkArg): Pgboolean =
var a = a
Result = cast[ptr pgboolean](addr(a.d))^
proc GTK_RETLOC_INT*(a: TGtkArg): Pgint =
var a = a
Result = cast[ptr pgint](addr(a.d))^
proc GTK_RETLOC_UINT*(a: TGtkArg): Pguint =
var a = a
Result = cast[ptr pguint](addr(a.d))^
proc GTK_RETLOC_LONG*(a: TGtkArg): Pglong =
var a = a
Result = cast[ptr pglong](addr(a.d))^
proc GTK_RETLOC_ULONG*(a: TGtkArg): Pgulong =
var a = a
Result = cast[ptr pgulong](addr(a.d))^
proc GTK_RETLOC_FLOAT*(a: TGtkArg): Pgfloat =
var a = a
Result = cast[ptr pgfloat](addr(a.d))^
proc GTK_RETLOC_DOUBLE*(a: TGtkArg): Pgdouble =
var a = a
Result = cast[ptr pgdouble](addr(a.d))^
proc GTK_RETLOC_STRING*(a: TGtkArg): Ppgchar =
var a = a
Result = cast[ptr Ppgchar](addr(a.d))^
proc GTK_RETLOC_ENUM*(a: TGtkArg): Pgint =
var a = a
Result = cast[ptr Pgint](addr(a.d))^
proc GTK_RETLOC_FLAGS*(a: TGtkArg): Pguint =
var a = a
Result = cast[ptr pguint](addr(a.d))^
proc GTK_RETLOC_BOXED*(a: TGtkArg): Pgpointer =
var a = a
Result = cast[ptr pgpointer](addr(a.d))^
proc GTK_RETLOC_OBJECT*(a: TGtkArg): PPGtkObject =
var a = a
Result = cast[ptr ppgtkobject](addr(a.d))^
proc GTK_RETLOC_POINTER*(a: TGtkArg): Pgpointer =
var a = a
Result = cast[ptr pgpointer](addr(a.d))^
proc GTK_TYPE_WIDGET*(): GType =
@ -15108,7 +15139,7 @@ proc gtk_signal_handler_pending_by_func*(anObject: PGtkObject, signal_id: guint,
G_SIGNAL_MATCH_DATA)
if not may_be_blocked:
t = t or cast[int](G_SIGNAL_MATCH_UNBLOCKED)
Result = g_signal_handler_find(anObject, t, signal_id, 0, nil, addr(func_),
Result = g_signal_handler_find(anObject, t, signal_id, 0, nil, func_,
data) != 0
proc GTK_TYPE_SIZE_GROUP*(): GType =
@ -17045,7 +17076,7 @@ type
GTK_FILE_FILTER_FILENAME = 1 shl 0, GTK_FILE_FILTER_URI = 1 shl 1,
GTK_FILE_FILTER_DISPLAY_NAME = 1 shl 2, GTK_FILE_FILTER_MIME_TYPE = 1 shl 3
PGtkFileFilterInfo* = ref TGtkFileFilterInfo
TGtkFileFilterInfo* = record
TGtkFileFilterInfo* {.final.} = object
contains*: TGtkFileFilterFlags
filename*: cstring
uri*: cstring

View file

@ -68,12 +68,12 @@ type
exc: PDomException): PDomString{.cdecl.}
PDomDocument* = ptr TDomDocument
TDomDocument* = record
TDomDocument* {.final.} = object
parent*: PDomNode
iterators*: PGSList
PDomDocumentClass* = ptr TDomDocumentClass
TDomDocumentClass* = record
TDomDocumentClass* {.final.} = object
parent_class*: PDomNodeClass
PHtmlFocusIterator* = ptr THtmlFocusIterator

View file

@ -50,7 +50,7 @@ type
PPangoGlyph* = ptr TPangoGlyph
TPangoGlyph* = guint32
PPangoRectangle* = ptr TPangoRectangle
TPangoRectangle* = record
TPangoRectangle* {.final.} = object
x*: int32
y*: int32
width*: int32
@ -61,7 +61,7 @@ type
PANGO_DIRECTION_LTR, PANGO_DIRECTION_RTL, PANGO_DIRECTION_TTB_LTR,
PANGO_DIRECTION_TTB_RTL
PPangoColor* = ptr TPangoColor
TPangoColor* = record
TPangoColor* {.final.} = object
red*: guint16
green*: guint16
blue*: guint16
@ -72,12 +72,12 @@ type
TPangoUnderline* = int32
PPangoAttribute* = ptr TPangoAttribute
PPangoAttrClass* = ptr TPangoAttrClass
TPangoAttribute* = record
TPangoAttribute* {.final.} = object
klass*: PPangoAttrClass
start_index*: int
end_index*: int
TPangoAttrClass* = record
TPangoAttrClass* {.final.} = object
`type`*: TPangoAttrType
copy*: proc (attr: PPangoAttribute): PPangoAttribute{.cdecl.}
destroy*: proc (attr: PPangoAttribute){.cdecl.}
@ -85,43 +85,43 @@ type
cdecl.}
PPangoAttrString* = ptr TPangoAttrString
TPangoAttrString* = record
TPangoAttrString* {.final.} = object
attr*: TPangoAttribute
value*: cstring
PPangoAttrLanguage* = ptr TPangoAttrLanguage
TPangoAttrLanguage* = record
TPangoAttrLanguage* {.final.} = object
attr*: TPangoAttribute
value*: PPangoLanguage
PPangoAttrInt* = ptr TPangoAttrInt
TPangoAttrInt* = record
TPangoAttrInt* {.final.} = object
attr*: TPangoAttribute
value*: int32
PPangoAttrFloat* = ptr TPangoAttrFloat
TPangoAttrFloat* = record
TPangoAttrFloat* {.final.} = object
attr*: TPangoAttribute
value*: gdouble
PPangoAttrColor* = ptr TPangoAttrColor
TPangoAttrColor* = record
TPangoAttrColor* {.final.} = object
attr*: TPangoAttribute
color*: TPangoColor
PPangoAttrShape* = ptr TPangoAttrShape
TPangoAttrShape* = record
TPangoAttrShape* {.final.} = object
attr*: TPangoAttribute
ink_rect*: TPangoRectangle
logical_rect*: TPangoRectangle
PPangoAttrFontDesc* = ptr TPangoAttrFontDesc
TPangoAttrFontDesc* = record
TPangoAttrFontDesc* {.final.} = object
attr*: TPangoAttribute
desc*: PPangoFontDescription
PPangoLogAttr* = ptr TPangoLogAttr
TPangoLogAttr* = record
TPangoLogAttr* {.final.} = object
flag0*: guint16
PPangoCoverageLevel* = ptr TPangoCoverageLevel
@ -129,25 +129,25 @@ type
PANGO_COVERAGE_NONE, PANGO_COVERAGE_FALLBACK, PANGO_COVERAGE_APPROXIMATE,
PANGO_COVERAGE_EXACT
PPangoBlockInfo* = ptr TPangoBlockInfo
TPangoBlockInfo* = record
TPangoBlockInfo* {.final.} = object
data*: Pguchar
level*: TPangoCoverageLevel
PPangoCoverage* = ptr TPangoCoverage
TPangoCoverage* = record
TPangoCoverage* {.final.} = object
ref_count*: int
n_blocks*: int32
data_size*: int32
blocks*: PPangoBlockInfo
PPangoEngineRange* = ptr TPangoEngineRange
TPangoEngineRange* = record
TPangoEngineRange* {.final.} = object
start*: int32
theEnd*: int32
langs*: cstring
PPangoEngineInfo* = ptr TPangoEngineInfo
TPangoEngineInfo* = record
TPangoEngineInfo* {.final.} = object
id*: cstring
engine_type*: cstring
render_type*: cstring
@ -155,7 +155,7 @@ type
n_ranges*: gint
PPangoEngine* = ptr TPangoEngine
TPangoEngine* = record
TPangoEngine* {.final.} = object
id*: cstring
`type`*: cstring
length*: gint
@ -165,7 +165,7 @@ type
attrs: PPangoLogAttr, attrs_len: int32){.
cdecl.}
PPangoEngineLang* = ptr TPangoEngineLang
TPangoEngineLang* = record
TPangoEngineLang* {.final.} = object
engine*: TPangoEngine
script_break*: TPangoEngineLangScriptBreak
@ -176,7 +176,7 @@ type
language: PPangoLanguage): PPangoCoverage{.
cdecl.}
PPangoEngineShape* = ptr TPangoEngineShape
TPangoEngineShape* = record
TPangoEngineShape* {.final.} = object
engine*: TPangoEngine
script_shape*: TPangoEngineShapeScript
get_coverage*: TPangoEngineShapeGetCoverage
@ -194,28 +194,28 @@ type
PPangoGlyphUnit* = ptr TPangoGlyphUnit
TPangoGlyphUnit* = gint32
PPangoGlyphGeometry* = ptr TPangoGlyphGeometry
TPangoGlyphGeometry* = record
TPangoGlyphGeometry* {.final.} = object
width*: TPangoGlyphUnit
x_offset*: TPangoGlyphUnit
y_offset*: TPangoGlyphUnit
PPangoGlyphVisAttr* = ptr TPangoGlyphVisAttr
TPangoGlyphVisAttr* = record
TPangoGlyphVisAttr* {.final.} = object
flag0*: int16
PPangoGlyphInfo* = ptr TPangoGlyphInfo
TPangoGlyphInfo* = record
TPangoGlyphInfo* {.final.} = object
glyph*: TPangoGlyph
geometry*: TPangoGlyphGeometry
attr*: TPangoGlyphVisAttr
TPangoGlyphString* = record
TPangoGlyphString* {.final.} = object
num_glyphs*: gint
glyphs*: PPangoGlyphInfo
log_clusters*: Pgint
space*: gint
TPangoAnalysis* = record
TPangoAnalysis* {.final.} = object
shape_engine*: PPangoEngineShape
lang_engine*: PPangoEngineLang
font*: PPangoFont
@ -223,7 +223,7 @@ type
language*: PPangoLanguage
extra_attrs*: PGSList
TPangoItem* = record
TPangoItem* {.final.} = object
offset*: gint
length*: gint
num_chars*: gint
@ -236,14 +236,14 @@ type
TPangoWrapMode* = enum
PANGO_WRAP_WORD, PANGO_WRAP_CHAR
PPangoLayoutLine* = ptr TPangoLayoutLine
TPangoLayoutLine* = record
TPangoLayoutLine* {.final.} = object
layout*: PPangoLayout
start_index*: gint
length*: gint
runs*: PGSList
PPangoLayoutRun* = ptr TPangoLayoutRun
TPangoLayoutRun* = record
TPangoLayoutRun* {.final.} = object
item*: PPangoItem
glyphs*: PPangoGlyphString

View file

@ -12,7 +12,7 @@ type
regMN,
regNewline
TRegex = record
TRegex = object of TObject
case kind: TRegexKind
of regChar: c: char
of regSet: s: ref set[char]

View file

@ -162,7 +162,7 @@ type
# Data passed back in callouts
# Const before type ignored
# Pointer to character tables
Tpcre_extra* = record
Tpcre_extra* {.final.} = object
flags: cuint
study_data: pointer
match_limit: cuint
@ -189,7 +189,7 @@ type
# Offset to next item in the pattern
# Length of next item in the pattern
# ------------------------------------------------------------------
TPcre_callout_block* = record
TPcre_callout_block* {.final.} = object
version: cint
callout_number: cint
offset_vector: ptr cint

View file

@ -19,10 +19,8 @@ import
math
type
TComplex* = record ## a complex number, consisting of a real and an
## imaginary part
re*: float ## real part of the complex number
im*: float ## imarginary part of the complex number
TComplex* = tuple[re, im: float]
## a complex number, consisting of a real and an imaginary part
proc `==` *(x, y: TComplex): bool =
## Compare two complex numbers `x` and `y` for equality.

View file

@ -25,23 +25,24 @@ type
dbQuiting, # debugger wants to quit
dbBreakpoints # debugger is only interested in breakpoints
TDbgBreakpoint = record
TDbgBreakpoint {.final.} = object
low, high: int # range from low to high; if disabled
# both low and high are set to their negative values
# this makes the check faster and safes memory
filename: string
name: string # name of breakpoint
TVarSlot {.compilerproc.} = record # variable slots used for debugger:
TVarSlot {.compilerproc, final.} = object # variable slots used for debugger:
address: pointer
typ: PNimType
name: cstring # for globals this is "module.name"
PExtendedFrame = ptr TExtendedFrame
TExtendedFrame = record # If the debugger is enabled the compiler provides
# an extended frame. Of course only slots that are
# needed are allocated and not 10_000, except for
# the global data description.
TExtendedFrame {.final.} = object # If the debugger is enabled the compiler
# provides an extended frame. Of course
# only slots that are
# needed are allocated and not 10_000,
# except for the global data description.
f: TFrame
slots: array[0..10_000, TVarSlot]
@ -69,7 +70,7 @@ proc findBreakpoint(name: string): int =
return -1
proc ListBreakPoints() =
write(stdout, "*** emdb| Breakpoints:\n")
write(stdout, "*** endb| Breakpoints:\n")
for i in 0 .. dbgBPlen-1:
write(stdout, dbgBP[i].name & ": " & $abs(dbgBP[i].low) & ".." &
$abs(dbgBP[i].high) & dbgBP[i].filename)
@ -101,13 +102,13 @@ proc writeVariable(stream: TFile, slot: TVarSlot) =
writeln(stream, dbgRepr(slot.address, slot.typ))
proc ListFrame(stream: TFile, f: PExtendedFrame) =
write(stream, "*** emdb| Frame (" & $f.f.len & " slots):\n")
write(stream, "*** endb| Frame (" & $f.f.len & " slots):\n")
for i in 0 .. f.f.len-1:
writeVariable(stream, f.slots[i])
write(stream, "***\n")
proc ListVariables(stream: TFile, f: PExtendedFrame) =
write(stream, "*** emdb| Frame (" & $f.f.len & " slots):\n")
write(stream, "*** endb| Frame (" & $f.f.len & " slots):\n")
for i in 0 .. f.f.len-1:
writeln(stream, f.slots[i].name)
write(stream, "***\n")
@ -115,7 +116,7 @@ proc ListVariables(stream: TFile, f: PExtendedFrame) =
proc debugOut(msg: cstring) =
# the *** *** markers are for easy recognition of debugger
# output for external frontends.
write(stdout, "*** emdb| ")
write(stdout, "*** endb| ")
write(stdout, msg)
write(stdout, "***\n")
@ -131,14 +132,14 @@ proc findVariable(frame: PExtendedFrame, varname: cstring): int =
proc dbgShowCurrentProc(dbgFramePointer: PFrame) =
if dbgFramePointer != nil:
write(stdout, "*** emdb| now in proc: ")
write(stdout, "*** endb| now in proc: ")
write(stdout, dbgFramePointer.procname)
write(stdout, " ***\n")
else:
write(stdout, "*** emdb| (procedure name not available) ***\n")
write(stdout, "*** endb| (procedure name not available) ***\n")
proc dbgShowExecutionPoint() =
write(stdout, "*** emdb| " & $framePtr.filename & "(" & $framePtr.line &
write(stdout, "*** endb| " & $framePtr.filename & "(" & $framePtr.line &
") " & $framePtr.procname & " ***\n")
when defined(windows) or defined(dos) or defined(os2):
@ -219,26 +220,26 @@ h, help display this help message
q, quit quit the debugger and the program
<ENTER> repeat the previous debugger command
EXECUTING
s, stepinto single step, stepping into routine calls
n, stepover single step, without stepping into routine calls
s, step single step, stepping into routine calls
n, next single step, without stepping into routine calls
f, skipcurrent continue execution until the current routine finishes
c, continue continue execution until the next breakpoint
i, ignore continue execution, ignore all breakpoints
BREAKPOINTS
b, setbreak <name> [fromline [toline]] [file]
b, break <name> [fromline [toline]] [file]
set a new breakpoint named 'name' for line and file
if line or file are omitted the current one is used
breakpoints display the entire breakpoint list
disable <name> disable a breakpoint
enable <name> enable a breakpoint
DATA DISPLAY
e, eval <exp> evaluate the expression <exp>
o, out <file> <exp> evaluate <exp> and write it to <file>
e, eval <expr> evaluate the expression <expr>
o, out <file> <expr> evaluate <expr> and write it to <file>
w, where display the current execution point
stackframe [file] display current stack frame [and write it to file]
u, up go up in the call stack
d, down go down in the call stack
callstack display the entire call stack
bt, backtrace display the entire call stack
l, locals display available local variables
g, globals display available global variables
maxdisplay <integer> set the display's recursion maximum
@ -352,7 +353,7 @@ proc CommandPrompt() =
dbgDown: int = 0 # how often we did go down
while again:
write(stdout, "*** emdb| >>")
write(stdout, "*** endb| >>")
var tmp = readLine(stdin)
if tmp.len > 0: dbgUser = tmp
# now look what we have to do:
@ -360,10 +361,10 @@ proc CommandPrompt() =
var i = scanWord(dbgUser, dbgTemp, 0)
case dbgTemp
of "": InvalidCommand()
of "s", "stepinto":
of "s", "step":
dbgState = dbStepInto
again = false
of "n", "stepover":
of "n", "next":
dbgState = dbStepOver
dbgSkipToFrame = framePtr
again = false
@ -412,9 +413,9 @@ proc CommandPrompt() =
dbgShowCurrentProc(dbgFramePtr)
else:
debugOut("[Warning] cannot go down any further ")
of "callstack":
of "bt", "backtrace":
WriteStackTrace()
of "b", "setbreak":
of "b", "break":
setBreakPoint(dbgUser, i)
of "breakpoints":
ListBreakPoints()
@ -443,7 +444,7 @@ proc endbStep() =
proc checkForBreakpoint() =
var i = dbgBreakpointReached(framePtr.line)
if i >= 0:
write(stdout, "*** emdb| reached ")
write(stdout, "*** endb| reached ")
write(stdout, dbgBP[i].name)
write(stdout, " in ")
write(stdout, framePtr.filename)

View file

@ -6,6 +6,8 @@
#define ABORT_ON_ASSERT_FAILURE 0
*/
#define ABORT do { printf("abort was called\n"); abort(); } while (0)
/*
This is a version (aka dlmalloc) of malloc/free/realloc written by
Doug Lea and released to the public domain, as explained at

View file

@ -1,7 +1,7 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2006 Andreas Rumpf
# (c) Copyright 2008 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@ -35,35 +35,34 @@ proc chckNil(p: pointer) {.inline, compilerproc.}
type
PSafePoint = ptr TSafePoint
TSafePoint {.compilerproc.} = record
TSafePoint {.compilerproc, final.} = object
prev: PSafePoint # points to next safe point ON THE STACK
exc: ref E_Base
status: int
context: C_JmpBuf
var
excHandler {.compilerproc, volatile.}: PSafePoint = nil
excHandler {.compilerproc.}: PSafePoint = nil
# list of exception handlers
# a global variable for the root of all try blocks
proc reraiseException() =
if excHandler != nil:
if excHandler == nil:
raise newException(ENoExceptionToReraise, "no exception to reraise")
else:
c_longjmp(excHandler.context, 1)
type
PFrame = ptr TFrame
TFrame {.importc, nodecl.} = record
TFrame {.importc, nodecl, final.} = object
prev: PFrame
procname: CString
line: int # current line number
filename: CString
len: int # length of slots (when not debugging always zero)
TTempFrame = record # used for recursion elimination in WriteStackTrace
procname: CString
line: int
TTempFrame = tuple[ # used for recursion elimination in WriteStackTrace
procname: CString, line: int]
var
buf: string # cannot be allocated on the stack!
@ -71,7 +70,7 @@ var
# assert, as it raises an exception and
# exception handler needs the buffer too
framePtr {.exportc, volatile.}: PFrame
framePtr {.exportc.}: PFrame
tempFrames: array [0..255, TTempFrame] # cannot be allocated
# on the stack!
@ -82,8 +81,7 @@ proc auxWriteStackTrace(f: PFrame, s: var string) =
i = 0
total = 0
while it != nil and i <= high(tempFrames):
tempFrames[i].procname = it.procname
tempFrames[i].line = it.line
tempFrames[i] = (it.procname, it.line)
inc(i)
inc(total)
it = it.prev
@ -110,10 +108,10 @@ proc rawWriteStackTrace(s: var string) =
auxWriteStackTrace(framePtr, s)
proc quitOrDebug() {.inline.} =
when not defined(emdb):
when not defined(endb):
quit(1)
else:
emdbStep() # call the debugger
endbStep() # call the debugger
proc raiseException(e: ref E_Base, ename: CString) =
GC_disable() # a bad thing is an error in the GC while raising an exception
@ -122,7 +120,7 @@ proc raiseException(e: ref E_Base, ename: CString) =
excHandler.exc = e
c_longjmp(excHandler.context, 1)
else:
if cast[pointer](buf) != nil:
if not isNil(buf):
setLen(buf, 0)
rawWriteStackTrace(buf)
if e.msg != nil and e.msg[0] != '\0':
@ -135,9 +133,7 @@ proc raiseException(e: ref E_Base, ename: CString) =
add(buf, "]\n")
writeToStdErr(buf)
else:
writeToStdErr("*** FATAL ERROR *** ")
writeToStdErr(ename)
writeToStdErr("\n")
quitOrDebug()
GC_enable()
@ -147,7 +143,8 @@ var
proc internalAssert(file: cstring, line: int, cond: bool) {.compilerproc.} =
if not cond:
GC_disable() # BUGFIX: `$` allocates a new string object!
if cast[pointer](assertBuf) != nil: # BUGFIX: when debugging the GC, assertBuf may be nil
if not isNil(assertBuf):
# BUGFIX: when debugging the GC, assertBuf may be nil
setLen(assertBuf, 0)
add(assertBuf, "[Assertion failure] file: ")
add(assertBuf, file)
@ -164,6 +161,11 @@ proc WriteStackTrace() =
rawWriteStackTrace(s)
writeToStdErr(s)
#proc stackTraceWrapper {.noconv.} =
# writeStackTrace()
#addQuitProc(stackTraceWrapper)
var
dbgAborting: bool # whether the debugger wants to abort
@ -171,6 +173,7 @@ proc signalHandler(sig: cint) {.exportc: "signalHandler", noconv.} =
# print stack trace and quit
var
s = int(sig)
GC_disable()
setLen(buf, 0)
rawWriteStackTrace(buf)
@ -185,6 +188,7 @@ proc signalHandler(sig: cint) {.exportc: "signalHandler", noconv.} =
else: add(buf, "unknown signal\n")
writeToStdErr(buf)
dbgAborting = True # play safe here...
GC_enable()
quit(1) # always quit when SIGABRT
proc registerSignalHandler() =
@ -204,12 +208,15 @@ assertBuf = newString(2048)
setLen(buf, 0)
setLen(assertBuf, 0)
proc raiseRangeError() {.compilerproc, noreturn.} =
raise newException(EOutOfRange, "value out of range")
proc raiseRangeError(val: biggestInt) {.compilerproc, noreturn.} =
raise newException(EOutOfRange, "value " & $val & " out of range")
proc raiseIndexError() {.compilerproc, noreturn.} =
raise newException(EInvalidIndex, "index out of bounds")
proc raiseFieldError(f: string) {.compilerproc, noreturn.} =
raise newException(EInvalidField, f & " is not accessible")
proc chckIndx(i, a, b: int): int =
if i >= a and i <= b:
return i
@ -220,19 +227,19 @@ proc chckRange(i, a, b: int): int =
if i >= a and i <= b:
return i
else:
raiseRangeError()
raiseRangeError(i)
proc chckRange64(i, a, b: int64): int64 {.compilerproc.} =
if i >= a and i <= b:
return i
else:
raiseRangeError()
raiseRangeError(i)
proc chckRangeF(x, a, b: float): float =
if x >= a and x <= b:
return x
else:
raiseRangeError()
raise newException(EOutOfRange, "value " & $x & " out of range")
proc chckNil(p: pointer) =
if p == nil: c_raise(SIGSEGV)

View file

@ -1,7 +1,7 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2006 Andreas Rumpf
# (c) Copyright 2008 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@ -13,33 +13,39 @@
# For a description of the algorithms used here see:
# intern.html
#{.define: debugGC.} # we wish to debug the GC...
{.define: debugGC.} # we wish to debug the GC...
#when defined(debugGC):
# {.define: logGC.} # define if the GC should log some of its activities
{.define: cycleGC.}
const
traceGC = false # extensive debugging
reallyDealloc = true # for debugging purposes this can be set to false
# Guess the page size of the system; if it is the
# wrong value, performance may be worse (this is not
# for sure though), but GC still works; must be a power of two!
const
PageSize = 1024 * sizeof(int)
RC_Increase = 7 * PageSize # is an additive increase
PageShift = if sizeof(pointer) == 4: 12 else: 13
PageSize = 1 shl PageShift # on 32 bit systems 4096
CycleIncrease = 2 # is a multiplicative increase
InitialCycleThreshold = 8*1024*1024 # X MB because cycle checking is slow
ZctThreshold = 512 # we collect garbage if the ZCT's size
# reaches this threshold
# this needs benchmarking...
when defined(debugGC):
const InitialThreshold = 64*1024
const stressGC = True # GC is debugged; no need to stress it
const stressGC = False
else:
const stressGC = False
const InitialThreshold = RC_Increase
# this may need benchmarking...
# things the System module thinks should be available:
when defined(useDL) or defined(nativeDL):
type
TMallocInfo {.importc: "struct mallinfo", nodecl.} = record
TMallocInfo {.importc: "struct mallinfo", nodecl, final.} = object
arena: cint # non-mmapped space allocated from system
ordblks: cint # number of free chunks
smblks: cint # number of fastbin blocks
@ -68,8 +74,7 @@ else: # not available:
proc getTotalMem(): int = return -1
var
rcThreshold: int = InitialThreshold
cycleThreshold: int = InitialThreshold
cycleThreshold: int = InitialCycleThreshold
memUsed: int = 0 # we have to keep track how much we have allocated
@ -113,11 +118,12 @@ type
waNone, waRelease, waZctDecRef, waCycleDecRef, waCycleIncRef, waDebugIncRef
TCollectorData = int
TCell = record
TCell {.final.} = object
refcount: TCollectorData # the refcount and bit flags
typ: PNimType
stackcount: int # stack counter for debugging
drefc: int # real reference counter for debugging
when stressGC:
stackcount: int # stack counter for debugging
drefc: int # real reference counter for debugging
PCell = ptr TCell
@ -145,6 +151,7 @@ proc extGetCellType(c: pointer): PNimType {.compilerproc.} =
proc internRefcount(p: pointer): int {.exportc: "getRefcount".} =
result = int(usrToCell(p).refcount)
if result < 0: result = 0
proc gcAlloc(size: int): pointer =
result = alloc0(size)
@ -162,7 +169,7 @@ proc GC_setStrategy(strategy: TGC_Strategy) =
of gcOptimizeTime: nil
proc GC_enableMarkAndSweep() =
cycleThreshold = InitialThreshold
cycleThreshold = InitialCycleThreshold
proc GC_disableMarkAndSweep() =
cycleThreshold = high(cycleThreshold)-1
@ -174,7 +181,7 @@ proc nextTry(h, maxHash: int): int {.inline.} =
# generates each int in range(maxHash) exactly once (see any text on
# random-number generation for proof).
# ------------------ Zero count table (ZCT) and any table (AT) -------------
# ------------------ Any table (AT) -------------
# these values are for DL-malloc known for sure (and other allocators
# can only be worse):
@ -200,8 +207,7 @@ when BitsPerPage mod BitsPerUnit != 0:
# ------------------- cell set handling ------------------------------
# A cellset consists of a hash table of page descriptors. A page
# descriptor has a bit for
# every Memalignment'th byte in the page.
# descriptor has a bit for every Memalignment'th byte in the page.
# However, only bits corresponding to addresses that start memory blocks
# are set.
# Page descriptors are also linked to a list; the list
@ -217,17 +223,59 @@ type
TBitIndex = range[0..UnitsPerPage-1]
TPageDesc = record
TPageDesc {.final.} = object
next: PPageDesc # all nodes are connected with this pointer
key: TAddress # start address at bit 0
bits: array[TBitIndex, int] # a bit vector
PPageDescArray = ptr array[0..1000_000, PPageDesc]
TCellSet = record
TCellSet {.final.} = object
counter, max: int
head: PPageDesc
data: PPageDescArray
PCellArray = ptr array[0..100_000_000, PCell]
TCellSeq {.final.} = object
len, cap: int
d: PCellArray
TSlowSet {.final.} = object # used for debugging purposes only
L: int # current length
cap: int # capacity
d: PCellArray
TGcHeap {.final.} = object # this contains the zero count and
# non-zero count table
mask: TAddress # mask for fast pointer detection
zct: TCellSeq # the zero count table
at: TCellSet # a table that contains all references
newAT: TCellSet
stackCells: TCellSeq # cells that need to be decremented because they
# are in the hardware stack; a cell may occur
# several times in this data structure
var
stackBottom: pointer
gch: TGcHeap
proc add(s: var TCellSeq, c: PCell) {.inline.} =
if s.len >= s.cap:
s.cap = s.cap * 3 div 2
s.d = cast[PCellArray](realloc(s.d, s.cap * sizeof(PCell)))
if s.d == nil: raiseOutOfMem()
s.d[s.len] = c
inc(s.len)
proc inOperator(s: TCellSeq, c: PCell): bool {.inline.} =
for i in 0 .. s.len-1:
if s.d[i] == c: return True
return False
proc init(s: var TCellSeq, cap: int = 1024) =
s.len = 0
s.cap = cap
s.d = cast[PCellArray](gcAlloc(cap * sizeof(PCell)))
const
InitCellSetSize = 1024 # must be a power of two!
@ -284,7 +332,8 @@ proc CellSetPut(t: var TCellSet, key: TAddress): PPageDesc =
if x.key == key: return x
h = nextTry(h, t.max)
if (t.max+1) * 2 < t.counter * 3: CellSetEnlarge(t)
if ((t.max+1)*2 < t.counter*3) or ((t.max+1)-t.counter < 4):
CellSetEnlarge(t)
inc(t.counter)
h = cast[int](key) and t.max
while t.data[h] != nil: h = nextTry(h, t.max)
@ -303,7 +352,7 @@ proc in_Operator(s: TCellSet, cell: PCell): bool =
u: TAddress
t: PPageDesc
u = cast[TAddress](cell)
t = CellSetGet(s, u /% PageSize)
t = CellSetGet(s, u shr PageShift)
if t != nil:
u = (u %% PageSize) /% MemAlignment
result = (t.bits[u /% BitsPerUnit] and (1 shl (u %% BitsPerUnit))) != 0
@ -315,7 +364,7 @@ proc incl(s: var TCellSet, cell: PCell) =
u: TAddress
t: PPageDesc
u = cast[TAddress](cell)
t = CellSetPut(s, u /% PageSize)
t = CellSetPut(s, u shr PageShift)
u = (u %% PageSize) /% MemAlignment
t.bits[u /% BitsPerUnit] = t.bits[u /% BitsPerUnit] or
(1 shl (u %% BitsPerUnit))
@ -325,7 +374,7 @@ proc excl(s: var TCellSet, cell: PCell) =
u: TAddress
t: PPageDesc
u = cast[TAddress](cell)
t = CellSetGet(s, u /% PageSize)
t = CellSetGet(s, u shr PageShift)
if t != nil:
u = (u %% PageSize) /% MemAlignment
t.bits[u /% BitsPerUnit] = (t.bits[u /% BitsPerUnit] and
@ -342,7 +391,7 @@ iterator elements(t: TCellSet): PCell {.inline.} =
var j = 0
while w != 0: # test all remaining bits for zero
if (w and 1) != 0: # the bit is set!
yield cast[PCell]((r.key *% PageSize) +%
yield cast[PCell]((r.key shl PageShift) or # +%
(i*%BitsPerUnit+%j) *% MemAlignment)
inc(j)
w = w shr 1
@ -354,68 +403,121 @@ iterator elements(t: TCellSet): PCell {.inline.} =
proc testPageDescs() =
var root: TCellSet
CellSetInit(root)
var u = 10_000
while u <= 20_000:
incl(root, cast[PCell](u))
inc(u, 8)
for cell in elements(root):
c_fprintf(c_stdout, "%ld\n", cast[int](cell))
#var u = 10_000
#while u <= 20_000:
# incl(root, cast[PCell](u))
# inc(u, 8)
# testPageDescs()
incl(root, cast[PCell](0x81cdfb8))
for cell in elements(root):
c_fprintf(c_stdout, "%p\n", cast[int](cell))
#testPageDescs()
when defined(debugGC):
proc writeCell(msg: CString, c: PCell) =
c_fprintf(c_stdout, "%s: %p\n", msg, c)
if c.typ != nil:
if c.typ.kind == tyString:
c_fprintf(c_stdout, "%s\n", cast[TAddress](cellToUsr(c)) + sizeof(int)*2)
c_fprintf(c_stdout, "%s: %p %d\n", msg, c, c.typ.kind)
else: c_fprintf(c_stdout, "%s: %p (nil type)\n", msg, c)
proc writePtr(msg: CString, p: Pointer) =
c_fprintf(c_stdout, "%s: %p\n", msg, p)
when traceGC:
# traceGC is a special switch to enable extensive debugging
type
TCellState = enum
csAllocated, csZctFreed, csCycFreed
proc cellSetInit(s: var TSlowSet) =
s.L = 0
s.cap = 4096
s.d = cast[PCellArray](gcAlloc(s.cap * sizeof(PCell)))
proc cellSetDeinit(s: var TSlowSet) =
s.L = 0
s.cap = 0
dealloc(s.d)
proc incl(s: var TSlowSet, c: PCell) =
if s.L >= s.cap:
s.cap = s.cap * 3 div 2
s.d = cast[PCellArray](realloc(s.d, s.cap * sizeof(PCell)))
if s.d == nil: raiseOutOfMem()
s.d[s.L] = c
inc(s.L)
proc excl(s: var TSlowSet, c: PCell) =
var i = 0
while i < s.L:
if s.d[i] == c:
s.d[i] = s.d[s.L-1]
dec(s.L)
break
inc(i)
proc inOperator(s: TSlowSet, c: PCell): bool =
var i = 0
while i < s.L:
if s.d[i] == c: return true
inc(i)
iterator elements(s: TSlowSet): PCell =
var i = 0
while i < s.L:
yield s.d[i]
inc(i)
var
states: array[TCellState, TSlowSet] # TCellSet]
proc traceCell(c: PCell, state: TCellState) =
case state
of csAllocated:
if c in states[csAllocated]:
writeCell("attempt to alloc a already allocated cell", c)
assert(false)
excl(states[csCycFreed], c)
excl(states[csZctFreed], c)
of csZctFreed:
if c notin states[csAllocated]:
writeCell("attempt to free a not allocated cell", c)
assert(false)
if c in states[csZctFreed]:
writeCell("attempt to free zct cell twice", c)
assert(false)
if c in states[csCycFreed]:
writeCell("attempt to free with zct, but already freed with cyc", c)
assert(false)
excl(states[csAllocated], c)
of csCycFreed:
if c notin states[csAllocated]:
writeCell("attempt to free a not allocated cell", c)
assert(false)
if c in states[csCycFreed]:
writeCell("attempt to free cyc cell twice", c)
assert(false)
if c in states[csZctFreed]:
writeCell("attempt to free with cyc, but already freed with zct", c)
assert(false)
excl(states[csAllocated], c)
incl(states[state], c)
template gcTrace(cell, state: expr): stmt =
when traceGC: traceCell(cell, state)
# -------------------------------------------------------------------------
type
PStackCells = ptr array[0..1000_0000, PCell]
TCountTables = record # this contains the zero count and
# non-zero count table
mask: TAddress # mask for fast pointer detection
zct: TCellSet # the zero count table
at: TCellSet # a table that contains all references
newAT: TCellSet
newZCT: TCellSet
stackCells: PStackCells # cells that need to be decremented because they
# are in the hardware stack; a cell may occur
# several times in this data structure
stackLen, stackMax: int # for managing the stack cells
# forward declarations:
proc collectCT(gch: var TGcHeap)
proc IsOnStack(p: pointer): bool
proc forAllChildren(cell: PCell, op: TWalkOp)
proc collectCycles(gch: var TGcHeap)
proc addStackCell(ct: var TCountTables, cell: PCell) =
if ct.stackLen >= ct.stackMax:
ct.stackMax = ct.stackMax * 3 div 2
ct.stackCells = cast[PStackCells](realloc(ct.stackCells, ct.stackMax *
sizeof(PCell)))
if ct.stackCells == nil: raiseOutOfMem()
ct.stackCells[ct.stackLen] = cell
inc(ct.stackLen)
var
stackBottom: pointer
ct: TCountTables
proc GC_invariant(): bool =
result = True
when stressGC:
if recGcLock == 0:
GC_disable()
for cell in elements(ct.at):
var t = cell.typ # getCellType(cell)
if t == nil or t.kind notin {tySequence, tyString, tyRef}:
writeCell("corrupt cell?", cell)
result = false
GC_enable()
when stressGC:
proc GCdebugHook() =
if not GC_invariant():
assert(false)
dbgLineHook = GCdebugHook
proc reprAny(p: pointer, typ: PNimType): string {.compilerproc.}
# we need the prototype here for debugging purposes
proc prepareDealloc(cell: PCell) =
if cell.typ.finalizer != nil:
@ -433,79 +535,95 @@ proc prepareDealloc(cell: PCell) =
else:
memUsed = memUsed - cell.typ.size
proc checkZCT(): bool =
if recGcLock >= 1: return true # prevent endless recursion
inc(recGcLock)
result = true
for i in 0..gch.zct.len-1:
var c = gch.zct.d[i]
if c.refcount > 0: # should be in the ZCT!
writeCell("wrong ZCT entry", c)
result = false
elif gch.zct.d[-c.refcount] != c:
writeCell("wrong ZCT position", c)
result = false
dec(recGcLock)
proc GC_invariant(): bool =
if recGcLock >= 1: return true # prevent endless recursion
inc(recGcLock)
result = True
block checks:
if not checkZCT():
result = false
break checks
# set counters back to zero:
for c in elements(gch.AT):
var t = c.typ
if t == nil or t.kind notin {tySequence, tyString, tyRef}:
writeCell("corrupt cell?", c)
result = false
break checks
when stressGC: c.drefc = 0
for c in elements(gch.AT):
forAllChildren(c, waDebugIncRef)
when stressGC:
for c in elements(gch.AT):
var rc = c.refcount
if rc < 0: rc = 0
if c.drefc > rc + c.stackcount:
result = false # failed
c_fprintf(c_stdout,
"broken cell: %p, refc: %ld, stack: %ld, real: %ld\n",
c, c.refcount, c.stackcount, c.drefc)
break checks
dec(recGcLock)
when stressGC:
proc GCdebugHook() =
if not GC_invariant():
assert(false)
dbgLineHook = GCdebugHook
proc setStackBottom(theStackBottom: pointer) {.compilerproc.} =
stackBottom = theStackBottom
proc initGC() =
when traceGC:
for i in low(TCellState)..high(TCellState): CellSetInit(states[i])
# init the rt
CellSetInit(ct.zct)
CellSetInit(ct.at)
ct.stackLen = 0
ct.stackMax = 255
ct.stackCells = cast[PStackCells](gcAlloc((ct.stackMax+1) * sizeof(PCell)))
ct.mask = 0
init(gch.zct)
CellSetInit(gch.at)
init(gch.stackCells)
gch.mask = 0
new(gOutOfMem) # reserve space for the EOutOfMemory exception here!
assert(GC_invariant())
# forward declarations:
proc collectCT(ct: var TCountTables)
proc IsOnStack(p: pointer): bool
proc forAllChildren(cell: PCell, op: TWalkOp)
proc collectCycles()
proc reprAny(p: pointer, typ: PNimType): string {.compilerproc.}
# we need the prototype here for debugging purposes
proc outputCell(c: PCell) =
inc(recGcLock)
write(stdout, reprAny(cellToUsr(c), c.typ))
dec(recGcLock)
proc writeGraph() =
{.checkpoint.}
block:
inc(recGcLock)
for c in elements(ct.AT): outputCell(c)
dec(recGcLock)
proc checkRefc(): bool =
if recGcLock >= 1: return true # prevent endless recursion
inc(recGcLock)
result = True
# set counters back to zero:
for c in elements(ct.AT):
c.drefc = 0
for c in elements(ct.AT):
forAllChildren(c, waDebugIncRef)
for c in elements(ct.AT):
if c.drefc > c.refcount - c.stackcount:
result = false # failed
c_fprintf(c_stdout,
"broken cell: %p, refc: %ld, stack: %ld, real: %ld\n",
c, c.refcount, c.stackcount, c.drefc)
dec(recGcLock)
proc seqCheck(cell: PCell): bool =
assert(cell.typ != nil)
if cell.typ.kind in {tySequence, tyString}:
result = cell.refcount - cell.stackcount <= 1
else:
result = true
proc decRef(cell: PCell) {.inline.} =
assert(cell in ct.AT)
when defined(debugGC):
if cell.refcount == 0:
writePtr("decref broken", cellToUsr(cell))
assert(cell.refcount > 0) # this should be the case!
assert(seqCheck(cell))
when stressGC: assert(cell in gch.AT)
dec(cell.refcount)
if cell.refcount == 0:
incl(ct.zct, cell)
cell.refcount = -gch.zct.len
when stressGC: assert(cell notin gch.zct)
add(gch.zct, cell)
when stressGC: assert(checkZCT())
proc incRef(cell: PCell) {.inline.} =
assert(seqCheck(cell))
inc(cell.refcount)
var rc = cell.refcount
if rc <= 0:
# remove from zero count table:
when stressGC: assert(gch.zct.len > -rc)
when stressGC: assert(gch.zct.d[-rc] == cell)
gch.zct.d[-rc] = gch.zct.d[gch.zct.len-1]
gch.zct.d[-rc].refcount = rc
dec(gch.zct.len)
cell.refcount = 1
when stressGC: assert(checkZCT())
else:
inc(cell.refcount)
when stressGC: assert(checkZCT())
proc asgnRef(dest: ppointer, src: pointer) =
# the code generator calls this proc!
@ -514,18 +632,18 @@ proc asgnRef(dest: ppointer, src: pointer) =
if src != nil: incRef(usrToCell(src))
if dest^ != nil: decRef(usrToCell(dest^))
dest^ = src
#assert(checkRefc())
when stressGC: assert(GC_invariant())
proc unsureAsgnRef(dest: ppointer, src: pointer) =
if not IsOnStack(dest):
if src != nil: incRef(usrToCell(src))
if dest^ != nil: decRef(usrToCell(dest^))
dest^ = src
#assert(checkRefc())
when stressGC: assert(GC_invariant())
proc restore(cell: PCell) =
if cell notin ct.newAT:
incl(ct.newAT, Cell)
if cell notin gch.newAT:
incl(gch.newAT, Cell)
forAllChildren(cell, waCycleIncRef)
proc doOperation(p: pointer, op: TWalkOp) =
@ -536,19 +654,15 @@ proc doOperation(p: pointer, op: TWalkOp) =
of waNone: assert(false)
of waRelease: decRef(cell) # DEAD CODE!
of waZctDecRef:
assert(cell.refcount > 0)
assert(seqCheck(cell))
dec(cell.refcount)
if cell.refcount == 0:
incl(ct.newZCT, cell)
decRef(cell)
of waCycleDecRef:
assert(cell.refcount != 0)
assert(cell.refcount > 0)
dec(cell.refcount)
of waCycleIncRef:
inc(cell.refcount) # restore proper reference counts!
restore(cell)
of waDebugIncRef:
inc(cell.drefc)
when stressGC: inc(cell.drefc)
type
TByteArray = array[0..1000_0000, byte]
@ -590,16 +704,20 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
if m != nil: forAllSlotsAux(dest, m, op)
proc forAllChildrenAux(dest: Pointer, mt: PNimType, op: TWalkOp) =
const
handledTypes = {tyArray, tyArrayConstr, tyOpenArray, tyRef,
tyString, tySequence, tyObject, tyPureObject, tyTuple}
var
d = cast[TAddress](dest)
if dest == nil: return # nothing to do
case mt.Kind
of tyArray, tyArrayConstr, tyOpenArray:
for i in 0..(mt.size div mt.base.size)-1:
forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
if mt.base.kind in handledTypes:
for i in 0..(mt.size div mt.base.size)-1:
forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
of tyRef, tyString, tySequence: # leaf:
doOperation(cast[ppointer](d)^, op)
of tyRecord, tyObject, tyTuple:
of tyObject, tyTuple, tyPureObject:
forAllSlotsAux(dest, mt.node, op)
else: nil
@ -608,6 +726,13 @@ proc forAllChildren(cell: PCell, op: TWalkOp) =
when defined(debugGC):
if cell.typ == nil:
writeCell("cell has no type descriptor", cell)
when traceGC:
if cell notin states[csAllocated]:
writeCell("cell has never been allocated!", cell)
if cell in states[csCycFreed]:
writeCell("cell has been freed by Cyc", cell)
if cell in states[csZctFreed]:
writeCell("cell has been freed by Zct", cell)
assert(cell.typ != nil)
case cell.typ.Kind
of tyRef: # common case
@ -625,36 +750,36 @@ proc forAllChildren(cell: PCell, op: TWalkOp) =
proc checkCollection() {.inline.} =
# checks if a collection should be done
if recGcLock == 0:
if memUsed >= rcThreshold or stressGC:
collectCT(ct)
when defined(debugGC):
write(stdout, "threshold is now: ")
writeln(stdout, rcThreshold)
collectCT(gch)
proc newObj(typ: PNimType, size: int): pointer =
# generates a new object and sets its reference counter to 0
var
res: PCell
when stressGC: assert(checkZCT())
assert(typ.kind in {tyRef, tyString, tySequence})
# check if we have to collect:
checkCollection()
res = cast[PCell](Alloc0(size + sizeof(TCell)))
when stressGC: assert((cast[TAddress](res) and (MemAlignment-1)) == 0)
if res == nil: raiseOutOfMem()
when defined(nimSize):
memUsed = memUsed + nimSize(res)
else:
memUsed = memUsed + size
res.refcount = 0
# now it is buffered in the ZCT
res.typ = typ
incl(ct.zct, res) # its refcount is zero, so add it to the ZCT
incl(ct.at, res) # add it to the any table too
ct.mask = ct.mask or cast[TAddress](res)
res.refcount = -gch.zct.len
add(gch.zct, res) # its refcount is zero, so add it to the ZCT
incl(gch.at, res) # add it to the any table too
gch.mask = gch.mask or cast[TAddress](res)
when defined(debugGC):
writeCell("new cell", res)
assert(gcInvariant())
when defined(logGC): writeCell("new cell", res)
gcTrace(res, csAllocated)
result = cellToUsr(res)
assert(res.typ == typ)
when stressGC: assert(checkZCT())
proc newSeq(typ: PNimType, len: int): pointer =
# XXX: overflow checks!
@ -665,16 +790,19 @@ proc newSeq(typ: PNimType, len: int): pointer =
proc growObj(old: pointer, newsize: int): pointer =
var
res, ol: PCell
when stressGC: assert(checkZCT())
checkCollection()
ol = usrToCell(old)
assert(ol.typ.kind in {tyString, tySequence})
assert(seqCheck(ol))
when defined(nimSize):
memUsed = memUsed - nimSize(ol)
else:
memUsed = memUsed - ol.size # this is not exact
# pity that we don't know the old size
# pity that we don't know the old size
res = cast[PCell](realloc(ol, newsize + sizeof(TCell)))
#res = cast[PCell](gcAlloc(newsize + sizeof(TCell)))
#copyMem(res, ol, nimSize(ol))
assert((cast[TAddress](res) and (MemAlignment-1)) == 0)
when defined(nimSize):
memUsed = memUsed + nimSize(res)
else:
@ -682,74 +810,69 @@ proc growObj(old: pointer, newsize: int): pointer =
if res != ol:
if res == nil: raiseOutOfMem()
excl(ct.zct, ol) # remove old pointer in any case:
# It may have a refcount > 0 and is still in the ZCT.
# So do it safe here and remove it anyway.
excl(ct.at, ol)
if res.refcount == 0:
# store new pointer in ZCT, if refcount == 0:
incl(ct.zct, res)
incl(ct.at, res)
ct.mask = ct.mask or cast[TAddress](res)
when defined(debugGC):
if res.refcount <= 0:
assert(gch.zct.d[-res.refcount] == ol)
gch.zct.d[-res.refcount] = res
excl(gch.at, ol)
incl(gch.at, res)
gch.mask = gch.mask or cast[TAddress](res)
when defined(logGC):
writeCell("growObj old cell", ol)
writeCell("growObj new cell", res)
gcTrace(ol, csZctFreed)
gcTrace(res, csAllocated)
result = cellToUsr(res)
#assert(checkRefc())
when stressGC: assert(checkZCT())
proc collectCycles() =
when defined(debugGC):
echo("collecting cycles!\n")
proc collectCycles(gch: var TGcHeap) =
when defined(logGC):
c_fprintf(c_stdout, "collecting cycles!\n")
# step 1: pretend that any node is dead
for c in elements(ct.at):
for c in elements(gch.at):
forallChildren(c, waCycleDecRef)
CellSetInit(ct.newAt)
CellSetInit(gch.newAt)
# step 2: restore life cells
for c in elements(ct.at):
for c in elements(gch.at):
if c.refcount > 0: restore(c)
# step 3: free dead cells:
for cell in elements(ct.at):
for cell in elements(gch.at):
if cell.refcount == 0:
assert(cell notin ct.zct)
# We free an object that is part of a cycle here. Its children
# may have been freed already. Thus the finalizer could access
# garbage. To handle this case properly we need two passes for
# freeing here which is too expensive. We just don't call the
# finalizer for now. YYY: Any better ideas?
prepareDealloc(cell)
dealloc(cell)
when defined(debugGC):
gcTrace(cell, csCycFreed)
when defined(logGC):
writeCell("cycle collector dealloc cell", cell)
CellSetDeinit(ct.at)
ct.at = ct.newAt
#ct.newAt = nil
when reallyDealloc: dealloc(cell)
CellSetDeinit(gch.at)
gch.at = gch.newAt
proc gcMark(p: pointer) =
proc gcMark(gch: var TGcHeap, p: pointer) =
# the addresses are not as objects on the stack, so turn them to objects:
var cell = usrToCell(p)
var c = cast[TAddress](cell)
if ((c and ct.mask) == c) and cell in ct.at:
if ((c and gch.mask) == c) and cell in gch.at:
# is the page that p "points to" in the AT? (All allocated pages are
# always in the AT)
inc(cell.refcount)
inc(cell.stackcount)
addStackCell(ct, cell)
incRef(cell)
when stressGC: inc(cell.stackcount)
add(gch.stackCells, cell)
proc unmarkStackAndRegisters() =
for i in 0 .. ct.stackLen-1:
var cell = ct.stackCells[i]
proc unmarkStackAndRegisters(gch: var TGcHeap) =
when stressGC: assert(checkZCT())
for i in 0 .. gch.stackCells.len-1:
var cell = gch.stackCells.d[i]
assert(cell.refcount > 0)
when defined(debugGC):
if cell.stackcount == 0:
writeGraph()
writePtr("broken stackcount", cellToUsr(cell))
assert(cell.stackcount > 0)
dec(cell.refcount)
dec(cell.stackcount)
if cell.refcount == 0:
incl(ct.zct, cell)
ct.stackLen = 0 # reset to zero
when stressGC:
assert(cell.stackcount > 0)
dec(cell.stackcount)
decRef(cell)
gch.stackCells.len = 0 # reset to zero
when stressGC: assert(checkZCT())
# ----------------- stack management --------------------------------------
# inspired from Smart Eiffel (c)
@ -765,7 +888,7 @@ when defined(sparc): # For SPARC architecture.
stackTop: array[0..1, pointer]
result = p >= addr(stackTop[0]) and p <= stackBottom
proc markStackAndRegisters() =
proc markStackAndRegisters(gch: var TGcHeap) =
when defined(sparcv9):
asm " flushw"
else:
@ -780,7 +903,7 @@ when defined(sparc): # For SPARC architecture.
sp = addr(stackTop[0])
# Addresses decrease as the stack grows.
while sp <= max:
gcMark(sp^)
gcMark(gch, sp^)
sp = cast[ppointer](cast[TAddress](sp) +% sizeof(pointer))
elif defined(ELATE):
@ -802,7 +925,7 @@ elif defined(hppa) or defined(hp9000) or defined(hp9000s300) or
# a little hack to get the size of a TJmpBuf in the generated C code
# in a platform independant way
proc markStackAndRegisters() =
proc markStackAndRegisters(gch: var TGcHeap) =
var
max = stackBottom
registers: C_JmpBuf # The jmp_buf buffer is in the C stack.
@ -814,7 +937,7 @@ elif defined(hppa) or defined(hp9000) or defined(hp9000s300) or
# sp will traverse the JMP_BUF as well (jmp_buf size is added,
# otherwise sp would be below the registers structure).
while sp >= max:
gcMark(sp^)
gcMark(gch, sp^)
sp = cast[ppointer](cast[TAddress](sp) -% sizeof(pointer))
else:
@ -826,7 +949,7 @@ else:
stackTop: array [0..1, pointer]
result = p >= addr(stackTop[0]) and p <= stackBottom
proc markStackAndRegisters() =
proc markStackAndRegisters(gch: var TGcHeap) =
var
max = stackBottom
registers: C_JmpBuf # The jmp_buf buffer is in the C stack.
@ -835,63 +958,58 @@ else:
c_setjmp(registers) # To fill the C stack with registers.
sp = cast[ppointer](addr(registers))
while sp <= max:
gcMark(sp^)
gcMark(gch, sp^)
sp = cast[ppointer](cast[TAddress](sp) +% sizeof(pointer))
# ----------------------------------------------------------------------------
# end of non-portable code
# ----------------------------------------------------------------------------
proc CollectZCT =
CellSetInit(ct.newZCT)
for c in elements(ct.zct):
if c.refcount == 0:
# if != 0 the reference count has been increased, so this does not
# belong to the ZCT. We simply do nothing - it won't appear in the newZCT
# anyway.
# We are about to free the object, call the finalizer BEFORE its
# children are deleted as well, because otherwise the finalizer may
# access invalid memory. This is done by prepareDealloc():
prepareDealloc(c)
forAllChildren(c, waZctDecRef)
assert(c.refcount == 0) # should still be zero
excl(ct.at, c)
excl(ct.newZCT, c) # BUGFIX
when defined(debugGC):
writeCell("zct dealloc cell", c)
dealloc(c)
CellSetDeinit(ct.zct)
ct.zct = ct.newZCT
#ct.newZCT = nil
proc CollectZCT(gch: var TGcHeap) =
while gch.zct.len > 0:
var c = gch.zct.d[0]
assert(c.refcount <= 0)
# remove from ZCT:
gch.zct.d[0] = gch.zct.d[gch.zct.len-1]
gch.zct.d[0].refcount = 0
dec(gch.zct.len)
# We are about to free the object, call the finalizer BEFORE its
# children are deleted as well, because otherwise the finalizer may
# access invalid memory. This is done by prepareDealloc():
gcTrace(c, csZctFreed)
prepareDealloc(c)
forAllChildren(c, waZctDecRef)
excl(gch.at, c)
when defined(logGC):
writeCell("zct dealloc cell", c)
#when defined(debugGC) and defined(nimSize): zeroMem(c, nimSize(c))
when reallyDealloc: dealloc(c)
proc collectCT(ct: var TCountTables) =
when defined(debugGC):
proc collectCT(gch: var TGcHeap) =
when defined(logGC):
c_fprintf(c_stdout, "collecting zero count table; stack size: %ld\n",
stackSize())
markStackAndRegisters()
assert(GC_invariant())
while True:
collectZCT()
if ct.zct.counter == 0: break
# ``counter`` counts the pages, but zero pages means zero cells
when defined(cycleGC):
# still over the cycle threshold?
if memUsed >= cycleThreshold or stressGC:
# collect the cyclic things:
assert(ct.zct.counter == 0)
assert(GC_invariant())
collectCycles()
# recompute the thresholds:
rcThreshold = (memUsed div RC_increase + 1) * RC_Increase
cycleThreshold = memUsed * cycleIncrease
assert(GC_invariant())
unmarkStackAndRegisters()
when stressGC: assert(checkZCT())
if gch.zct.len >= ZctThreshold or memUsed >= cycleThreshold or stressGC:
markStackAndRegisters(gch)
when stressGC: assert(GC_invariant())
collectZCT(gch)
when stressGC: assert(GC_invariant())
assert(gch.zct.len == 0)
when defined(cycleGC):
if memUsed >= cycleThreshold or stressGC:
when defined(logGC):
c_fprintf(c_stdout, "collecting cycles; memory used: %ld\n", memUsed)
collectCycles(gch)
cycleThreshold = max(InitialCycleThreshold, memUsed * cycleIncrease)
when defined(logGC):
c_fprintf(c_stdout, "now used: %ld; threshold: %ld\n",
memUsed, cycleThreshold)
unmarkStackAndRegisters(gch)
when stressGC: assert(GC_invariant())
proc GC_fullCollect() =
var oldThreshold = cycleThreshold
cycleThreshold = 0 # forces cycle collection
collectCT(ct)
collectCT(gch)
cycleThreshold = oldThreshold

View file

@ -10,29 +10,38 @@
type # This should be he same as ast.TTypeKind
# some enum fields are not used at runtime
TNimKind = enum
tyNone, tyBool, tyChar,
tyEmptySet, tyArrayConstr, tyNil, tyRecordConstr,
tyGeneric,
tyGenericInst,
tyGenericParam,
tyEnum, tyAnyEnum,
tyArray,
tyRecord,
tyObject,
tyTuple,
tySet,
tyRange,
tyPtr, tyRef,
tyVar,
tySequence,
tyProc,
tyPointer, tyOpenArray,
tyString, tyCString, tyForward,
tyNone, # 0
tyBool, # 1
tyChar, # 2
tyEmptySet, # 3
tyArrayConstr, # 4
tyNil, # 5
tyGeneric, # 6
tyGenericInst, # 7
tyGenericParam, # 8
tyEnum, # 9
tyAnyEnum, # 10
tyArray, # 11
tyObject, # 12
tyTuple, # 13
tySet, # 14
tyRange, # 15
tyPtr, # 16
tyRef, # 17
tyVar, # 18
tySequence, # 19
tyProc, # 20
tyPointer, # 21
tyOpenArray, # 22
tyString, # 23
tyCString, # 24
tyForward, # 25
tyInt, tyInt8, tyInt16, tyInt32, tyInt64,
tyFloat, tyFloat32, tyFloat64, tyFloat128
tyFloat, tyFloat32, tyFloat64, tyFloat128,
tyPureObject # 35: signals that object has no `n_type` field
TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase
TNimNode {.compilerproc.} = record
TNimNode {.compilerproc, final.} = object
kind: TNimNodeKind
offset: int
typ: ptr TNimType
@ -40,7 +49,7 @@ type # This should be he same as ast.TTypeKind
len: int
sons: ptr array [0..0x7fff, ptr TNimNode]
TNimType {.compilerproc.} = record
TNimType {.compilerproc, final.} = object
size: int
kind: TNimKind
base: ptr TNimType

View file

@ -10,8 +10,7 @@
# 64 bit integers for platforms that don't have those
type
IInt64 = record # "internal" int64
lo, hi: int32
IInt64 = tuple[lo, hi: int32]
proc cmpI64(x, y: IInt64): int32 {.compilerproc.} =
result = x.hi -% y.hi

View file

@ -1,75 +1,22 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2006 Andreas Rumpf
# (c) Copyright 2008 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# math routines
# interface
## Basic math routines for Nimrod.
## This module is available for the ECMAScript target.
{.push debugger:off .} # the user does not want to trace a part
# of the standard library!
{.push checks:off, line_dir:off, stack_trace:off.}
proc nextPowerOfTwo*(x: int): int
## returns the nearest power of two, so that
## result**2 >= x > (result-1)**2.
proc isPowerOfTwo*(x: int): bool {.noSideEffect.}
## returns true, if x is a power of two, false otherwise.
## Negative numbers are not a power of two.
proc countBits*(n: int32): int {.noSideEffect.}
## counts the set bits in `n`.
proc random*(max: int): int
## returns a random number in the range 0..max-1. The sequence of
## random number is always the same, unless `randomize` is called
## which initializes the random number generator with a "random"
## number, i.e. a tickcount.
proc randomize*()
## initializes the random number generator with a "random"
## number, i.e. a tickcount.
proc sqrt*(x: float): float {.importc: "sqrt", header: "<math.h>".}
## computes the square root of `x`.
proc ln*(x: float): float {.importc: "log", header: "<math.h>".}
## computes ln(x).
proc exp*(x: float): float {.importc: "exp", header: "<math.h>".}
## computes e**x.
proc frexp*(x: float, exponent: var int): float {.
importc: "frexp", header: "<math.h>".}
## Split a number into mantissa and exponent.
## `frexp` calculates the mantissa m (a float greater than or equal to 0.5
## and less than 1) and the integer value n such that `x` (the original
## float value) equals m * 2**n. frexp stores n in `exponent` and returns
## m.
proc arccos*(x: float): float {.importc: "acos", header: "<math.h>".}
proc arcsin*(x: float): float {.importc: "asin", header: "<math.h>".}
proc arctan*(x: float): float {.importc: "atan", header: "<math.h>".}
proc arctan2*(y, x: float): float {.importc: "atan2", header: "<math.h>".}
## Calculate the arc tangent of `y` / `x`.
## `atan2` returns the arc tangent of `y` / `x`; it produces correct
## results even when the resulting angle is near pi/2 or -pi/2
## (`x` near 0).
proc cos*(x: float): float {.importc: "cos", header: "<math.h>".}
proc cosh*(x: float): float {.importc: "cosh", header: "<math.h>".}
proc hypot*(x: float): float {.importc: "hypot", header: "<math.h>".}
proc log10*(x: float): float {.importc: "log10", header: "<math.h>".}
proc sinh*(x: float): float {.importc: "sinh", header: "<math.h>".}
proc tan*(x: float): float {.importc: "tan", header: "<math.h>".}
proc tanh*(x: float): float {.importc: "tanh", header: "<math.h>".}
proc pow*(x, y: float): float {.importc: "pos", header: "<math.h>".}
## computes x to power raised of y.
when defined(Posix):
{.passl: "-lm".}
type
TFloatClass* = enum ## describes the class a floating point value belongs to.
@ -82,34 +29,11 @@ type
fcInf, ## value is positive infinity
fcNegInf ## value is negative infinity
proc classify*(x: float): TFloatClass
proc classify*(x: float): TFloatClass =
## classifies a floating point value. Returns `x`'s class as specified by
## `TFloatClass`
## `TFloatClass`.
# implementation
include cntbits
proc nextPowerOfTwo(x: int): int =
result = x - 1
when defined(cpu64):
result = result or (result shr 32)
result = result or (result shr 16)
result = result or (result shr 8)
result = result or (result shr 4)
result = result or (result shr 2)
result = result or (result shr 1)
Inc(result)
# C procs:
proc gettime(dummy: ptr cint): cint {.
importc: "time", header: "<time.h>".}
proc srand(seed: cint) {.
importc: "srand", nodecl.}
proc rand(): cint {.importc: "rand", nodecl.}
# most C compilers have no classify:
proc classify(x: float): TFloatClass =
# ECMAScript and most C compilers have no classify:
if x == 0.0:
if 1.0/x == 1.0/0.0:
return fcZero
@ -122,10 +46,130 @@ proc classify(x: float): TFloatClass =
return fcNormal
# XXX: fcSubnormal is not detected!
proc randomize() = srand(gettime(nil))
proc random(max: int): int = return rand() mod max
proc isPowerOfTwo(x: int): bool = return (x and -x) == x
proc isPowerOfTwo*(x: int): bool {.noSideEffect.} =
## returns true, if x is a power of two, false otherwise.
## Negative numbers are not a power of two.
return (x and -x) == x
proc nextPowerOfTwo*(x: int): int =
## returns the nearest power of two, so that
## result**2 >= x > (result-1)**2.
result = x - 1
when defined(cpu64):
result = result or (result shr 32)
result = result or (result shr 16)
result = result or (result shr 8)
result = result or (result shr 4)
result = result or (result shr 2)
result = result or (result shr 1)
Inc(result)
proc countBits*(n: int32): int {.noSideEffect.}
## counts the set bits in `n`.
include cntbits
when not defined(ECMAScript):
proc random*(max: int): int
## returns a random number in the range 0..max-1. The sequence of
## random number is always the same, unless `randomize` is called
## which initializes the random number generator with a "random"
## number, i.e. a tickcount.
proc randomize*()
## initializes the random number generator with a "random"
## number, i.e. a tickcount. Note: Does nothing for the ECMAScript target,
## as ECMAScript does not support this.
proc sqrt*(x: float): float {.importc: "sqrt", header: "<math.h>".}
## computes the square root of `x`.
proc ln*(x: float): float {.importc: "log", header: "<math.h>".}
## computes ln(x).
proc log10*(x: float): float {.importc: "log10", header: "<math.h>".}
proc log2*(x: float): float = return ln(x) / ln(2.0)
proc exp*(x: float): float {.importc: "exp", header: "<math.h>".}
## computes e**x.
proc frexp*(x: float, exponent: var int): float {.
importc: "frexp", header: "<math.h>".}
## Split a number into mantissa and exponent.
## `frexp` calculates the mantissa m (a float greater than or equal to 0.5
## and less than 1) and the integer value n such that `x` (the original
## float value) equals m * 2**n. frexp stores n in `exponent` and returns
## m.
proc round*(x: float): int {.importc: "lrint", nodecl.}
## converts a float to an int by rounding.
proc arccos*(x: float): float {.importc: "acos", header: "<math.h>".}
proc arcsin*(x: float): float {.importc: "asin", header: "<math.h>".}
proc arctan*(x: float): float {.importc: "atan", header: "<math.h>".}
proc arctan2*(y, x: float): float {.importc: "atan2", header: "<math.h>".}
## Calculate the arc tangent of `y` / `x`.
## `atan2` returns the arc tangent of `y` / `x`; it produces correct
## results even when the resulting angle is near pi/2 or -pi/2
## (`x` near 0).
proc cos*(x: float): float {.importc: "cos", header: "<math.h>".}
proc cosh*(x: float): float {.importc: "cosh", header: "<math.h>".}
proc hypot*(x, y: float): float {.importc: "hypot", header: "<math.h>".}
## same as ``sqrt(x*x + y*y)``.
proc sinh*(x: float): float {.importc: "sinh", header: "<math.h>".}
proc tan*(x: float): float {.importc: "tan", header: "<math.h>".}
proc tanh*(x: float): float {.importc: "tanh", header: "<math.h>".}
proc pow*(x, y: float): float {.importc: "pow", header: "<math.h>".}
## computes x to power raised of y.
# C procs:
proc gettime(dummy: ptr cint): cint {.importc: "time", header: "<time.h>".}
proc srand(seed: cint) {.importc: "srand", nodecl.}
proc rand(): cint {.importc: "rand", nodecl.}
proc randomize() = srand(gettime(nil))
proc random(max: int): int = return rand() mod max
else:
proc mathrandom(): float {.importc: "Math.random", nodecl.}
proc mathfloor(x: float): float {.importc: "Math.floor", nodecl.}
proc random*(max: int): int = return mathfloor(mathrandom() * max)
proc randomize*() = nil
proc sqrt*(x: float): float {.importc: "Math.sqrt", nodecl.}
proc ln*(x: float): float {.importc: "Math.log", nodecl.}
proc log10*(x: float): float = return ln(x) / ln(10.0)
proc log2*(x: float): float = return ln(x) / ln(2.0)
proc exp*(x: float): float {.importc: "Math.exp", nodecl.}
proc round*(x: float): int {.importc: "Math.round", nodecl.}
proc pow*(x, y: float): float {.importc: "Math.pow", nodecl.}
proc frexp*(x: float, exponent: var int): float =
if x == 0.0:
exponent = 0.0
result = 0.0
elif x < 0.0:
result = -frexp(-x, exponent)
else:
var ex = mathfloor(log2(x))
exponent = round(ex)
result = x / pow(2.0, ex)
proc arccos*(x: float): float {.importc: "Math.acos", nodecl.}
proc arcsin*(x: float): float {.importc: "Math.asin", nodecl.}
proc arctan*(x: float): float {.importc: "Math.atan", nodecl.}
proc arctan2*(y, x: float): float {.importc: "Math.atan2", nodecl.}
proc cos*(x: float): float {.importc: "Math.cos", nodecl.}
proc cosh*(x: float): float = return (exp(x)+exp(-x))*0.5
proc hypot*(x, y: float): float = return sqrt(x*x + y*y)
proc sinh*(x: float): float = return (exp(x)-exp(-x))*0.5
proc tan*(x: float): float {.importc: "Math.tan", nodecl.}
proc tanh*(x: float): float =
var y = exp(2.0*x)
return (y-1.0)/(y+1.0)
{.pop.}
{.pop.}

View file

@ -37,24 +37,24 @@ const
realFli = MaxFli - fliOffset
type
TFreePtr = record
TFreePtr {.final.} = object
prev, next: PBhdr
Pbhdr = ptr Tbhdr
Tbhdr = record
Tbhdr {.final.} = object
prevHdr: Pbhdr # this is just valid if the first bit of size is set
size: int # the size is stored in bytes
# bit 0 indicates whether the block is used and
# bit 1 allows to know whether the previous block is free
freePtr: TFreePtr # at this offset bhdr.buffer starts (was a union in the
# C version)
TAreaInfo = record # This structure is embedded at the beginning of each
# area, giving us enough information to cope with a set
# of areas
TAreaInfo {.final.} = object # This structure is embedded at the beginning
# of each area, giving us enough information
# to cope with a set of areas
theEnd: Pbhdr
next: PAreaInfo
PAreaInfo = ptr TAreaInfo
TLSF = record
TLSF {.final.} = object
tlsf_signature: int32 # the TLSF's structure signature
usedSize, maxSize: int
areaHead: PAreaInfo # A linked list holding all the existing areas
@ -147,6 +147,7 @@ elif defined(windows):
if result == nil: raiseOutOfMem()
else:
{.warning: "Generic code for allocating pages is used".}
# generic implementation relying on malloc:
proc malloc(size: int): pointer {.nodecl, importc.}
@ -155,6 +156,124 @@ else:
result = malloc(size)
if result == nil: raiseOutOfMem()
# ---------------------------------------------------------------------------
# small fixed size allocator:
# Design: We manage pages. A page is of constant size, but not necessarily
# the OS's page size. Pages are managed in a hash table taking advantage of
# the fact that the OS is likely to give us pages with contingous numbers.
# A page contains either small fixed size objects of the same size or
# variable length objects. An object's size is always aligned at 16 byte
# boundry. Huge objects are dealt with the TLSF algorithm.
# The design supports iterating over any object in a fast way.
# A bitset contains any page that starts an allocated page. The page may be
# empty however. This bitset can be used to quickly determine if a given
# page belongs to the GC heap. The design of the memory allocator makes it
# simple to return unused pages back to the OS.
# Small bocks
# -----------
#
# If we use a list in the free object's space. Allocation and deallocation are
# O(1). Since any object is of the same size, iteration is quite efficient too.
# However, pointer detection is easy too: Just check if the type-field is nil.
# Deallocation sets it to nil.
# Algorithm:
# i = 0
# f = b.f # first free address
# while i < max:
# if a[i] == f: # not a valid block
# f = f.next # next free address
# else:
# a[i] is a valid object of size s
# inc(i)
# The zero count table is an array. Since we know that the RC is zero, we can
# use the bits for an index into this array. Thus multiple ZCT tables are not
# difficult to support and insertion and removal is O(1). We use negative
# indexes for this. This makes it even fast enough (and necessary!) to do a ZCT
# removal if the RC is incremented.
#
# Huge blocks
# -----------
#
# Huge blocks are always rounded up to a multiple of the page size. These are
# called *strides*. We also need to keep an index structure
# of (stridesize, pagelist).
#
const
MemAlign = 8
PageShift = if sizeof(int) == 4: 12 else: 13
PageSize = 1 shl PageShift
type
TFreeList {.final.} = object
next, prev: ptr TFreeList
TPageDesc {.final.} = object # the start of a stride always starts with this!
size: int # lowest bit is set, if it is a huge block
free: ptr TFreeList # only used if it manages multiple cells
snext, sprev: ptr TPageDesc # next and prev pagedescs with the same size
TCellArray {.final.} = object
i: int # length
d: ptr array [0..1000_000, TCell]
TPageManager = table[page, ptr TPageDesc]
TGcHeap {.final.} = object
# structure that manages the garbage collected heap
zct: TCellArray
stackCells: TCellArray
smallBlocks: array [PageSize div MemAlign, ptr TPageDesc]
pages: TPageManager
usedPages: TPageList
freePages: TPageList
# small blocks:
proc allocSmall(var h: TGcHeap, size: int): pointer =
var s = align(size)
var p = h.smallBlocks[s]
if p == nil or p.free == nil:
p = newSmallBlock(s, p)
h.smallBlocks[s] = p
proc decRef(cell: PCell) {.inline.} =
assert(cell in ct.AT)
assert(cell.refcount > 0) # this should be the case!
assert(seqCheck(cell))
dec(cell.refcount)
if cell.refcount == 0:
# add to zero count table:
zct.d[zct.i] = cell
cell.recfcount = -zct.i
inc(zct.i)
proc incRef(cell: PCell) {.inline.} =
assert(seqCheck(cell))
if cell.refcount < 0:
# remove from zero count table:
zct.d[-cell.refcount] = zct.d[zct.i-1]
dec(zct.i)
cell.refcount = 1
else:
inc(cell.refcount)
proc asgnRef(dest: ppointer, src: pointer) =
# the code generator calls this proc!
assert(not isOnStack(dest))
# BUGFIX: first incRef then decRef!
if src != nil: incRef(usrToCell(src))
if dest^ != nil: decRef(usrToCell(dest^))
dest^ = src
# ----------------------------------------------------------------------------
# helpers
@ -261,7 +380,7 @@ proc extractBlock(b: Pbhdr, t: var TLSF, fl, sl: int) {.inline.} =
proc insertBlock(b: Pbhdr, t: var TLSF, fl, sl: int) {.inline.} =
b.freePtr.prev = nil
b.freePtr.next = t.matrix[fl][sl]
if t.matrix[fl][sl] != 0:
if t.matrix[fl][sl] != nil:
t.matrix[fl][sl].freePtr.prev = b
t.matrix[fl][sl] = b
set_bit(sl, t.slBitmap[fl])
@ -295,9 +414,6 @@ proc processArea(area: pointer, size: int): Pbhdr =
# ----------------------------------------------------------------------------
# Begin of the allocator code
var
mp: pointer # default memory pool.
proc initMemoryPool(memPoolSize: int, memPool: pointer): int =
var
t: PLSF
@ -307,16 +423,14 @@ proc initMemoryPool(memPoolSize: int, memPool: pointer): int =
writeToStdErr("initMemoryPool(): memory_pool invalid\n")
return -1
if (memPool and ptrMask) != 0:
if (cast[TAddress](memPool) and ptrMask) != 0:
writeToStdErr("initMemoryPool(): memPool must be aligned to a word\n")
return -1
t = cast[PLSF](memPool)
# Check if already initialised
if t.signature == tlsfSignature:
mp = memPool
b = getNextBlock(mp, roundupSize(sizeof(TLSF)))
b = getNextBlock(memPool, roundupSize(sizeof(TLSF)))
return b.size and blockSize
mp = memPool
zeroMem(memPool, sizeof(TLSF))
t.signature = tlsfSignature
@ -456,7 +570,7 @@ proc freeEx(p: pointer, t: var TLSF) =
b.freePtr.prev = nil
b.freePtr.next = nil
tmpB = getNextBlock(getBuffer(b), b.size and blockSize)
if tmpB.size and freeBlock != 0:
if (tmpB.size and freeBlock) != 0:
mappingInsert(tmpB.size and blockSize, fl, sl)
extractBlock(tmpB, t, fl, sl)
inc(b.size, (tmpB.size and blockSize) + bhdrOverhead)
@ -549,51 +663,30 @@ proc ansiCrealloc(p: pointer, newSize: int, t: var TLSF): pointer =
else:
result = reallocEx(p, newSize, t)
proc InitTLSF(t: var TLSF) =
var areaSize = sizeof(TLSF) + BHDR_OVERHEAD * 8 # Just a safety constant
areaSize = max(areaSize, DEFAULT_areaSize)
var area = getNewArea(areaSize)
void *tlsf_malloc(size_t size)
{
void *ret
#if USE_MMAP || USE_SBRK
if (!mp) {
size_t areaSize
void *area
initMemoryPool(areaSize, area)
areaSize = sizeof(tlsf_t) + BHDR_OVERHEAD * 8 # Just a safety constant
areaSize = (areaSize > DEFAULT_areaSize) ? areaSize : DEFAULT_areaSize
area = get_new_area(&areaSize)
if (area == ((void *) ~0))
return NULL # Not enough system memory
initMemoryPool(areaSize, area)
}
#endif
var
t: PLSF
b, ib: Pbhdr
TLSF_ACQUIRE_LOCK(&((tlsf_t *)mp)->lock)
t = cast[PLSF](memPool)
ret = malloc_ex(size, mp)
zeroMem(area, areaSize)
TLSF_RELEASE_LOCK(&((tlsf_t *)mp)->lock)
t.signature = tlsfSignature
var ib = processArea(getNextBlock(memPool, roundupSize(sizeof(TLSF))),
rounddownSize(memPoolSize - sizeof(TLSF)))
var b = getNextBlock(getBuffer(ib), ib.size and blockSize)
freeEx(getBuffer(b), t)
t.areaHead = cast[PAreaInfo](getBuffer(ib))
return ret
}
t.used_size = memPoolSize - (b.size and blockSize)
t.max_size = t.used_size
void tlsf_free(void *p)
{
TLSF_ACQUIRE_LOCK(&((tlsf_t *)mp)->lock)
free_ex(p, mp)
TLSF_RELEASE_LOCK(&((tlsf_t *)mp)->lock)
}
void *tlsf_realloc(void *p, size_t size)
{
void *ret
#if USE_MMAP || USE_SBRK
if (!mp) {
return tlsf_malloc(size)
}
#endif
TLSF_ACQUIRE_LOCK(&((tlsf_t *)mp)->lock)
ret = realloc_ex(p, size, mp)
TLSF_RELEASE_LOCK(&((tlsf_t *)mp)->lock)
return ret
}
# XXX

View file

@ -1,7 +1,7 @@
/*
Nimrod's Runtime Library
(c) Copyright 2006 Andreas Rumpf
(c) Copyright 2008 Andreas Rumpf
See the file "copying.txt", included in this
distribution, for details about the copyright.
@ -11,7 +11,8 @@
#define NIMBASE_H
/* calling convention mess ----------------------------------------------- */
#if defined(__GNUC__) || defined(__LCC__) || defined(__POCC__)
#if defined(__GNUC__) || defined(__LCC__) || defined(__POCC__) \
|| defined(__TINYC__)
/* these should support C99's inline */
/* the test for __POCC__ has to come before the test for _MSC_VER,
because PellesC defines _MSC_VER too. This is brain-dead. */
@ -30,10 +31,18 @@
# define N_INLINE(rettype, name) rettype __inline name
#endif
#if defined(_MSC_VER)
#if defined(__POCC__) || defined(_MSC_VER)
# define HAVE_LRINT 1
#endif
#if defined(__POCC__)
# define NIM_CONST /* PCC is really picky with const modifiers */
#elif defined(__cplusplus)
# define NIM_CONST /* C++ is picky with const modifiers */
#else
# define NIM_CONST const
#endif
/* --------------- how int64 constants should be declared: ----------- */
#if defined(__GNUC__) || defined(__LCC__) || \
defined(__POCC__) || defined(__DMC__)
@ -136,8 +145,7 @@
** long int lrint (double x);
*/
#if defined(__LCC__) || defined(__POCC__) \
|| (defined(__GNUC__) && defined(WIN32))
#if defined(__LCC__) || (defined(__GNUC__) && defined(WIN32))
/* Linux' GCC does not seem to have these. Why? */
# define HAVE_LRINT
# define HAVE_LRINTF
@ -159,7 +167,7 @@
# include <math.h>
#elif (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) \
&& !defined(__BORLANDC__)
&& !defined(__BORLANDC__) && !defined(__POCC__)
# include <math.h>
@ -206,6 +214,17 @@ static N_INLINE(long int, lrintf)(float flt) {
#include <signal.h>
#include <setjmp.h>
#ifndef NAN
static unsigned long nimNaN[2]={0xffffffff, 0x7fffffff};
# define NAN (*(double*) nimNaN)
#endif
/*
#ifndef INF
static unsigned long nimInf[2]={0xffffffff, 0x7fffffff};
# define INF (*(double*) nimInf)
#endif */
/* compiler symbols:
__BORLANDC__
_MSC_VER
@ -214,6 +233,7 @@ __LCC__
__GNUC__
__DMC__
__POCC__
__TINYC__
*/
/* C99 compiler? */
@ -250,50 +270,41 @@ __POCC__
#endif
#define NIM_NIL ((void*)0) /* C's NULL is fucked up in some C compilers, so
the generated code does not rely on it anymore */
the generated code does not rely on it anymore */
#if defined(HAVE_STDINT_H)
# include <stdint.h>
typedef int8_t NS8;
typedef int16_t NS16;
typedef int32_t NS32;
typedef int64_t NS64;
typedef int8_t NI8;
typedef int16_t NI16;
typedef int32_t NI32;
typedef int64_t NI64;
typedef uint64_t NU64;
typedef uint8_t NU8;
typedef uint16_t NU16;
typedef uint32_t NU32;
#elif defined(__BORLANDC__) || defined(__DMC__) \
|| defined(__WATCOMC__) || defined(_MSC_VER)
typedef signed char NS8;
typedef signed short int NS16;
typedef signed int NS32;
typedef signed char NI8;
typedef signed short int NI16;
typedef signed int NI32;
/* XXX: Float128? */
typedef unsigned char NU8;
typedef unsigned short int NU16;
typedef unsigned __int64 NU64;
typedef __int64 NS64;
typedef __int64 NI64;
typedef unsigned int NU32;
#else
typedef signed char NS8;
typedef signed short int NS16;
typedef signed int NS32;
typedef signed char NI8;
typedef signed short int NI16;
typedef signed int NI32;
/* XXX: Float128? */
typedef unsigned char NU8;
typedef unsigned short int NU16;
typedef unsigned long long int NU64;
typedef long long int NS64;
typedef long long int NI64;
typedef unsigned int NU32;
#endif
#if defined(_MSC_VER) && (defined(AMD64) || defined(_M_AMD64))
/* Microsoft C is brain-dead in this case; long is still not an int64 */
typedef unsigned long long int NU;
typedef signed long long int NS;
#else
typedef unsigned long int NU; /* note: int would be wrong for AMD64 */
typedef signed long int NS;
#endif
typedef float NF32;
typedef double NF64;
typedef double NF;
@ -307,13 +318,13 @@ typedef char* NCSTRING;
# define NIM_IMAN 0
#endif
static N_INLINE(NS32, float64ToInt32)(double val) {
static N_INLINE(NI32, float64ToInt32)(double val) {
val = val + 68719476736.0*1.5;
/* 2^36 * 1.5, (52-_shiftamt=36) uses limited precisicion to floor */
return ((NS32*)&val)[NIM_IMAN] >> 16; /* 16.16 fixed point representation */
return ((NI32*)&val)[NIM_IMAN] >> 16; /* 16.16 fixed point representation */
}
static N_INLINE(NS32, float32ToInt32)(float val) {
static N_INLINE(NI32, float32ToInt32)(float val) {
return float64ToInt32((double)val);
}
@ -322,7 +333,7 @@ static N_INLINE(NS32, float32ToInt32)(float val) {
#define STRING_LITERAL(name, str, length) \
static const struct { \
NS len, space; \
NI len, space; \
NIM_CHAR data[length + 1]; \
} name = {length, length, str}
@ -357,7 +368,7 @@ typedef struct TStringDesc* string;
/*
typedef struct TSafePoint TSafePoint;
struct TSafePoint {
NS exc;
NI exc;
NCSTRING excname;
NCSTRING msg;
TSafePoint* prev;
@ -368,19 +379,19 @@ typedef struct TFrame TFrame;
struct TFrame {
TFrame* prev;
NCSTRING procname;
NS line;
NI line;
NCSTRING filename;
NS len;
NI len;
};
extern TFrame* volatile framePtr;
/*extern TSafePoint* volatile excHandler; */
extern TFrame* framePtr;
/*extern TSafePoint* excHandler; */
#if defined(__cplusplus)
struct NimException {
TSafePoint sp;
NimException(NS aExc, NCSTRING aExcname, NCSTRING aMsg) {
NimException(NI aExc, NCSTRING aExcname, NCSTRING aMsg) {
sp.exc = aExc; sp.excname = aExcname; sp.msg = aMsg;
sp.prev = excHandler;
excHandler = &sp;
@ -389,13 +400,13 @@ struct NimException {
#endif
typedef struct TStringDesc {
NS len;
NS space;
NI len;
NI space;
NIM_CHAR data[1]; /* SEQ_DECL_SIZE]; */
} TStringDesc;
typedef struct {
NS len, space;
NI len, space;
} TGenericSeq;
typedef TGenericSeq* PGenericSeq;

View file

@ -1,39 +0,0 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2006 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module provides a command line parser.
## It supports one iterator over all command line options.
#interface
{.push debugger: off.}
import
os
proc findSep(s: string): int {.nostatic.} =
for i in 0 .. high(s)-1:
if s[i] in {'=', ':'}: return i
return high(s)+1
iterator getopt*(): tuple[string, string] =
# returns a (cmd, arg) tuple.
for k in 1 .. ParamCount():
var param = paramStr(k)
if param[0] == '-':
var j = findSep(param)
cmd = copy(param, 0, j-1)
arg = copy(param, j+1)
else:
cmd = ""
arg = param
yield cmd, arg
{.pop.}

View file

@ -1,7 +1,7 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2006 Andreas Rumpf
# (c) Copyright 2008 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@ -10,7 +10,9 @@
## Basic operating system facilities like retrieving environment variables,
## reading command line arguments, working with directories, running shell
## commands, etc. This module is -- like any other basic library --
## platform independant.
## platform independant. However, the ECMAScript target is not supported,
## as there is no way to perform these operations in ECMAScript portably
## or at all.
{.push debugger:off.}
@ -371,8 +373,11 @@ proc UnixToNativePath(path: string): string =
# interface to C library:
const
cunder = if defined(pcc): "_" else: ""
type
TStat {.importc: "struct stat".} = record
TStat {.importc: "struct " & cunder & "stat", final.} = object
st_dev: int16
st_ino: int16
st_mode: int16
@ -397,7 +402,8 @@ else:
{.error: "os library not ported to your OS. Please help!".}
proc chdir(path: CString): cint {.importc: "chdir", header: dirHeader.}
proc chdir(path: CString): cint {.
importc: cunder & "chdir", header: dirHeader.}
when defined(unix):
proc mkdir(dir: CString, theAccess: cint): cint {.
@ -412,7 +418,7 @@ elif defined(windows):
proc fullpath(buffer, file: CString, size: int): CString {.
importc: "_fullpath", header: "<stdlib.h>".}
proc getcwd(buf: CString, buflen: cint): CString {.
importc: "getcwd", header: "<direct.h>".}
importc: cunder & "getcwd", header: "<direct.h>".}
proc CreateDirectory(pathName: cstring, security: Pointer): cint {.
importc: "CreateDirectory", header: "<windows.h>".}
@ -421,7 +427,8 @@ else:
{.error: "os library not ported to your OS. Please help!".}
proc rmdir(dir: CString): cint {.importc: "rmdir", header: "<time.h>".}
proc rmdir(dir: CString): cint {.
importc: cunder & "rmdir", header: "<time.h>".}
# rmdir is of course in ``dirHeader``, but we check here to include
# time.h which is needed for stat(). stat() needs time.h and
# sys/stat.h; we workaround a C library issue here.
@ -432,17 +439,7 @@ proc free(c: cstring) {.importc: "free", nodecl.}
proc strlen(str: CString): int {.importc: "strlen", nodecl.}
proc stat(f: CString, res: var TStat): cint {.
importc: "stat", header: "<sys/stat.h>".}
proc sameFile*(path1, path2: string): bool =
## Returns True if both pathname arguments refer to the same file or
## directory (as indicated by device number and i-node number).
## Raises an exception if an os.stat() call on either pathname fails.
var
a, b: TStat
if stat(path1, a) < 0 or stat(path2, b) < 0:
raise newException(EOS, "stat() call failed")
return int(a.st_dev) == b.st_dev and int(a.st_ino) == b.st_ino
importc: cunder & "stat", header: "<sys/stat.h>".}
when defined(windows):
proc getModuleFilename(handle: int32, buf: CString, size: int32): int32 {.
@ -473,6 +470,13 @@ when defined(linux) or defined(solaris) or defined(bsd):
when defined(solaris) or defined(bsd):
proc getpid(): int {.importc, header: "<unistd.h>", cdecl.}
elif defined(macosx):
# a really hacky solution: since we like to include 2 headers we have to
# define two procs which in reality are the same
proc getExecPath1(c: cstring, size: var int32) {.
importc: "_NSGetExecutablePath", header: "<sys/param.h>".}
proc getExecPath2(c: cstring, size: var int32): bool {.
importc: "_NSGetExecutablePath", header: "<mach-o/dyld.h>".}
proc getApplicationFilename(): string =
# Linux: /proc/<pid>/exe
@ -491,6 +495,12 @@ proc getApplicationFilename(): string =
result = getApplAux("/proc/" & $getpid() & "/path/a.out")
elif defined(bsd):
result = getApplAux("/proc/" & $getpid() & "file")
elif defined(macosx):
var size: int32
getExecPath1(nil, size)
result = newString(int(size))
if getExecPath2(result, size):
result = "" # error!
else:
# little heuristic that may work on other POSIX-like systems:
result = getEnv("_")
@ -612,7 +622,7 @@ when defined(wcc):
proc cputenv(env: CString): cint {.importc: "putenv", header: "<process.h>".}
else: # is in <stdlib.h>
proc cputenv(env: CString): cint {.importc: "putenv", noDecl.}
proc cputenv(env: CString): cint {.importc: cunder & "putenv", noDecl.}
proc cgetenv(env: CString): CString {.importc: "getenv", noDecl.}
@ -621,7 +631,7 @@ proc cgetenv(env: CString): CString {.importc: "getenv", noDecl.}
#int _findclose(long);
when defined(windows):
type
TFindData {.importc: "struct _finddata_t".} = record
TFindData {.importc: "struct _finddata_t", final.} = object
attrib {.importc: "attrib".}: cint
time_create {.importc: "time_create".}: cint
time_access {.importc: "time_access".}: cint
@ -636,7 +646,7 @@ when defined(windows):
proc findclose(handle: cint) {.importc: "_findclose", header: "<io.h>".}
else:
type
TFindData {.importc: "glob_t".} = record
TFindData {.importc: "glob_t", final.} = object
gl_pathc: int # count of paths matched by pattern
gl_pathv: ptr array[0..1000_000, CString] # list of matched path names
gl_offs: int # slots to reserve at beginning of gl_pathv
@ -649,6 +659,30 @@ else:
proc globfree(pglob: PFindData) {.
importc: "globfree", header: "<glob.h>".}
proc sameFile*(path1, path2: string): bool =
## Returns True if both pathname arguments refer to the same file or
## directory (as indicated by device number and i-node number).
## Raises an exception if an os.stat() call on either pathname fails.
when defined(Windows):
var
a, b: TFindData
var resA = findfirst(path1, addr(a))
var resB = findfirst(path2, addr(b))
if resA != -1 and resB != -1:
result = $a.name == $b.name
else:
# work around some ``findfirst`` bugs
result = cmpPaths(path1, path2) == 0
if resA != -1: findclose(resA)
if resB != -1: findclose(resB)
else:
var
a, b: TStat
if stat(path1, a) < 0 or stat(path2, b) < 0:
result = cmpPaths(path1, path2) == 0 # be consistent with Windows
else:
result = int(a.st_dev) == b.st_dev and int(a.st_ino) == b.st_ino
proc cremove(filename: CString): cint {.importc: "remove", noDecl.}
proc crename(oldname, newname: CString): cint {.importc: "rename", noDecl.}
@ -787,7 +821,7 @@ proc existsEnv(key: string): bool =
if cgetenv(key) != nil: return true
else: return findEnvVar(key) >= 0
iterator iterOverEnvironment*(): tuple[string, string] =
iterator iterOverEnvironment*(): tuple[key, value: string] =
## Iterate over all environments varialbes. In the first component of the
## tuple is the name of the current variable stored, in the second its value.
getEnvVarsC()

View file

@ -14,7 +14,7 @@
## This is a raw POSIX interface module. It does not not provide any
## convenience: cstrings are used instead of proper Nimrod strings and
## return codes indicate errors. If you want exceptions
## and a proper Nimrod-like interface, use the OS module.
## and a proper Nimrod-like interface, use the OS module or write a wrapper.
## Coding conventions:
## ALL types are named the same as in the POSIX standard except that they start
@ -60,7 +60,7 @@ const
STDOUT_FILENO = 1 ## File number of stdout;
type
Taiocb* {.importc: "struct aiocb", header: "<aio.h>".} = record
Taiocb* {.importc: "struct aiocb", header: "<aio.h>", final.} = object
aio_fildes*: cint ## File descriptor.
aio_offset*: TOff ## File offset.
aio_buf*: pointer ## Location of buffer.
@ -69,14 +69,14 @@ type
aio_sigevent*: TSigEvent ## Signal number and value.
aio_lio_opcode: cint ## Operation to be performed.
TDIR* {.importc: "DIR", header: "<dirent.h>".} = record
TDIR* {.importc: "DIR", header: "<dirent.h>", final.} = object
## A type representing a directory stream.
Tdirent* {.importc: "struct dirent", header: "<dirent.h>".} = record
Tdirent* {.importc: "struct dirent", header: "<dirent.h>", final.} = object
d_ino*: TIno ## File serial number.
d_name*: array [0..255, char] ## Name of entry.
Tflock* {.importc: "flock", header: "<fcntl>".} = record
Tflock* {.importc: "flock", header: "<fcntl>", final.} = object
l_type*: cshort ## Type of lock; F_RDLCK, F_WRLCK, F_UNLCK.
l_whence*: cshort ## Flag for starting offset.
l_start*: Toff ## Relative offset in bytes.
@ -84,13 +84,13 @@ type
l_pid*: TPid ## Process ID of the process holding the lock;
## returned with F_GETLK.
Tfenv* {.importc: "fenv_t", header: "<fenv.h>".} =
record ## Represents the entire floating-point environment. The
Tfenv* {.importc: "fenv_t", header: "<fenv.h>", final.} =
object ## Represents the entire floating-point environment. The
## floating-point environment refers collectively to any
## floating-point status flags and control modes supported
## by the implementation.
Tfexcept* {.importc: "fexcept_t", header: "<fenv.h>".} =
record ## Represents the floating-point status flags collectively,
Tfexcept* {.importc: "fexcept_t", header: "<fenv.h>", final.} =
object ## Represents the floating-point status flags collectively,
## including any status the implementation associates with the
## flags. A floating-point status flag is a system variable
## whose value is set (but never cleared) when a floating-point
@ -100,25 +100,25 @@ type
## whose value may be set by the user to affect the subsequent
## behavior of floating-point arithmetic.
TFTW* {.importc: "struct FTW", header: "<ftw.h>".} = record
TFTW* {.importc: "struct FTW", header: "<ftw.h>", final.} = object
base*: cint
level*: cint
TGlob* {.importc: "glob_t", header: "<glob.h>".} = record
TGlob* {.importc: "glob_t", header: "<glob.h>", final.} = object
gl_pathc*: int ## Count of paths matched by pattern.
gl_pathv*: ptr cstring ## Pointer to a list of matched pathnames.
gl_offs*: int ## Slots to reserve at the beginning of gl_pathv.
TGroup* {.importc: "struct group", header: "<grp.h>".} = record
TGroup* {.importc: "struct group", header: "<grp.h>", final.} = object
gr_name*: cstring ## The name of the group.
gr_gid*: TGid ## Numerical group ID.
gr_mem*: cstringArray ## Pointer to a null-terminated array of character
## pointers to member names.
Ticonv* {.importc: "iconv_t", header: "<iconv.h>".} =
record ## Identifies the conversion from one codeset to another.
Ticonv* {.importc: "iconv_t", header: "<iconv.h>", final.} =
object ## Identifies the conversion from one codeset to another.
Tlconv* {.importc: "struct lconv", header: "<locale.h>".} = record
Tlconv* {.importc: "struct lconv", header: "<locale.h>", final.} = object
currency_symbol*: cstring
decimal_point*: cstring
frac_digits*: char
@ -144,14 +144,14 @@ type
p_sign_posn*: char
thousands_sep*: cstring
TMqd* {.importc: "mqd_t", header: "<mqueue.h>".} = record
TMqAttr* {.importc: "struct mq_attr", header: "<mqueue.h>".} = record
TMqd* {.importc: "mqd_t", header: "<mqueue.h>", final.} = object
TMqAttr* {.importc: "struct mq_attr", header: "<mqueue.h>", final.} = object
mq_flags*: int ## Message queue flags.
mq_maxmsg*: int ## Maximum number of messages.
mq_msgsize*: int ## Maximum message size.
mq_curmsgs*: int ## Number of messages currently queued.
TPasswd* {.importc: "struct passwd", header: "<pwd.h>".} = record
TPasswd* {.importc: "struct passwd", header: "<pwd.h>", final.} = object
pw_name*: cstring ## User's login name.
pw_uid*: TUid ## Numerical user ID.
pw_gid*: TGid ## Numerical group ID.
@ -198,7 +198,7 @@ type
Tuid* {.importc: "uid_t", header: "<sys/types.h>".} = int
Tuseconds* {.importc: "useconds_t", header: "<sys/types.h>".} = int
Tutsname* {.importc: "struct utsname", header: "<sys/utsname.h>".} = record
Tutsname* {.importc: "struct utsname", header: "<sys/utsname.h>", final.} = object
sysname*, ## Name of this implementation of the operating system.
nodename*, ## Name of this node within the communications
## network to which this node is attached, if any.
@ -207,15 +207,15 @@ type
machine*: array [0..255, char] ## Name of the hardware type on which the
## system is running.
TSem* {.importc: "sem_t", header: "<semaphore.h>".} = record
Tipc_perm* {.importc: "struct ipc_perm", header: "<sys/ipc.h>".} = record
TSem* {.importc: "sem_t", header: "<semaphore.h>", final.} = object
Tipc_perm* {.importc: "struct ipc_perm", header: "<sys/ipc.h>", final.} = object
uid*: tuid ## Owner's user ID.
gid*: tgid ## Owner's group ID.
cuid*: Tuid ## Creator's user ID.
cgid*: Tgid ## Creator's group ID.
mode*: TMode ## Read/write permission.
TStat* {.importc: "struct stat", header: "<sys/stat.h>".} = record
TStat* {.importc: "struct stat", header: "<sys/stat.h>", final.} = object
st_dev*: TDev ## Device ID of device containing file.
st_ino*: TIno ## File serial number.
st_mode*: TMode ## Mode of file (see below).
@ -239,7 +239,7 @@ type
st_blocks*: Tblkcnt ## Number of blocks allocated for this object.
TStatvfs* {.importc: "struct statvfs", header: "<sys/statvfs.h>".} = record
TStatvfs* {.importc: "struct statvfs", header: "<sys/statvfs.h>", final.} = object
f_bsize*: int ## File system block size.
f_frsize*: int ## Fundamental file system block size.
f_blocks*: Tfsblkcnt ## Total number of blocks on file system in units of f_frsize.
@ -255,10 +255,10 @@ type
f_namemax*: int ## Maximum filename length.
Tposix_typed_mem_info* {.importc: "struct posix_typed_mem_info",
header: "<sys/mman.h>".} = record
header: "<sys/mman.h>", final.} = object
posix_tmi_length*: int
Ttm* {.importc: "struct tm", header: "<time.h>".} = record
Ttm* {.importc: "struct tm", header: "<time.h>", final.} = object
tm_sec*: cint ## Seconds [0,60].
tm_min*: cint ## Minutes [0,59].
tm_hour*: cint ## Hour [0,23].
@ -268,10 +268,10 @@ type
tm_wday*: cint ## Day of week [0,6] (Sunday =0).
tm_yday*: cint ## Day of year [0,365].
tm_isdst*: cint ## Daylight Savings flag.
Ttimespec* {.importc: "struct timespec", header: "<time.h>".} = record
Ttimespec* {.importc: "struct timespec", header: "<time.h>", final.} = object
tv_sec*: Ttime ## Seconds.
tv_nsec*: int ## Nanoseconds.
titimerspec* {.importc: "struct itimerspec", header: "<time.h>".} = record
titimerspec* {.importc: "struct itimerspec", header: "<time.h>", final.} = object
it_interval*: ttimespec ## Timer period.
it_value*: ttimespec ## Timer expiration.
@ -279,19 +279,19 @@ type
## Possibly volatile-qualified integer type of an object that can be
## accessed as an atomic entity, even in the presence of asynchronous
## interrupts.
Tsigset* {.importc: "sigset_t", header: "<signal.h>".} = record
Tsigset* {.importc: "sigset_t", header: "<signal.h>", final.} = object
TsigEvent* {.importc: "struct sigevent", header: "<signal.h>".} = record
TsigEvent* {.importc: "struct sigevent", header: "<signal.h>", final.} = object
sigev_notify*: cint ## Notification type.
sigev_signo*: cint ## Signal number.
sigev_value*: Tsigval ## Signal value.
sigev_notify_function*: proc (x: TSigval) {.noconv.} ## Notification function.
sigev_notify_attributes*: ptr Tpthreadattr ## Notification attributes.
TsigVal* {.importc: "union sigval", header: "<signal.h>".} = record
TsigVal* {.importc: "union sigval", header: "<signal.h>", final.} = object
sival_ptr*: pointer ## pointer signal value;
## integer signal value not defined!
TSigaction* {.importc: "struct sigaction", header: "<signal.h>".} = record
TSigaction* {.importc: "struct sigaction", header: "<signal.h>", final.} = object
sa_handler*: proc (x: cint) {.noconv.} ## Pointer to a signal-catching
## function or one of the macros
## SIG_IGN or SIG_DFL.
@ -300,16 +300,16 @@ type
sa_flags*: cint ## Special flags.
sa_sigaction*: proc (x: cint, y: var TSigInfo, z: pointer) {.noconv.}
TStack* {.importc: "stack_t", header: "<signal.h>".} = record
TStack* {.importc: "stack_t", header: "<signal.h>", final.} = object
ss_sp*: pointer ## Stack base or pointer.
ss_size*: int ## Stack size.
ss_flags*: cint ## Flags.
TSigStack* {.importc: "struct sigstack", header: "<signal.h>".} = record
TSigStack* {.importc: "struct sigstack", header: "<signal.h>", final.} = object
ss_onstack*: cint ## Non-zero when signal stack is in use.
ss_sp*: pointer ## Signal stack pointer.
TsigInfo* {.importc: "siginfo_t", header: "<signal.h>".} = record
TsigInfo* {.importc: "siginfo_t", header: "<signal.h>", final.} = object
si_signo*: cint ## Signal number.
si_code*: cint ## Signal code.
si_errno*: cint ## If non-zero, an errno value associated with
@ -324,7 +324,7 @@ type
Tnl_item* {.importc: "nl_item", header: "<nl_types.h>".} = cint
Tnl_catd* {.importc: "nl_catd", header: "<nl_types.h>".} = cint
Tsched_param* {.importc: "struct sched_param", header: "<sched.h>".} = record
Tsched_param* {.importc: "struct sched_param", header: "<sched.h>", final.} = object
sched_priority*: cint
sched_ss_low_priority*: cint ## Low scheduling priority for
## sporadic server.
@ -334,15 +334,15 @@ type
sched_ss_max_repl*: cint ## Maximum pending replenishments for
## sporadic server.
Ttimeval* {.importc: "struct timeval", header: "<sys/select.h>".} = record
Ttimeval* {.importc: "struct timeval", header: "<sys/select.h>", final.} = object
tv_sec*: ttime ## Seconds.
tv_usec*: tsuseconds ## Microseconds.
Tfd_set* {.importc: "struct fd_set", header: "<sys/select.h>".} = record
Tfd_set* {.importc: "struct fd_set", header: "<sys/select.h>", final.} = object
Tposix_spawnattr* {.importc: "posix_spawnattr_t", header: "<spawn.h>".} = cint
Tposix_spawn_file_actions* {.importc: "posix_spawn_file_actions_t", header: "<spawn.h>".} = cint
Tmcontext* {.importc: "mcontext_t", header: "<ucontext.h>".} = record
Tucontext* {.importc: "ucontext_t", header: "<ucontext.h>".} = record
Tmcontext* {.importc: "mcontext_t", header: "<ucontext.h>", final.} = object
Tucontext* {.importc: "ucontext_t", header: "<ucontext.h>", final.} = object
uc_link*: ptr Tucontext ## Pointer to the context that is resumed
## when this context returns.
uc_sigmask*: Tsigset ## The set of signals that are blocked when this
@ -729,7 +729,7 @@ var
GLOB_NOSORT* {.importc, header: "<glob.h>".}: cint
## Do not sort the pathnames returned.
GLOB_ABORTED* {.importc, header: "<glob.h>".}: cint
## The scan was stopped because GLOB_ERR was set or (*errfunc)()
## The scan was stopped because GLOB_ERR was set or errfunc()
## returned non-zero.
GLOB_NOMATCH* {.importc, header: "<glob.h>".}: cint
## The pattern does not match any existing pathname, and GLOB_NOCHECK

View file

@ -1,7 +1,7 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2006 Andreas Rumpf
# (c) Copyright 2008 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.

View file

@ -18,7 +18,7 @@ type
PPointer = ptr pointer
TCollectorData = int
TCell = record
TCell {.final.} = object
refcount: TCollectorData # the refcount and bit flags
typ: PNimType
stackcount: int # stack counter for debugging
@ -67,18 +67,18 @@ type
TBitIndex = range[0..UnitsPerPage-1]
TPageDesc = record
TPageDesc {.final.} = object
next: PPageDesc # all nodes are connected with this pointer
key: TAddress # start address at bit 0
bits: array[TBitIndex, int] # a bit vector
PPageDescArray = ptr array[0..1000_000, PPageDesc]
TCellSet = record
TCellSet {.final.} = object
counter, max: int
head: PPageDesc
data: PPageDescArray
TSetNode = record
TSetNode {.final.} = object
n: array[0.. (1 shl bitsPerNode)-1, PSetNode]
PSetNode = ptr TSetNode

View file

@ -81,9 +81,9 @@ proc reprSetAux(result: var string, p: pointer, typ: PNimType) =
of 1: u = ze64(cast[ptr int8](p)^)
of 2: u = ze64(cast[ptr int16](p)^)
of 4: u = ze64(cast[ptr int32](p)^)
of 8: u = ze64(cast[ptr int64](p)^)
of 8: u = cast[ptr int64](p)^
else:
var a = cast[pbyteArray](p)^
var a = cast[pbyteArray](p)
for i in 0 .. typ.size*8-1:
if (a[i div 8] and (1 shl (i mod 8))) != 0:
if elemCounter > 0: add result, ", "
@ -102,8 +102,8 @@ proc reprSet(p: pointer, typ: PNimType): string {.compilerproc.} =
reprSetAux(result, p, typ)
type
TReprClosure = record # we cannot use a global variable here
# as this wouldn't be thread-safe
TReprClosure {.final.} = object # we cannot use a global variable here
# as this wouldn't be thread-safe
marked: TCellSet
recdepth: int # do not recurse endless
indent: int # indentation
@ -189,8 +189,8 @@ proc reprAux(result: var string, p: pointer, typ: PNimType,
case typ.kind
of tySet: reprSetAux(result, p, typ)
of tyArray: reprArray(result, p, typ, cl)
of tyRecord: reprRecord(result, p, typ, cl)
of tyObject: # result = reprRecord(p, typ, cl)
of tyTuple, tyPureObject: reprRecord(result, p, typ, cl)
of tyObject:
var t = cast[ptr PNimType](p)^
reprRecord(result, p, t, cl)
of tyRef, tyPtr:
@ -220,14 +220,28 @@ proc reprAux(result: var string, p: pointer, typ: PNimType,
add result, "(invalid data!)"
inc(cl.recdepth)
proc reprOpenArray(p: pointer, length: int, elemtyp: PNimType): string {.
compilerproc.} =
var
cl: TReprClosure
initReprClosure(cl)
result = "["
var bs = elemtyp.size
for i in 0..length - 1:
if i > 0: add result, ", "
reprAux(result, cast[pointer](cast[TAddress](p) + i*bs), elemtyp, cl)
add result, "]"
deinitReprClosure(cl)
proc reprAny(p: pointer, typ: PNimType): string =
var
cl: TReprClosure
initReprClosure(cl)
result = ""
if typ.kind in {tyObject, tyRecord, tyArray, tySet}:
if typ.kind in {tyObject, tyPureObject, tyTuple, tyArray, tySet}:
reprAux(result, p, typ, cl)
else:
var p = p
reprAux(result, addr(p), typ, cl)
add result, "\n"
deinitReprClosure(cl)

View file

@ -7,10 +7,10 @@
# distribution, for details about the copyright.
#
## This module contains various string utility routines.
## See the module `regexprs` for regular expression support.
## All the routines here are avaiable for the EMCAScript target
## too!
{.push debugger:off .} # the user does not want to trace a part
# of the standard library!
@ -153,6 +153,10 @@ proc ParseInt*(s: string): int {.noSideEffect.}
## a valid integer, `EInvalidValue` is raised.
# XXX: make this biggestint!
proc ParseBiggestInt*(s: string): biggestInt {.noSideEffect.}
## Parses a decimal integer value contained in `s`. If `s` is not
## a valid integer, `EInvalidValue` is raised.
proc ParseFloat*(s: string): float {.noSideEffect.}
## Parses a decimal floating point value contained in `s`. If `s` is not
## a valid floating point number, `EInvalidValue` is raised.
@ -213,7 +217,13 @@ proc allCharsInSet*(s: string, theSet: TCharSet): bool =
if not (c in theSet): return false
return true
proc c_strcmp(a, b: CString): int {.importc: "strcmp", nodecl.}
proc quoteIfSpaceExists*(s: string): string =
## returns ``'"' & s & '"'`` if `s` contains a space and does not
## start with a quote, else returns `s`
if findSubStr(' ', s) >= 0 and s[0] != '"':
result = '"' & s & '"'
else:
result = s
proc startsWith(s, prefix: string): bool =
var i = 0
@ -262,7 +272,7 @@ proc findNormalized(x: string, inArray: openarray[string]): int =
while i < high(inArray):
if cmpIgnoreStyle(x, inArray[i]) == 0: return i
inc(i, 2) # incrementing by 1 would probably result in a
# security whole ...
# security whole ...
return -1
proc `%`(formatstr: string, a: openarray[string]): string =
@ -306,11 +316,9 @@ proc `%`(formatstr: string, a: openarray[string]): string =
proc cmpIgnoreCase(a, b: string): int =
# makes usage of the fact that strings are zero-terminated
var
aa, bb: char
for i in 0..len(a)-1:
aa = toLower(a[i])
bb = toLower(b[i])
var aa = toLower(a[i])
var bb = toLower(b[i])
result = ord(aa) - ord(bb)
if result != 0: break
@ -319,14 +327,13 @@ proc cmpIgnoreCase(a, b: string): int =
proc cmpIgnoreStyle(a, b: string): int =
var
aa, bb: char
i = 0
j = 0
while True:
while a[i] == '_': inc(i)
while b[j] == '_': inc(j) # BUGFIX: typo
aa = toLower(a[i])
bb = toLower(b[j])
var aa = toLower(a[i])
var bb = toLower(b[j])
result = ord(aa) - ord(bb)
if result != 0 or aa == '\0': break
inc(i)
@ -475,15 +482,12 @@ proc deleteStr(s: var string, first, last: int) =
# parsing numbers:
proc sprintf(buf, frmt: CString) {.nodecl, importc: "sprintf", varargs.}
proc toHex(x: BiggestInt, len: int): string =
const
HexChars = "0123456789ABCDEF"
var
shift: BiggestInt
result = newString(len)
shift = 0
for j in countdown(len-1, 0):
result[j] = HexChars[toU32(x shr shift) and 0xF]
shift = shift + 4
@ -497,11 +501,8 @@ proc rawParseInt(s: string, index: var int): BiggestInt =
# one more valid negative than prositive integer. Thus we perform the
# computation as a negative number and then change the sign at the end.
var
i: int
sign: BiggestInt
i = index
# a local i is more efficient than accessing an in out parameter
sign = -1
i: int = index # a local i is more efficient than accessing a var parameter
sign: BiggestInt = -1
if s[i] == '+':
inc(i)
elif s[i] == '-':
@ -523,10 +524,8 @@ proc rawParseInt(s: string, index: var int): BiggestInt =
proc parseInt(s: string): int =
var
index: int
res: BiggestInt
index = strStart
res = rawParseInt(s, index)
index: int = 0
res = rawParseInt(s, index)
if index == -1:
raise newException(EInvalidValue, "invalid integer: " & s)
elif (sizeof(int) <= 4) and
@ -535,17 +534,20 @@ proc parseInt(s: string): int =
else:
result = int(res) # convert to smaller integer type
proc ParseBiggestInt(s: string): biggestInt =
var
index: int = 0
result = rawParseInt(s, index)
if index == -1:
raise newException(EInvalidValue, "invalid integer: " & s)
proc ParseFloat(s: string): float =
var
hd, esign, sign: float
esign = 1.0
sign = 1.0
exponent, i: int
flags: int
result = 0.0
i = 0
exponent = 0
esign = 1.0
flags = 0
sign = 1.0
if s[i] == '+': inc(i)
elif s[i] == '-':
sign = -1.0
@ -558,7 +560,7 @@ proc ParseFloat(s: string): float =
while s[i] == '_': inc(i)
# Decimal?
if s[i] == '.':
hd = 1.0
var hd = 1.0
inc(i)
while s[i] in {'0'..'9'}:
# Read fractional part
@ -586,7 +588,7 @@ proc ParseFloat(s: string): float =
inc(i)
while s[i] == '_': inc(i)
# Calculate Exponent
hd = 1.0
var hd = 1.0
for j in 1..exponent:
hd = hd * 10.0
if esign > 0.0: result = result * hd
@ -600,11 +602,10 @@ proc toOct*(x: BiggestInt, len: int): string =
## converts `x` into its octal representation. The resulting string is
## always `len` characters long. No leading ``0c`` prefix is generated.
var
mask, shift: BiggestInt
mask: BiggestInt = 7
shift: BiggestInt = 0
assert(len > 0)
result = newString(len)
mask = 7
shift = 0
for j in countdown(len-1, 0):
result[j] = chr(int((x and mask) shr shift) + ord('0'))
shift = shift + 3
@ -614,11 +615,10 @@ proc toBin*(x: BiggestInt, len: int): string =
## converts `x` into its binary representation. The resulting string is
## always `len` characters long. No leading ``0b`` prefix is generated.
var
mask, shift: BiggestInt
mask: BiggestInt = 1
shift: BiggestInt = 0
assert(len > 0)
result = newString(len)
mask = 1
shift = 0
for j in countdown(len-1, 0):
result[j] = chr(int((x and mask) shr shift) + ord('0'))
shift = shift + 1

View file

@ -33,10 +33,6 @@ var
IOFBF {.importc: "_IOFBF", nodecl.}: cint
IONBF {.importc: "_IONBF", nodecl.}: cint
# copied here to remove dependancy on strutils:
#proc toNimstr(x: Cstring, len: int): string {.
# noSideEffect, importc: "toNimStr".}
proc rawReadLine(f: TFile, result: var string) {.noStatic.} =
# of course this could be optimized a bit; but IO is slow anyway...
# and it was difficult to get this CORRECT with Ansi C's methods
@ -81,6 +77,8 @@ proc write(f: TFile, b: bool) =
else: write(f, "false")
proc write(f: TFile, r: float) = fprintf(f, "%g", r)
proc write(f: TFile, c: Char) = putc(c, f)
proc write(f: TFile, a: openArray[string]) =
for x in items(a): write(f, x)
proc EndOfFile(f: TFile): bool =
# do not blame me; blame the ANSI C standard this is so brain-damaged
@ -93,6 +91,11 @@ proc EndOfFile(f: TFile): bool =
proc writeln[Ty](f: TFile, x: Ty) =
write(f, x)
write(f, "\n")
proc writeln[Ty](f: TFile, x: openArray[Ty]) =
write(f, x)
write(f, "\n")
proc echo[Ty](x: Ty) = writeln(stdout, x)
# interface to the C procs:
@ -128,7 +131,6 @@ proc ftell(f: TFile): int {.importc: "ftell", noDecl.}
proc fwrite(buf: Pointer, size, n: int, f: TFile): int {.
importc: "fwrite", noDecl.}
# size_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream);
proc readBuffer(f: TFile, buffer: pointer, len: int): int =
result = fread(buffer, 1, len, f)
@ -140,9 +142,11 @@ proc ReadChars(f: TFile, a: var openarray[char], start, len: int): int =
result = readBuffer(f, addr(a[start]), len)
proc writeBytes(f: TFile, a: openarray[byte], start, len: int): int =
result = writeBuffer(f, addr(a[start]), len)
var x = cast[ptr array[0..1000_000_000, byte]](a)
result = writeBuffer(f, addr(x[start]), len)
proc writeChars(f: TFile, a: openarray[char], start, len: int): int =
result = writeBuffer(f, addr(a[start]), len)
var x = cast[ptr array[0..1000_000_000, byte]](a)
result = writeBuffer(f, addr(x[start]), len)
proc writeBuffer(f: TFile, buffer: pointer, len: int): int =
result = fwrite(buffer, 1, len, f)

View file

@ -16,7 +16,7 @@
# the programmer may not want
type
TStringDesc {.importc, nodecl.} = record
TStringDesc {.importc, nodecl, final.} = object
len, space: int # len and space without counting the terminating zero
data: array[0..0, char] # for the '\0' character
@ -25,7 +25,6 @@ type
# implementation:
proc resize(old: int): int {.inline.} =
assert(old < 65536 * 4)
if old <= 0: return 1
elif old < 65536: return old * 2
else: return old * 3 div 2 # for large arrays * 3/2 is better
@ -64,6 +63,7 @@ proc cstrToNimstr(str: CString): mstring {.compilerProc.} =
return toNimstr(str, c_strlen(str))
proc copyString(src: mstring): mstring {.compilerProc.} =
if src == nil: return nil
result = rawNewString(src.space)
result.len = src.len
c_memcpy(result.data, src.data, (src.len + 1) * sizeof(Char))
@ -220,7 +220,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
result.len = newLen
# --------------- other string routines ----------------------------------
proc `$`(x: int): string =
proc nimIntToStr(x: int): string {.compilerproc.} =
result = newString(sizeof(x)*4)
var i = 0
var y = x
@ -238,14 +238,12 @@ proc `$`(x: int): string =
for j in 0..i div 2 - 1:
swap(result[j], result[i-j-1])
{.push warnings: off.}
proc `$`(x: float): string =
proc nimFloatToStr(x: float): string {.compilerproc.} =
var buf: array [0..59, char]
c_sprintf(buf, "%#g", x)
return $buf
{.pop.}
proc `$`(x: int64): string =
proc nimInt64ToStr(x: int64): string {.compilerproc.} =
# we don't rely on C's runtime here as some C compiler's
# int64 support is weak
result = newString(sizeof(x)*4)
@ -265,19 +263,13 @@ proc `$`(x: int64): string =
for j in 0..i div 2 - 1:
swap(result[j], result[i-j-1])
proc `$`(x: bool): string =
if x: result = "true"
else: result = "false"
proc nimBoolToStr(x: bool): string {.compilerproc.} =
return if x: "true" else: "false"
proc `$`(x: char): string =
proc nimCharToStr(x: char): string {.compilerproc.} =
result = newString(1)
result[0] = x
proc `$`(x: string): string =
# this is useful for generic code!
return x
proc binaryStrSearch(x: openarray[string], y: string): int {.compilerproc.} =
var
a = 0

View file

@ -86,7 +86,6 @@ type
## length field.
seq*{.magic: "Seq".}[T] ## Generic type to construct sequences.
set*{.magic: "Set".}[T] ## Generic type to construct bit sets.
tuple*{.magic: "Tuple".}[T] ## Generic type to construct tuple types.
Byte* = Int8 ## this is an alias for ``int8``, that is a signed
## int 8 bits wide.
@ -110,8 +109,9 @@ type
name*: cstring ## The exception's name is its Nimrod identifier.
## This field is filled automatically in the
## ``raise`` statement.
msg*: cstring ## the exception's message. Not providing an
## exception message is bad style.
msg* {.exportc: "message".}: cstring ## the exception's message. Not
## providing an
## exception message is bad style.
EAsynch* = object of E_Base ## Abstract exception class for
## *asynchronous exceptions* (interrupts).
@ -129,18 +129,21 @@ type
## could not be fullfilled.
EArithmetic* = object of ESynch ## raised if any kind of arithmetic
## error occured.
EDivByZero* = object of EArithmetic ## is the exception class for integer
## divide-by-zero errors.
EOverflow* = object of EArithmetic ## is the exception class for integer
## calculations whose results are too
## large to fit in the provided bits.
EDivByZero* {.compilerproc.} =
object of EArithmetic ## is the exception class for integer divide-by-zero
## errors.
EOverflow* {.compilerproc.} =
object of EArithmetic ## is the exception class for integer calculations
## whose results are too large to fit in the
## provided bits.
EAccessViolation* = object of ESynch ## the exception class for
## invalid memory access errors
EAccessViolation* {.compilerproc.} =
object of ESynch ## the exception class for invalid memory access errors
EAssertionFailed* = object of ESynch ## is the exception class for Assert
## procedures that is raised if the
## assertion proves wrong
EAssertionFailed* {.compilerproc.} =
object of ESynch ## is the exception class for Assert
## procedures that is raised if the
## assertion proves wrong
EControlC* = object of EAsynch ## is the exception class for Ctrl+C
## key presses in console applications.
@ -154,6 +157,9 @@ type
EInvalidIndex* = object of ESynch ## is raised if an array index is out
## of bounds.
EInvalidField* = object of ESynch ## is raised if a record field is not
## accessible because its dicriminant's
## value does not fit.
EOutOfRange* = object of ESynch ## is raised if a range check error
## occured.
@ -164,13 +170,13 @@ type
ENoExceptionToReraise* = object of ESynch ## is raised if there is no
## exception to reraise.
EInvalidObjectAssignment* = object of ESynch ## is raised if an object
## gets assigned to its
## farther's object.
EInvalidObjectAssignment* =
object of ESynch ## is raised if an object gets assigned to its
## farther's object.
EInvalidObjectConversion* = object of ESynch ## is raised if an object is
## converted to an incompatible
## object type.
EInvalidObjectConversion* =
object of ESynch ## is raised if an object is converted to an incompatible
## object type.
TResult* = enum Failure, Success
@ -394,7 +400,7 @@ proc in_Operator*[T](x: set[T], y: T): bool {.magic: "InSet", noSideEffect.}
## writeln(stdout, 'b' in s)
##
## If ``in`` had been declared as ``[T](elem: T, s: set[T])`` then ``T`` would
## have been bound to ``char``. But ``s`` is not compatible with type
## have been bound to ``char``. But ``s`` is not compatible to type
## ``set[char]``! The solution is to bind ``T`` to ``range['a'..'z']``. This
## is achieved by reversing the parameters for ``in_operator``; ``in`` then
## passes its arguments in reverse order.
@ -418,25 +424,31 @@ proc cmp*(x, y: string): int {.noSideEffect.}
## Compare proc for strings. More efficient than the generic version.
# concat operator:
proc `&` * (x: string, y: char): string {.
magic: "ConStrStr", noSideEffect, returnsNew.}
proc `&` * (x: char, y: char): string {.
magic: "ConStrStr", noSideEffect, returnsNew.}
proc `&` * (x, y: string): string {.
magic: "ConStrStr", noSideEffect, returnsNew.}
proc `&` * (x: char, y: string): string {.
magic: "ConStrStr", noSideEffect, returnsNew.}
## is the `concatenation operator`. It
## concatenates `x` and `y`.
proc `&` * (x: string, y: char): string {.magic: "ConStrStr", noSideEffect.}
proc `&` * (x: char, y: char): string {.magic: "ConStrStr", noSideEffect.}
proc `&` * (x, y: string): string {.magic: "ConStrStr", noSideEffect.}
proc `&` * (x: char, y: string): string {.magic: "ConStrStr", noSideEffect.}
## is the `concatenation operator`. It concatenates `x` and `y`.
proc add * (x: var string, y: char) {.magic: "AppendStrCh".}
proc add * (x: var string, y: string) {.magic: "AppendStrStr".}
proc add* (x: var string, y: cstring) =
var i = 0
while y[i] != '\0':
add(x, y[i])
inc(i)
when not defined(ECMAScript):
proc add* (x: var string, y: cstring) =
var i = 0
while y[i] != '\0':
add(x, y[i])
inc(i)
else:
proc add* (x: var string, y: cstring) {.pure.} =
asm """
var len = `x`[0].length-1;
for (var i = 0; i < `y`.length; ++i) {
`x`[0][len] = `y`.charCodeAt(i);
++len;
}
`x`[0][len] = 0
"""
proc add *[T](x: var seq[T], y: T) {.magic: "AppendSeqElem".}
proc add *[T](x: var seq[T], y: seq[T]) {.magic: "AppendSeqSeq".}
@ -675,20 +687,27 @@ proc swap*[T](a, b: var T) {.magic: "Swap".}
## swaps the values `a` and `b`. This is often more efficient than
## ``tmp = a; a = b; b = tmp``. Particularly useful for sorting algorithms.
proc ze*(x: int8): int {.magic: "Ze", noSideEffect.}
proc ze*(x: int8): int {.magic: "Ze8ToI", noSideEffect.}
## zero extends a smaller integer type to ``int``. This treats `x` as
## unsigned.
proc ze*(x: int16): int {.magic: "Ze", noSideEffect.}
proc ze*(x: int16): int {.magic: "Ze16ToI", noSideEffect.}
## zero extends a smaller integer type to ``int``. This treats `x` as
## unsigned.
proc ze64*(x: int32): int64 {.magic: "Ze64", noSideEffect.}
proc ze64*(x: int8): int64 {.magic: "Ze8ToI64", noSideEffect.}
## zero extends a smaller integer type to ``int64``. This treats `x` as
## unsigned.
proc ze*(x: int): int64 {.magic: "Ze", noDecl, noSideEffect.}
proc ze64*(x: int16): int64 {.magic: "Ze16ToI64", noSideEffect.}
## zero extends a smaller integer type to ``int64``. This treats `x` as
## unsigned.
proc ze64*(x: int32): int64 {.magic: "Ze32ToI64", noSideEffect.}
## zero extends a smaller integer type to ``int64``. This treats `x` as
## unsigned.
proc ze64*(x: int): int64 {.magic: "ZeIToI64", noDecl, noSideEffect.}
## zero extends a smaller integer type to ``int64``. This treats `x` as
## unsigned. Does nothing if the size of an ``int`` is the same as ``int64``.
## (This is the case an 64 bit processors.)
## (This is the case on 64 bit processors.)
proc toU8*(x: int): int8 {.magic: "ToU8", noSideEffect.}
## treats `x` as unsigned and converts it to a byte by taking the last 8 bits
@ -749,34 +768,34 @@ template `>%` *(x, y: expr): expr = y <% x
## treats `x` and `y` as unsigned and compares them.
## Returns true iff ``unsigned(x) > unsigned(y)``.
proc `$` *(x: int): string {.noSideEffect.}
proc `$` *(x: int): string {.magic: "IntToStr", noSideEffect.}
## The stingify operator for an integer argument. Returns `x`
## converted to a decimal string.
proc `$` *(x: int64): string {.noSideEffect.}
proc `$` *(x: int64): string {.magic: "Int64ToStr", noSideEffect.}
## The stingify operator for an integer argument. Returns `x`
## converted to a decimal string.
proc `$` *(x: float): string {.noSideEffect.}
proc `$` *(x: float): string {.magic: "FloatToStr", noSideEffect.}
## The stingify operator for a float argument. Returns `x`
## converted to a decimal string.
proc `$` *(x: bool): string {.noSideEffect.}
proc `$` *(x: bool): string {.magic: "BoolToStr", noSideEffect.}
## The stingify operator for a boolean argument. Returns `x`
## converted to the string "false" or "true".
proc `$` *(x: char): string {.noSideEffect.}
proc `$` *(x: char): string {.magic: "CharToStr", noSideEffect.}
## The stingify operator for a character argument. Returns `x`
## converted to a string.
proc `$` *(x: Cstring): string {.noSideEffect, importc: "cstrToNimstr".}
proc `$` *(x: Cstring): string {.magic: "CStrToStr", noSideEffect.}
## The stingify operator for a CString argument. Returns `x`
## converted to a string.
proc `$` *(x: string): string {.noSideEffect.}
proc `$` *(x: string): string {.magic: "StrToStr", noSideEffect.}
## The stingify operator for a string argument. Returns `x`
## as it is. This operator is useful for generic code, so
## that ``$expr`` works if ``expr`` is already a string.
## that ``$expr`` also works if ``expr`` is already a string.
# undocumented:
proc getRefcount*[T](x: ref T): int {.importc: "getRefcount".}
@ -790,10 +809,12 @@ proc getCurrentExceptionMsg*(): string {.exportc.}
# new constants:
const
inf* = 1.0 / 0.0
inf* {.magic: "Inf".} = 0.0
## contains the IEEE floating point value of positive infinity.
nan* = 0.0 / 0.0
## contains the IEEE floating point value of *Not A Number*. Note
neginf* {.magic: "NegInf".} = 0.0
## contains the IEEE floating point value of negative infinity.
nan* {.magic: "NaN".} = 0.0
## contains an IEEE floating point value of *Not A Number*. Note
## that you cannot compare a floating point value to this value
## and expect a reasonable result - use the `classify` procedure
## in the module ``math`` for checking for NaN.
@ -885,11 +906,22 @@ iterator items*(a: cstring): char {.inline.} =
yield a[i]
inc(i)
proc isNil*[T](x: seq[T]): bool {.noSideEffect, magic: "IsNil".}
proc isNil*[T](x: ref T): bool {.noSideEffect, magic: "IsNil".}
proc isNil*(x: string): bool {.noSideEffect, magic: "IsNil".}
proc isNil*[T](x: ptr T): bool {.noSideEffect, magic: "IsNil".}
proc isNil*(x: pointer): bool {.noSideEffect, magic: "IsNil".}
proc isNil*(x: cstring): bool {.noSideEffect, magic: "IsNil".}
## Fast check whether `x` is nil. This is sometimes more efficient than
## ``== nil``.
# Fixup some magic symbols here:
{.fixup_system.} # This is an undocumented pragma that can only be used
# once in the system module.
proc `&` *[T](x, y: seq[T]): seq[T] {.noSideEffect, returnsNew.} =
proc `&` *[T](x, y: seq[T]): seq[T] {.noSideEffect.} =
result = []
setLen(result, x.len + y.len)
for i in 0..x.len-1:
@ -897,85 +929,49 @@ proc `&` *[T](x, y: seq[T]): seq[T] {.noSideEffect, returnsNew.} =
for i in 0..y.len-1:
result[i] = y[i]
proc `&` *[T](x: seq[T], y: T): seq[T] {.noSideEffect, returnsNew.} =
proc `&` *[T](x: seq[T], y: T): seq[T] {.noSideEffect.} =
result = []
setLen(x.len + 1)
for i in 0..x.len-1:
result[i] = x[i]
result[x.len] = y
proc `&` *[T](x: T, y: seq[T]): seq[T] {.noSideEffect, returnsNew.} =
proc `&` *[T](x: T, y: seq[T]): seq[T] {.noSideEffect.} =
result = []
setLen(y.len + 1)
for i in 0..y.len-1:
result[i] = y[i]
result[y.len] = x
proc `&` *[T](x, y: T): seq[T] {.noSideEffect, returnsNew.} =
proc `&` *[T](x, y: T): seq[T] {.noSideEffect.} =
return [x, y]
when not defined(ECMAScript): # XXX make this local procs
proc seqToPtr*[T](x: seq[T]): pointer {.inline, nosideeffect.} =
result = cast[pointer](x)
else:
proc seqToPtr*[T](x: seq[T]): pointer {.pure, nosideeffect.} =
asm """return `x`"""
proc `==` *[T](x, y: seq[T]): bool {.noSideEffect.} =
## Generic equals operator for sequences: relies on a equals operator for
## the element type `T`.
if cast[pointer](x) == cast[pointer](y):
if seqToPtr(x) == seqToPtr(y):
result = true
elif cast[pointer](x) == nil or cast[pointer](y) == nil:
elif seqToPtr(x) == nil or seqToPtr(y) == nil:
result = false
elif x.len == y.len:
for i in 0..x.len-1:
if x[i] != y[i]: return false
result = true
{.push checks: off, line_dir: off, debugger: off,
assertions: on.} # obviously we cannot generate checking operations here :-)
# because it would yield into an endless recursion
# however, stack-traces are available for most parts
# of the code
# ----------------- FPU ------------------------------------------------------
include hti
#proc disableFPUExceptions*()
# disables all floating point unit exceptions
proc initGC()
var
strDesc: TNimType
strDesc.size = sizeof(string)
strDesc.kind = tyString
initGC() # BUGFIX: need to be called here!
{.push stack_trace: off.}
include ansi_c
proc cmp(x, y: string): int =
return c_strcmp(x, y)
when defined(windows):
# work-around C's sucking abstraction:
# BUGFIX: stdin and stdout should be binary files!
const pccHack = if defined(pcc): "_" else: "" # Hack for PCC
proc setmode(handle, mode: int) {.importc: pccHack & "setmode",
header: "<io.h>".}
proc fileno(f: C_TextFileStar): int {.importc: pccHack & "fileno",
header: "<fcntl.h>".}
var
O_BINARY {.importc: pccHack & "O_BINARY", nodecl.}: int
# we use binary mode in Windows:
setmode(fileno(c_stdin), O_BINARY)
setmode(fileno(c_stdout), O_BINARY)
when defined(endb):
proc endbStep()
template newException(exceptn, message: expr): expr =
block: # open a new scope
var
e: ref exceptn
new(e)
e.msg = message
e
#proc enableFPUExceptions*()
# enables all floating point unit exceptions
# ----------------- GC interface ---------------------------------------------
@ -993,7 +989,7 @@ proc GC_fullCollect*()
type
TGC_Strategy* = enum ## the strategy the GC should use for the application
gcThroughput , ## optimize for throughput
gcThroughput, ## optimize for throughput
gcResponsiveness, ## optimize for responsiveness (default)
gcOptimizeTime, ## optimize for speed
gcOptimizeSpace ## optimize for memory footprint
@ -1010,175 +1006,241 @@ proc GC_disableMarkAndSweep*()
## and activated separately from the rest of the GC.
# ----------------- IO Part --------------------------------------------------
{.push checks: off, line_dir: off, debugger: off,
assertions: on.} # obviously we cannot generate checking operations here :-)
# because it would yield into an endless recursion
# however, stack-traces are available for most parts
# of the code
type
CFile {.importc: "FILE", nodecl.} = record # empty record for
# data hiding
TFile* = ptr CFile ## The type representing a file handle.
TFileMode* = enum ## The file mode when opening a file.
fmRead, ## Open the file for read access only.
fmWrite, ## Open the file for write access only.
fmReadWrite, ## Open the file for read and write access.
## If the file does not exist, it will be
## created.
fmReadWriteExisting, ## Open the file for read and write access.
## If the file does not exist, it will not be
## created.
fmAppend ## Open the file for writing only; append data
## at the end.
# text file handling:
var
stdin* {.importc: "stdin", noDecl.}: TFile ## The standard input stream.
stdout* {.importc: "stdout", noDecl.}: TFile ## The standard output stream.
stderr* {.importc: "stderr", noDecl.}: TFile
## The standard error stream.
##
## Note: In my opinion, this should not be used -- the concept of a
## separate error stream is a design flaw of UNIX. A seperate *message
## stream* is a good idea, but since it is named ``stderr`` there are few
## programs out there that distinguish properly between ``stdout`` and
## ``stderr``. So, that's what you get if you don't name your variables
## appropriately. It also annoys people if redirection via ``>output.txt``
## does not work because the program writes to ``stderr``.
proc OpenFile*(f: var TFile, filename: string,
mode: TFileMode = fmRead, bufSize: int = -1): Bool
## Opens a file named `filename` with given `mode`.
##
## Default mode is readonly. Returns true iff the file could be opened.
## This throws no exception if the file could not be opened. The reason is
## that the programmer needs to provide an appropriate error message anyway
## (yes, even in scripts).
proc CloseFile*(f: TFile) {.importc: "fclose", nodecl.}
## Closes the file.
proc EndOfFile*(f: TFile): Bool
## Returns true iff `f` is at the end.
proc readChar*(f: TFile): char {.importc: "fgetc", nodecl.}
## Reads a single character from the stream `f`. If the stream
## has no more characters, `EEndOfFile` is raised.
proc FlushFile*(f: TFile) {.importc: "fflush", noDecl.}
## Flushes `f`'s buffer.
proc readFile*(filename: string): string
## Opens a file name `filename` for reading. Then reads the
## file's content completely into a string and
## closes the file afterwards. Returns the string. Returns nil if there was
## an error. Does not throw an IO exception.
proc write*(f: TFile, r: float)
proc write*(f: TFile, i: int)
proc write*(f: TFile, s: string)
proc write*(f: TFile, b: Bool)
proc write*(f: TFile, c: char)
proc write*(f: TFile, c: cstring)
## Writes a value to the file `f`. May throw an IO exception.
proc readLine*(f: TFile): string
## reads a line of text from the file `f`. May throw an IO exception.
## Reading from an empty file buffer, does not throw an exception, but
## returns nil. A line of text may be delimited by ``CR``, ``LF`` or
## ``CRLF``. The newline character(s) are not part of the returned string.
proc writeln*[Ty](f: TFile, x: Ty) {.inline.}
## writes a value `x` to `f` and then writes "\n". May throw an IO exception.
proc echo*[Ty](x: Ty) {.inline.}
## equivalent to ``writeln(stdout, x); flush(stdout)``.
## equivalent to ``writeln(stdout, x); flush(stdout)``. BUT: This is
## available for the ECMAScript target too!
proc getFileSize*(f: TFile): int64
## retrieves the file size (in bytes) of `f`.
proc ReadBytes*(f: TFile, a: var openarray[byte], start, len: int): int
## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
## the actual number of bytes that have been read which may be less than
## `len` (if not as many bytes are remaining), but not greater.
template newException(exceptn, message: expr): expr =
block: # open a new scope
var
e: ref exceptn
new(e)
e.msg = message
e
proc ReadChars*(f: TFile, a: var openarray[char], start, len: int): int
## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
## the actual number of bytes that have been read which may be less than
## `len` (if not as many bytes are remaining), but not greater.
when not defined(EcmaScript):
proc readBuffer*(f: TFile, buffer: pointer, len: int): int
## reads `len` bytes into the buffer pointed to by `buffer`. Returns
## the actual number of bytes that have been read which may be less than
## `len` (if not as many bytes are remaining), but not greater.
include hti
proc writeBytes*(f: TFile, a: openarray[byte], start, len: int): int
## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
## the number of actual written bytes, which may be less than `len` in case
## of an error.
proc initGC()
proc writeChars*(f: tFile, a: openarray[char], start, len: int): int
## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
## the number of actual written bytes, which may be less than `len` in case
## of an error.
proc writeBuffer*(f: TFile, buffer: pointer, len: int): int
## writes the bytes of buffer pointed to by the parameter `buffer` to the
## file `f`. Returns the number of actual written bytes, which may be less
## than `len` in case of an error.
proc setFilePos*(f: TFile, pos: int64)
## sets the position of the file pointer that is used for read/write
## operations. The file's first byte has the index zero.
proc getFilePos*(f: TFile): int64
## retrieves the current position of the file pointer that is used to
## read from the file `f`. The file's first byte has the index zero.
include sysio
iterator lines*(filename: string): string =
## Iterate over any line in the file named `filename`.
## If the file does not exist `EIO` is raised.
var
f: TFile
if not openFile(f, filename):
raise newException(EIO, "cannot open: " & filename)
var res = ""
while not endOfFile(f):
rawReadLine(f, res)
yield res
CloseFile(f)
strDesc: TNimType
# ----------------------------------------------------------------------------
strDesc.size = sizeof(string)
strDesc.kind = tyString
initGC() # BUGFIX: need to be called here!
include excpt
# we cannot compile this with stack tracing on
# as it would recurse endlessly!
include arithm
{.pop.} # stack trace
{.push stack_trace: off.}
# sequence type declarations here because the GC needs them too:
type
TGenericSeq {.importc, nodecl.} = record
len, space: int
include ansi_c
PGenericSeq {.importc, nodecl.} = ptr TGenericSeq
proc cmp(x, y: string): int =
return c_strcmp(x, y)
const
GenericSeqSize = (2 * sizeof(int))
when defined(windows):
# work-around C's sucking abstraction:
# BUGFIX: stdin and stdout should be binary files!
const pccHack = if defined(pcc): "_" else: "" # Hack for PCC
proc setmode(handle, mode: int) {.importc: pccHack & "setmode",
header: "<io.h>".}
proc fileno(f: C_TextFileStar): int {.importc: pccHack & "fileno",
header: "<fcntl.h>".}
var
O_BINARY {.importc: pccHack & "O_BINARY", nodecl.}: int
when not defined(boehmgc) and not defined(nogc):
include gc
# we use binary mode in Windows:
setmode(fileno(c_stdin), O_BINARY)
setmode(fileno(c_stdout), O_BINARY)
include sysstr
include assign
include dyncalls
include repr
when defined(endb):
proc endbStep()
# we have to implement it here after gentostr for the cstrToNimStrDummy proc
proc getCurrentExceptionMsg(): string =
if excHandler == nil: return ""
return $excHandler.exc.msg
# ----------------- IO Part --------------------------------------------------
type
CFile {.importc: "FILE", nodecl, final.} = object # empty record for
# data hiding
TFile* = ptr CFile ## The type representing a file handle.
TFileMode* = enum ## The file mode when opening a file.
fmRead, ## Open the file for read access only.
fmWrite, ## Open the file for write access only.
fmReadWrite, ## Open the file for read and write access.
## If the file does not exist, it will be
## created.
fmReadWriteExisting, ## Open the file for read and write access.
## If the file does not exist, it will not be
## created.
fmAppend ## Open the file for writing only; append data
## at the end.
# text file handling:
var
stdin* {.importc: "stdin", noDecl.}: TFile ## The standard input stream.
stdout* {.importc: "stdout", noDecl.}: TFile ## The standard output stream.
stderr* {.importc: "stderr", noDecl.}: TFile
## The standard error stream.
##
## Note: In my opinion, this should not be used -- the concept of a
## separate error stream is a design flaw of UNIX. A seperate *message
## stream* is a good idea, but since it is named ``stderr`` there are few
## programs out there that distinguish properly between ``stdout`` and
## ``stderr``. So, that's what you get if you don't name your variables
## appropriately. It also annoys people if redirection via ``>output.txt``
## does not work because the program writes to ``stderr``.
proc OpenFile*(f: var TFile, filename: string,
mode: TFileMode = fmRead, bufSize: int = -1): Bool
## Opens a file named `filename` with given `mode`.
##
## Default mode is readonly. Returns true iff the file could be opened.
## This throws no exception if the file could not be opened. The reason is
## that the programmer needs to provide an appropriate error message anyway
## (yes, even in scripts).
proc CloseFile*(f: TFile) {.importc: "fclose", nodecl.}
## Closes the file.
proc EndOfFile*(f: TFile): Bool
## Returns true iff `f` is at the end.
proc readChar*(f: TFile): char {.importc: "fgetc", nodecl.}
## Reads a single character from the stream `f`. If the stream
## has no more characters, `EEndOfFile` is raised.
proc FlushFile*(f: TFile) {.importc: "fflush", noDecl.}
## Flushes `f`'s buffer.
proc readFile*(filename: string): string
## Opens a file name `filename` for reading. Then reads the
## file's content completely into a string and
## closes the file afterwards. Returns the string. Returns nil if there was
## an error. Does not throw an IO exception.
proc write*(f: TFile, r: float)
proc write*(f: TFile, i: int)
proc write*(f: TFile, s: string)
proc write*(f: TFile, b: Bool)
proc write*(f: TFile, c: char)
proc write*(f: TFile, c: cstring)
proc write*(f: TFile, a: openArray[string])
## Writes a value to the file `f`. May throw an IO exception.
proc readLine*(f: TFile): string
## reads a line of text from the file `f`. May throw an IO exception.
## Reading from an empty file buffer, does not throw an exception, but
## returns nil. A line of text may be delimited by ``CR``, ``LF`` or
## ``CRLF``. The newline character(s) are not part of the returned string.
proc writeln*[Ty](f: TFile, x: Ty) {.inline.}
## writes a value `x` to `f` and then writes "\n".
## May throw an IO exception.
proc writeln*[Ty](f: TFile, x: openArray[Ty]) {.inline.}
## writes a value `x` to `f` and then writes "\n".
## May throw an IO exception.
proc getFileSize*(f: TFile): int64
## retrieves the file size (in bytes) of `f`.
proc ReadBytes*(f: TFile, a: var openarray[byte], start, len: int): int
## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
## the actual number of bytes that have been read which may be less than
## `len` (if not as many bytes are remaining), but not greater.
proc ReadChars*(f: TFile, a: var openarray[char], start, len: int): int
## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
## the actual number of bytes that have been read which may be less than
## `len` (if not as many bytes are remaining), but not greater.
proc readBuffer*(f: TFile, buffer: pointer, len: int): int
## reads `len` bytes into the buffer pointed to by `buffer`. Returns
## the actual number of bytes that have been read which may be less than
## `len` (if not as many bytes are remaining), but not greater.
proc writeBytes*(f: TFile, a: openarray[byte], start, len: int): int
## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
## the number of actual written bytes, which may be less than `len` in case
## of an error.
proc writeChars*(f: tFile, a: openarray[char], start, len: int): int
## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
## the number of actual written bytes, which may be less than `len` in case
## of an error.
proc writeBuffer*(f: TFile, buffer: pointer, len: int): int
## writes the bytes of buffer pointed to by the parameter `buffer` to the
## file `f`. Returns the number of actual written bytes, which may be less
## than `len` in case of an error.
proc setFilePos*(f: TFile, pos: int64)
## sets the position of the file pointer that is used for read/write
## operations. The file's first byte has the index zero.
proc getFilePos*(f: TFile): int64
## retrieves the current position of the file pointer that is used to
## read from the file `f`. The file's first byte has the index zero.
include sysio
iterator lines*(filename: string): string =
## Iterate over any line in the file named `filename`.
## If the file does not exist `EIO` is raised.
var
f: TFile
if not openFile(f, filename):
raise newException(EIO, "cannot open: " & filename)
var res = ""
while not endOfFile(f):
rawReadLine(f, res)
yield res
CloseFile(f)
# ----------------------------------------------------------------------------
include excpt
# we cannot compile this with stack tracing on
# as it would recurse endlessly!
include arithm
{.pop.} # stack trace
# sequence type declarations here because the GC needs them too:
type
TGenericSeq {.importc, nodecl, final.} = object
len, space: int
PGenericSeq {.importc, nodecl.} = ptr TGenericSeq
const
GenericSeqSize = (2 * sizeof(int))
when not defined(boehmgc) and not defined(nogc):
include gc
include sysstr
include assign
include dyncalls
include repr
# we have to implement it here after gentostr for the cstrToNimStrDummy proc
proc getCurrentExceptionMsg(): string =
if excHandler == nil: return ""
return $excHandler.exc.msg
{.push stack_trace: off.}
when defined(endb):
include debugger
{.pop.} # stacktrace
else:
include ecmasys
include macros
{.push stack_trace: off.}
when defined(endb):
include debugger
{.pop.} # stacktrace
{.pop.} # checks
{.pop.} # hints

View file

@ -1,7 +1,7 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2006 Andreas Rumpf
# (c) Copyright 2008 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@ -9,6 +9,7 @@
## This module contains routines and types for dealing with time.
## This module is available for the ECMAScript target.
{.push debugger:off .} # the user does not want to trace a part
# of the standard library!
@ -22,9 +23,49 @@ type
TWeekDay* = enum ## represents a weekday
dMon, dTue, dWed, dThu, dFri, dSat, dSun
TTime* {.importc: "time_t".} = record ## abstract type that represents a time
TTime* {.importc: "time_t", final.} = object ## abstract type that
## represents a time
when defined(ECMAScript):
getDay: proc (): int
getFullYear: proc (): int
getHours: proc (): int
getMilliseconds: proc (): int
getMinutes: proc (): int
getMonth: proc (): int
getSeconds: proc (): int
getTime: proc (): int
getTimezoneOffset: proc (): int
getUTCDate: proc (): int
getUTCFullYear: proc (): int
getUTCHours: proc (): int
getUTCMilliseconds: proc (): int
getUTCMinutes: proc (): int
getUTCMonth: proc (): int
getUTCSeconds: proc (): int
getYear: proc (): int
parse: proc (s: cstring): TTime
setDate: proc (x: int)
setFullYear: proc (x: int)
setHours: proc (x: int)
setMilliseconds: proc (x: int)
setMinutes: proc (x: int)
setMonth: proc (x: int)
setSeconds: proc (x: int)
setTime: proc (x: int)
setUTCDate: proc (x: int)
setUTCFullYear: proc (x: int)
setUTCHours: proc (x: int)
setUTCMilliseconds: proc (x: int)
setUTCMinutes: proc (x: int)
setUTCMonth: proc (x: int)
setUTCSeconds: proc (x: int)
setYear: proc (x: int)
toGMTString: proc (): cstring
toLocaleString: proc (): cstring
UTC: proc (): int
TTimeInfo* = record ## represents a time in different parts
TTimeInfo* = object of TObject ## represents a time in different parts
second*: range[0..61] ## The number of seconds after the minute,
## normally in the range 0 to 59, but can
## be up to 61 to allow for leap seconds.
@ -38,6 +79,7 @@ type
weekday*: TWeekDay ## The current day of the week.
yearday*: range[0..365] ## The number of days since January 1,
## in the range 0 to 365.
## Always 0 if the target is ECMAScript.
proc getTime*(): TTime ## gets the current calendar time
proc getLocalTime*(t: TTime): TTimeInfo
@ -54,7 +96,7 @@ proc TimeInfoToTime*(timeInfo: TTimeInfo): TTime
## them from the other information in the broken-down time structure.
proc `$` *(timeInfo: TTimeInfo): string
## converts a `TTimeInfo` record to a
## converts a `TTimeInfo` object to a
## string representation.
proc `$` *(time: TTime): string
## converts a calendar time to a
@ -72,92 +114,149 @@ proc `-` *(a, b: TTime): int64
proc getStartMilsecs*(): int
## get the miliseconds from the start of the program
#implementation
# C wrapper:
type
structTM {.importc: "struct tm".} = record
second {.importc: "tm_sec".},
minute {.importc: "tm_min".},
hour {.importc: "tm_hour".},
monthday {.importc: "tm_mday".},
month {.importc: "tm_mon".},
year {.importc: "tm_year".},
weekday {.importc: "tm_wday".},
yearday {.importc: "tm_yday".},
isdst {.importc: "tm_isdst".}: cint
when not defined(ECMAScript):
PTimeInfo = ptr structTM
PTime = ptr TTime
# C wrapper:
type
structTM {.importc: "struct tm", final.} = object
second {.importc: "tm_sec".},
minute {.importc: "tm_min".},
hour {.importc: "tm_hour".},
monthday {.importc: "tm_mday".},
month {.importc: "tm_mon".},
year {.importc: "tm_year".},
weekday {.importc: "tm_wday".},
yearday {.importc: "tm_yday".},
isdst {.importc: "tm_isdst".}: cint
TClock {.importc: "clock_t".} = range[low(int)..high(int)]
PTimeInfo = ptr structTM
PTime = ptr TTime
proc localtime(timer: PTime): PTimeInfo {.
importc: "localtime", header: "<time.h>".}
proc gmtime(timer: PTime): PTimeInfo {.importc: "gmtime", header: "<time.h>".}
proc timec(timer: PTime): TTime {.importc: "time", header: "<time.h>".}
proc mktime(t: structTM): TTime {.importc: "mktime", header: "<time.h>".}
proc asctime(tblock: structTM): CString {.
importc: "asctime", header: "<time.h>".}
proc ctime(time: PTime): CString {.importc: "ctime", header: "<time.h>".}
# strftime(s: CString, maxsize: int, fmt: CString, t: tm): int {.
# importc: "strftime", header: "<time.h>".}
proc clock(): TClock {.importc: "clock", header: "<time.h>".}
proc difftime(a, b: TTime): float {.importc: "difftime", header: "<time.h>".}
TClock {.importc: "clock_t".} = range[low(int)..high(int)]
var
clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl.}: int
proc localtime(timer: PTime): PTimeInfo {.
importc: "localtime", header: "<time.h>".}
proc gmtime(timer: PTime): PTimeInfo {.importc: "gmtime", header: "<time.h>".}
proc timec(timer: PTime): TTime {.importc: "time", header: "<time.h>".}
proc mktime(t: structTM): TTime {.importc: "mktime", header: "<time.h>".}
proc asctime(tblock: structTM): CString {.
importc: "asctime", header: "<time.h>".}
proc ctime(time: PTime): CString {.importc: "ctime", header: "<time.h>".}
# strftime(s: CString, maxsize: int, fmt: CString, t: tm): int {.
# importc: "strftime", header: "<time.h>".}
proc clock(): TClock {.importc: "clock", header: "<time.h>".}
proc difftime(a, b: TTime): float {.importc: "difftime", header: "<time.h>".}
var
clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl.}: int
# our own procs on top of that:
proc tmToTimeInfo(tm: structTM): TTimeInfo =
# our own procs on top of that:
proc tmToTimeInfo(tm: structTM): TTimeInfo =
const
weekDays: array [0..6, TWeekDay] = [
dSun, dMon, dTue, dWed, dThu, dFri, dSat]
result.second = int(tm.second)
result.minute = int(tm.minute)
result.hour = int(tm.hour)
result.monthday = int(tm.monthday)
result.month = TMonth(tm.month)
result.year = tm.year + 1900
result.weekday = weekDays[int(tm.weekDay)]
result.yearday = int(tm.yearday)
proc timeInfoToTM(t: TTimeInfo): structTM =
const
weekDays: array [TWeekDay, int] = [1, 2, 3, 4, 5, 6, 0]
result.second = t.second
result.minute = t.minute
result.hour = t.hour
result.monthday = t.monthday
result.month = ord(t.month)
result.year = t.year - 1900
result.weekday = weekDays[t.weekDay]
result.yearday = t.yearday
result.isdst = -1
proc `-` (a, b: TTime): int64 =
return toInt(difftime(a, b)) # XXX: toBiggestInt is needed here, but
# Nim does not support it!
proc getStartMilsecs(): int = return clock() div (clocksPerSec div 1000)
proc getTime(): TTime = return timec(nil)
proc getLocalTime(t: TTime): TTimeInfo =
var a = t
result = tmToTimeInfo(localtime(addr(a))^)
# copying is needed anyway to provide reentrancity; thus
# the convertion is not expensive
proc getGMTime(t: TTime): TTimeInfo =
var a = t
result = tmToTimeInfo(gmtime(addr(a))^)
# copying is needed anyway to provide reentrancity; thus
# the convertion is not expensive
proc TimeInfoToTime(timeInfo: TTimeInfo): TTime =
var cTimeInfo = timeInfo # for C++ we have to make a copy,
# because the header of mktime is broken in my version of libc
return mktime(timeInfoToTM(cTimeInfo))
proc `$`(timeInfo: TTimeInfo): string =
return $asctime(timeInfoToTM(timeInfo))
proc `$`(time: TTime): string =
var a = time
return $ctime(addr(a))
else:
proc getTime(): TTime {.importc: "new Date", nodecl.}
const
weekDays: array [0..6, TWeekDay] = [
dSun, dMon, dTue, dWed, dThu, dFri, dSat]
result.second = int(tm.second)
result.minute = int(tm.minute)
result.hour = int(tm.hour)
result.monthday = int(tm.monthday)
result.month = TMonth(tm.month)
result.year = tm.year + 1900
result.weekday = weekDays[int(tm.weekDay)]
result.yearday = int(tm.yearday)
proc timeInfoToTM(t: TTimeInfo): structTM =
const
weekDays: array [TWeekDay, int] = [1, 2, 3, 4, 5, 6, 0]
result.second = t.second
result.minute = t.minute
result.hour = t.hour
result.monthday = t.monthday
result.month = ord(t.month)
result.year = t.year - 1900
result.weekday = weekDays[t.weekDay]
result.yearday = t.yearday
result.isdst = -1
proc getLocalTime(t: TTime): TTimeInfo =
result.second = t.getSeconds()
result.minute = t.getMinutes()
result.hour = t.getHours()
result.monthday = t.getDate()
result.month = TMonth(t.getMonth())
result.year = t.getFullYear()
result.weekday = weekDays[t.getDay()]
result.yearday = 0
proc `-` (a, b: TTime): int64 =
return toInt(difftime(a, b)) # XXX: toBiggestInt is needed here, but
# Nim does not support it!
proc getGMTime(t: TTime): TTimeInfo =
result.second = t.getUTCSeconds()
result.minute = t.getUTCMinutes()
result.hour = t.getUTCHours()
result.monthday = t.getUTCDate()
result.month = TMonth(t.getUTCMonth())
result.year = t.getUTCFullYear()
result.weekday = weekDays[t.getDay()]
result.yearday = 0
proc getStartMilsecs(): int = return clock() div (clocksPerSec div 1000)
proc getTime(): TTime = return timec(nil)
proc getLocalTime(t: TTime): TTimeInfo =
var a = t
result = tmToTimeInfo(localtime(addr(a))^)
# copying is needed anyway to provide reentrancity; thus
# the convertion is not expensive
proc TimeInfoToTime*(timeInfo: TTimeInfo): TTime =
result = getTime()
result.setSeconds(timeInfo.second)
result.setMinutes(timeInfo.minute)
result.setHours(timeInfo.hour)
result.setMonth(ord(timeInfo.month))
result.setFullYear(timeInfo.year)
result.setDate(timeInfo.monthday)
proc getGMTime(t: TTime): TTimeInfo =
var a = t
result = tmToTimeInfo(gmtime(addr(a))^)
# copying is needed anyway to provide reentrancity; thus
# the convertion is not expensive
proc `$`(timeInfo: TTimeInfo): string = return $(TimeInfoToTIme(timeInfo))
proc `$`(time: TTime): string = $time.toLocaleString()
proc TimeInfoToTime(timeInfo: TTimeInfo): TTime =
var cTimeInfo = timeInfo # for C++ we have to make a copy,
# because the header of mktime is broken in my version of libc
return mktime(timeInfoToTM(cTimeInfo))
proc `-` (a, b: TTime): int64 =
return a.getTime() - b.getTime()
var
startMilsecs = getTime()
proc getStartMilsecs(): int =
## get the miliseconds from the start of the program
return int(getTime() - startMilsecs)
proc getDateStr(): string =
var ti = getLocalTime(getTime())
@ -169,11 +268,4 @@ proc getClockStr(): string =
result = intToStr(ti.hour, 2) & ':' & intToStr(ti.minute, 2) &
':' & intToStr(ti.second, 2)
proc `$`(timeInfo: TTimeInfo): string =
return $asctime(timeInfoToTM(timeInfo))
proc `$`(time: TTime): string =
var a = time
return $ctime(addr(a))
{.pop.}

View file

@ -1,221 +0,0 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2006 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# type-info module for Nimrod
include hti
proc typeid(x: any): PNimType
type
Variant = opaque record
# contains the address and a typeinfo
a: pointer # an address
k: TNimTypeKind
# conversions to any and from any are inserted by the compiler!
# x.attr is supported, as well as x[]!
# here is a special iterator for variants:
iterator fields(x: variant): (fieldname: string, value: variant) =
proc setField(structure: variant, fieldname: string, value: variant)
proc getField(structure: variant, fieldname: string)
# any is implemented as a pair (val: pointer, info: PTypeInfo)
# val is for:
# an array - its address
# a record - its address
# an object - its address
# a string - the address of the pointer to the string data
# a sequence - the address of the pointer to the sequence data
# a float - the address of a memory location where the float is stored
# this is a given address; storage comes from compiler or is
# already there (in a container)
# an int - the address of a memory location where the int is stored
# storage comes from compiler or is
# already there (in a container)
# a cstring - the address of an address of an array of chars
# a ref - the address of the ref! (not the ref itself!)
# But this does not work too well...
# Better: any is a ref to Object; than we define intObj, floatObj,
# etc.; for strings this not needed as they already fit into the
# scheme!
#
type
TAnyImpl {.exportc: "TAnyImpl".} = record
typ {.exportc: "info".}: PNimType
val {.exportc: "val".}: pointer
proc
typeKind(p: PNimType): TTypeKind {.inline.}
getAnyLength(x: any): int
isContainer(x: any): bool
writeAny(container: any, index: int, val: any)
readAny(container: any, index: int): any
writeAny(container: any, name: string, val: any)
readAny(container: any, name: string): any
getAttr(container: any, index: int, out name: string, out val: any)
getEnumStrings(enumeration: any): sequence of string
anyToInt(x: any): biggestint
anyToFloat(x: any): biggestfloat
anyToString(x: any): string
anyToChar(x: any): char
anyToBool(x: any): bool
#anyToT{T}(x: any, out result: T)
# etc...
#write(a: array of any) # also possible!
#generic proc
# deepCopy{T}(x: T): T
import
strutils
proc anyToImpl(a: any): TAnyImpl {.inline.} =
result = cast{TAnyImpl}(a)
proc typeKind(p: PNimType): TTypeKind =
result = p.typeKind
type
Pint = untraced ref int
Pint8 = untraced ref int8
Pint16 = untraced ref int16
Pint32 = untraced ref int32
Pint64 = untraced ref int64
Puint = untraced ref uint
Puint8 = untraced ref uint8
Puint16 = untraced ref uint16
Puint32 = untraced ref uint32
Puint64 = untraced ref uint64
Pfloat = untraced ref float
Pfloat32 = untraced ref float32
Pfloat64 = untraced ref float64
Pstring = untraced ref string
Pbool = untraced ref bool
Pchar = untraced ref char
proc anyToInt(x: any): biggestint =
var impl = anyToImpl(x)
case impl.typ.typeKind
of tyInt, tyEnum: result = cast{pint}(x.val)^
of tySInt8: result = cast{pint8}(x.val)^
of tySInt16: result = cast{pint16}(x.val)^
of tySInt32: result = cast{pint32}(x.val)^
of tySInt64: result = cast{pint64}(x.val)^
of tyUInt: result = cast{puint}(x.val)^
of tyUInt8: result = cast{puint8}(x.val)^
of tyUInt16: result = cast{puint16}(x.val)^
of tyUInt32: result = cast{puint32}(x.val)^
of tyUInt64: result = cast{puint64}(x.val)^
else: raise EConvertError
proc anyToFloat(x: any): biggestfloat =
var impl = anyToImpl(x)
case impl.typ.typeKind
of tyReal: result = cast{pfloat}(x.val)^
of tyReal32: result = cast{pfloat32}(x.val)^
of tyReal64: result = cast{pfloat64}(x.val)^
# of tyReal128:
else: raise EConvertError
proc anyToString(x: any): string =
var impl = anyToImpl(x)
case impl.typ.typeKind
of tyString: result = cast{pstring}(x.val)^
else: raise EConvertError
proc anyToChar(x: any): char =
var impl = anyToImpl(x)
case impl.typ.typeKind
of tyChar: result = cast{pchar}(x.val)^
else: raise EConvertError
proc anyToBool(x: any): bool =
var impl = anyToImpl(x)
case impl.typ.typeKind
of tyBool: result = cast{pbool}(x.val)^
else: raise EConvertError
proc getAnyLength(x: any): int =
result = anyToImpl(x).typ.len
const
ContainerSet = {tyArray, tyRecord, tyObject, tyOpenArray, tySequence, tyTable}
proc isContainer(x: any): bool =
result = anyToImpl(x).typ.typeKind in ContainerSet
proc strcmp(a, b: cstring): int {.external: "strcmp", nodecl.}
proc strToIndex(info: PTypeInfo, str: string): int =
for i in 0..typ.len-1:
if strcmp(info.slots[i].name, str) == 0:
return i
raise EConvertError
proc writeAny(container: any, index: int, val: any) =
var x = anyToImpl(container)
if index >= 0 and index < container.len:
case x.typ.typeKind
of tySequence:
var u = cast{TAddress}(x.val)
genericAssignAux(cast{pointer}(u) +% x.typ.slots[index].offset +%
GenericSeqSize,
anyToImpl(val).val, u.typ.baseType)
of tyArray:
of tyRecord, tyObject:
else: raise EConvertError
else:
raise EIndexError
proc readAny(container: any, index: int): any =
var x = anyToImpl(container)
if x.typ.typeKind in ContainerSet:
if index >= 0 and index < container.len:
# XXX
else:
raise EIndexError
else:
raise EConvertError
proc writeAny(container: any, name: string, val: any) =
result = writeAny(container, strToIndex(anyToImpl(container).typ), val)
proc readAny(container: any, name: string): any =
result = readAny(container, strToIndex(anyToImpl(container).typ))
proc getAttr(container: any, index: int, out name: string, out val: any) =
var x = anyToImpl(container)
if x.typ.typeKind in ContainerSet:
val = readAny(container, index)
name = $x.typ.slots[index].name
else:
raise EConvertError
proc getEnumStrings(enumeration: any): sequence of string =
result = []
var x = anyToImpl(enumeration)
if x.typ.typekind == tyEnum:
for i in 0 .. x.typ.len-1:
result &= $x.typ.slots[i].name
else:
raise EConvertError

View file

@ -980,7 +980,7 @@ const
#/////////////////////////////////////////////////////////
type
mmtime* = record
mmtime* {.final.} = object
wType*: UINT
hour*, min*, sec*, frame*, fps*, dummy*: int8
pad*: array[0..1, int8]
@ -990,7 +990,7 @@ type
LPMMTIME* = ptr mmtime
PWAVEHDR* = ptr wavehdr
TMMTime* = mmtime
wavehdr* = record
wavehdr* {.final.} = object
lpData*: cstring
dwBufferLength*: DWORD
dwBytesRecorded*: DWORD
@ -1003,7 +1003,7 @@ type
TWAVEHDR* = WAVEHDR
NPWAVEHDR* = ptr wavehdr
LPWAVEHDR* = ptr wavehdr
WAVEOUTCAPSA* = record
WAVEOUTCAPSA* {.final.} = object
wMid*: int16
wPid*: int16
vDriverVersion*: MMVERSION
@ -1017,7 +1017,7 @@ type
PWAVEOUTCAPSA* = ptr WAVEOUTCAPSA
NPWAVEOUTCAPSA* = ptr WAVEOUTCAPSA
LPWAVEOUTCAPSA* = ptr WAVEOUTCAPSA
WAVEOUTCAPSW* = record
WAVEOUTCAPSW* {.final.} = object
wMid*: int16
wPid*: int16
vDriverVersion*: MMVERSION
@ -1046,7 +1046,7 @@ else:
LPWAVEOUTCAPS* = LPWAVEOUTCAPSA
type
TWAVEOUTCAPS* = WAVEOUTCAPS
WAVEINCAPSA* = record
WAVEINCAPSA* {.final.} = object
wMid*: int16
wPid*: int16
vDriverVersion*: MMVERSION
@ -1059,7 +1059,7 @@ type
NPWAVEINCAPSA* = ptr WAVEINCAPSA
LPWAVEINCAPSA* = ptr WAVEINCAPSA
TWAVEINCAPSA* = WAVEINCAPSA
WAVEINCAPSW* = record
WAVEINCAPSW* {.final.} = object
wMid*: int16
wPid*: int16
vDriverVersion*: MMVERSION
@ -1087,7 +1087,7 @@ else:
LPWAVEINCAPS* = LPWAVEINCAPSA
type
TWAVEINCAPS* = WAVEINCAPS
waveformat* = record
waveformat* {.final.} = object
wFormatTag*: int16
nChannels*: int16
nSamplesPerSec*: DWORD
@ -1103,7 +1103,7 @@ const
WAVE_FORMAT_PCM* = 1
type
pcmwaveformat* = record
pcmwaveformat* {.final.} = object
wf*: WAVEFORMAT
wBitsPerSample*: int16
@ -1111,7 +1111,7 @@ type
NPPCMWAVEFORMAT* = ptr pcmwaveformat
LPPCMWAVEFORMAT* = ptr pcmwaveformat
TPCMWAVEFORMAT* = PCMWAVEFORMAT
WAVEFORMATEX* = record
WAVEFORMATEX* {.final.} = object
wFormatTag*: int16
nChannels*: int16
nSamplesPerSec*: DWORD
@ -1143,7 +1143,7 @@ type
LPPATCHARRAY* = ptr int16
KEYARRAY* = array[0..Pred(MIDIPATCHSIZE), int16]
LPKEYARRAY* = ptr int16
MIDIOUTCAPSA* = record
MIDIOUTCAPSA* {.final.} = object
wMid*: int16
wPid*: int16
vDriverVersion*: MMVERSION
@ -1158,7 +1158,7 @@ type
NPMIDIOUTCAPSA* = ptr MIDIOUTCAPSA
LPMIDIOUTCAPSA* = ptr MIDIOUTCAPSA
TMIDIOUTCAPSA* = MIDIOUTCAPSA
MIDIOUTCAPSW* = record
MIDIOUTCAPSW* {.final.} = object
wMid*: int16
wPid*: int16
vDriverVersion*: MMVERSION
@ -1173,7 +1173,7 @@ type
NPMIDIOUTCAPSW* = ptr MIDIOUTCAPSW
LPMIDIOUTCAPSW* = ptr MIDIOUTCAPSW
TMIDIOUTCAPSW* = MIDIOUTCAPSW
MIDIINCAPSA* = record
MIDIINCAPSA* {.final.} = object
wMid*: int16
wPid*: int16
vDriverVersion*: MMVERSION
@ -1184,7 +1184,7 @@ type
NPMIDIINCAPSA* = ptr MIDIINCAPSA
LPMIDIINCAPSA* = ptr MIDIINCAPSA
TMIDIINCAPSA* = MIDIINCAPSA
MIDIINCAPSW* = record
MIDIINCAPSW* {.final.} = object
wMid*: int16
wPid*: int16
vDriverVersion*: MMVERSION
@ -1219,7 +1219,7 @@ else:
type
TMIDIINCAPS* = MIDIINCAPS
PMIDIHDR* = ptr midihdr
midihdr* = record
midihdr* {.final.} = object
lpData*: cstring
dwBufferLength*: DWORD
dwBytesRecorded*: DWORD
@ -1233,30 +1233,30 @@ type
NPMIDIHDR* = ptr midihdr
LPMIDIHDR* = ptr midihdr
TMIDIHDR* = MIDIHDR
midievent* = record
midievent* {.final.} = object
dwDeltaTime*: DWORD
dwStreamID*: DWORD
dwEvent*: DWORD
dwParms*: array[0..Pred(1), DWORD]
TMIDIEVENT* = MIDIEVENT
midistrmbuffver* = record
midistrmbuffver* {.final.} = object
dwVersion*: DWORD
dwMid*: DWORD
dwOEMVersion*: DWORD
TMIDISTRMBUFFVER* = MIDISTRMBUFFVER
Tmidiproptimediv* = record
Tmidiproptimediv* {.final.} = object
cbStruct*: DWORD
dwTimeDiv*: DWORD
LPMIDIPROPTIMEDIV* = ptr Tmidiproptimediv
Tmidiproptempo* = record
Tmidiproptempo* {.final.} = object
cbStruct*: DWORD
dwTempo*: DWORD
LPMIDIPROPTEMPO* = ptr Tmidiproptempo
AUXCAPSA* = record
AUXCAPSA* {.final.} = object
wMid*: int16
wPid*: int16
vDriverVersion*: MMVERSION
@ -1269,7 +1269,7 @@ type
NPAUXCAPSA* = ptr AUXCAPSA
LPAUXCAPSA* = ptr AUXCAPSA
TAUXCAPSA* = AUXCAPSA
AUXCAPSW* = record
AUXCAPSW* {.final.} = object
wMid*: int16
wPid*: int16
vDriverVersion*: MMVERSION
@ -1305,7 +1305,7 @@ type
proc mixerGetNumDevs*(): UINT{.stdcall, dynlib: "winmm.dll",
importc: "mixerGetNumDevs".}
type
MIXERCAPSA* = record
MIXERCAPSA* {.final.} = object
wMid*: int16
wPid*: int16
vDriverVersion*: MMVERSION
@ -1316,7 +1316,7 @@ type
PMIXERCAPSA* = ptr MIXERCAPSA
LPMIXERCAPSA* = ptr MIXERCAPSA
TMIXERCAPSA* = MIXERCAPSA
MIXERCAPSW* = record
MIXERCAPSW* {.final.} = object
wMid*: int16
wPid*: int16
vDriverVersion*: MMVERSION
@ -1340,7 +1340,7 @@ else:
LPMIXERCAPS* = LPMIXERCAPSA
type
TMIXERCAPS* = MIXERCAPS
MIXERLINEA* = record
MIXERLINEA* {.final.} = object
cbStruct*: DWORD
dwDestination*: DWORD
dwSource*: DWORD
@ -1361,7 +1361,7 @@ type
PMIXERLINEA* = ptr MIXERLINEA
LPMIXERLINEA* = ptr MIXERLINEA
TMIXERLINEA* = MIXERLINEA
MIXERLINEW* = record
MIXERLINEW* {.final.} = object
cbStruct*: DWORD
dwDestination*: DWORD
dwSource*: DWORD
@ -1395,7 +1395,7 @@ else:
LPMIXERLINE* = LPMIXERLINEA
type
TMIXERLINE* = MIXERLINE
MIXERCONTROLA* = record
MIXERCONTROLA* {.final.} = object
cbStruct*: DWORD
dwControlID*: DWORD
dwControlType*: DWORD
@ -1411,7 +1411,7 @@ type
PMIXERCONTROLA* = ptr MIXERCONTROLA
LPMIXERCONTROLA* = ptr MIXERCONTROLA
TMIXERCONTROLA* = MIXERCONTROLA
MIXERCONTROLW* = record
MIXERCONTROLW* {.final.} = object
cbStruct*: DWORD
dwControlID*: DWORD
dwControlType*: DWORD
@ -1440,7 +1440,7 @@ else:
LPMIXERCONTROL* = LPMIXERCONTROLA
type
TMIXERCONTROL* = MIXERCONTROL
MIXERLINECONTROLSA* = record
MIXERLINECONTROLSA* {.final.} = object
cbStruct*: DWORD
dwLineID*: DWORD
dwControlType*, cControls*, cbmxctrl*: DWORD
@ -1449,7 +1449,7 @@ type
PMIXERLINECONTROLSA* = ptr MIXERLINECONTROLSA
LPMIXERLINECONTROLSA* = ptr MIXERLINECONTROLSA
TMIXERLINECONTROLSA* = MIXERLINECONTROLSA
MIXERLINECONTROLSW* = record
MIXERLINECONTROLSW* {.final.} = object
cbStruct*: DWORD
dwLineID*: DWORD
dwControlType*, cControls*, cbmxctrl*: DWORD
@ -1471,7 +1471,7 @@ else:
LPMIXERLINECONTROLS* = LPMIXERLINECONTROLSA
type
TMIXERLINECONTROLS* = MIXERLINECONTROLS
TMIXERCONTROLDETAILS* = record
TMIXERCONTROLDETAILS* {.final.} = object
cbStruct*: DWORD
dwControlID*: DWORD
cChannels*: DWORD
@ -1481,7 +1481,7 @@ type
MIXERCONTROLDETAILS* = tMIXERCONTROLDETAILS
PMIXERCONTROLDETAILS* = ptr tMIXERCONTROLDETAILS
LPMIXERCONTROLDETAILS* = ptr tMIXERCONTROLDETAILS
MIXERCONTROLDETAILS_LISTTEXTA* = record
MIXERCONTROLDETAILS_LISTTEXTA* {.final.} = object
dwParam1*: DWORD
dwParam2*: DWORD
szName*: array[0..Pred(MIXER_LONG_NAME_CHARS), CHAR]
@ -1489,7 +1489,7 @@ type
PMIXERCONTROLDETAILS_LISTTEXTA* = ptr MIXERCONTROLDETAILS_LISTTEXTA
LPMIXERCONTROLDETAILS_LISTTEXTA* = ptr MIXERCONTROLDETAILS_LISTTEXTA
TMIXERCONTROLDETAILS_LISTTEXTA* = MIXERCONTROLDETAILS_LISTTEXTA
MIXERCONTROLDETAILS_LISTTEXTW* = record
MIXERCONTROLDETAILS_LISTTEXTW* {.final.} = object
dwParam1*: DWORD
dwParam2*: DWORD
szName*: array[0..Pred(MIXER_LONG_NAME_CHARS), WCHAR]
@ -1510,19 +1510,19 @@ else:
LPMIXERCONTROLDETAILS_LISTTEXT* = LPMIXERCONTROLDETAILS_LISTTEXTA
type
TMIXERCONTROLDETAILS_LISTTEXT* = MIXERCONTROLDETAILS_LISTTEXT
MIXERCONTROLDETAILS_BOOLEAN* = record
MIXERCONTROLDETAILS_BOOLEAN* {.final.} = object
fValue*: int32
PMIXERCONTROLDETAILS_BOOLEAN* = ptr MIXERCONTROLDETAILS_BOOLEAN
LPMIXERCONTROLDETAILS_BOOLEAN* = ptr MIXERCONTROLDETAILS_BOOLEAN
TMIXERCONTROLDETAILS_BOOLEAN* = MIXERCONTROLDETAILS_BOOLEAN
MIXERCONTROLDETAILS_SIGNED* = record
MIXERCONTROLDETAILS_SIGNED* {.final.} = object
lValue*: int32
PMIXERCONTROLDETAILS_SIGNED* = ptr MIXERCONTROLDETAILS_SIGNED
LPMIXERCONTROLDETAILS_SIGNED* = ptr MIXERCONTROLDETAILS_SIGNED
TMIXERCONTROLDETAILS_SIGNED* = MIXERCONTROLDETAILS_SIGNED
MIXERCONTROLDETAILS_UNSIGNED* = record
MIXERCONTROLDETAILS_UNSIGNED* {.final.} = object
dwValue*: DWORD
PMIXERCONTROLDETAILS_UNSIGNED* = ptr MIXERCONTROLDETAILS_UNSIGNED
@ -1531,7 +1531,7 @@ type
LPTIMECALLBACK* = proc (uTimerID, uMsg: UINT, dwUser, dw1, dw2: DWORD){.
stdcall.}
TTIMECALLBACK* = LPTIMECALLBACK
timecaps* = record
timecaps* {.final.} = object
wPeriodMin*: UINT
wPeriodMax*: UINT
@ -1539,7 +1539,7 @@ type
NPTIMECAPS* = ptr timecaps
LPTIMECAPS* = ptr timecaps
TTIMECAS* = TIMECAPS
JOYCAPSA* = record
JOYCAPSA* {.final.} = object
wMid*: int16
wPid*: int16
szPname*: array[0..Pred(MAXPNAMELEN), CHAR]
@ -1569,7 +1569,7 @@ type
NPJOYCAPSA* = ptr JOYCAPSA
LPJOYCAPSA* = ptr JOYCAPSA
TJOYCAPSA* = JOYCAPSA
JOYCAPSW* = record
JOYCAPSW* {.final.} = object
wMid*: int16
wPid*: int16
szPname*: array[0..Pred(MAXPNAMELEN), WCHAR]
@ -1614,7 +1614,7 @@ else:
LPJOYCAPS* = LPJOYCAPSA
type
TJOYCAPS* = JOYCAPS
joyinfo* = record
joyinfo* {.final.} = object
wXpos*: UINT
wYpos*: UINT
wZpos*: UINT
@ -1624,7 +1624,7 @@ type
NPJOYINFO* = ptr joyinfo
LPJOYINFO* = ptr joyinfo
TJOYINFO* = JOYINFO
joyinfoex* = record
joyinfoex* {.final.} = object
dwSize*: DWORD
dwFlags*: DWORD
wXpos*: UINT
@ -1648,7 +1648,7 @@ type
HMMIO* = THandle
LPMMIOPROC* = proc (x1: LPSTR, x2: UINT, x3, x4: LPARAM): LRESULT{.stdcall.}
TMMIOPROC* = LPMMIOPROC
MMIOINFO* = record
MMIOINFO* {.final.} = object
dwFlags*: DWORD
fccIOProc*: FOURCC
pIOProc*: LPMMIOPROC
@ -1671,7 +1671,7 @@ type
LPMMIOINFO* = ptr MMIOINFO
LPCMMIOINFO* = ptr MMIOINFO
TMMIOINFO* = MMIOINFO
MMCKINFO* = record
MMCKINFO* {.final.} = object
ckid*: FOURCC
cksize*: DWORD
fccType*: FOURCC
@ -1687,13 +1687,13 @@ type
MCIDEVICEID* = UINT
YIELDPROC* = proc (mciId: MCIDEVICEID, dwYieldData: DWORD): UINT{.stdcall.}
TYIELDPROC* = YIELDPROC
MCI_GENERIC_PARMS* = record
MCI_GENERIC_PARMS* {.final.} = object
dwCallback*: DWORD
PMCI_GENERIC_PARMS* = ptr MCI_GENERIC_PARMS
LPMCI_GENERIC_PARMS* = ptr MCI_GENERIC_PARMS
TMCI_GENERIC_PARMS* = MCI_GENERIC_PARMS
MCI_OPEN_PARMSA* = record
MCI_OPEN_PARMSA* {.final.} = object
dwCallback*: DWORD
wDeviceID*: MCIDEVICEID
lpstrDeviceType*: LPCSTR
@ -1703,7 +1703,7 @@ type
PMCI_OPEN_PARMSA* = ptr MCI_OPEN_PARMSA
LPMCI_OPEN_PARMSA* = ptr MCI_OPEN_PARMSA
TMCI_OPEN_PARMSA* = MCI_OPEN_PARMSA
MCI_OPEN_PARMSW* = record
MCI_OPEN_PARMSW* {.final.} = object
dwCallback*: DWORD
wDeviceID*: MCIDEVICEID
lpstrDeviceType*: LPCWSTR
@ -1726,7 +1726,7 @@ else:
LPMCI_OPEN_PARMS* = LPMCI_OPEN_PARMSA
type
TMCI_OPEN_PARMS* = MCI_OPEN_PARMS
MCI_PLAY_PARMS* = record
MCI_PLAY_PARMS* {.final.} = object
dwCallback*: DWORD
dwFrom*: DWORD
dwTo*: DWORD
@ -1734,14 +1734,14 @@ type
PMCI_PLAY_PARMS* = ptr MCI_PLAY_PARMS
LPMCI_PLAY_PARMS* = ptr MCI_PLAY_PARMS
TMCI_PLAY_PARMS* = MCI_PLAY_PARMS
MCI_SEEK_PARMS* = record
MCI_SEEK_PARMS* {.final.} = object
dwCallback*: DWORD
dwTo*: DWORD
PMCI_SEEK_PARMS* = ptr MCI_SEEK_PARMS
LPMCI_SEEK_PARMS* = ptr MCI_SEEK_PARMS
TMCI_SEEK_PARMS* = MCI_SEEK_PARMS
MCI_STATUS_PARMS* = record
MCI_STATUS_PARMS* {.final.} = object
dwCallback*: DWORD
dwReturn*: DWORD
dwItem*: DWORD
@ -1750,14 +1750,14 @@ type
PMCI_STATUS_PARMS* = ptr MCI_STATUS_PARMS
LPMCI_STATUS_PARMS* = ptr MCI_STATUS_PARMS
TMCI_STATUS_PARMS* = MCI_STATUS_PARMS
MCI_INFO_PARMSA* = record
MCI_INFO_PARMSA* {.final.} = object
dwCallback*: DWORD
lpstrReturn*: cstring
dwRetSize*: DWORD
LPMCI_INFO_PARMSA* = ptr MCI_INFO_PARMSA
TMCI_INFO_PARMSA* = MCI_INFO_PARMSA
MCI_INFO_PARMSW* = record
MCI_INFO_PARMSW* {.final.} = object
dwCallback*: DWORD
lpstrReturn*: LPWSTR
dwRetSize*: DWORD
@ -1775,7 +1775,7 @@ else:
LPMCI_INFO_PARMS* = LPMCI_INFO_PARMSA
type
TMCI_INFO_PARMS* = MCI_INFO_PARMS
MCI_GETDEVCAPS_PARMS* = record
MCI_GETDEVCAPS_PARMS* {.final.} = object
dwCallback*: DWORD
dwReturn*: DWORD
dwItem*: DWORD
@ -1783,7 +1783,7 @@ type
PMCI_GETDEVCAPS_PARMS* = ptr MCI_GETDEVCAPS_PARMS
LPMCI_GETDEVCAPS_PARMS* = ptr MCI_GETDEVCAPS_PARMS
TMCI_GETDEVCAPS_PARMS* = MCI_GETDEVCAPS_PARMS
MCI_SYSINFO_PARMSA* = record
MCI_SYSINFO_PARMSA* {.final.} = object
dwCallback*: DWORD
lpstrReturn*: cstring
dwRetSize*: DWORD
@ -1793,7 +1793,7 @@ type
PMCI_SYSINFO_PARMSA* = ptr MCI_SYSINFO_PARMSA
LPMCI_SYSINFO_PARMSA* = ptr MCI_SYSINFO_PARMSA
TMCI_SYSINFO_PARMSA* = MCI_SYSINFO_PARMSA
MCI_SYSINFO_PARMSW* = record
MCI_SYSINFO_PARMSW* {.final.} = object
dwCallback*: DWORD
lpstrReturn*: LPWSTR
dwRetSize*: DWORD
@ -1816,7 +1816,7 @@ else:
LPMCI_SYSINFO_PARMS* = LPMCI_SYSINFO_PARMSA
type
TMCI_SYSINFO_PARMS* = MCI_SYSINFO_PARMS
MCI_SET_PARMS* = record
MCI_SET_PARMS* {.final.} = object
dwCallback*: DWORD
dwTimeFormat*: DWORD
dwAudio*: DWORD
@ -1824,7 +1824,7 @@ type
PMCI_SET_PARMS* = ptr MCI_SET_PARMS
LPMCI_SET_PARMS* = ptr MCI_SET_PARMS
TMCI_SET_PARMS* = MCI_SET_PARMS
MCI_BREAK_PARMS* = record
MCI_BREAK_PARMS* {.final.} = object
dwCallback*: DWORD
nVirtKey*: int32
hwndBreak*: HWND
@ -1832,14 +1832,14 @@ type
PMCI_BREAK_PARMS* = ptr MCI_BREAK_PARMS
LPMCI_BREAK_PARMS* = ptr MCI_BREAK_PARMS
TMCI_BREAK_PARMS* = MCI_BREAK_PARMS
MCI_SAVE_PARMSA* = record
MCI_SAVE_PARMSA* {.final.} = object
dwCallback*: DWORD
lpfilename*: LPCSTR
PMCI_SAVE_PARMSA* = ptr MCI_SAVE_PARMSA
LPMCI_SAVE_PARMSA* = ptr MCI_SAVE_PARMSA
TMCI_SAVE_PARMSA* = MCI_SAVE_PARMSA
MCI_SAVE_PARMSW* = record
MCI_SAVE_PARMSW* {.final.} = object
dwCallback*: DWORD
lpfilename*: LPCWSTR
@ -1859,14 +1859,14 @@ else:
LPMCI_SAVE_PARMS* = LPMCI_SAVE_PARMSA
type
TMCI_SAVE_PARMS* = MCI_SAVE_PARMS
MCI_LOAD_PARMSA* = record
MCI_LOAD_PARMSA* {.final.} = object
dwCallback*: DWORD
lpfilename*: LPCSTR
PMCI_LOAD_PARMSA* = ptr MCI_LOAD_PARMSA
LPMCI_LOAD_PARMSA* = ptr MCI_LOAD_PARMSA
TMCI_LOAD_PARMSA* = MCI_LOAD_PARMSA
MCI_LOAD_PARMSW* = record
MCI_LOAD_PARMSW* {.final.} = object
dwCallback*: DWORD
lpfilename*: LPCWSTR
@ -1886,14 +1886,14 @@ else:
LPMCI_LOAD_PARMS* = LPMCI_LOAD_PARMSA
type
TMCI_LOAD_PARMS* = MCI_LOAD_PARMS
MCI_RECORD_PARMS* = record
MCI_RECORD_PARMS* {.final.} = object
dwCallback*: DWORD
dwFrom*: DWORD
dwTo*: DWORD
LPMCI_RECORD_PARMS* = ptr MCI_RECORD_PARMS
TMCI_RECORD_PARMS* = MCI_RECORD_PARMS
MCI_VD_PLAY_PARMS* = record
MCI_VD_PLAY_PARMS* {.final.} = object
dwCallback*: DWORD
dwFrom*: DWORD
dwTo*: DWORD
@ -1902,20 +1902,20 @@ type
PMCI_VD_PLAY_PARMS* = ptr MCI_VD_PLAY_PARMS
LPMCI_VD_PLAY_PARMS* = ptr MCI_VD_PLAY_PARMS
TMCI_VD_PLAY_PARMS* = MCI_VD_PLAY_PARMS
MCI_VD_STEP_PARMS* = record
MCI_VD_STEP_PARMS* {.final.} = object
dwCallback*: DWORD
dwFrames*: DWORD
PMCI_VD_STEP_PARMS* = ptr MCI_VD_STEP_PARMS
LPMCI_VD_STEP_PARMS* = ptr MCI_VD_STEP_PARMS
MCI_VD_ESCAPE_PARMSA* = record
MCI_VD_ESCAPE_PARMSA* {.final.} = object
dwCallback*: DWORD
lpstrCommand*: LPCSTR
PMCI_VD_ESCAPE_PARMSA* = ptr MCI_VD_ESCAPE_PARMSA
LPMCI_VD_ESCAPE_PARMSA* = ptr MCI_VD_ESCAPE_PARMSA
TMCI_VD_ESCAPE_PARMSA* = MCI_VD_ESCAPE_PARMSA
MCI_VD_ESCAPE_PARMSW* = record
MCI_VD_ESCAPE_PARMSW* {.final.} = object
dwCallback*: DWORD
lpstrCommand*: LPCWSTR
@ -1935,7 +1935,7 @@ else:
LPMCI_VD_ESCAPE_PARMS* = LPMCI_VD_ESCAPE_PARMSA
type
TMCI_VD_ESCAPE_PARMS* = MCI_VD_ESCAPE_PARMS
MCI_WAVE_OPEN_PARMSA* = record
MCI_WAVE_OPEN_PARMSA* {.final.} = object
dwCallback*: DWORD
wDeviceID*: MCIDEVICEID
lpstrDeviceType*: LPCSTR
@ -1946,7 +1946,7 @@ type
PMCI_WAVE_OPEN_PARMSA* = ptr MCI_WAVE_OPEN_PARMSA
LPMCI_WAVE_OPEN_PARMSA* = ptr MCI_WAVE_OPEN_PARMSA
TMCI_WAVE_OPEN_PARMSA* = MCI_WAVE_OPEN_PARMSA
MCI_WAVE_OPEN_PARMSW* = record
MCI_WAVE_OPEN_PARMSW* {.final.} = object
dwCallback*: DWORD
wDeviceID*: MCIDEVICEID
lpstrDeviceType*: LPCWSTR
@ -1970,7 +1970,7 @@ else:
LPMCI_WAVE_OPEN_PARMS* = LPMCI_WAVE_OPEN_PARMSA
type
TMCI_WAVE_OPEN_PARMS* = MCI_WAVE_OPEN_PARMS
MCI_WAVE_DELETE_PARMS* = record
MCI_WAVE_DELETE_PARMS* {.final.} = object
dwCallback*: DWORD
dwFrom*: DWORD
dwTo*: DWORD
@ -1978,7 +1978,7 @@ type
PMCI_WAVE_DELETE_PARMS* = ptr MCI_WAVE_DELETE_PARMS
LPMCI_WAVE_DELETE_PARMS* = ptr MCI_WAVE_DELETE_PARMS
TMCI_WAVE_DELETE_PARMS* = MCI_WAVE_DELETE_PARMS
MCI_WAVE_SET_PARMS* = record
MCI_WAVE_SET_PARMS* {.final.} = object
dwCallback*: DWORD
dwTimeFormat*: DWORD
dwAudio*: DWORD
@ -1998,7 +1998,7 @@ type
PMCI_WAVE_SET_PARMS* = ptr MCI_WAVE_SET_PARMS
LPMCI_WAVE_SET_PARMS* = ptr MCI_WAVE_SET_PARMS
TMCI_WAVE_SET_PARMS* = MCI_WAVE_SET_PARMS
MCI_SEQ_SET_PARMS* = record
MCI_SEQ_SET_PARMS* {.final.} = object
dwCallback*: DWORD
dwTimeFormat*: DWORD
dwAudio*: DWORD
@ -2011,7 +2011,7 @@ type
PMCI_SEQ_SET_PARMS* = ptr MCI_SEQ_SET_PARMS
LPMCI_SEQ_SET_PARMS* = ptr MCI_SEQ_SET_PARMS
TMCI_SEQ_SET_PARMS* = MCI_SEQ_SET_PARMS
MCI_ANIM_OPEN_PARMSA* = record
MCI_ANIM_OPEN_PARMSA* {.final.} = object
dwCallback*: DWORD
wDeviceID*: MCIDEVICEID
lpstrDeviceType*: LPCSTR
@ -2023,7 +2023,7 @@ type
PMCI_ANIM_OPEN_PARMSA* = ptr MCI_ANIM_OPEN_PARMSA
LPMCI_ANIM_OPEN_PARMSA* = ptr MCI_ANIM_OPEN_PARMSA
TMCI_ANIM_OPEN_PARMSA* = MCI_ANIM_OPEN_PARMSA
MCI_ANIM_OPEN_PARMSW* = record
MCI_ANIM_OPEN_PARMSW* {.final.} = object
dwCallback*: DWORD
wDeviceID*: MCIDEVICEID
lpstrDeviceType*: LPCWSTR
@ -2047,7 +2047,7 @@ else:
LPMCI_ANIM_OPEN_PARMS* = LPMCI_ANIM_OPEN_PARMSA
type
TMCI_ANIM_OPEN_PARMS* = MCI_ANIM_OPEN_PARMS
MCI_ANIM_WINDOW_PARMSW* = record
MCI_ANIM_WINDOW_PARMSW* {.final.} = object
dwCallback*: DWORD
hWnd*: HWND
nCmdShow*: UINT
@ -2056,14 +2056,14 @@ type
PMCI_ANIM_WINDOW_PARMSW* = ptr MCI_ANIM_WINDOW_PARMSW
LPMCI_ANIM_WINDOW_PARMSW* = ptr MCI_ANIM_WINDOW_PARMSW
TMCI_ANIM_WINDOW_PARMSW* = MCI_ANIM_WINDOW_PARMSW
MCI_ANIM_STEP_PARMS* = record
MCI_ANIM_STEP_PARMS* {.final.} = object
dwCallback*: DWORD
dwFrames*: DWORD
PMCI_ANIM_STEP_PARMS* = ptr MCI_ANIM_STEP_PARMS
LPMCI_ANIM_STEP_PARMS* = ptr MCI_ANIM_STEP_PARMS
TMCI_ANIM_STEP_PARMS* = MCI_ANIM_STEP_PARMS
MCI_ANIM_WINDOW_PARMSA* = record
MCI_ANIM_WINDOW_PARMSA* {.final.} = object
dwCallback*: DWORD
hWnd*: HWND
nCmdShow*: UINT
@ -2072,7 +2072,7 @@ type
PMCI_ANIM_WINDOW_PARMSA* = ptr MCI_ANIM_WINDOW_PARMSA
LPMCI_ANIM_WINDOW_PARMSA* = ptr MCI_ANIM_WINDOW_PARMSA
TMCI_ANIM_WINDOW_PARMSA* = MCI_ANIM_WINDOW_PARMSA
MCI_ANIM_PLAY_PARMS* = record
MCI_ANIM_PLAY_PARMS* {.final.} = object
dwCallback*: DWORD
dwFrom*: DWORD
dwTo*: DWORD
@ -2092,14 +2092,14 @@ else:
PMCI_ANIM_WINDOW_PARMS* = PMCI_ANIM_WINDOW_PARMSA
LPMCI_ANIM_WINDOW_PARMS* = LPMCI_ANIM_WINDOW_PARMSA
type
MCI_ANIM_RECT_PARMS* = record
MCI_ANIM_RECT_PARMS* {.final.} = object
dwCallback*: DWORD
rc*: TRECT
PMCI_ANIM_RECT_PARMS* = ptr MCI_ANIM_RECT_PARMS
LPMCI_ANIM_RECT_PARMS* = ptr MCI_ANIM_RECT_PARMS
TMCI_ANIM_RECT_PARMS* = MCI_ANIM_RECT_PARMS
MCI_ANIM_UPDATE_PARMS* = record
MCI_ANIM_UPDATE_PARMS* {.final.} = object
dwCallback*: DWORD
rc*: TRECT
hDC*: HDC
@ -2107,7 +2107,7 @@ type
PMCI_ANIM_UPDATE_PARMS* = ptr MCI_ANIM_UPDATE_PARMS
LPMCI_ANIM_UPDATE_PARMS* = ptr MCI_ANIM_UPDATE_PARMS
TMCI_ANIM_UPDATE_PARMS* = MCI_ANIM_UPDATE_PARMS
MCI_OVLY_OPEN_PARMSA* = record
MCI_OVLY_OPEN_PARMSA* {.final.} = object
dwCallback*: DWORD
wDeviceID*: MCIDEVICEID
lpstrDeviceType*: LPCSTR
@ -2119,7 +2119,7 @@ type
PMCI_OVLY_OPEN_PARMSA* = ptr MCI_OVLY_OPEN_PARMSA
LPMCI_OVLY_OPEN_PARMSA* = ptr MCI_OVLY_OPEN_PARMSA
TMCI_OVLY_OPEN_PARMSA* = MCI_OVLY_OPEN_PARMSA
MCI_OVLY_OPEN_PARMSW* = record
MCI_OVLY_OPEN_PARMSW* {.final.} = object
dwCallback*: DWORD
wDeviceID*: MCIDEVICEID
lpstrDeviceType*: LPCWSTR
@ -2144,7 +2144,7 @@ else:
LPMCI_OVLY_OPEN_PARMS* = LPMCI_OVLY_OPEN_PARMSA
type
TMCI_OVLY_OPEN_PARMS* = MCI_OVLY_OPEN_PARMS
MCI_OVLY_WINDOW_PARMSA* = record
MCI_OVLY_WINDOW_PARMSA* {.final.} = object
dwCallback*: DWORD
hWnd*: HWND
nCmdShow*: UINT
@ -2153,7 +2153,7 @@ type
PMCI_OVLY_WINDOW_PARMSA* = ptr MCI_OVLY_WINDOW_PARMSA
LPMCI_OVLY_WINDOW_PARMSA* = ptr MCI_OVLY_WINDOW_PARMSA
TMCI_OVLY_WINDOW_PARMSA* = MCI_OVLY_WINDOW_PARMSA
MCI_OVLY_WINDOW_PARMSW* = record
MCI_OVLY_WINDOW_PARMSW* {.final.} = object
dwCallback*: DWORD
hWnd*: HWND
nCmdShow*: UINT
@ -2175,14 +2175,14 @@ else:
LPMCI_OVLY_WINDOW_PARMS* = LPMCI_OVLY_WINDOW_PARMSA
type
TMCI_OVLY_WINDOW_PARMS* = MCI_OVLY_WINDOW_PARMSW
MCI_OVLY_RECT_PARMS* = record
MCI_OVLY_RECT_PARMS* {.final.} = object
dwCallback*: DWORD
rc*: TRECT
PMCI_OVLY_RECT_PARMS* = ptr MCI_OVLY_RECT_PARMS
LPMCI_OVLY_RECT_PARMS* = ptr MCI_OVLY_RECT_PARMS
TMCI_OVLY_RECT_PARMS* = MCI_OVLY_RECT_PARMS
MCI_OVLY_SAVE_PARMSA* = record
MCI_OVLY_SAVE_PARMSA* {.final.} = object
dwCallback*: DWORD
lpfilename*: LPCSTR
rc*: TRECT
@ -2190,7 +2190,7 @@ type
PMCI_OVLY_SAVE_PARMSA* = ptr MCI_OVLY_SAVE_PARMSA
LPMCI_OVLY_SAVE_PARMSA* = ptr MCI_OVLY_SAVE_PARMSA
TMCI_OVLY_SAVE_PARMSA* = MCI_OVLY_SAVE_PARMSA
MCI_OVLY_SAVE_PARMSW* = record
MCI_OVLY_SAVE_PARMSW* {.final.} = object
dwCallback*: DWORD
lpfilename*: LPCWSTR
rc*: TRECT
@ -2211,7 +2211,7 @@ else:
LPMCI_OVLY_SAVE_PARMS* = LPMCI_OVLY_SAVE_PARMSA
type
TMCI_OVLY_SAVE_PARMS* = MCI_OVLY_SAVE_PARMS
MCI_OVLY_LOAD_PARMSA* = record
MCI_OVLY_LOAD_PARMSA* {.final.} = object
dwCallback*: DWORD
lpfilename*: LPCSTR
rc*: TRECT
@ -2219,7 +2219,7 @@ type
PMCI_OVLY_LOAD_PARMSA* = ptr MCI_OVLY_LOAD_PARMSA
LPMCI_OVLY_LOAD_PARMSA* = ptr MCI_OVLY_LOAD_PARMSA
TMCI_OVLY_LOAD_PARMSA* = MCI_OVLY_LOAD_PARMSA
MCI_OVLY_LOAD_PARMSW* = record
MCI_OVLY_LOAD_PARMSW* {.final.} = object
dwCallback*: DWORD
lpfilename*: LPCWSTR
rc*: TRECT

View file

@ -8,7 +8,7 @@
#
# NetBIOS 3.0 interface unit
# This unit contains the definitions for portable NetBIOS 3.0 support.
# This module contains the definitions for portable NetBIOS 3.0 support.
import # Data structure templates
Windows
@ -20,8 +20,8 @@ const
type # Network Control Block
PNCB* = ptr TNCB
TNCBPostProc* = proc (P: PNCB)
TNCB* = record # Structure returned to the NCB command NCBASTAT is ADAPTER_STATUS followed
# by an array of NAME_BUFFER structures.
TNCB* {.final.} = object # Structure returned to the NCB command NCBASTAT is ADAPTER_STATUS followed
# by an array of NAME_BUFFER structures.
ncb_command*: Char # command code
ncb_retcode*: Char # return code
ncb_lsn*: Char # local session number
@ -42,7 +42,7 @@ type # Network Control Block
# completes
PAdapterStatus* = ptr TAdapterStatus
TAdapterStatus* = record
TAdapterStatus* {.final.} = object
adapter_address*: array[0..5, Char]
rev_major*: Char
reserved0*: Char
@ -72,7 +72,7 @@ type # Network Control Block
name_count*: int16
PNameBuffer* = ptr TNameBuffer
TNameBuffer* = record
TNameBuffer* {.final.} = object
name*: array[0..NCBNAMSZ - 1, Char]
name_num*: Char
name_flags*: Char
@ -93,14 +93,14 @@ type # Structure returned to the NCB command NCBSSTAT is SESSION_HEADER followed
# asterisk then an array of these structures is returned containing the
# status for all names.
PSessionHeader* = ptr TSessionHeader
TSessionHeader* = record
TSessionHeader* {.final.} = object
sess_name*: Char
num_sess*: Char
rcv_dg_outstanding*: Char
rcv_any_outstanding*: Char
PSessionBuffer* = ptr TSessionBuffer
TSessionBuffer* = record
TSessionBuffer* {.final.} = object
lsn*: Char
state*: Char
local_name*: array[0..NCBNAMSZ - 1, Char]
@ -121,20 +121,20 @@ type # Structure returned to the NCB command NCBENUM.
# On a system containing lana's 0, 2 and 3, a structure with
# length =3, lana[0]=0, lana[1]=2 and lana[2]=3 will be returned.
PLanaEnum* = ptr TLanaEnum
TLanaEnum* = record # Structure returned to the NCB command NCBFINDNAME is FIND_NAME_HEADER followed
# by an array of FIND_NAME_BUFFER structures.
TLanaEnum* {.final.} = object # Structure returned to the NCB command NCBFINDNAME is FIND_NAME_HEADER followed
# by an array of FIND_NAME_BUFFER structures.
len*: Char # Number of valid entries in lana[]
lana*: array[0..MAX_LANA, Char]
PFindNameHeader* = ptr TFindNameHeader
TFindNameHeader* = record
TFindNameHeader* {.final.} = object
node_count*: int16
reserved*: Char
unique_group*: Char
PFindNameBuffer* = ptr TFindNameBuffer
TFindNameBuffer* = record # Structure provided with NCBACTION. The purpose of NCBACTION is to provide
# transport specific extensions to netbios.
TFindNameBuffer* {.final.} = object # Structure provided with NCBACTION. The purpose of NCBACTION is to provide
# transport specific extensions to netbios.
len*: Char
access_control*: Char
frame_control*: Char
@ -143,7 +143,7 @@ type # Structure returned to the NCB command NCBENUM.
routing_info*: array[0..17, Char]
PActionHeader* = ptr TActionHeader
TActionHeader* = record
TActionHeader* {.final.} = object
transport_id*: int32
action_code*: int16
reserved*: int16

View file

@ -33,7 +33,7 @@ type
DWORD_PTR* = ptr DWORD
pHICON* = ptr HICON
pBool* = ptr BOOL
STARTUPINFOW* = record # a guess. Omission should get fixed in Windows.
STARTUPINFOW* {.final.} = object # a guess. Omission should get fixed in Windows.
cb*: DWORD
lpReserved*: LPTSTR
lpDesktop*: LPTSTR
@ -122,7 +122,7 @@ proc ExtractIcon*(hInst: HINST, lpszExeFileName: LPCWSTR, nIconIndex: UINT): HIC
stdcall, dynlib: "shell32.dll", importc: "ExtractIconW".}
# if(WINVER >= 0x0400)
type # init with sizeof(DRAGINFO)
DRAGINFOA* = record
DRAGINFOA* {.final.} = object
uSize*: UINT
pt*: POINT
fNC*: BOOL
@ -131,7 +131,7 @@ type # init with sizeof(DRAGINFO)
TDRAGINFOA* = DRAGINFOA
LPDRAGINFOA* = ptr DRAGINFOA # init with sizeof(DRAGINFO)
DRAGINFOW* = record
DRAGINFOW* {.final.} = object
uSize*: UINT
pt*: POINT
fNC*: BOOL
@ -178,7 +178,7 @@ const
ABE_BOTTOM* = 3
type
AppBarData* = record
AppBarData* {.final.} = object
cbSize*: DWORD
hWnd*: HWND
uCallbackMessage*: UINT
@ -286,7 +286,7 @@ type
# only used if FOF_SIMPLEPROGRESS
type
SHFILEOPSTRUCTA* = record
SHFILEOPSTRUCTA* {.final.} = object
hwnd*: HWND
wFunc*: UINT
pFrom*: LPCSTR
@ -298,7 +298,7 @@ type
TSHFILEOPSTRUCTA* = SHFILEOPSTRUCTA
LPSHFILEOPSTRUCTA* = ptr SHFILEOPSTRUCTA
SHFILEOPSTRUCTW* = record
SHFILEOPSTRUCTW* {.final.} = object
hwnd*: HWND
wFunc*: UINT
pFrom*: LPCWSTR
@ -332,7 +332,7 @@ proc SHFileOperation*(lpFileOp: LPSHFILEOPSTRUCTW): int32{.stdcall,
proc SHFreeNameMappings*(hNameMappings: THandle){.stdcall,
dynlib: "shell32.dll", importc: "SHFreeNameMappings".}
type
SHNAMEMAPPINGA* = record
SHNAMEMAPPINGA* {.final.} = object
pszOldPath*: LPSTR
pszNewPath*: LPSTR
cchOldPath*: int32
@ -340,7 +340,7 @@ type
TSHNAMEMAPPINGA* = SHNAMEMAPPINGA
LPSHNAMEMAPPINGA* = ptr SHNAMEMAPPINGA
SHNAMEMAPPINGW* = record
SHNAMEMAPPINGW* {.final.} = object
pszOldPath*: LPWSTR
pszNewPath*: LPWSTR
cchOldPath*: int32
@ -404,7 +404,7 @@ const
# (_WIN32_IE >= 0x560)
type
SHELLEXECUTEINFOA* = record
SHELLEXECUTEINFOA* {.final.} = object
cbSize*: DWORD
fMask*: ULONG
hwnd*: HWND
@ -423,7 +423,7 @@ type
TSHELLEXECUTEINFOA* = SHELLEXECUTEINFOA
LPSHELLEXECUTEINFOA* = ptr SHELLEXECUTEINFOA
SHELLEXECUTEINFOW* = record
SHELLEXECUTEINFOW* {.final.} = object
cbSize*: DWORD
fMask*: ULONG
hwnd*: HWND
@ -474,7 +474,7 @@ proc WinExecError*(HWND: hwnd, error: int32, lpstrFileName: LPCWSTR,
lpstrTitle: LPCWSTR){.stdcall, dynlib: "shell32.dll",
importc: "WinExecErrorW".}
type
SHCREATEPROCESSINFOW* = record
SHCREATEPROCESSINFOW* {.final.} = object
cbSize*: DWORD
fMask*: ULONG
hwnd*: HWND
@ -502,7 +502,7 @@ proc SHCreateProcessAsUserW*(pscpi: PSHCREATEPROCESSINFOW): Bool{.stdcall,
#
# struct for query recycle bin info
type
SHQUERYRBINFO* = record
SHQUERYRBINFO* {.final.} = object
cbSize*: DWORD
i64Size*: int64
i64NumItems*: int64
@ -538,7 +538,7 @@ proc SHEmptyRecycleBin*(hwnd: HWND, pszRootPath: LPCWSTR, dwFlags: DWORD): HRESU
# Tray notification definitions
#
type
NOTIFYICONDATAA* = record
NOTIFYICONDATAA* {.final.} = object
cbSize*: DWORD
hWnd*: HWND
uID*: UINT
@ -556,7 +556,7 @@ type
TNOTIFYICONDATAA* = NOTIFYICONDATAA
PNOTIFYICONDATAA* = ptr NOTIFYICONDATAA
NOTIFYICONDATAW* = record
NOTIFYICONDATAW* {.final.} = object
cbSize*: DWORD
hWnd*: HWND
uID*: UINT
@ -645,7 +645,7 @@ proc Shell_NotifyIcon*(dwMessage: Dword, lpData: PNOTIFYICONDATAW): Bool{.
# out: display name (or path)
# out: type name
type
SHFILEINFOA* = record
SHFILEINFOA* {.final.} = object
hIcon*: HICON # out: icon
iIcon*: int32 # out: icon index
dwAttributes*: DWORD # out: SFGAO_ flags
@ -654,7 +654,7 @@ type
TSHFILEINFOA* = SHFILEINFOA
pSHFILEINFOA* = ptr SHFILEINFOA
SHFILEINFOW* = record
SHFILEINFOW* {.final.} = object
hIcon*: HICON # out: icon
iIcon*: int32 # out: icon index
dwAttributes*: DWORD # out: SFGAO_ flags

File diff suppressed because it is too large Load diff

View file

@ -64,6 +64,135 @@ for key, val in enums.iteritems():
cog.out(a)
cog.out(b)
]]]*)
type
TNodeKind = (
nkNone, nkEmpty, nkIdent, nkSym,
nkType, nkCharLit, nkIntLit, nkInt8Lit,
nkInt16Lit, nkInt32Lit, nkInt64Lit, nkFloatLit,
nkFloat32Lit, nkFloat64Lit, nkStrLit, nkRStrLit,
nkTripleStrLit, nkMetaNode, nkNilLit, nkDotCall,
nkCommand, nkCall, nkGenericCall, nkExplicitTypeListCall,
nkExprEqExpr, nkExprColonExpr, nkIdentDefs, nkInfix,
nkPrefix, nkPostfix, nkPar, nkCurly,
nkBracket, nkBracketExpr, nkPragmaExpr, nkRange,
nkDotExpr, nkCheckedFieldExpr, nkDerefExpr, nkIfExpr,
nkElifExpr, nkElseExpr, nkLambda, nkAccQuoted,
nkHeaderQuoted, nkTableConstr, nkQualified, nkHiddenStdConv,
nkHiddenSubConv, nkHiddenCallConv, nkConv, nkCast,
nkAddr, nkHiddenAddr, nkHiddenDeref, nkObjDownConv,
nkObjUpConv, nkChckRangeF, nkChckRange64, nkChckRange,
nkStringToCString, nkCStringToString, nkPassAsOpenArray, nkAsgn,
nkDefaultTypeParam, nkGenericParams, nkFormalParams, nkOfInherit,
nkModule, nkProcDef, nkConverterDef, nkMacroDef,
nkTemplateDef, nkIteratorDef, nkOfBranch, nkElifBranch,
nkExceptBranch, nkElse, nkMacroStmt, nkAsmStmt,
nkPragma, nkIfStmt, nkWhenStmt, nkForStmt,
nkWhileStmt, nkCaseStmt, nkVarSection, nkConstSection,
nkConstDef, nkTypeSection, nkTypeDef, nkYieldStmt,
nkTryStmt, nkFinally, nkRaiseStmt, nkReturnStmt,
nkBreakStmt, nkContinueStmt, nkBlockStmt, nkDiscardStmt,
nkStmtList, nkImportStmt, nkFromStmt, nkImportAs,
nkIncludeStmt, nkAccessStmt, nkCommentStmt, nkStmtListExpr,
nkBlockExpr, nkVm, nkTypeOfExpr, nkObjectTy,
nkTupleTy, nkRecList, nkRecCase, nkRecWhen,
nkRefTy, nkPtrTy, nkVarTy, nkProcTy,
nkEnumTy, nkEnumFieldDef, nkReturnToken);
TNodeKinds = set of TNodeKind;
const
NodeKindToStr: array [TNodeKind] of string = (
'nkNone', 'nkEmpty', 'nkIdent', 'nkSym',
'nkType', 'nkCharLit', 'nkIntLit', 'nkInt8Lit',
'nkInt16Lit', 'nkInt32Lit', 'nkInt64Lit', 'nkFloatLit',
'nkFloat32Lit', 'nkFloat64Lit', 'nkStrLit', 'nkRStrLit',
'nkTripleStrLit', 'nkMetaNode', 'nkNilLit', 'nkDotCall',
'nkCommand', 'nkCall', 'nkGenericCall', 'nkExplicitTypeListCall',
'nkExprEqExpr', 'nkExprColonExpr', 'nkIdentDefs', 'nkInfix',
'nkPrefix', 'nkPostfix', 'nkPar', 'nkCurly',
'nkBracket', 'nkBracketExpr', 'nkPragmaExpr', 'nkRange',
'nkDotExpr', 'nkCheckedFieldExpr', 'nkDerefExpr', 'nkIfExpr',
'nkElifExpr', 'nkElseExpr', 'nkLambda', 'nkAccQuoted',
'nkHeaderQuoted', 'nkTableConstr', 'nkQualified', 'nkHiddenStdConv',
'nkHiddenSubConv', 'nkHiddenCallConv', 'nkConv', 'nkCast',
'nkAddr', 'nkHiddenAddr', 'nkHiddenDeref', 'nkObjDownConv',
'nkObjUpConv', 'nkChckRangeF', 'nkChckRange64', 'nkChckRange',
'nkStringToCString', 'nkCStringToString', 'nkPassAsOpenArray', 'nkAsgn',
'nkDefaultTypeParam', 'nkGenericParams', 'nkFormalParams', 'nkOfInherit',
'nkModule', 'nkProcDef', 'nkConverterDef', 'nkMacroDef',
'nkTemplateDef', 'nkIteratorDef', 'nkOfBranch', 'nkElifBranch',
'nkExceptBranch', 'nkElse', 'nkMacroStmt', 'nkAsmStmt',
'nkPragma', 'nkIfStmt', 'nkWhenStmt', 'nkForStmt',
'nkWhileStmt', 'nkCaseStmt', 'nkVarSection', 'nkConstSection',
'nkConstDef', 'nkTypeSection', 'nkTypeDef', 'nkYieldStmt',
'nkTryStmt', 'nkFinally', 'nkRaiseStmt', 'nkReturnStmt',
'nkBreakStmt', 'nkContinueStmt', 'nkBlockStmt', 'nkDiscardStmt',
'nkStmtList', 'nkImportStmt', 'nkFromStmt', 'nkImportAs',
'nkIncludeStmt', 'nkAccessStmt', 'nkCommentStmt', 'nkStmtListExpr',
'nkBlockExpr', 'nkVm', 'nkTypeOfExpr', 'nkObjectTy',
'nkTupleTy', 'nkRecList', 'nkRecCase', 'nkRecWhen',
'nkRefTy', 'nkPtrTy', 'nkVarTy', 'nkProcTy',
'nkEnumTy', 'nkEnumFieldDef', 'nkReturnToken');
type
TSymFlag = (
sfTypeCheck, sfForward, sfImportc, sfExportc,
sfVolatile, sfUsed, sfWrite, sfRegister,
sfPure, sfCodeGenerated, sfPrivate, sfGlobal,
sfResult, sfNoSideEffect, sfMainModule, sfSystemModule,
sfNoReturn, sfAddrTaken, sfInInterface, sfNoStatic,
sfCompilerProc, sfCppMethod, sfDiscriminant, sfDeprecated,
sfInClosure, sfIsCopy, sfStar, sfMinus);
TSymFlags = set of TSymFlag;
const
SymFlagToStr: array [TSymFlag] of string = (
'sfTypeCheck', 'sfForward', 'sfImportc', 'sfExportc',
'sfVolatile', 'sfUsed', 'sfWrite', 'sfRegister',
'sfPure', 'sfCodeGenerated', 'sfPrivate', 'sfGlobal',
'sfResult', 'sfNoSideEffect', 'sfMainModule', 'sfSystemModule',
'sfNoReturn', 'sfAddrTaken', 'sfInInterface', 'sfNoStatic',
'sfCompilerProc', 'sfCppMethod', 'sfDiscriminant', 'sfDeprecated',
'sfInClosure', 'sfIsCopy', 'sfStar', 'sfMinus');
type
TTypeKind = (
tyNone, tyBool, tyChar, tyEmptySet,
tyArrayConstr, tyNil, tyGeneric, tyGenericInst,
tyGenericParam, tyEnum, tyAnyEnum, tyArray,
tyObject, tyTuple, tySet, tyRange,
tyPtr, tyRef, tyVar, tySequence,
tyProc, tyPointer, tyOpenArray, tyString,
tyCString, tyForward, tyInt, tyInt8,
tyInt16, tyInt32, tyInt64, tyFloat,
tyFloat32, tyFloat64, tyFloat128);
TTypeKinds = set of TTypeKind;
const
TypeKindToStr: array [TTypeKind] of string = (
'tyNone', 'tyBool', 'tyChar', 'tyEmptySet',
'tyArrayConstr', 'tyNil', 'tyGeneric', 'tyGenericInst',
'tyGenericParam', 'tyEnum', 'tyAnyEnum', 'tyArray',
'tyObject', 'tyTuple', 'tySet', 'tyRange',
'tyPtr', 'tyRef', 'tyVar', 'tySequence',
'tyProc', 'tyPointer', 'tyOpenArray', 'tyString',
'tyCString', 'tyForward', 'tyInt', 'tyInt8',
'tyInt16', 'tyInt32', 'tyInt64', 'tyFloat',
'tyFloat32', 'tyFloat64', 'tyFloat128');
type
TNodeFlag = (
nfNone, nfBase2, nfBase8, nfBase16,
nfAllConst);
TNodeFlags = set of TNodeFlag;
const
NodeFlagToStr: array [TNodeFlag] of string = (
'nfNone', 'nfBase2', 'nfBase8', 'nfBase16',
'nfAllConst');
type
TTypeFlag = (
tfIsDistinct, tfGeneric, tfExternal, tfImported,
tfInfoGenerated, tfSemChecked, tfHasOutParams, tfEnumHasWholes,
tfVarargs, tfFinal);
TTypeFlags = set of TTypeFlag;
const
TypeFlagToStr: array [TTypeFlag] of string = (
'tfIsDistinct', 'tfGeneric', 'tfExternal', 'tfImported',
'tfInfoGenerated', 'tfSemChecked', 'tfHasOutParams', 'tfEnumHasWholes',
'tfVarargs', 'tfFinal');
type
TSymKind = (
skUnknownSym, skConditional, skDynLib, skParam,
@ -79,126 +208,6 @@ const
'skVar', 'skProc', 'skIterator', 'skConverter',
'skMacro', 'skTemplate', 'skField', 'skEnumField',
'skForVar', 'skModule', 'skLabel');
type
TNodeKind = (
nkNone, nkEmpty, nkIdent, nkSym,
nkType, nkCharLit, nkRCharLit, nkIntLit,
nkInt8Lit, nkInt16Lit, nkInt32Lit, nkInt64Lit,
nkFloatLit, nkFloat32Lit, nkFloat64Lit, nkStrLit,
nkRStrLit, nkTripleStrLit, nkNilLit, nkDotCall,
nkCommand, nkCall, nkGenericCall, nkExplicitTypeListCall,
nkExprEqExpr, nkExprColonExpr, nkIdentDefs, nkInfix,
nkPrefix, nkPostfix, nkPar, nkCurly,
nkBracket, nkBracketExpr, nkPragmaExpr, nkRange,
nkDotExpr, nkCheckedFieldExpr, nkDerefExpr, nkIfExpr,
nkElifExpr, nkElseExpr, nkLambda, nkAccQuoted,
nkHeaderQuoted, nkSetConstr, nkConstSetConstr, nkArrayConstr,
nkConstArrayConstr, nkRecordConstr, nkConstRecordConstr, nkTableConstr,
nkConstTableConstr, nkQualified, nkHiddenStdConv, nkHiddenSubConv,
nkHiddenCallConv, nkConv, nkCast, nkAddr,
nkAsgn, nkDefaultTypeParam, nkGenericParams, nkFormalParams,
nkOfInherit, nkModule, nkProcDef, nkConverterDef,
nkMacroDef, nkTemplateDef, nkIteratorDef, nkOfBranch,
nkElifBranch, nkExceptBranch, nkElse, nkMacroStmt,
nkAsmStmt, nkPragma, nkIfStmt, nkWhenStmt,
nkForStmt, nkWhileStmt, nkCaseStmt, nkVarSection,
nkConstSection, nkConstDef, nkTypeSection, nkTypeDef,
nkYieldStmt, nkTryStmt, nkFinally, nkRaiseStmt,
nkReturnStmt, nkBreakStmt, nkContinueStmt, nkBlockStmt,
nkGotoStmt, nkDiscardStmt, nkStmtList, nkImportStmt,
nkFromStmt, nkImportAs, nkIncludeStmt, nkAccessStmt,
nkCommentStmt, nkStmtListExpr, nkBlockExpr, nkVm,
nkTypeOfExpr, nkRecordTy, nkObjectTy, nkRecList,
nkRecCase, nkRecWhen, nkRefTy, nkPtrTy,
nkVarTy, nkProcTy, nkEnumTy, nkEnumFieldDef);
TNodeKinds = set of TNodeKind;
const
NodeKindToStr: array [TNodeKind] of string = (
'nkNone', 'nkEmpty', 'nkIdent', 'nkSym',
'nkType', 'nkCharLit', 'nkRCharLit', 'nkIntLit',
'nkInt8Lit', 'nkInt16Lit', 'nkInt32Lit', 'nkInt64Lit',
'nkFloatLit', 'nkFloat32Lit', 'nkFloat64Lit', 'nkStrLit',
'nkRStrLit', 'nkTripleStrLit', 'nkNilLit', 'nkDotCall',
'nkCommand', 'nkCall', 'nkGenericCall', 'nkExplicitTypeListCall',
'nkExprEqExpr', 'nkExprColonExpr', 'nkIdentDefs', 'nkInfix',
'nkPrefix', 'nkPostfix', 'nkPar', 'nkCurly',
'nkBracket', 'nkBracketExpr', 'nkPragmaExpr', 'nkRange',
'nkDotExpr', 'nkCheckedFieldExpr', 'nkDerefExpr', 'nkIfExpr',
'nkElifExpr', 'nkElseExpr', 'nkLambda', 'nkAccQuoted',
'nkHeaderQuoted', 'nkSetConstr', 'nkConstSetConstr', 'nkArrayConstr',
'nkConstArrayConstr', 'nkRecordConstr', 'nkConstRecordConstr', 'nkTableConstr',
'nkConstTableConstr', 'nkQualified', 'nkHiddenStdConv', 'nkHiddenSubConv',
'nkHiddenCallConv', 'nkConv', 'nkCast', 'nkAddr',
'nkAsgn', 'nkDefaultTypeParam', 'nkGenericParams', 'nkFormalParams',
'nkOfInherit', 'nkModule', 'nkProcDef', 'nkConverterDef',
'nkMacroDef', 'nkTemplateDef', 'nkIteratorDef', 'nkOfBranch',
'nkElifBranch', 'nkExceptBranch', 'nkElse', 'nkMacroStmt',
'nkAsmStmt', 'nkPragma', 'nkIfStmt', 'nkWhenStmt',
'nkForStmt', 'nkWhileStmt', 'nkCaseStmt', 'nkVarSection',
'nkConstSection', 'nkConstDef', 'nkTypeSection', 'nkTypeDef',
'nkYieldStmt', 'nkTryStmt', 'nkFinally', 'nkRaiseStmt',
'nkReturnStmt', 'nkBreakStmt', 'nkContinueStmt', 'nkBlockStmt',
'nkGotoStmt', 'nkDiscardStmt', 'nkStmtList', 'nkImportStmt',
'nkFromStmt', 'nkImportAs', 'nkIncludeStmt', 'nkAccessStmt',
'nkCommentStmt', 'nkStmtListExpr', 'nkBlockExpr', 'nkVm',
'nkTypeOfExpr', 'nkRecordTy', 'nkObjectTy', 'nkRecList',
'nkRecCase', 'nkRecWhen', 'nkRefTy', 'nkPtrTy',
'nkVarTy', 'nkProcTy', 'nkEnumTy', 'nkEnumFieldDef');
type
TSymFlag = (
sfGeneric, sfForward, sfImportc, sfExportc,
sfVolatile, sfUsed, sfWrite, sfRegister,
sfPure, sfCodeGenerated, sfPrivate, sfGlobal,
sfResult, sfNoSideEffect, sfMainModule, sfSystemModule,
sfNoReturn, sfReturnsNew, sfInInterface, sfNoStatic,
sfCompilerProc, sfCppMethod, sfDiscriminant, sfDeprecated,
sfInClosure, sfIsCopy, sfStar, sfMinus);
TSymFlags = set of TSymFlag;
const
SymFlagToStr: array [TSymFlag] of string = (
'sfGeneric', 'sfForward', 'sfImportc', 'sfExportc',
'sfVolatile', 'sfUsed', 'sfWrite', 'sfRegister',
'sfPure', 'sfCodeGenerated', 'sfPrivate', 'sfGlobal',
'sfResult', 'sfNoSideEffect', 'sfMainModule', 'sfSystemModule',
'sfNoReturn', 'sfReturnsNew', 'sfInInterface', 'sfNoStatic',
'sfCompilerProc', 'sfCppMethod', 'sfDiscriminant', 'sfDeprecated',
'sfInClosure', 'sfIsCopy', 'sfStar', 'sfMinus');
type
TTypeKind = (
tyNone, tyBool, tyChar, tyEmptySet,
tyArrayConstr, tyNil, tyRecordConstr, tyGeneric,
tyGenericInst, tyGenericParam, tyEnum, tyAnyEnum,
tyArray, tyRecord, tyObject, tyTuple,
tySet, tyRange, tyPtr, tyRef,
tyVar, tySequence, tyProc, tyPointer,
tyOpenArray, tyString, tyCString, tyForward,
tyInt, tyInt8, tyInt16, tyInt32,
tyInt64, tyFloat, tyFloat32, tyFloat64,
tyFloat128);
TTypeKinds = set of TTypeKind;
const
TypeKindToStr: array [TTypeKind] of string = (
'tyNone', 'tyBool', 'tyChar', 'tyEmptySet',
'tyArrayConstr', 'tyNil', 'tyRecordConstr', 'tyGeneric',
'tyGenericInst', 'tyGenericParam', 'tyEnum', 'tyAnyEnum',
'tyArray', 'tyRecord', 'tyObject', 'tyTuple',
'tySet', 'tyRange', 'tyPtr', 'tyRef',
'tyVar', 'tySequence', 'tyProc', 'tyPointer',
'tyOpenArray', 'tyString', 'tyCString', 'tyForward',
'tyInt', 'tyInt8', 'tyInt16', 'tyInt32',
'tyInt64', 'tyFloat', 'tyFloat32', 'tyFloat64',
'tyFloat128');
type
TTypeFlag = (
tfIsDistinct, tfGeneric, tfExternal, tfImported,
tfInfoGenerated, tfSemChecked, tfHasOutParams, tfEnumHasWholes,
tfVarargs, tfAssignable);
TTypeFlags = set of TTypeFlag;
const
TypeFlagToStr: array [TTypeFlag] of string = (
'tfIsDistinct', 'tfGeneric', 'tfExternal', 'tfImported',
'tfInfoGenerated', 'tfSemChecked', 'tfHasOutParams', 'tfEnumHasWholes',
'tfVarargs', 'tfAssignable');
{[[[end]]]}
type
@ -228,20 +237,28 @@ type
mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor,
mUnaryMinusI, mUnaryMinusI64, mAbsI, mAbsI64, mNot, mUnaryPlusI,
mBitnotI, mUnaryPlusI64, mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64,
mZe, mZe64, mToU8, mToU16, mToU32, mToFloat,
mToBiggestFloat, mToInt, mToBiggestInt, mAnd, mOr, mEqStr,
mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT,
mConTArr, mConTT, mSlice, mAppendStrCh, mAppendStrStr, mAppendSeqElem,
mAppendSeqSeq, mInRange, mInSet, mIs, mAsgn, mRepr,
mExit, mSetLengthStr, mSetLengthSeq, mAssert, mSwap, mArray,
mOpenArray, mRange, mTuple, mSet, mSeq, mCompileDate,
mCompileTime, mNimrodVersion, mNimrodMajor, mNimrodMinor, mNimrodPatch, mCpuEndian
mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64,
mToU8, mToU16, mToU32, mToFloat, mToBiggestFloat, mToInt,
mToBiggestInt, mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr,
mCStrToStr, mStrToStr, mAnd, mOr, mEqStr, mLeStr,
mLtStr, mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet,
mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT, mConTArr,
mConTT, mSlice, mAppendStrCh, mAppendStrStr, mAppendSeqElem, mAppendSeqSeq,
mInRange, mInSet, mIs, mAsgn, mRepr, mExit,
mSetLengthStr, mSetLengthSeq, mAssert, mSwap, mIsNil, mArray,
mOpenArray, mRange, mSet, mSeq, mCompileDate, mCompileTime,
mNimrodVersion, mNimrodMajor, mNimrodMinor, mNimrodPatch, mCpuEndian, mNaN,
mInf, mNegInf, mNLen, mNChild, mNSetChild, mNAdd,
mNAddMultiple, mNDel, mNKind, mNIntVal, mNFloatVal, mNSymbol,
mNIdent, mNGetType, mNStrVal, mNSetIntVal, mNSetFloatVal, mNSetSymbol,
mNSetIdent, mNSetType, mNSetStrVal, mNNewNimNode, mNCopyNimNode, mNCopyNimTree,
mStrToIdent, mIdentToStr, mEqIdent, mNHint, mNWarning, mNError
//[[[end]]]
);
type
PNode = ^TNode;
PNodePtr = ^{@ptr}PNode;
TNodeSeq = array of PNode;
PType = ^TType;
@ -254,22 +271,22 @@ type
comment: string;
sons: TNodeSeq; // else!
info: TLineInfo;
base: TNumericalBase; // only valid for int or float literals
flags: TNodeFlags;
case Kind: TNodeKind of
nkCharLit, nkRCharLit,
nkIntLit, nkInt8Lit, nkInt16Lit, nkInt32Lit, nkInt64Lit:
nkCharLit, nkIntLit, nkInt8Lit, nkInt16Lit, nkInt32Lit, nkInt64Lit:
(intVal: biggestInt);
nkFloatLit, nkFloat32Lit, nkFloat64Lit:
(floatVal: biggestFloat);
nkSym: (sym: PSym);
nkIdent: (ident: PIdent);
nkMetaNode: (nodePtr: PNodePtr);
end;
{@emit
record // keep this below 32 bytes; otherwise the AST grows too much
typ: PType;
comment: string;
info: TLineInfo;
base: TNumericalBase; // only valid for int or float literals
flags: TNodeFlags;
case Kind: TNodeKind of
nkCharLit..nkInt64Lit:
(intVal: biggestInt);
@ -279,6 +296,7 @@ type
(strVal: string);
nkSym: (sym: PSym);
nkIdent: (ident: PIdent);
nkMetaNode: (nodePtr: PNodePtr);
else (sons: TNodeSeq);
end; }
@ -307,27 +325,27 @@ type
);
TLocFlag = (
// lfIndirect, // location needs to be derefered
lfOnStack, // location is on hardware stack
lfOnHeap, // location is on heap
lfOnData, // location is in the static constant data
lfOnUnknown, // location is unknown (stack, heap or static)
// other backend-flags:
lfIndirect, // backend introduced a pointer
lfNoDeepCopy, // no need for a deep copy
lfNoDecl, // do not declare it in C
lfDynamicLib, // link symbol to dynamic library
lfHeader // include header file for symbol
);
TStorageLoc = (
OnUnknown, // location is unknown (stack, heap or static)
OnStack, // location is on hardware stack
OnHeap // location is on heap or global (reference counting needed)
);
TLocFlags = set of TLocFlag;
TLoc = record
k: TLocKind; // kind of location
t: PType; // type of location
r: PRope; // rope value of location (C code generator)
a: int; // location's "address", i.e. slot for temporaries
s: TStorageLoc;
flags: TLocFlags; // location's flags
indirect: int; // count the number of dereferences needed to access the
// location
t: PType; // type of location
r: PRope; // rope value of location (code generators)
a: int; // location's "address", i.e. slot for temporaries
end;
// ---------------- end of backend information ------------------------------
@ -447,7 +465,7 @@ type
PLib = ^TLib;
const
OverloadableSyms = {@set}[skProc, skIterator, skEnumField];
OverloadableSyms = {@set}[skProc, skIterator, skConverter];
const // "MagicToStr" array:
MagicToStr: array [TMagic] of string = (
@ -474,15 +492,22 @@ const // "MagicToStr" array:
'EqProc', 'EqUntracedRef', 'LePtr', 'LtPtr', 'EqCString', 'Xor',
'UnaryMinusI', 'UnaryMinusI64', 'AbsI', 'AbsI64', 'Not', 'UnaryPlusI',
'BitnotI', 'UnaryPlusI64', 'BitnotI64', 'UnaryPlusF64', 'UnaryMinusF64', 'AbsF64',
'Ze', 'Ze64', 'ToU8', 'ToU16', 'ToU32', 'ToFloat',
'ToBiggestFloat', 'ToInt', 'ToBiggestInt', 'And', 'Or', 'EqStr',
'LeStr', 'LtStr', 'EqSet', 'LeSet', 'LtSet', 'MulSet',
'PlusSet', 'MinusSet', 'SymDiffSet', 'ConStrStr', 'ConArrArr', 'ConArrT',
'ConTArr', 'ConTT', 'Slice', 'AppendStrCh', 'AppendStrStr', 'AppendSeqElem',
'AppendSeqSeq', 'InRange', 'InSet', 'Is', 'Asgn', 'Repr',
'Exit', 'SetLengthStr', 'SetLengthSeq', 'Assert', 'Swap', 'Array',
'OpenArray', 'Range', 'Tuple', 'Set', 'Seq', 'CompileDate',
'CompileTime', 'NimrodVersion', 'NimrodMajor', 'NimrodMinor', 'NimrodPatch', 'CpuEndian'
'Ze8ToI', 'Ze8ToI64', 'Ze16ToI', 'Ze16ToI64', 'Ze32ToI64', 'ZeIToI64',
'ToU8', 'ToU16', 'ToU32', 'ToFloat', 'ToBiggestFloat', 'ToInt',
'ToBiggestInt', 'CharToStr', 'BoolToStr', 'IntToStr', 'Int64ToStr', 'FloatToStr',
'CStrToStr', 'StrToStr', 'And', 'Or', 'EqStr', 'LeStr',
'LtStr', 'EqSet', 'LeSet', 'LtSet', 'MulSet', 'PlusSet',
'MinusSet', 'SymDiffSet', 'ConStrStr', 'ConArrArr', 'ConArrT', 'ConTArr',
'ConTT', 'Slice', 'AppendStrCh', 'AppendStrStr', 'AppendSeqElem', 'AppendSeqSeq',
'InRange', 'InSet', 'Is', 'Asgn', 'Repr', 'Exit',
'SetLengthStr', 'SetLengthSeq', 'Assert', 'Swap', 'IsNil', 'Array',
'OpenArray', 'Range', 'Set', 'Seq', 'CompileDate', 'CompileTime',
'NimrodVersion', 'NimrodMajor', 'NimrodMinor', 'NimrodPatch', 'CpuEndian', 'NaN',
'Inf', 'NegInf', 'NLen', 'NChild', 'NSetChild', 'NAdd',
'NAddMultiple', 'NDel', 'NKind', 'NIntVal', 'NFloatVal', 'NSymbol',
'NIdent', 'NGetType', 'NStrVal', 'NSetIntVal', 'NSetFloatVal', 'NSetSymbol',
'NSetIdent', 'NSetType', 'NSetStrVal', 'NNewNimNode', 'NCopyNimNode', 'NCopyNimTree',
'StrToIdent', 'IdentToStr', 'EqIdent', 'NHint', 'NWarning', 'NError'
//[[[end]]]
);
@ -490,7 +515,7 @@ const
GenericTypes: TTypeKinds = {@set}[tyGeneric, tyGenericParam];
StructuralEquivTypes: TTypeKinds = {@set}[
tyEmptySet, tyArrayConstr, tyNil, tyRecordConstr, tyTuple,
tyEmptySet, tyArrayConstr, tyNil, tyTuple,
tyArray,
tySet,
tyRange,
@ -503,16 +528,16 @@ const
ConcreteTypes: TTypeKinds = {@set}[
// types of the expr that may occur in::
// var x = expr
tyBool, tyChar, tyEnum, tyArray, tyRecord, tyObject, tySet, tyTuple,
tyBool, tyChar, tyEnum, tyArray, tyObject, tySet, tyTuple,
tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc,
tyPointer, tyOpenArray,
tyString, tyCString,
tyInt..tyInt64,
tyFloat..tyFloat128
];
ConstantDataTypes: TTypeKinds = {@set}[tyArray, tyRecord, tySet, tyTuple];
ExportableSymKinds = {@set}[skVar, skConst, skProc, skType, skEnumField,
skIterator, skMacro, skTemplate];
ConstantDataTypes: TTypeKinds = {@set}[tyArray, tySet, tyTuple];
ExportableSymKinds = {@set}[skVar, skConst, skProc, skType,
skIterator, skMacro, skTemplate, skConverter];
namePos = 0;
genericParamsPos = 1;
paramsPos = 2;
@ -534,7 +559,7 @@ function newIntTypeNode(kind: TNodeKind; const intVal: BiggestInt;
typ: PType): PNode;
function newFloatNode(kind: TNodeKind; const floatVal: BiggestFloat): PNode;
function newStrNode(kind: TNodeKind; const strVal: string): PNode;
function newIdentNode(ident: PIdent): PNode;
function newIdentNode(ident: PIdent; const info: TLineInfo): PNode;
function newSymNode(sym: PSym): PNode;
function newNodeI(kind: TNodeKind; const info: TLineInfo): PNode;
function newNodeIT(kind: TNodeKind; const info: TLineInfo; typ: PType): PNode;
@ -548,7 +573,7 @@ procedure initNodeTable(out x: TNodeTable);
// copy procs:
function copyType(t: PType; owner: PSym): PType;
function copySym(s: PSym; owner: PSym): PSym;
function copySym(s: PSym; keepId: bool = false): PSym;
procedure assignType(dest, src: PType);
procedure copyStrTable(out dest: TStrTable; const src: TStrTable);
@ -620,7 +645,7 @@ begin
if b.kind in [nkStrLit..nkTripleStrLit] then
result := a.strVal <= b.strVal;
end
else assert(false);
else InternalError(a.info, 'leValue');
end
end;
@ -638,7 +663,7 @@ begin
if b.kind in [nkStrLit..nkTripleStrLit] then
result := a.strVal = b.strVal;
end
else assert(false);
else InternalError(a.info, 'SameValue');
end
end;
@ -652,7 +677,7 @@ begin
nkStrLit..nkTripleStrLit:
result := a.strVal;
else begin
assert(false);
InternalError(a.info, 'valueToString');
result := ''
end
end
@ -663,6 +688,9 @@ var
i: int;
begin
dest.counter := src.counter;
{@emit
if isNil(src.data) then exit;
}
setLength(dest.data, length(src.data));
for i := 0 to high(src.data) do
dest.data[i] := src.data[i];
@ -673,6 +701,9 @@ var
i: int;
begin
dest.counter := src.counter;
{@emit
if isNil(src.data) then exit;
}
setLength(dest.data, length(src.data));
for i := 0 to high(src.data) do
dest.data[i] := src.data[i];
@ -683,6 +714,9 @@ var
i: int;
begin
dest.counter := src.counter;
{@emit
if isNil(src.data) then exit;
}
setLength(dest.data, length(src.data));
for i := 0 to high(src.data) do
dest.data[i] := src.data[i];
@ -700,7 +734,7 @@ begin
FillChar(result^, sizeof(result^), 0);
{@emit}
result.kind := kind;
result.info := UnknownLineInfo;
result.info := UnknownLineInfo();
end;
function newIntNode(kind: TNodeKind; const intVal: BiggestInt): PNode;
@ -728,10 +762,11 @@ begin
result.strVal := strVal
end;
function newIdentNode(ident: PIdent): PNode;
function newIdentNode(ident: PIdent; const info: TLineInfo): PNode;
begin
result := newNode(nkIdent);
result.ident := ident
result.ident := ident;
result.info := info;
end;
function newSymNode(sym: PSym): PNode;
@ -778,6 +813,7 @@ begin
dest.n := src.n;
dest.size := src.size;
dest.align := src.align;
dest.containerID := src.containerID;
newSons(dest, sonsLen(src));
for i := 0 to sonsLen(src)-1 do
dest.sons[i] := src.sons[i];
@ -793,14 +829,13 @@ begin
// backend-info should not be copied
end;
function copySym(s: PSym; owner: PSym): PSym;
function copySym(s: PSym; keepId: bool = false): PSym;
begin
result := newSym(s.kind, s.name, owner);
result := newSym(s.kind, s.name, s.owner);
result.ast := nil; // BUGFIX; was: s.ast which made problems
result.info := s.info;
result.typ := s.typ;
if owner = s.owner then result.id := s.id
else result.id := getID();
if keepId then result.id := s.id else result.id := getID();
result.flags := s.flags;
result.magic := s.magic;
copyStrTable(result.tab, s.tab);
@ -820,7 +855,7 @@ begin
result.Name := Name;
result.Kind := symKind;
result.flags := {@set}[];
result.info := UnknownLineInfo;
result.info := UnknownLineInfo();
result.options := gOptions;
result.owner := owner;
result.offset := -1;
@ -972,7 +1007,7 @@ begin
result := newNode(src.kind);
result.info := src.info;
result.typ := src.typ;
result.base := src.base;
result.flags := src.flags;
case src.Kind of
nkCharLit..nkInt64Lit:
result.intVal := src.intVal;
@ -984,6 +1019,8 @@ begin
result.ident := src.ident;
nkStrLit..nkTripleStrLit:
result.strVal := src.strVal;
nkMetaNode:
result.nodePtr := src.nodePtr;
else begin end;
end;
end;
@ -994,11 +1031,30 @@ var
i: int;
begin
if src = nil then begin result := nil; exit end;
result := copyNode(src);
result.sons := nil; // BUGFIX
newSons(result, sonsLen(src));
for i := 0 to sonsLen(src)-1 do
result.sons[i] := copyTree(src.sons[i]);
result := newNode(src.kind);
result.info := src.info;
result.typ := src.typ;
result.flags := src.flags;
case src.Kind of
nkCharLit..nkInt64Lit:
result.intVal := src.intVal;
nkFloatLit, nkFloat32Lit, nkFloat64Lit:
result.floatVal := src.floatVal;
nkSym:
result.sym := src.sym;
nkIdent:
result.ident := src.ident;
nkStrLit..nkTripleStrLit:
result.strVal := src.strVal;
nkMetaNode:
result.nodePtr := src.nodePtr;
else begin
result.sons := nil;
newSons(result, sonsLen(src));
for i := 0 to sonsLen(src)-1 do
result.sons[i] := copyTree(src.sons[i]);
end;
end
end;
function lastSon(n: PNode): PNode;

View file

@ -136,6 +136,10 @@ procedure debug(n: PNode); overload;
function IdTableGet(const t: TIdTable; key: PIdObj): PObject;
procedure IdTablePut(var t: TIdTable; key: PIdObj; val: PObject);
function IdTableHasObjectAsKey(const t: TIdTable; key: PIdObj): bool;
// checks if `t` contains the `key` (compared by the pointer value, not only
// `key`'s id)
function IdNodeTableGet(const t: TIdNodeTable; key: PIdObj): PNode;
procedure IdNodeTablePut(var t: TIdNodeTable; key: PIdObj; val: PNode);
@ -180,8 +184,6 @@ function nextTry(h, maxHash: THash): THash;
implementation
function lookupInRecord(n: PNode; field: PIdent): PSym;
// XXX: transform in a node that contains the runtime check for the
// field, if it is in a case-part...
var
i: int;
begin
@ -194,7 +196,7 @@ begin
end
end;
nkRecCase: begin
assert(n.sons[0].kind = nkSym);
if (n.sons[0].kind <> nkSym) then InternalError(n.info, 'lookupInRecord');
result := lookupInRecord(n.sons[0], field);
if result <> nil then exit;
for i := 1 to sonsLen(n)-1 do begin
@ -203,7 +205,7 @@ begin
result := lookupInRecord(lastSon(n.sons[i]), field);
if result <> nil then exit;
end;
else internalError('lookupInRecord(record case branch)');
else internalError(n.info, 'lookupInRecord(record case branch)');
end
end
end;
@ -226,7 +228,8 @@ var
i: int;
begin
for i := start to sonsLen(list)-1 do begin
assert(list.sons[i].kind = nkSym);
if list.sons[i].kind <> nkSym then
InternalError(list.info, 'getSymFromList');
result := list.sons[i].sym;
if result.name.id = ident.id then exit
end;
@ -342,7 +345,7 @@ end;
function lineInfoToStr(const info: TLineInfo): PRope;
begin
result := ropeFormat('[$1, $2, $3]', [makeYamlString(toFilename(info)),
result := ropef('[$1, $2, $3]', [makeYamlString(toFilename(info)),
toRope(toLinenumber(info)), toRope(toColumn(info))]);
end;
@ -367,11 +370,11 @@ begin
for i := 0 to high(n.data) do
if n.data[i] <> nil then begin
if mycount > 0 then app(result, ','+'');
appRopeFormat(result, '$n$1$2',
appf(result, '$n$1$2',
[istr, symToYamlAux(n.data[i], marker, indent+2, maxRecDepth-1)]);
inc(mycount)
end;
if mycount > 0 then appRopeFormat(result, '$n$1', [spaces(indent)]);
if mycount > 0 then appf(result, '$n$1', [spaces(indent)]);
app(result, ']'+'');
assert(mycount = n.counter);
end;
@ -387,10 +390,10 @@ begin
i := 0;
while i <= high(c) do begin
if i > 0 then app(result, ','+'');
appRopeFormat(result, '$n$1"$2": $3', [istr, c[i], c[i+1]]);
appf(result, '$n$1"$2": $3', [istr, c[i], c[i+1]]);
inc(i, 2)
end;
appRopeFormat(result, '$n$1}', [spaces(indent)]);
appf(result, '$n$1}', [spaces(indent)]);
end;
function symToYamlAux(n: PSym; var marker: TObjectSet;
@ -401,7 +404,7 @@ begin
if n = nil then
result := toRope('null')
else if ObjectSetContainsOrIncl(marker, n) then
result := ropeFormat('"$1 @$2"', [
result := ropef('"$1 @$2"', [
toRope(n.name.s),
toRope(strutils.toHex({@cast}TAddress(n), sizeof(n)*2))])
else begin
@ -427,7 +430,7 @@ begin
if n = nil then
result := toRope('null')
else if objectSetContainsOrIncl(marker, n) then
result := ropeFormat('"$1 @$2"', [
result := ropef('"$1 @$2"', [
toRope(typeKindToStr[n.kind]),
toRope(strutils.toHex({@cast}TAddress(n), sizeof(n)*2))])
else begin
@ -453,48 +456,48 @@ begin
result := toRope('null')
else begin
istr := spaces(indent+2);
result := ropeFormat('{$n$1"kind": $2',
result := ropef('{$n$1"kind": $2',
[istr, makeYamlString(nodeKindToStr[n.kind])]);
if maxRecDepth <> 0 then begin
appRopeFormat(result, ',$n$1"typ": $2',
[istr, typeToYamlAux(n.typ, marker, indent+2, maxRecDepth)]);
appRopeFormat(result, ',$n$1"info": $2',
appf(result, ',$n$1"info": $2',
[istr, lineInfoToStr(n.info)]);
case n.kind of
nkCharLit..nkInt64Lit:
appRopeFormat(result, '$n$1"intVal": $2', [istr, toRope(n.intVal)]);
appf(result, '$n$1"intVal": $2', [istr, toRope(n.intVal)]);
nkFloatLit, nkFloat32Lit, nkFloat64Lit:
appRopeFormat(result, '$n$1"floatVal": $2',
appf(result, '$n$1"floatVal": $2',
[istr, toRopeF(n.floatVal)]);
nkStrLit..nkTripleStrLit:
appRopeFormat(result, '$n$1"strVal": $2',
appf(result, '$n$1"strVal": $2',
[istr, makeYamlString(n.strVal)]);
nkSym:
appRopeFormat(result, ',$n$1"sym": $2',
appf(result, ',$n$1"sym": $2',
[istr, symToYamlAux(n.sym, marker, indent+2, maxRecDepth)]);
nkIdent: begin
if n.ident <> nil then
appRopeFormat(result, '$n$1"ident": $2',
appf(result, '$n$1"ident": $2',
[istr, makeYamlString(n.ident.s)])
else
appRopeFormat(result, '$n$1"ident": null', [istr])
appf(result, '$n$1"ident": null', [istr])
end
else begin
if sonsLen(n) > 0 then begin
appRopeFormat(result, ',$n$1"sons": [', [istr]);
appf(result, ',$n$1"sons": [', [istr]);
for i := 0 to sonsLen(n)-1 do begin
if i > 0 then app(result, ','+'');
appRopeFormat(result, '$n$1$2',
appf(result, '$n$1$2',
[spaces(indent+4),
treeToYamlAux(n.sons[i], marker, indent + 4, maxRecDepth-1)]);
end;
appRopeFormat(result, '$n$1]', [istr]);
appf(result, '$n$1]', [istr]);
end
end
end
end;
appf(result, ',$n$1"typ": $2',
[istr, typeToYamlAux(n.typ, marker, indent+2, maxRecDepth)]);
end;
appRopeFormat(result, '$n$1}', [spaces(indent)]);
appf(result, '$n$1}', [spaces(indent)]);
end
end;
@ -523,19 +526,88 @@ begin
end;
// these are for debugging only:
function debugType(n: PType): PRope;
var
i: int;
begin
if n = nil then
result := toRope('null')
else begin
result := toRope(typeKindToStr[n.kind]);
app(result, '('+'');
for i := 0 to sonsLen(n)-1 do begin
if i > 0 then app(result, ', ');
if n.sons[i] = nil then app(result, 'null')
else app(result, debugType(n.sons[i]));
// app(result, typeKindToStr[n.sons[i].kind]);
end;
app(result, ')'+'');
end
end;
function debugTree(n: PNode; indent: int; maxRecDepth: int): PRope;
var
istr: PRope;
i: int;
begin
if n = nil then
result := toRope('null')
else begin
istr := spaces(indent+2);
result := ropef('{$n$1"kind": $2',
[istr, makeYamlString(nodeKindToStr[n.kind])]);
if maxRecDepth <> 0 then begin
case n.kind of
nkCharLit..nkInt64Lit:
appf(result, '$n$1"intVal": $2', [istr, toRope(n.intVal)]);
nkFloatLit, nkFloat32Lit, nkFloat64Lit:
appf(result, '$n$1"floatVal": $2',
[istr, toRopeF(n.floatVal)]);
nkStrLit..nkTripleStrLit:
appf(result, '$n$1"strVal": $2',
[istr, makeYamlString(n.strVal)]);
nkSym:
appf(result, ',$n$1"sym": $2_$3',
[istr, toRope(n.sym.name.s), toRope(n.sym.id)]);
nkIdent: begin
if n.ident <> nil then
appf(result, '$n$1"ident": $2',
[istr, makeYamlString(n.ident.s)])
else
appf(result, '$n$1"ident": null', [istr])
end
else begin
if sonsLen(n) > 0 then begin
appf(result, ',$n$1"sons": [', [istr]);
for i := 0 to sonsLen(n)-1 do begin
if i > 0 then app(result, ','+'');
appf(result, '$n$1$2',
[spaces(indent+4),
debugTree(n.sons[i], indent + 4, maxRecDepth-1)]);
end;
appf(result, '$n$1]', [istr]);
end
end
end;
end;
appf(result, '$n$1}', [spaces(indent)]);
end
end;
procedure debug(n: PSym); overload;
begin
writeln(output, ropeToStr(symToYaml(n, 0, 3)));
writeln(output, ropeToStr(ropef('$1_$2', [toRope(n.name.s), toRope(n.id)])));
end;
procedure debug(n: PType); overload;
begin
writeln(output, ropeToStr(typeToYaml(n, 0, 3)));
writeln(output, ropeToStr(debugType(n)));
end;
procedure debug(n: PNode); overload;
begin
writeln(output, ropeToStr(treeToYaml(n, 0, -1)));
writeln(output, ropeToStr(debugTree(n, 0, 100)));
end;
// -------------------- node sets --------------------------------------------
@ -748,7 +820,8 @@ var
begin
h := n.name.h and high(data);
while data[h] <> nil do begin
assert(data[h] <> n);
if data[h] = n then
InternalError(n.info, 'StrTableRawInsert: ' + n.name.s);
h := nextTry(h, high(data))
end;
assert(data[h] = nil);
@ -963,6 +1036,15 @@ begin
result := -1
end;
function IdTableHasObjectAsKey(const t: TIdTable; key: PIdObj): bool;
var
index: int;
begin
index := IdTableRawGet(t, key);
if index >= 0 then result := t.data[index].key = key
else result := false
end;
function IdTableGet(const t: TIdTable; key: PIdObj): PObject;
var
index: int;
@ -999,6 +1081,7 @@ begin
end
else begin
if mustRehash(length(t.data), t.counter) then begin
{@emit n := [];}
setLength(n, length(t.data) * growthFactor);
{@ignore}
fillChar(n[0], length(n)*sizeof(n[0]), 0);
@ -1083,6 +1166,7 @@ begin
end
else begin
if mustRehash(length(t.data), t.counter) then begin
{@emit n := [];}
setLength(n, length(t.data) * growthFactor);
{@ignore}
fillChar(n[0], length(n)*sizeof(n[0]), 0);

View file

@ -49,17 +49,20 @@ end;
procedure BitSetIncl(var x: TBitSet; const elem: BiggestInt);
begin
x[int(elem div ElemSize)] := x[int(elem div ElemSize)] or (1 shl (elem mod ElemSize))
assert(elem >= 0);
x[int(elem div ElemSize)] := toU8(x[int(elem div ElemSize)] or
int(1 shl (elem mod ElemSize)))
end;
procedure BitSetExcl(var x: TBitSet; const elem: BiggestInt);
begin
x[int(elem div ElemSize)] := x[int(elem div ElemSize)] and
not (1 shl (elem mod ElemSize))
x[int(elem div ElemSize)] := toU8(x[int(elem div ElemSize)] and
not int(1 shl (elem mod ElemSize)))
end;
procedure BitSetInit(out b: TBitSet; len: int);
begin
{@emit b := [];}
setLength(b, len);
{@ignore}
fillChar(b[0], length(b)*sizeof(b[0]), 0);
@ -70,28 +73,28 @@ procedure BitSetUnion(var x: TBitSet; const y: TBitSet);
var
i: int;
begin
for i := 0 to high(x) do x[i] := x[i] or int(y[i])
for i := 0 to high(x) do x[i] := toU8(x[i] or int(y[i]))
end;
procedure BitSetDiff(var x: TBitSet; const y: TBitSet);
var
i: int;
begin
for i := 0 to high(x) do x[i] := x[i] and not int(y[i])
for i := 0 to high(x) do x[i] := toU8(x[i] and not int(y[i]))
end;
procedure BitSetSymDiff(var x: TBitSet; const y: TBitSet);
var
i: int;
begin
for i := 0 to high(x) do x[i] := x[i] xor int(y[i])
for i := 0 to high(x) do x[i] := toU8(x[i] xor int(y[i]))
end;
procedure BitSetIntersect(var x: TBitSet; const y: TBitSet);
var
i: int;
begin
for i := 0 to high(x) do x[i] := x[i] and int(y[i])
for i := 0 to high(x) do x[i] := toU8(x[i] and int(y[i]))
end;
function BitSetEquals(const x, y: TBitSet): Boolean;

File diff suppressed because it is too large Load diff

View file

@ -18,17 +18,25 @@ begin
line := toLinenumber(t.info); // BUGFIX
if line < 0 then line := 0; // negative numbers are not allowed in #line
if optLineDir in p.Options then
appRopeFormat(p.s[cpsStmts], '#line $2 "$1"$n',
appf(p.s[cpsStmts], '#line $2 "$1"$n',
[toRope(toFilename(t.info)), toRope(line)]);
if ([optStackTrace, optEndb] * p.Options = [optStackTrace, optEndb]) and
((p.prc = nil) or not (sfPure in p.prc.flags)) then begin
useMagic('endb'); // new: endb support
appRopeFormat(p.s[cpsStmts], 'endb($1);$n', [toRope(line)])
useMagic(p.module, 'endb'); // new: endb support
appf(p.s[cpsStmts], 'endb($1);$n', [toRope(line)])
end
else if ([optLineTrace, optStackTrace] * p.Options =
[optLineTrace, optStackTrace]) and ((p.prc = nil) or
not (sfPure in p.prc.flags)) then
appRopeFormat(p.s[cpsStmts], 'F.line = $1;$n', [toRope(line)])
appf(p.s[cpsStmts], 'F.line = $1;$n', [toRope(line)])
end;
procedure finishTryStmt(p: BProc; howMany: int);
var
i: int;
begin
for i := 1 to howMany do
app(p.s[cpsStmts], 'excHandler = excHandler->prev;' + tnl);
end;
procedure genReturnStmt(p: BProc; t: PNode);
@ -36,15 +44,16 @@ begin
p.beforeRetNeeded := true;
genLineDir(p, t);
if (t.sons[0] <> nil) then genStmts(p, t.sons[0]);
finishTryStmt(p, p.nestedTryStmts);
app(p.s[cpsStmts], 'goto BeforeRet;' + tnl)
end;
procedure genObjectInit(p: BProc; sym: PSym);
begin
if containsObject(sym.typ) then begin
useMagic('objectInit');
appRopeFormat(p.s[cpsInit], 'objectInit($1, $2);$n',
[addrLoc(sym.loc), genTypeInfo(currMod, sym.typ)])
useMagic(p.module, 'objectInit');
appf(p.s[cpsInit], 'objectInit($1, $2);$n',
[addrLoc(sym.loc), genTypeInfo(p.module, sym.typ)])
end
end;
@ -52,11 +61,11 @@ procedure initVariable(p: BProc; v: PSym);
begin
if containsGarbageCollectedRef(v.typ) or (v.ast = nil) then
// Language change: always initialize variables if v.ast == nil!
if not (skipAbstract(v.typ).Kind in [tyArray, tyArrayConstr, tySet,
tyRecord, tyTuple, tyObject]) then
appRopeFormat(p.s[cpsInit], '$1 = 0;$n', [v.loc.r])
if not (skipVarGenericRange(v.typ).Kind in [tyArray, tyArrayConstr, tySet,
tyTuple, tyObject]) then
appf(p.s[cpsStmts], '$1 = 0;$n', [v.loc.r])
else
appRopeFormat(p.s[cpsInit], 'memset((void*)&$1, 0, sizeof($1));$n',
appf(p.s[cpsStmts], 'memset((void*)&$1, 0, sizeof($1));$n',
[v.loc.r])
end;
@ -73,7 +82,7 @@ begin
assert(a.sons[0].kind = nkSym);
v := a.sons[0].sym;
if sfGlobal in v.flags then
assignGlobalVar(v)
assignGlobalVar(p.module, v)
else begin
assignLocalVar(p, v);
initVariable(p, v) // XXX: this is not required if a.sons[2] != nil,
@ -95,19 +104,20 @@ var
begin
for i := 0 to sonsLen(t)-1 do begin
if t.sons[i].kind = nkCommentStmt then continue;
assert(t.sons[i].kind = nkConstDef);
if t.sons[i].kind <> nkConstDef then InternalError(t.info, 'genConstStmt');
c := t.sons[i].sons[0].sym;
// This can happen for forward consts:
if (c.ast <> nil) and (c.typ.kind in ConstantDataTypes) and
not (lfNoDecl in c.loc.flags) then begin
// generate the data:
fillLoc(c.loc, locData, c.typ, mangleName(c), {@set}[lfOnData]);
fillLoc(c.loc, locData, c.typ, mangleName(c), OnUnknown);
if sfImportc in c.flags then
appRopeFormat(currMod.s[cfsData], 'extern $1$2 $3;$n',
[constTok, getTypeDesc(c.typ), c.loc.r])
appf(p.module.s[cfsData], 'extern NIM_CONST $1 $2;$n',
[getTypeDesc(p.module, c.typ), c.loc.r])
else
appRopeFormat(currMod.s[cfsData], '$1$2 $3 = $4;$n',
[constTok, getTypeDesc(c.typ), c.loc.r, genConstExpr(p, c.ast)])
appf(p.module.s[cfsData], 'NIM_CONST $1 $2 = $3;$n',
[getTypeDesc(p.module, c.typ), c.loc.r,
genConstExpr(p, c.ast)])
end
end
end;
@ -139,11 +149,11 @@ begin
nkElifBranch: begin
a := initLocExpr(p, it.sons[0]);
Lelse := getLabel(p);
appRopeFormat(p.s[cpsStmts], 'if (!$1) goto $2;$n', [rdLoc(a), Lelse]);
appf(p.s[cpsStmts], 'if (!$1) goto $2;$n', [rdLoc(a), Lelse]);
freeTemp(p, a);
genStmts(p, it.sons[1]);
if sonsLen(n) > 1 then
appRopeFormat(p.s[cpsStmts], 'goto $1;$n', [Lend]);
appf(p.s[cpsStmts], 'goto $1;$n', [Lend]);
fixLabel(p, Lelse);
end;
nkElse: begin
@ -166,17 +176,18 @@ var
begin
genLineDir(p, t);
assert(sonsLen(t) = 2);
inc(p.unique);
Labl := con('L'+'', toRope(p.unique));
inc(p.labels);
Labl := con('L'+'', toRope(p.labels));
len := length(p.blocks);
setLength(p.blocks, len+1);
p.blocks[len] := p.unique; // positive because we use it right away:
p.blocks[len].id := p.labels; // positive because we use it right away:
p.blocks[len].nestedTryStmts := p.nestedTryStmts;
app(p.s[cpsStmts], 'while (1) {' + tnl);
a := initLocExpr(p, t.sons[0]);
appRopeFormat(p.s[cpsStmts], 'if (!$1) goto $2;$n', [rdLoc(a), Labl]);
appf(p.s[cpsStmts], 'if (!$1) goto $2;$n', [rdLoc(a), Labl]);
freeTemp(p, a);
genStmts(p, t.sons[1]);
appRopeFormat(p.s[cpsStmts], '} $1: ;$n', [Labl]);
appf(p.s[cpsStmts], '} $1: ;$n', [Labl]);
setLength(p.blocks, length(p.blocks)-1)
end;
@ -185,7 +196,7 @@ var
idx: int;
sym: PSym;
begin
inc(p.unique);
inc(p.labels);
idx := length(p.blocks);
if t.sons[0] <> nil then begin // named block?
assert(t.sons[0].kind = nkSym);
@ -194,14 +205,22 @@ begin
sym.loc.a := idx
end;
setLength(p.blocks, idx+1);
p.blocks[idx] := -p.unique; // negative because it isn't used yet
p.blocks[idx].id := -p.labels; // negative because it isn't used yet
p.blocks[idx].nestedTryStmts := p.nestedTryStmts;
if t.kind = nkBlockExpr then genStmtListExpr(p, t.sons[1], d)
else genStmts(p, t.sons[1]);
if p.blocks[idx] > 0 then // label has been used:
appRopeFormat(p.s[cpsStmts], 'L$1: ;$n', [toRope(p.blocks[idx])]);
if p.blocks[idx].id > 0 then // label has been used:
appf(p.s[cpsStmts], 'L$1: ;$n', [toRope(p.blocks[idx].id)]);
setLength(p.blocks, idx)
end;
// try:
// while:
// try:
// if ...:
// break # we need to finish only one try statement here!
// finally:
procedure genBreakStmt(p: BProc; t: PNode);
var
idx: int;
@ -215,8 +234,9 @@ begin
assert(sym.loc.k = locOther);
idx := sym.loc.a
end;
p.blocks[idx] := abs(p.blocks[idx]); // label is used
appRopeFormat(p.s[cpsStmts], 'goto L$1;$n', [toRope(p.blocks[idx])])
p.blocks[idx].id := abs(p.blocks[idx].id); // label is used
finishTryStmt(p, p.nestedTryStmts - p.blocks[idx].nestedTryStmts);
appf(p.s[cpsStmts], 'goto L$1;$n', [toRope(p.blocks[idx].id)])
end;
procedure genAsmStmt(p: BProc; t: PNode);
@ -245,15 +265,15 @@ begin
InternalError(t.sons[i].info, 'genAsmStmt()')
end
end;
appRopeFormat(p.s[cpsStmts], CC[ccompiler].asmStmtFrmt, [s]);
appf(p.s[cpsStmts], CC[ccompiler].asmStmtFrmt, [s]);
end;
function getRaiseFrmt(): string;
function getRaiseFrmt(p: BProc): string;
begin
if gCmd = cmdCompileToCpp then
result := 'throw nimException($1, $2);$n'
else begin
useMagic('E_Base');
useMagic(p.module, 'E_Base');
result := 'raiseException((E_Base*)$1, $2);$n'
end
end;
@ -266,14 +286,13 @@ var
begin
genLineDir(p, t);
if t.sons[0] <> nil then begin
if gCmd <> cmdCompileToCpp then
useMagic('raiseException');
if gCmd <> cmdCompileToCpp then useMagic(p.module, 'raiseException');
a := InitLocExpr(p, t.sons[0]);
e := rdLoc(a);
freeTemp(p, a);
typ := t.sons[0].typ;
while typ.kind in [tyVar, tyRef, tyPtr] do typ := typ.sons[0];
appRopeFormat(p.s[cpsStmts], getRaiseFrmt(),
appf(p.s[cpsStmts], getRaiseFrmt(p),
[e, makeCString(typ.sym.name.s)])
end
else begin
@ -281,7 +300,7 @@ begin
if gCmd = cmdCompileToCpp then
app(p.s[cpsStmts], 'throw;' + tnl)
else begin
useMagic('reraiseException');
useMagic(p.module, 'reraiseException');
app(p.s[cpsStmts], 'reraiseException();' + tnl)
end
end
@ -309,13 +328,13 @@ begin
y := initLocExpr(p, b.sons[i].sons[1]);
freeTemp(p, x);
freeTemp(p, y);
appRopeFormat(p.s[cpsStmts], rangeFormat,
appf(p.s[cpsStmts], rangeFormat,
[rdCharLoc(e), rdCharLoc(x), rdCharLoc(y), labl])
end
else begin
x := initLocExpr(p, b.sons[i]);
freeTemp(p, x);
appRopeFormat(p.s[cpsStmts], eqFormat,
appf(p.s[cpsStmts], eqFormat,
[rdCharLoc(e), rdCharLoc(x), labl])
end
end
@ -328,11 +347,11 @@ var
begin
Lend := getLabel(p);
for i := 1 to sonsLen(t) - 1 do begin
appRopeFormat(p.s[cpsStmts], 'L$1: ;$n', [toRope(labId+i)]);
appf(p.s[cpsStmts], 'L$1: ;$n', [toRope(labId+i)]);
if t.sons[i].kind = nkOfBranch then begin
len := sonsLen(t.sons[i]);
genStmts(p, t.sons[i].sons[len-1]);
appRopeFormat(p.s[cpsStmts], 'goto $1;$n', [Lend])
appf(p.s[cpsStmts], 'goto $1;$n', [Lend])
end
else // else statement
genStmts(p, t.sons[i].sons[0])
@ -349,15 +368,15 @@ var
begin
a := initLocExpr(p, t.sons[0]);
// fist pass: gnerate ifs+goto:
labId := p.unique;
labId := p.labels;
for i := 1 to sonsLen(t) - 1 do begin
inc(p.unique);
inc(p.labels);
if t.sons[i].kind = nkOfBranch then
genCaseGenericBranch(p, t.sons[i], a, rangeFormat, eqFormat,
con('L'+'', toRope(p.unique)))
con('L'+'', toRope(p.labels)))
else
// else statement
appRopeFormat(p.s[cpsStmts], 'goto L$1;$n', [toRope(p.unique)]);
appf(p.s[cpsStmts], 'goto L$1;$n', [toRope(p.labels)]);
end;
// second pass: generate statements
genCaseSecondPass(p, t, labId);
@ -435,7 +454,7 @@ begin
freeTemp(p, x);
assert(b.sons[i].kind in [nkStrLit..nkTripleStrLit]);
j := int(hashString(b.sons[i].strVal) and high(branches));
appRopeFormat(branches[j], 'if (eqStrings($1, $2)) goto $3;$n',
appf(branches[j], 'if (eqStrings($1, $2)) goto $3;$n',
[rdLoc(e), rdLoc(x), labl])
end
end;
@ -446,38 +465,39 @@ var
a: TLoc;
branches: TRopeSeq;
begin
useMagic('eqStrings');
useMagic(p.module, 'eqStrings');
// count how many constant strings there are in the case:
strings := 0;
for i := 1 to sonsLen(t)-1 do
if t.sons[i].kind = nkOfBranch then inc(strings, sonsLen(t.sons[i])-1);
if strings > stringCaseThreshold then begin
useMagic('hashString');
useMagic(p.module, 'hashString');
bitMask := nmath.nextPowerOfTwo(strings)-1;
setLength(branches, bitMask+1);
a := initLocExpr(p, t.sons[0]);
// fist pass: gnerate ifs+goto:
labId := p.unique;
labId := p.labels;
for i := 1 to sonsLen(t) - 1 do begin
inc(p.unique);
inc(p.labels);
if t.sons[i].kind = nkOfBranch then
genCaseStringBranch(p, t.sons[i], a, con('L'+'', toRope(p.unique)),
genCaseStringBranch(p, t.sons[i], a, con('L'+'', toRope(p.labels)),
branches)
else begin end
else begin
// else statement: nothing to do yet
// but we reserved a label, which we use later
end
end;
// second pass: generate switch statement based on hash of string:
appRopeFormat(p.s[cpsStmts], 'switch (hashString($1) & $2) {$n',
appf(p.s[cpsStmts], 'switch (hashString($1) & $2) {$n',
[rdLoc(a), toRope(bitMask)]);
for j := 0 to high(branches) do
if branches[j] <> nil then
appRopeFormat(p.s[cpsStmts], 'case $1: $n$2break;$n',
appf(p.s[cpsStmts], 'case $1: $n$2break;$n',
[intLiteral(j), branches[j]]);
app(p.s[cpsStmts], '}' + tnl);
// else statement:
if t.sons[sonsLen(t)-1].kind <> nkOfBranch then
appRopeFormat(p.s[cpsStmts], 'goto L$1;$n', [toRope(p.unique)]);
appf(p.s[cpsStmts], 'goto L$1;$n', [toRope(p.labels)]);
// third pass: generate statements
genCaseSecondPass(p, t, labId);
freeTemp(p, a);
@ -521,7 +541,7 @@ begin
end;
if canGenerateSwitch then begin
a := initLocExpr(p, t.sons[0]);
appRopeFormat(p.s[cpsStmts], 'switch ($1) {$n', [rdCharLoc(a)]);
appf(p.s[cpsStmts], 'switch ($1) {$n', [rdCharLoc(a)]);
freeTemp(p, a);
for i := 1 to sonsLen(t)-1 do begin
if t.sons[i].kind = nkOfBranch then begin
@ -529,19 +549,19 @@ begin
for j := 0 to len-2 do begin
if t.sons[i].sons[j].kind = nkRange then begin // a range
if hasSwitchRange in CC[ccompiler].props then
appRopeFormat(p.s[cpsStmts], 'case $1 ... $2:$n',
appf(p.s[cpsStmts], 'case $1 ... $2:$n',
[genLiteral(p, t.sons[i].sons[j].sons[0]),
genLiteral(p, t.sons[i].sons[j].sons[1])])
else begin
v := copyNode(t.sons[i].sons[j].sons[0]);
while (v.intVal <= t.sons[i].sons[j].sons[1].intVal) do begin
appRopeFormat(p.s[cpsStmts], 'case $1:$n', [genLiteral(p, v)]);
appf(p.s[cpsStmts], 'case $1:$n', [genLiteral(p, v)]);
Inc(v.intVal)
end
end;
end
else
appRopeFormat(p.s[cpsStmts], 'case $1:$n',
appf(p.s[cpsStmts], 'case $1:$n',
[genLiteral(p, t.sons[i].sons[j])]);
end;
genStmts(p, t.sons[i].sons[len-1])
@ -563,7 +583,7 @@ end;
procedure genCaseStmt(p: BProc; t: PNode);
begin
genLineDir(p, t);
case skipAbstract(t.sons[0].typ).kind of
case skipVarGenericRange(t.sons[0].typ).kind of
tyString: genStringCase(p, t);
tyFloat..tyFloat128:
genCaseGeneric(p, t, 'if ($1 >= $2 && $1 <= $3) goto $4;$n',
@ -622,21 +642,20 @@ begin
exc := getTempName();
if not hasGeneralExceptSection(t) then begin
rethrowFlag := getTempName();
appRopeFormat(p.s[cpsLocals], 'volatile NIM_BOOL $1 = NIM_FALSE;$n',
appf(p.s[cpsLocals], 'volatile NIM_BOOL $1 = NIM_FALSE;$n',
[rethrowFlag])
end;
if optStackTrace in p.Options then
app(p.s[cpsStmts], 'framePtr = (TFrame*)&F;' + tnl);
app(p.s[cpsStmts], 'try {' + tnl);
inc(p.inTryStmt);
inc(p.nestedTryStmts);
genStmts(p, t.sons[0]);
dec(p.inTryStmt);
len := sonsLen(t);
if t.sons[1].kind = nkExceptBranch then begin
appRopeFormat(p.s[cpsStmts], '} catch (NimException& $1) {$n', [exc]);
appf(p.s[cpsStmts], '} catch (NimException& $1) {$n', [exc]);
if rethrowFlag <> nil then
appRopeFormat(p.s[cpsStmts], '$1 = NIM_TRUE;$n', [rethrowFlag]);
appRopeFormat(p.s[cpsStmts], 'if ($1.sp.exc) {$n', [exc])
appf(p.s[cpsStmts], '$1 = NIM_TRUE;$n', [rethrowFlag]);
appf(p.s[cpsStmts], 'if ($1.sp.exc) {$n', [exc])
end; // XXX: this is not correct!
i := 1;
while (i < len) and (t.sons[i].kind = nkExceptBranch) do begin
@ -648,24 +667,25 @@ begin
else begin
for j := 0 to blen - 2 do begin
assert(t.sons[i].sons[j].kind = nkType);
appRopeFormat(p.s[cpsStmts], 'case $1:$n',
appf(p.s[cpsStmts], 'case $1:$n',
[toRope(t.sons[i].sons[j].typ.id)])
end;
genStmts(p, t.sons[i].sons[blen - 1])
end;
// code to clear the exception:
if rethrowFlag <> nil then
appRopeFormat(p.s[cpsStmts], '$1 = NIM_FALSE; ', [rethrowFlag]);
appf(p.s[cpsStmts], '$1 = NIM_FALSE; ', [rethrowFlag]);
app(p.s[cpsStmts], 'break;' + tnl);
inc(i);
end;
if t.sons[1].kind = nkExceptBranch then // BUGFIX
app(p.s[cpsStmts], '}}' + tnl); // end of catch-switch statement
dec(p.nestedTryStmts);
app(p.s[cpsStmts], 'excHandler = excHandler->prev;' + tnl);
if (i < len) and (t.sons[i].kind = nkFinally) then begin
genStmts(p, t.sons[i].sons[0]);
if rethrowFlag <> nil then
appRopeFormat(p.s[cpsStmts], 'if ($1) { throw; }$n', [rethrowFlag])
appf(p.s[cpsStmts], 'if ($1) { throw; }$n', [rethrowFlag])
end
end;
@ -698,21 +718,21 @@ begin
genLineDir(p, t);
safePoint := getTempName();
useMagic('TSafePoint');
useMagic('E_Base');
useMagic('excHandler');
appRopeFormat(p.s[cpsLocals], 'volatile TSafePoint $1;$n', [safePoint]);
appRopeFormat(p.s[cpsStmts], '$1.prev = excHandler;$n' +
'excHandler = &$1;$n' +
'$1.status = setjmp($1.context);$n' +
'if ($1.status == 0) {$n', [safePoint]);
useMagic(p.module, 'TSafePoint');
useMagic(p.module, 'E_Base');
useMagic(p.module, 'excHandler');
appf(p.s[cpsLocals], 'TSafePoint $1;$n', [safePoint]);
appf(p.s[cpsStmts], '$1.prev = excHandler;$n' +
'excHandler = &$1;$n' +
'$1.status = setjmp($1.context);$n',
[safePoint]);
if optStackTrace in p.Options then
app(p.s[cpsStmts], 'framePtr = (TFrame*)&F;' + tnl);
appf(p.s[cpsStmts], 'if ($1.status == 0) {$n', [safePoint]);
len := sonsLen(t);
inc(p.inTryStmt);
inc(p.nestedTryStmts);
genStmts(p, t.sons[0]);
app(p.s[cpsStmts], '} else {' + tnl);
dec(p.inTryStmt);
i := 1;
while (i < len) and (t.sons[i].kind = nkExceptBranch) do begin
blen := sonsLen(t.sons[i]);
@ -720,7 +740,7 @@ begin
// general except section:
if i > 1 then app(p.s[cpsStmts], 'else {' + tnl);
genStmts(p, t.sons[i].sons[0]);
appRopeFormat(p.s[cpsStmts], '$1.status = 0;$n', [safePoint]);
appf(p.s[cpsStmts], '$1.status = 0;$n', [safePoint]);
if i > 1 then app(p.s[cpsStmts], '}' + tnl);
end
else begin
@ -728,24 +748,25 @@ begin
for j := 0 to blen - 2 do begin
assert(t.sons[i].sons[j].kind = nkType);
if orExpr <> nil then app(orExpr, '||');
appRopeFormat(orExpr, '($1.exc->Sup.m_type == $2)',
[safePoint, genTypeInfo(currMod, t.sons[i].sons[j].typ)])
appf(orExpr, '($1.exc->Sup.m_type == $2)',
[safePoint, genTypeInfo(p.module, t.sons[i].sons[j].typ)])
end;
if i > 1 then app(p.s[cpsStmts], 'else ');
appRopeFormat(p.s[cpsStmts], 'if ($1) {$n', [orExpr]);
appf(p.s[cpsStmts], 'if ($1) {$n', [orExpr]);
genStmts(p, t.sons[i].sons[blen - 1]);
// code to clear the exception:
appRopeFormat(p.s[cpsStmts], '$1.status = 0;}$n', [safePoint]);
appf(p.s[cpsStmts], '$1.status = 0;}$n', [safePoint]);
end;
inc(i)
end;
app(p.s[cpsStmts], '}' + tnl); // end of if statement
app(p.s[cpsStmts], 'excHandler = excHandler->prev;' + tnl);
finishTryStmt(p, p.nestedTryStmts);
dec(p.nestedTryStmts);
if (i < len) and (t.sons[i].kind = nkFinally) then begin
genStmts(p, t.sons[i].sons[0]);
useMagic('raiseException');
appRopeFormat(p.s[cpsStmts], 'if ($1.status != 0) { ' +
'raiseException($1.exc, $1.exc->Name); }$n', [safePoint])
useMagic(p.module, 'raiseException');
appf(p.s[cpsStmts], 'if ($1.status != 0) { ' +
'raiseException($1.exc, $1.exc->name); }$n', [safePoint])
end
end;
@ -767,7 +788,7 @@ begin
name := 'bp' + toString(breakPointId)
end;
genLineDir(p, t); // BUGFIX
appRopeFormat(gBreakpoints,
appf(gBreakpoints,
'dbgRegisterBreakpoint($1, (NCSTRING)$2, (NCSTRING)$3);$n',
[toRope(toLinenumber(t.info)), makeCString(toFilename(t.info)),
makeCString(name)])
@ -852,15 +873,15 @@ begin
nkCommentStmt, nkNilLit, nkIteratorDef, nkIncludeStmt, nkImportStmt,
nkFromStmt, nkTemplateDef, nkMacroDef: begin end;
nkPragma: genPragma(p, t);
nkProcDef: begin
nkProcDef, nkConverterDef: begin
if (t.sons[genericParamsPos] = nil) then begin
prc := t.sons[namePos].sym;
if (t.sons[codePos] <> nil)
or (lfDynamicLib in prc.loc.flags) then begin // BUGFIX
if IntSetContainsOrIncl(currMod.debugDeclared, prc.id) then begin
if IntSetContainsOrIncl(p.module.debugDeclared, prc.id) then begin
internalError(t.info, 'genProc()'); // XXX: remove this check!
end;
genProc(prc)
genProc(p.module, prc)
end
//else if sfCompilerProc in prc.flags then genProcPrototype(prc);
end

View file

@ -9,12 +9,6 @@
// ------------------------- Name Mangling --------------------------------
function getUnique(p: BProc): PRope;
begin
inc(p.unique);
result := toRope(p.unique)
end;
function mangle(const name: string): string;
var
i: int;
@ -23,7 +17,7 @@ begin
result := toUpper(name[strStart])+''
else
result := 'HEX' + toHex(ord(name[strStart]), 2);
for i := 2 to length(name) - 1 + strStart do begin
for i := strStart+1 to length(name) + strStart-1 do begin
case name[i] of
'A'..'Z': addChar(result, chr(ord(name[i]) - ord('A') + ord('a')));
'_': begin end;
@ -35,22 +29,68 @@ end;
function mangleName(s: PSym): PRope;
begin
if s.owner <> nil then
result := ropeFormat('$1_$2_$3', [toRope(mangle(s.owner.name.s)),
toRope(mangle(s.name.s)),
toRope(s.id)])
else
result := ropeFormat('$1_$2', [toRope(mangle(s.name.s)),
toRope(s.id)]);
result := ropef('$1_$2', [toRope(mangle(s.name.s)), toRope(s.id)]);
if optGenMapping in gGlobalOptions then
if s.owner <> nil then
appRopeFormat(gMapping, '$1.$2 $3$n',
appf(gMapping, '$1.$2 $3$n',
[toRope(s.owner.Name.s), toRope(s.name.s), result])
end;
// ------------------------------ C type generator ------------------------
function getTypeDesc(typ: PType): PRope; forward;
function mapType(typ: PType): TCTypeKind;
begin
case typ.kind of
tyNone: result := ctVoid;
tyBool: result := ctBool;
tyChar: result := ctChar;
tyEmptySet, tySet: begin
case int(getSize(typ)) of
1: result := ctInt8;
2: result := ctInt16;
4: result := ctInt32;
8: result := ctInt64;
else result := ctArray
end
end;
tyOpenArray, tyArrayConstr, tyArray: result := ctArray;
tyObject, tyTuple: result := ctStruct;
tyGeneric, tyGenericInst, tyGenericParam: result := mapType(lastSon(typ));
tyEnum, tyAnyEnum: begin
if firstOrd(typ) < 0 then
result := ctInt32
else begin
case int(getSize(typ)) of
1: result := ctUInt8;
2: result := ctUInt16;
4: result := ctInt32;
else internalError('mapType');
end
end
end;
tyRange: result := mapType(typ.sons[0]);
tyPtr, tyVar, tyRef: begin
case typ.sons[0].kind of
tyOpenArray, tyArrayConstr, tyArray: result := ctArray;
(*tySet: begin
if mapType(typ.sons[0]) = ctArray then result := ctArray
else result := ctPtr
end*)
else result := ctPtr
end
end;
tyPointer: result := ctPtr;
tySequence: result := ctNimSeq;
tyProc: result := ctProc;
tyString: result := ctNimStr;
tyCString: result := ctCString;
tyInt..tyFloat128:
result := TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt));
else InternalError('mapType');
end
end;
function getTypeDesc(m: BModule; typ: PType): PRope; forward;
function needsComplexAssignment(typ: PType): bool;
begin
@ -58,8 +98,6 @@ begin
end;
function isInvalidReturnType(rettype: PType): bool;
var
t: PType;
begin
// Arrays and sets cannot be returned by a C procedure, because C is
// such a poor programming language.
@ -68,16 +106,9 @@ begin
if rettype = nil then
result := true
else begin
t := skipAbstract(rettype);
case t.kind of
tyArray, tyArrayConstr: result := true;
tyObject, tyRecord: result := needsComplexAssignment(t);
tySet: begin
case int(getSize(t)) of
1, 2, 4, 8: result := false;
else result := true
end
end
case mapType(rettype) of
ctArray: result := true;
ctStruct: result := needsComplexAssignment(skipGeneric(rettype));
else result := false;
end
end
@ -96,65 +127,46 @@ begin
result := PRope(TableGetType(tab, key))
end;
var
gUnique: int;
function getTempName(): PRope;
begin
inc(gUnique);
result := con('T'+'', toRope(gUnique))
end;
function isCArray(typ: PType): bool;
var
t: PType;
begin
t := skipVarGeneric(typ);
case t.kind of
tyArray, tyArrayConstr, tyOpenArray: result := true;
tySet: result := getSize(t) > 8;
else result := false
end
end;
function UsePtrPassing(param: PSym): bool;
// this is pretty complicated ...
function ccgIntroducedPtr(s: PSym): bool;
var
pt: PType;
begin
pt := param.typ;
if (sfResult in param.flags) and not isInvalidReturnType(pt) then
result := false // BUGFIX
else if pt.Kind = tyObject then begin
// objects are always passed by reference,
// otherwise implicit casting doesn't work
result := true;
pt := s.typ;
assert(not (sfResult in s.flags));
case pt.Kind of
tyObject: begin
if (optByRef in s.options) or (getSize(pt) > platform.floatSize) then
result := true // requested anyway
else if (tfFinal in pt.flags) and (pt.sons[0] = nil) then
result := false // no need, because no subtyping possible
else
result := true; // ordinary objects are always passed by reference,
// otherwise casting doesn't work
end;
tyTuple:
result := (getSize(pt) > platform.floatSize) or (optByRef in s.options);
else
result := false
end
else if (pt.kind in [tyRecordConstr, tyRecord]) and
((getSize(pt) > platform.floatSize) or
(optByRef in param.options)) then begin
result := true;
end
else if isCArray(pt) then
result := false
else if (pt.kind = tyVar) or (getSize(pt) > platform.floatSize) then begin
result := true;
end
else
result := false
end;
const
PointerTypes = {@set}[tySequence, tyString, tyRef, tyPtr, tyPointer];
procedure fillResult(param: PSym);
begin
fillLoc(param.loc, locParam, param.typ,
toRope('Result'), {@set}[lfOnUnknown]);
if UsePtrPassing(param) then param.loc.indirect := 1
fillLoc(param.loc, locParam, param.typ, toRope('Result'), OnStack);
if (mapType(param.typ) <> ctArray) and IsInvalidReturnType(param.typ) then
begin
include(param.loc.flags, lfIndirect);
param.loc.s := OnUnknown
end
end;
procedure genProcParams(t: PType; out rettype, params: PRope);
procedure genProcParams(m: BModule; t: PType; out rettype, params: PRope);
var
i, j: int;
param: PSym;
@ -165,31 +177,25 @@ begin
// C cannot return arrays (what a poor language...)
rettype := toRope('void')
else
rettype := getTypeDesc(t.sons[0]);
rettype := getTypeDesc(m, t.sons[0]);
for i := 1 to sonsLen(t.n)-1 do begin
assert(t.n.sons[i].kind = nkSym);
if t.n.sons[i].kind <> nkSym then InternalError(t.n.info, 'genProcParams');
param := t.n.sons[i].sym;
fillLoc(param.loc, locParam, param.typ,
con(toRope('Par'), toRope(i)), {@set}[lfOnStack]);
if param.typ.kind = tyVar then begin
param.loc.flags := {@set}[lfOnUnknown]; // BUGFIX!
app(params, getTypeDesc(param.typ.sons[0]));
end
else
app(params, getTypeDesc(param.typ));
if UsePtrPassing(param) then begin
fillLoc(param.loc, locParam, param.typ, mangleName(param), OnStack);
app(params, getTypeDesc(m, param.typ));
if ccgIntroducedPtr(param) then begin
app(params, '*'+'');
param.loc.indirect := 1
include(param.loc.flags, lfIndirect);
param.loc.s := OnUnknown;
end;
app(params, ' '+'');
app(params, param.loc.r);
// declare the len field for open arrays:
arr := param.typ;
if arr.kind = tyVar then arr := arr.sons[0];
j := 0;
while arr.Kind = tyOpenArray do begin // need to pass hidden parameter:
appRopeFormat(params, ', const int $1Len$2', [param.loc.r, toRope(j)]);
appf(params, ', NI $1Len$2', [param.loc.r, toRope(j)]);
inc(j);
arr := arr.sons[0]
end;
@ -197,8 +203,8 @@ begin
end;
if (t.sons[0] <> nil) and isInvalidReturnType(t.sons[0]) then begin
if params <> nil then app(params, ', ');
app(params, getTypeDesc(t.sons[0]));
if not isCArray(t.sons[0]) then app(params, '*'+'');
app(params, getTypeDesc(m, t.sons[0]));
if mapType(t.sons[0]) <> ctArray then app(params, '*'+'');
app(params, ' Result');
end;
if t.callConv = ccClosure then begin
@ -216,11 +222,6 @@ begin
params := con('('+'', params);
end;
function getLengthOfSet(s: PNode): int;
begin
result := int(getSize(s.typ))
end;
function isImportedType(t: PType): bool;
begin
result := (t.sym <> nil) and (sfImportc in t.sym.flags)
@ -228,25 +229,10 @@ end;
function getTypeName(typ: PType): PRope;
begin
if typ.sym <> nil then begin
result := typ.sym.loc.r;
if result = nil then begin
assert(typ.owner <> nil);
result := toRope(mangle(typ.owner.Name.s) + '_' +{&}
mangle(typ.sym.name.s));
end
end
if (typ.sym <> nil) and ([sfImportc, sfExportc] * typ.sym.flags <> []) then
result := typ.sym.loc.r
else begin
// we must use a unique type id here because we don't store
// whether a type has to be given a certain name because its
// forward declaration has already been given:
if typ.loc.r = nil then begin
inc(currMod.unique);
assert(typ.owner <> nil);
typ.loc.r := ropeFormat('$1_Ty$2', [
toRope(mangle(typ.owner.Name.s)),
toRope(currMod.unique)])
end;
if typ.loc.r = nil then typ.loc.r := con('Ty', toRope(typ.id));
result := typ.loc.r
end
end;
@ -262,18 +248,18 @@ end;
function getSimpleTypeDesc(typ: PType): PRope;
const
NumericalTypeToStr: array [tyInt..tyFloat128] of string = (
'NS', 'NS8', 'NS16', 'NS32', 'NS64', 'NF', 'NF32', 'NF64', 'NF128');
'NI', 'NI8', 'NI16', 'NI32', 'NI64', 'NF', 'NF32', 'NF64', 'NF128');
begin
case typ.Kind of
tyPointer: result := typeNameOrLiteral(typ, 'void*');
tyEnum: begin
if firstOrd(typ) < 0 then
result := typeNameOrLiteral(typ, 'NS32')
result := typeNameOrLiteral(typ, 'NI32')
else begin
case int(getSize(typ)) of
1: result := typeNameOrLiteral(typ, 'NU8');
2: result := typeNameOrLiteral(typ, 'NU16');
4: result := typeNameOrLiteral(typ, 'NS32');
4: result := typeNameOrLiteral(typ, 'NI32');
else begin
internalError('getSimpleTypeDesc()');
result := nil
@ -293,14 +279,14 @@ begin
end
end;
function getTypePre(typ: PType): PRope;
function getTypePre(m: BModule; typ: PType): PRope;
begin
if typ = nil then
result := toRope('void')
else begin
result := getSimpleTypeDesc(typ);
if result = nil then
result := CacheGetType(currMod.typeCache, typ)
result := CacheGetType(m.typeCache, typ)
end
end;
@ -310,19 +296,18 @@ begin
else result := 'typedef struct $1 $1;$n'
end;
function getTypeForward(typ: PType): PRope;
function getTypeForward(m: BModule; typ: PType): PRope;
begin
result := CacheGetType(currMod.forwTypeCache, typ);
result := CacheGetType(m.forwTypeCache, typ);
if result <> nil then exit;
result := getTypePre(typ);
result := getTypePre(m, typ);
if result <> nil then exit;
case typ.kind of
tySequence, tyRecord, tyObject: begin
tySequence, tyTuple, tyObject: begin
result := getTypeName(typ);
if not isImportedType(typ) then
appRopeFormat(currMod.s[cfsForwardTypes],
getForwardStructFormat(), [result]);
IdTablePut(currMod.forwTypeCache, typ, result)
appf(m.s[cfsForwardTypes], getForwardStructFormat(), [result]);
IdTablePut(m.forwTypeCache, typ, result)
end
else
InternalError('getTypeForward(' + typeKindToStr[typ.kind] + ')')
@ -333,205 +318,254 @@ function mangleRecFieldName(field: PSym; rectype: PType): PRope;
begin
if (rectype.sym <> nil)
and ([sfImportc, sfExportc] * rectype.sym.flags <> []) then
result := toRope(field.name.s)
result := field.loc.r
else
result := toRope(mangle(field.name.s))
result := toRope(mangle(field.name.s));
if result = nil then InternalError(field.info, 'mangleRecFieldName');
end;
function genRecordFieldsAux(n: PNode; accessExpr: PRope; rectype: PType): PRope;
function genRecordFieldsAux(m: BModule; n: PNode; accessExpr: PRope;
rectype: PType): PRope;
var
i: int;
ae, uname, sname, a: PRope;
m: PNode;
k: PNode;
field: PSym;
begin
result := nil;
case n.kind of
nkRecList: begin
for i := 0 to sonsLen(n)-1 do begin
app(result, genRecordFieldsAux(n.sons[i], accessExpr, rectype));
app(result, genRecordFieldsAux(m, n.sons[i], accessExpr, rectype));
end
end;
nkRecCase: begin
assert(n.sons[0].kind = nkSym);
app(result, genRecordFieldsAux(n.sons[0], accessExpr, rectype));
if (n.sons[0].kind <> nkSym) then
InternalError(n.info, 'genRecordFieldsAux');
app(result, genRecordFieldsAux(m, n.sons[0], accessExpr, rectype));
uname := toRope(mangle(n.sons[0].sym.name.s)+ 'U');
if accessExpr <> nil then ae := ropeFormat('$1.$2', [accessExpr, uname])
if accessExpr <> nil then ae := ropef('$1.$2', [accessExpr, uname])
else ae := uname;
app(result, 'union {'+tnl);
for i := 1 to sonsLen(n)-1 do begin
case n.sons[i].kind of
nkOfBranch, nkElse: begin
m := lastSon(n.sons[i]);
if m.kind <> nkSym then begin
k := lastSon(n.sons[i]);
if k.kind <> nkSym then begin
sname := con('S'+'', toRope(i));
a := genRecordFieldsAux(m, ropeFormat('$1.$2', [ae, sname]),
a := genRecordFieldsAux(m, k, ropef('$1.$2', [ae, sname]),
rectype);
if a <> nil then begin
app(result, 'struct {');
app(result, a);
appRopeFormat(result, '} $1;$n', [sname]);
appf(result, '} $1;$n', [sname]);
end
end
else app(result, genRecordFieldsAux(m, ae, rectype));
else app(result, genRecordFieldsAux(m, k, ae, rectype));
end;
else internalError('genRecordFieldsAux(record case branch)');
end;
end;
appRopeFormat(result, '} $1;$n', [uname])
appf(result, '} $1;$n', [uname])
end;
nkSym: begin
field := n.sym;
assert(field.ast = nil);
sname := mangleRecFieldName(field, rectype);
if accessExpr <> nil then ae := ropeFormat('$1.$2', [accessExpr, sname])
if accessExpr <> nil then ae := ropef('$1.$2', [accessExpr, sname])
else ae := sname;
fillLoc(field.loc, locField, field.typ, ae, {@set}[]);
appRopeFormat(result, '$1 $2;$n', [getTypeDesc(field.loc.t), sname])
fillLoc(field.loc, locField, field.typ, ae, OnUnknown);
appf(result, '$1 $2;$n', [getTypeDesc(m, field.loc.t), sname])
end;
else internalError(n.info, 'genRecordFieldsAux()');
end
end;
function getRecordFields(typ: PType): PRope;
function getRecordFields(m: BModule; typ: PType): PRope;
begin
result := genRecordFieldsAux(typ.n, nil, typ);
result := genRecordFieldsAux(m, typ.n, nil, typ);
end;
function getRecordDesc(typ: PType; name: PRope): PRope;
function getRecordDesc(m: BModule; typ: PType; name: PRope): PRope;
var
desc: PRope;
hasField: bool;
begin
// declare the record:
hasField := false;
if typ.kind = tyObject then begin
useMagic('TNimType');
useMagic(m, 'TNimType');
if typ.sons[0] = nil then begin
if (typ.sym <> nil) and (sfPure in typ.sym.flags) then
result := ropeFormat('struct $1 {$n', [name])
else
result := ropeFormat('struct $1 {$nTNimType* m_type;$n', [name])
if (typ.sym <> nil) and (sfPure in typ.sym.flags)
or (tfFinal in typ.flags) then
result := ropef('struct $1 {$n', [name])
else begin
result := ropef('struct $1 {$nTNimType* m_type;$n', [name]);
hasField := true
end
end
else if gCmd = cmdCompileToCpp then begin
result := ropef('struct $1 : public $2 {$n',
[name, getTypeDesc(m, typ.sons[0])]);
hasField := true
end
else begin
result := ropef('struct $1 {$n $2 Sup;$n',
[name, getTypeDesc(m, typ.sons[0])]);
hasField := true
end
else if gCmd = cmdCompileToCpp then
result := ropeFormat('struct $1 : public $2 {$n',
[name, getTypeDesc(typ.sons[0])])
else
result := ropeFormat('struct $1 {$n $2 Sup;$n',
[name, getTypeDesc(typ.sons[0])])
end
else
result := ropeFormat('struct $1 {$n', [name]);
desc := getRecordFields(typ);
if (typ.kind <> tyObject) and (desc = nil) and (gCmd <> cmdCompileToCpp) then
result := ropef('struct $1 {$n', [name]);
desc := getRecordFields(m, typ);
if (desc = nil) and not hasField then
// no fields in struct are not valid in C, so generate a dummy:
appRopeFormat(result, 'char dummy;$n', [])
appf(result, 'char dummy;$n', [])
else
app(result, desc);
app(result, '};' + tnl);
end;
function getTypeDesc(typ: PType): PRope;
procedure pushType(m: BModule; typ: PType);
var
L: int;
begin
L := length(m.typeStack);
setLength(m.typeStack, L+1);
m.typeStack[L] := typ;
end;
function getTypeDesc(m: BModule; typ: PType): PRope;
// returns only the type's name
var
name, rettype, desc, recdesc: PRope;
n: biggestInt;
t, et: PType;
begin
if typ.sym <> nil then useHeader(typ.sym);
result := getTypePre(typ);
t := getUniqueType(typ);
if t = nil then InternalError('getTypeDesc: t == nil');
if t.sym <> nil then useHeader(m, t.sym);
result := getTypePre(m, t);
if result <> nil then exit;
case typ.Kind of
case t.Kind of
tyRef, tyPtr, tyVar, tyOpenArray: begin
case typ.sons[0].Kind of
tyRecord, tyObject, tySequence: begin
// no restriction!
// We have a forward declaration for structs
name := getTypeForward(typ.sons[0]);
et := getUniqueType(t.sons[0]);
if et.kind in [tyArrayConstr, tyArray, tyOpenArray] then
et := getUniqueType(elemType(et));
case et.Kind of
tyObject, tyTuple: begin
// no restriction! We have a forward declaration for structs
name := getTypeForward(m, et);
result := con(name, '*'+'');
IdTablePut(currMod.typeCache, typ, result)
IdTablePut(m.typeCache, t, result);
pushType(m, et);
end;
tySequence: begin
// no restriction! We have a forward declaration for structs
name := getTypeForward(m, et);
result := con(name, '**');
IdTablePut(m.typeCache, t, result);
pushType(m, et);
end;
else begin
// else we have a strong dependency :-(
result := con(getTypeDesc(typ.sons[0]), '*'+'');
IdTablePut(currMod.typeCache, typ, result)
result := con(getTypeDesc(m, et), '*'+'');
IdTablePut(m.typeCache, t, result)
end
end
end;
tyProc: begin
result := getTypeName(typ);
IdTablePut(currMod.typeCache, typ, result);
genProcParams(typ, rettype, desc);
if not isImportedType(typ) then begin
if typ.callConv <> ccClosure then
appRopeFormat(currMod.s[cfsTypes], 'typedef $1_PTR($2, $3) $4;$n',
[toRope(CallingConvToStr[typ.callConv]), rettype, result, desc])
result := getTypeName(t);
IdTablePut(m.typeCache, t, result);
genProcParams(m, t, rettype, desc);
if not isImportedType(t) then begin
if t.callConv <> ccClosure then
appf(m.s[cfsTypes], 'typedef $1_PTR($2, $3) $4;$n',
[toRope(CallingConvToStr[t.callConv]), rettype, result, desc])
else // procedure vars may need a closure!
appRopeFormat(currMod.s[cfsTypes], 'typedef struct $1 {$n' +
'N_CDECL_PTR($2, PrcPart) $3;$n' +
'void* ClPart;$n};$n',
appf(m.s[cfsTypes], 'typedef struct $1 {$n' +
'N_CDECL_PTR($2, PrcPart) $3;$n' +
'void* ClPart;$n};$n',
[result, rettype, desc]);
end
end;
tySequence: begin
// we cannot use getTypeForward here because then typ would be associated
// we cannot use getTypeForward here because then t would be associated
// with the name of the struct, not with the pointer to the struct:
result := getTypeName(typ);
IdTablePut(currMod.typeCache, typ, con(result, '*'+''));
if not isImportedType(typ) then begin
appRopeFormat(currMod.s[cfsForwardTypes],
getForwardStructFormat(), [result]);
appRopeFormat(currMod.s[cfsSeqTypes],
// BUGFIX: needed to introduce cfsSeqTypes
'struct $2 {$n' +
' NS len, space;$n' +
' $1 data[SEQ_DECL_SIZE];$n' +
'};$n', [getTypeDesc(typ.sons[0]), result]);
result := CacheGetType(m.forwTypeCache, t);
if result = nil then begin
result := getTypeName(t);
if not isImportedType(t) then
appf(m.s[cfsForwardTypes], getForwardStructFormat(), [result]);
IdTablePut(m.forwTypeCache, t, result);
end;
assert(CacheGetType(m.typeCache, t) = nil);
IdTablePut(m.typeCache, t, con(result, '*'+''));
if not isImportedType(t) then
appf(m.s[cfsSeqTypes],
'struct $2 {$n' +
' NI len, space;$n' +
' $1 data[SEQ_DECL_SIZE];$n' +
'};$n', [getTypeDesc(m, t.sons[0]), result]);
app(result, '*'+'');
end;
tyArrayConstr, tyArray: begin
n := lengthOrd(typ);
n := lengthOrd(t);
if n <= 0 then n := 1; // make an array of at least one element
result := getTypeName(typ);
IdTablePut(currMod.typeCache, typ, result);
if not isImportedType(typ) then
appRopeFormat(currMod.s[cfsTypes], 'typedef $1 $2[$3];$n',
[getTypeDesc(typ.sons[1]), result, ToRope(n)])
result := getTypeName(t);
IdTablePut(m.typeCache, t, result);
if not isImportedType(t) then
appf(m.s[cfsTypes], 'typedef $1 $2[$3];$n',
[getTypeDesc(m, t.sons[1]), result, ToRope(n)])
end;
tyObject, tyRecord, tyRecordConstr: begin
result := getTypeName(typ);
IdTablePut(currMod.typeCache, typ, result);
recdesc := getRecordDesc(typ, result); // always compute for sideeffects
if not isImportedType(typ) then
app(currMod.s[cfsTypes], recdesc);
if CacheGetType(currMod.forwTypeCache, typ) = nil then begin
if not isImportedType(typ) then
appRopeFormat(currMod.s[cfsForwardTypes],
tyObject, tyTuple: begin
result := CacheGetType(m.forwTypeCache, t);
if result = nil then begin
result := getTypeName(t);
if not isImportedType(t) then
appf(m.s[cfsForwardTypes],
getForwardStructFormat(), [result]);
IdTablePut(currMod.forwTypeCache, typ, result)
end
IdTablePut(m.forwTypeCache, t, result)
end;
IdTablePut(m.typeCache, t, result);
recdesc := getRecordDesc(m, t, result); // always call for sideeffects
if not isImportedType(t) then app(m.s[cfsTypes], recdesc);
end;
tySet: begin
case int(getSize(typ)) of
1: result := toRope('NS8');
2: result := toRope('NS16');
4: result := toRope('NS32');
8: result := toRope('NS64');
case int(getSize(t)) of
1: result := toRope('NU8');
2: result := toRope('NU16');
4: result := toRope('NU32');
8: result := toRope('NU64');
else begin
result := getTypeName(typ);
IdTablePut(currMod.typeCache, typ, result);
if not isImportedType(typ) then
appRopeFormat(currMod.s[cfsTypes], 'typedef NS8 $1[$2];$n',
[result, toRope(getSize(typ))])
result := getTypeName(t);
IdTablePut(m.typeCache, t, result);
if not isImportedType(t) then
appf(m.s[cfsTypes], 'typedef NU8 $1[$2];$n',
[result, toRope(getSize(t))])
end
end
end
end;
tyGenericInst: result := getTypeDesc(m, lastSon(t));
else begin
InternalError('getTypeDesc(' + typeKindToStr[typ.kind] + ')');
InternalError('getTypeDesc(' + typeKindToStr[t.kind] + ')');
result := nil
end
end
end;
function genProcHeader(prc: PSym): PRope;
procedure finishTypeDescriptions(m: BModule);
var
i: int;
begin
i := 0;
while i < length(m.typeStack) do begin
{@discard} getTypeDesc(m, m.typeStack[i]);
inc(i);
end;
end;
function genProcHeader(m: BModule; prc: PSym): PRope;
var
rettype, params: PRope;
begin
@ -540,9 +574,9 @@ begin
result := toRope('static ')
else
result := nil;
fillLoc(prc.loc, locProc, prc.typ, mangleName(prc), {@set}[]);
genProcParams(prc.typ, rettype, params);
appRopeFormat(result, '$1($2, $3)$4',
fillLoc(prc.loc, locProc, prc.typ, mangleName(prc), OnUnknown);
genProcParams(m, prc.typ, rettype, params);
appf(result, '$1($2, $3)$4',
[toRope(CallingConvToStr[prc.typ.callConv]),
rettype, prc.loc.r, params])
end;
@ -559,19 +593,26 @@ var
tmp: PRope;
begin
tmp := getTempName();
appRopeFormat(m.s[cfsTypeInit1], 'static TNimType $1;$n', [tmp]);
appRopeFormat(m.s[cfsTypeInit2], '$2 = &$1;$n', [tmp, name]);
appf(m.s[cfsTypeInit1], 'static TNimType $1;$n', [tmp]);
appf(m.s[cfsTypeInit2], '$2 = &$1;$n', [tmp, name]);
end;
procedure genTypeInfoAuxBase(m: BModule; typ: PType; name, base: PRope);
var
nimtypeKind: int;
begin
allocMemTI(m, name);
appRopeFormat(m.s[cfsTypeInit3],
if (typ.kind = tyObject) and (tfFinal in typ.flags)
and (typ.sons[0] = nil) then
nimtypeKind := ord(high(TTypeKind))+1 // tyPureObject
else
nimtypeKind := ord(typ.kind);
appf(m.s[cfsTypeInit3],
'$1->size = sizeof($2);$n' +
'$1->kind = $3;$n' +
'$1->base = $4;$n', [
name, getTypeDesc(typ), toRope(ord(typ.kind)), base]);
appRopeFormat(m.s[cfsVars], 'TNimType* $1;$n', [name]);
name, getTypeDesc(m, typ), toRope(nimtypeKind), base]);
appf(m.s[cfsVars], 'TNimType* $1;$n', [name]);
end;
procedure genTypeInfoAux(m: BModule; typ: PType; name: PRope);
@ -599,21 +640,21 @@ begin
genObjectFields(m, typ, n.sons[0], expr)
else if len > 0 then begin
tmp := getTempName();
appRopeFormat(m.s[cfsTypeInit1], 'static TNimNode* $1[$2];$n',
[tmp, toRope(len)]);
appf(m.s[cfsTypeInit1], 'static TNimNode* $1[$2];$n',
[tmp, toRope(len)]);
for i := 0 to len-1 do begin
tmp2 := getTempName();
appRopeFormat(m.s[cfsTypeInit1], 'static TNimNode $1;$n', [tmp2]);
appRopeFormat(m.s[cfsTypeInit3], '$1[$2] = &$3;$n',
appf(m.s[cfsTypeInit1], 'static TNimNode $1;$n', [tmp2]);
appf(m.s[cfsTypeInit3], '$1[$2] = &$3;$n',
[tmp, toRope(i), tmp2]);
genObjectFields(m, typ, n.sons[i], tmp2);
end;
appRopeFormat(m.s[cfsTypeInit3],
'$1.len = $2; $1.kind = 2; $1.sons = &$3;$n', [
appf(m.s[cfsTypeInit3],
'$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n', [
expr, toRope(len), tmp]);
end
else
appRopeFormat(m.s[cfsTypeInit3],
appf(m.s[cfsTypeInit3],
'$1.len = $2; $1.kind = 2;$n', [expr, toRope(len)]);
end;
nkRecCase: begin
@ -621,22 +662,22 @@ begin
assert(n.sons[0].kind = nkSym);
field := n.sons[0].sym;
tmp := getTempName();
appRopeFormat(m.s[cfsTypeInit3], '$1.kind = 3;$n' +
'$1.offset = offsetof($2, $3);$n' +
'$1.typ = $4;$n' +
'$1.name = $5;$n' +
'$1.sons = &$6;$n' +
'$1.len = $7;$n',
[expr, getTypeDesc(typ), field.loc.r,
appf(m.s[cfsTypeInit3], '$1.kind = 3;$n' +
'$1.offset = offsetof($2, $3);$n' +
'$1.typ = $4;$n' +
'$1.name = $5;$n' +
'$1.sons = &$6[0];$n' +
'$1.len = $7;$n',
[expr, getTypeDesc(m, typ), field.loc.r,
genTypeInfo(m, field.typ),
makeCString(field.name.s), tmp,
toRope(lengthOrd(field.typ))]);
appRopeFormat(m.s[cfsTypeInit1], 'static TNimNode* $1[$2];$n',
appf(m.s[cfsTypeInit1], 'static TNimNode* $1[$2];$n',
[tmp, toRope(lengthOrd(field.typ)+1)]);
for i := 1 to len-1 do begin
b := n.sons[i]; // branch
tmp2 := getTempName();
appRopeFormat(m.s[cfsTypeInit1], 'static TNimNode $1;$n', [tmp2]);
appf(m.s[cfsTypeInit1], 'static TNimNode $1;$n', [tmp2]);
genObjectFields(m, typ, lastSon(b), tmp2);
//writeln(output, renderTree(b.sons[j]));
case b.kind of
@ -648,18 +689,18 @@ begin
x := int(getOrdValue(b.sons[j].sons[0]));
y := int(getOrdValue(b.sons[j].sons[1]));
while x <= y do begin
appRopeFormat(m.s[cfsTypeInit3], '$1[$2] = &$3;$n',
appf(m.s[cfsTypeInit3], '$1[$2] = &$3;$n',
[tmp, toRope(x), tmp2]);
inc(x);
end;
end
else
appRopeFormat(m.s[cfsTypeInit3], '$1[$2] = &$3;$n',
appf(m.s[cfsTypeInit3], '$1[$2] = &$3;$n',
[tmp, toRope(getOrdValue(b.sons[j])), tmp2])
end
end;
nkElse: begin
appRopeFormat(m.s[cfsTypeInit3], '$1[$2] = &$3;$n',
appf(m.s[cfsTypeInit3], '$1[$2] = &$3;$n',
[tmp, toRope(lengthOrd(field.typ)), tmp2]);
end
else
@ -669,13 +710,13 @@ begin
end;
nkSym: begin
field := n.sym;
appRopeFormat(m.s[cfsTypeInit3], '$1.kind = 1;$n' +
'$1.offset = offsetof($2, $3);$n' +
'$1.typ = $4;$n' +
'$1.name = $5;$n',
[expr, getTypeDesc(typ), field.loc.r,
genTypeInfo(m, field.typ),
makeCString(field.name.s)]);
appf(m.s[cfsTypeInit3], '$1.kind = 1;$n' +
'$1.offset = offsetof($2, $3);$n' +
'$1.typ = $4;$n' +
'$1.name = $5;$n',
[expr, getTypeDesc(m, typ), field.loc.r,
genTypeInfo(m, field.typ),
makeCString(field.name.s)]);
end;
else internalError(n.info, 'genObjectFields');
end
@ -685,11 +726,12 @@ procedure genObjectInfo(m: BModule; typ: PType; name: PRope);
var
tmp: PRope;
begin
genTypeInfoAux(m, typ, name);
if typ.kind = tyObject then genTypeInfoAux(m, typ, name)
else genTypeInfoAuxBase(m, typ, name, toRope('0'+''));
tmp := getTempName();
appRopeFormat(m.s[cfsTypeInit1], 'static TNimNode $1;$n', [tmp]);
appf(m.s[cfsTypeInit1], 'static TNimNode $1;$n', [tmp]);
genObjectFields(m, typ, typ.n, tmp);
appRopeFormat(m.s[cfsTypeInit3], '$1->node = &$2;$n', [name, tmp]);
appf(m.s[cfsTypeInit3], '$1->node = &$2;$n', [name, tmp]);
end;
procedure genEnumInfo(m: BModule; typ: PType; name: PRope);
@ -702,25 +744,25 @@ begin
tmp := getTempName();
tmp2 := getTempName();
len := sonsLen(typ.n);
appRopeFormat(m.s[cfsTypeInit1], 'static TNimNode* $1[$2];$n' +
'static TNimNode $3;$n',
[tmp, toRope(len), tmp2]);
appf(m.s[cfsTypeInit1], 'static TNimNode* $1[$2];$n' +
'static TNimNode $3;$n',
[tmp, toRope(len), tmp2]);
for i := 0 to len-1 do begin
assert(typ.n.sons[i].kind = nkSym);
field := typ.n.sons[i].sym;
tmp3 := getTempName();
appRopeFormat(m.s[cfsTypeInit1], 'static TNimNode $1;$n', [tmp3]);
appRopeFormat(m.s[cfsTypeInit3], '$1[$2] = &$3;$n' +
'$3.kind = 1;$n' +
'$3.offset = $4;$n' +
'$3.typ = $5;$n' +
'$3.name = $6;$n',
appf(m.s[cfsTypeInit1], 'static TNimNode $1;$n', [tmp3]);
appf(m.s[cfsTypeInit3], '$1[$2] = &$3;$n' +
'$3.kind = 1;$n' +
'$3.offset = $4;$n' +
'$3.typ = $5;$n' +
'$3.name = $6;$n',
[tmp, toRope(i), tmp3,
toRope(field.position),
name, makeCString(field.name.s)]);
end;
appRopeFormat(m.s[cfsTypeInit3],
'$1.len = $2; $1.kind = 2; $1.sons = &$3;$n$4->node = &$1;$n', [
appf(m.s[cfsTypeInit3],
'$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n$4->node = &$1;$n', [
tmp2, toRope(len), tmp, name]);
end;
@ -731,8 +773,8 @@ begin
assert(typ.sons[0] <> nil);
genTypeInfoAux(m, typ, name);
tmp := getTempName();
appRopeFormat(m.s[cfsTypeInit1], 'static TNimNode $1;$n', [tmp]);
appRopeFormat(m.s[cfsTypeInit3],
appf(m.s[cfsTypeInit1], 'static TNimNode $1;$n', [tmp]);
appf(m.s[cfsTypeInit3],
'$1.len = $2; $1.kind = 0;$n' +
'$3->node = &$1;$n', [tmp, toRope(firstOrd(typ)), name]);
end;
@ -746,14 +788,13 @@ function genTypeInfo(m: BModule; typ: PType): PRope;
var
t: PType;
begin
t := typ;
if t.kind = tyGenericInst then t := lastSon(t);
result := ropeFormat('NTI$1', [toRope(t.id)]);
t := getUniqueType(typ);
result := ropef('NTI$1', [toRope(t.id)]);
if not IntSetContainsOrIncl(m.typeInfoMarker, t.id) then begin
// declare type information structures:
useMagic('TNimType');
useMagic('TNimNode');
appRopeFormat(m.s[cfsVars], 'extern TNimType* $1;$n', [result]);
useMagic(m, 'TNimType');
useMagic(m, 'TNimNode');
appf(m.s[cfsVars], 'extern TNimType* $1;$n', [result]);
end;
if IntSetContainsOrIncl(gTypeInfoGenerated, t.id) then exit;
case t.kind of
@ -763,7 +804,7 @@ begin
tyArrayConstr, tyArray: genArrayInfo(m, t, result);
tySet: genSetInfo(m, t, result);
tyEnum: genEnumInfo(m, t, result);
tyObject, tyRecord, tyRecordConstr: genObjectInfo(m, t, result);
tyObject, tyTuple: genObjectInfo(m, t, result);
tyVar: result := genTypeInfo(m, typ.sons[0]);
else InternalError('genTypeInfo(' + typekindToStr[t.kind] + ')');
end

View file

@ -17,15 +17,41 @@ interface
uses
charsets, nsystem,
ast, astalgo, ropes, lists, hashes, strutils, types;
ast, astalgo, ropes, lists, hashes, strutils, types, msgs;
function toCChar(c: Char): string;
function makeCString(const s: string): PRope;
function TableGetType(const tab: TIdTable; key: PType): PObject;
function GetUniqueType(key: PType): PType;
implementation
var
gTypeTable: TIdTable;
function GetUniqueType(key: PType): PType;
var
t: PType;
h: THash;
begin
result := key;
if key = nil then exit;
assert(key.kind <> tyForward);
if key.kind = tyGenericInst then begin
result := GetUniqueType(lastSon(key));
exit
end;
if IdTableHasObjectAsKey(gTypeTable, key) then exit;
// we have to do a slow linear search because types may need
// to be compared by their structure:
for h := 0 to high(gTypeTable.data) do begin
t := PType(gTypeTable.data[h].key);
if (t <> nil) and sameType(t, key) then begin result := t; exit end
end;
IdTablePut(gTypeTable, key, key);
end;
function TableGetType(const tab: TIdTable; key: PType): PObject;
var
t: PType;
@ -69,7 +95,7 @@ begin
result := nil;
res := '"'+'';
for i := strStart to length(s)+strStart-1 do begin
if i mod MaxLineLength = 0 then begin
if (i-strStart+1) mod MaxLineLength = 0 then begin
res := res +{&} '"' +{&} nl;
app(result, toRope(res));
res := '"'+''; // reset
@ -80,4 +106,6 @@ begin
app(result, toRope(res));
end;
initialization
InitIdTable(gTypeTable);
end.

View file

@ -43,13 +43,28 @@ type
cfsProcHeaders, // section for C procs prototypes
cfsProcs, // section for C procs that are not inline
cfsTypeInit1, // section 1 for declarations of type information
cfsTypeInit2, // section A for initialization of type information
cfsTypeInit3, // section B for init of type information
cfsTypeInit2, // section 2 for initialization of type information
cfsTypeInit3, // section 3 for init of type information
cfsDebugInit, // section for initialization of debug information
cfsDynLibInit, // section for initialization of dynamic library binding
cfsDynLibDeinit // section for deinitialization of dynamic libraries
);
TCTypeKind = ( // describes the type kind of a C type
ctVoid,
ctChar,
ctBool,
ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64,
ctInt, ctInt8, ctInt16, ctInt32, ctInt64,
ctFloat, ctFloat32, ctFloat64, ctFloat128,
ctArray,
ctStruct,
ctPtr,
ctNimStr,
ctNimSeq,
ctProc,
ctCString
);
TCFileSections = array [TCFileSection] of PRope;
// TCFileSections represents a generated C file
@ -66,15 +81,20 @@ type
BModule = ^TCGen;
BProc = ^TCProc;
TBlock = record
id: int; // the ID of the label; positive means that it
// has been used (i.e. the label should be emitted)
nestedTryStmts: int; // how many try statements is it nested into
end;
TCProc = record // represents C proc that is currently generated
s: TCProcSections; // the procs sections; short name for readability
prc: PSym; // the Nimrod proc that this C proc belongs to
BeforeRetNeeded: bool; // true iff 'BeforeRet' label for proc is needed
inTryStmt: Natural; // wether we are in a try statement
nestedTryStmts: Natural; // in how many nested try statements we are
// (the vars must be volatile then)
unique: Natural; // for generating unique names in the C proc
blocks: array of int; // the ID of the label; positive means that it
// has been used (i.e. the label should be emitted)
labels: Natural; // for generating unique labels in the C proc
blocks: array of TBlock; // nested blocks
locals: array of TLoc; // locNone means slot is free again
options: TOptions; // options that should be used for code
// generation; this is the same as prc.options
@ -82,8 +102,9 @@ type
frameLen: int; // current length of frame descriptor
sendClosure: PType; // closure record type that we pass
receiveClosure: PType; // closure record type that we get
module: BModule; // used to prevent excessive parameter passing
end;
TTypeSeq = array of PType;
TCGen = object(TBackend) // represents a C source file
s: TCFileSections; // sections of the C file
cfilename: string; // filename of the module (including path,
@ -93,55 +114,48 @@ type
declaredThings: TIntSet; // things we have declared in this .c file
debugDeclared: TIntSet; // for debugging purposes
headerFiles: TLinkedList; // needed headers to include
unique: Natural; // for generating unique names
//unique: Natural; // for generating unique names
typeInfoMarker: TIntSet; // needed for generating type information
initProc: BProc; // code for init procedure
typeStack: TTypeSeq; // used for type generation
end;
var
currMod: BModule; // currently compiled module
// a global so that this needs not to be
// passed to every proc
gUnique: Natural;
mainModProcs, mainModInit: PRope; // parts of the main module
gMapping: PRope; // the generated mapping file (if requested)
constTok: PRope; // either 'const ' or nil depending on gCmd
function initLoc(k: TLocKind; typ: PType): TLoc;
function initLoc(k: TLocKind; typ: PType; s: TStorageLoc): TLoc;
begin
result.k := k;
result.t := typ;
result.s := s;
result.t := GetUniqueType(typ);
result.r := nil;
result.a := -1;
result.indirect := 0;
result.flags := {@set}[]
end;
procedure fillLoc(var a: TLoc; k: TLocKind; typ: PType; r: PRope;
flags: TLocFlags);
s: TStorageLoc);
begin
// fills the loc if it is not already initialized
if a.k = locNone then begin
a.k := k;
if typ.kind = tyGenericInst then a.t := lastSon(typ) else a.t := typ;
a.t := getUniqueType(typ);
a.a := -1;
a.s := s;
if a.r = nil then a.r := r;
a.flags := a.flags + flags
end
end;
procedure inheritStorage(var dest: TLoc; const src: TLoc);
begin
dest.flags := src.flags * [lfOnStack, lfOnHeap, lfOnData, lfOnUnknown]
end;
function newProc(prc: PSym): BProc;
function newProc(prc: PSym; module: BModule): BProc;
begin
new(result);
{@ignore}
fillChar(result^, sizeof(result^), 0);
{@emit}
result.prc := prc;
result.module := module;
if prc <> nil then
result.options := prc.options
else
@ -157,20 +171,19 @@ end;
function isSimpleConst(typ: PType): bool;
begin
result := not (skipAbstract(typ).kind in [tyRecord, tyRecordConstr,
tyObject, tyArray,
result := not (skipVarGeneric(typ).kind in [tyTuple, tyObject, tyArray,
tyArrayConstr, tySet, tySequence])
end;
procedure useHeader(sym: PSym);
procedure useHeader(m: BModule; sym: PSym);
begin
if lfHeader in sym.loc.Flags then begin
assert(sym.annex <> nil);
{@discard} lists.IncludeStr(currMod.headerFiles, PLib(sym.annex).path)
{@discard} lists.IncludeStr(m.headerFiles, PLib(sym.annex).path)
end
end;
procedure UseMagic(const name: string); forward;
procedure UseMagic(m: BModule; const name: string); forward;
// ----------------------------- name mangling
// +++++++++++++++++++++++++++++ type generation
@ -182,14 +195,14 @@ procedure UseMagic(const name: string); forward;
function beEqualTypes(a, b: PType): bool;
begin
// returns whether two type are equal for the backend
result := sameType(skipAbstract(a), skipAbstract(b))
result := sameType(skipGenericRange(a), skipGenericRange(b))
end;
function getTemp(p: BProc; t: PType): TLoc;
var
i, index: int;
name: PRope;
begin
begin (*
for i := 0 to high(p.locals) do begin
assert(i = p.locals[i].a);
if (p.locals[i].k = locNone) and beEqualTypes(p.locals[i].t, t) then begin
@ -198,41 +211,41 @@ begin
result := p.locals[i];
exit
end
end;
end; *)
// not found:
index := length(p.locals);
setLength(p.locals, index+1);
// declare the new temporary:
name := con('Loc', toRope(index));
appRopeFormat(p.s[cpsLocals], '$1 $2; /* temporary */$n',
[getTypeDesc(t), name]);
appf(p.s[cpsLocals], '$1 $2; /* temporary */$n',
[getTypeDesc(p.module, t), name]);
p.locals[index].k := locTemp;
p.locals[index].a := index;
p.locals[index].r := name;
p.locals[index].t := t;
p.locals[index].flags := {@set}[lfOnStack];
p.locals[index].t := getUniqueType(t);
p.locals[index].s := OnStack;
p.locals[index].flags := {@set}[];
result := p.locals[index] // BUGFIX!
end;
procedure freeTemp(p: BProc; const temp: TLoc);
begin
begin (*
if (temp.a >= 0) and (temp.a < length(p.locals)) and
(p.locals[temp.a].k = locTemp) then
p.locals[temp.a].k := locNone
p.locals[temp.a].k := locNone *)
end;
// -------------------------- Variable manager ----------------------------
procedure declareGlobalVar(s: PSym);
procedure declareGlobalVar(m: BModule; s: PSym);
begin
if not IntSetContainsOrIncl(currMod.declaredThings, s.id) then begin
app(currMod.s[cfsVars], getTypeDesc(s.loc.t));
if not IntSetContainsOrIncl(m.declaredThings, s.id) then begin
app(m.s[cfsVars], getTypeDesc(m, s.loc.t));
if sfRegister in s.flags then
app(currMod.s[cfsVars], ' register');
app(m.s[cfsVars], ' register');
if sfVolatile in s.flags then
app(currMod.s[cfsVars], ' volatile');
appRopeFormat(currMod.s[cfsVars], ' $1; /* $2 */$n',
[s.loc.r, toRope(s.name.s)])
app(m.s[cfsVars], ' volatile');
appf(m.s[cfsVars], ' $1;$n', [s.loc.r])
end
end;
@ -241,39 +254,38 @@ begin
//assert(s.loc.k == locNone) // not yet assigned
// this need not be fullfilled for inline procs; they are regenerated
// for each module that uses them!
fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), {@set}[lfOnStack]);
app(p.s[cpsLocals], getTypeDesc(s.loc.t));
fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack);
app(p.s[cpsLocals], getTypeDesc(p.module, s.loc.t));
if sfRegister in s.flags then
app(p.s[cpsLocals], ' register');
if (sfVolatile in s.flags) or (p.inTryStmt > 0) then
if (sfVolatile in s.flags) or (p.nestedTryStmts > 0) then
app(p.s[cpsLocals], ' volatile');
appRopeFormat(p.s[cpsLocals], ' $1; /* $2 */$n',
[s.loc.r, toRope(s.name.s)]);
appf(p.s[cpsLocals], ' $1;$n', [s.loc.r]);
// if debugging we need a new slot for the local variable:
if [optStackTrace, optEndb] * p.Options = [optStackTrace, optEndb] then begin
appRopeFormat(p.s[cpsInit],
appf(p.s[cpsInit],
'F.s[$1].name = $2; F.s[$1].address = (void*)&$3; F.s[$1].typ = $4;$n',
[toRope(p.frameLen), makeCString(normalize(s.name.s)), s.loc.r,
genTypeInfo(currMod, s.loc.t)]);
genTypeInfo(p.module, s.loc.t)]);
inc(p.frameLen);
end
end;
procedure assignGlobalVar(s: PSym);
procedure assignGlobalVar(m: BModule; s: PSym);
begin
fillLoc(s.loc, locGlobalVar, s.typ, mangleName(s), {@set}[lfOnData]);
useHeader(s);
fillLoc(s.loc, locGlobalVar, s.typ, mangleName(s), OnHeap);
useHeader(m, s);
if lfNoDecl in s.loc.flags then exit;
if sfImportc in s.flags then app(currMod.s[cfsVars], 'extern ');
declareGlobalVar(s);
if [optStackTrace, optEndb] * currMod.module.options =
if sfImportc in s.flags then app(m.s[cfsVars], 'extern ');
declareGlobalVar(m, s);
if [optStackTrace, optEndb] * m.module.options =
[optStackTrace, optEndb] then begin
useMagic('dbgRegisterGlobal');
appRopeFormat(currMod.s[cfsDebugInit],
useMagic(m, 'dbgRegisterGlobal');
appf(m.s[cfsDebugInit],
'dbgRegisterGlobal($1, &$2, $3);$n',
[makeCString(normalize(s.owner.name.s + '.' +{&} s.name.s)), s.loc.r,
genTypeInfo(currMod, s.typ)])
genTypeInfo(m, s.typ)])
end;
end;
@ -286,12 +298,12 @@ procedure assignParam(p: BProc; s: PSym);
begin
assert(s.loc.r <> nil);
if [optStackTrace, optEndb] * p.options = [optStackTrace, optEndb] then begin
appRopeFormat(p.s[cpsInit],
appf(p.s[cpsInit],
'F.s[$1].name = $2; F.s[$1].address = (void*)$3; ' +
'F.s[$1].typ = $4;$n',
[toRope(p.frameLen), makeCString(normalize(s.name.s)),
iff(usePtrPassing(s), s.loc.r, con('&'+'', s.loc.r)),
genTypeInfo(currMod, s.loc.t)]);
iff(ccgIntroducedPtr(s), s.loc.r, con('&'+'', s.loc.r)),
genTypeInfo(p.module, s.loc.t)]);
inc(p.frameLen)
end
end;
@ -301,19 +313,19 @@ end;
// note that a label is a location too
function getLabel(p: BProc): TLabel;
begin
inc(p.unique);
result := con('L'+'', toRope(p.unique))
inc(p.labels);
result := con('L'+'', toRope(p.labels))
end;
procedure fixLabel(p: BProc; labl: TLabel);
begin
appRopeFormat(p.s[cpsStmts], '$1: ;$n', [labl])
appf(p.s[cpsStmts], '$1: ;$n', [labl])
end;
procedure genProcPrototype(sym: PSym); forward;
procedure genVarPrototype(sym: PSym); forward;
procedure genConstPrototype(sym: PSym); forward;
procedure genProc(prc: PSym); forward;
procedure genProcPrototype(m: BModule; sym: PSym); forward;
procedure genVarPrototype(m: BModule; sym: PSym); forward;
procedure genConstPrototype(m: BModule; sym: PSym); forward;
procedure genProc(m: BModule; prc: PSym); forward;
procedure genStmts(p: BProc; t: PNode); forward;
{$include 'ccgexprs.pas'}
@ -323,76 +335,76 @@ procedure genStmts(p: BProc; t: PNode); forward;
// We don't finalize dynamic libs as this does the OS for us.
procedure loadDynamicLib(lib: PLib);
procedure loadDynamicLib(m: BModule; lib: PLib);
var
tmp: PRope;
begin
assert(lib <> nil);
if lib.kind = libDynamic then begin
lib.kind := libDynamicGenerated;
useMagic('nimLoadLibrary');
useMagic('nimUnloadLibrary');
useMagic(m, 'nimLoadLibrary');
useMagic(m, 'nimUnloadLibrary');
tmp := getTempName();
appRopeFormat(currMod.s[cfsVars], 'static void* $1;$n', [tmp]);
appRopeFormat(currMod.s[cfsDynLibInit],
appf(m.s[cfsVars], 'static void* $1;$n', [tmp]);
appf(m.s[cfsDynLibInit],
'$1 = nimLoadLibrary((string) &$2);$n',
[tmp, getStrLit(lib.path)]);
appRopeFormat(currMod.s[cfsDynLibDeinit],
[tmp, getStrLit(m, lib.path)]);
appf(m.s[cfsDynLibDeinit],
'if ($1 != NIM_NIL) nimUnloadLibrary($1);$n', [tmp]);
assert(lib.name = nil);
lib.name := tmp
end
end;
procedure SymInDynamicLib(sym: PSym);
procedure SymInDynamicLib(m: BModule; sym: PSym);
var
lib: PLib;
extname, tmp: PRope;
begin
lib := PLib(sym.annex);
extname := sym.loc.r;
loadDynamicLib(lib);
useMagic('nimGetProcAddr');
tmp := ropeFormat('Dl_$1', [toRope(sym.id)]);
loadDynamicLib(m, lib);
useMagic(m, 'nimGetProcAddr');
tmp := ropef('Dl_$1', [toRope(sym.id)]);
sym.loc.r := tmp; // from now on we only need the internal name
sym.typ.sym := nil; // generate a new name
appRopeFormat(currMod.s[cfsDynLibInit],
appf(m.s[cfsDynLibInit],
'$1 = ($2) nimGetProcAddr($3, $4);$n',
[tmp, getTypeDesc(sym.typ), lib.name,
[tmp, getTypeDesc(m, sym.typ), lib.name,
makeCString(ropeToStr(extname))]);
declareGlobalVar(sym)
declareGlobalVar(m, sym)
end;
// ----------------------------- sections ---------------------------------
procedure UseMagic(const name: string);
procedure UseMagic(m: BModule; const name: string);
var
sym: PSym;
begin
if (sfSystemModule in currMod.module.flags) then exit;
if (sfSystemModule in m.module.flags) then exit;
// we don't know the magic symbols in the system module, but they will be
// there anyway, because that is the way the code generator works
sym := magicsys.getCompilerProc(name);
case sym.kind of
skProc: genProcPrototype(sym);
skVar: genVarPrototype(sym);
skType: {@discard} getTypeDesc(sym.typ);
skProc, skConverter: genProcPrototype(m, sym);
skVar: genVarPrototype(m, sym);
skType: {@discard} getTypeDesc(m, sym.typ);
else InternalError('useMagic: ' + name)
end
end;
procedure generateHeaders();
procedure generateHeaders(m: BModule);
var
it: PStrEntry;
begin
app(currMod.s[cfsHeaders], '#include "nimbase.h"' +{&} tnl +{&} tnl);
it := PStrEntry(currMod.headerFiles.head);
app(m.s[cfsHeaders], '#include "nimbase.h"' +{&} tnl +{&} tnl);
it := PStrEntry(m.headerFiles.head);
while it <> nil do begin
if not (it.data[strStart] in ['"', '<']) then
appRopeFormat(currMod.s[cfsHeaders],
appf(m.s[cfsHeaders],
'#include "$1"$n', [toRope(it.data)])
else
appRopeFormat(currMod.s[cfsHeaders], '#include $1$n', [toRope(it.data)]);
appf(m.s[cfsHeaders], '#include $1$n', [toRope(it.data)]);
it := PStrEntry(it.Next)
end
end;
@ -402,15 +414,15 @@ var
slots: PRope;
begin
if p.frameLen > 0 then begin
useMagic('TVarSlot');
slots := ropeFormat(' TVarSlot s[$1];$n', [toRope(p.frameLen)])
useMagic(p.module, 'TVarSlot');
slots := ropef(' TVarSlot s[$1];$n', [toRope(p.frameLen)])
end
else
slots := nil;
appRopeFormat(p.s[cpsLocals], 'volatile struct {TFrame* prev;' +
'NCSTRING procname;NS line;NCSTRING filename;' +
'NS len;$n$1} F;$n', [slots]);
prepend(p.s[cpsInit], ropeFormat('F.len = $1;$n', [toRope(p.frameLen)]))
appf(p.s[cpsLocals], 'volatile struct {TFrame* prev;' +
'NCSTRING procname;NI line;NCSTRING filename;' +
'NI len;$n$1} F;$n', [slots]);
prepend(p.s[cpsInit], ropef('F.len = $1;$n', [toRope(p.frameLen)]))
end;
function retIsNotVoid(s: PSym): bool;
@ -418,27 +430,27 @@ begin
result := (s.typ.sons[0] <> nil) and not isInvalidReturnType(s.typ.sons[0])
end;
procedure genProc(prc: PSym);
procedure genProc(m: BModule; prc: PSym);
var
p: BProc;
generatedProc, header, returnStmt: PRope;
i: int;
res, param: PSym;
begin
useHeader(prc);
fillLoc(prc.loc, locProc, prc.typ, mangleName(prc), {@set}[lfOnData]);
useHeader(m, prc);
fillLoc(prc.loc, locProc, prc.typ, mangleName(prc), OnStack);
if (lfNoDecl in prc.loc.Flags) then exit;
if lfDynamicLib in prc.loc.flags then
SymInDynamicLib(prc)
SymInDynamicLib(m, prc)
else if not (sfImportc in prc.flags) then begin
// we have a real proc here:
p := newProc(prc);
header := genProcHeader(prc);
p := newProc(prc, m);
header := genProcHeader(m, prc);
if (sfCompilerProc in prc.flags)
and (sfSystemModule in currMod.module.flags)
and not IntSetContains(currMod.declaredThings, prc.id) then
appRopeFormat(currMod.s[cfsProcHeaders], '$1;$n', [header]);
intSetIncl(currMod.declaredThings, prc.id);
and (sfSystemModule in m.module.flags)
and not IntSetContains(m.declaredThings, prc.id) then
appf(m.s[cfsProcHeaders], '$1;$n', [header]);
intSetIncl(m.declaredThings, prc.id);
returnStmt := nil;
assert(prc.ast <> nil);
@ -450,7 +462,7 @@ begin
assert(res.loc.r <> nil);
initVariable(p, res);
genObjectInit(p, res);
returnStmt := ropeFormat('return $1;$n', [rdLoc(res.loc)]);
returnStmt := ropef('return $1;$n', [rdLoc(res.loc)]);
end
else if (prc.typ.sons[0] <> nil) then begin
res := prc.ast.sons[resultPos].sym; // get result symbol
@ -465,13 +477,13 @@ begin
genStmts(p, prc.ast.sons[codePos]); // modifies p.locals, p.init, etc.
if sfPure in prc.flags then
generatedProc := ropeFormat('$1 {$n$2$3$4}$n',
generatedProc := ropef('$1 {$n$2$3$4}$n',
[header, p.s[cpsLocals], p.s[cpsInit], p.s[cpsStmts]])
else begin
generatedProc := con(header, '{' + tnl);
if optStackTrace in prc.options then begin
getFrameDecl(p);
prepend(p.s[cpsInit], ropeFormat(
prepend(p.s[cpsInit], ropef(
'F.procname = $1;$n' +
'F.prev = framePtr;$n' +
'F.filename = $2;$n' +
@ -491,86 +503,93 @@ begin
//if prc.typ.callConv <> ccInline then
// prc.ast.sons[codePos] := nil;
end;
app(currMod.s[cfsProcs], generatedProc);
app(m.s[cfsProcs], generatedProc);
end
end;
procedure genVarPrototype(sym: PSym);
procedure genVarPrototype(m: BModule; sym: PSym);
begin
assert(sfGlobal in sym.flags);
useHeader(sym);
fillLoc(sym.loc, locGlobalVar, sym.typ, mangleName(sym), {@set}[lfOnData]);
useHeader(m, sym);
fillLoc(sym.loc, locGlobalVar, sym.typ, mangleName(sym), OnHeap);
if (lfNoDecl in sym.loc.Flags) or
intSetContainsOrIncl(currMod.declaredThings, sym.id) then
intSetContainsOrIncl(m.declaredThings, sym.id) then
exit;
if sym.owner.id <> currMod.module.id then begin
if sym.owner.id <> m.module.id then begin
// else we already have the symbol generated!
assert(sym.loc.r <> nil);
app(currMod.s[cfsVars], 'extern ');
app(currMod.s[cfsVars], getTypeDesc(sym.loc.t));
app(m.s[cfsVars], 'extern ');
app(m.s[cfsVars], getTypeDesc(m, sym.loc.t));
if sfRegister in sym.flags then
app(currMod.s[cfsVars], ' register');
app(m.s[cfsVars], ' register');
if sfVolatile in sym.flags then
app(currMod.s[cfsVars], ' volatile');
appRopeFormat(currMod.s[cfsVars], ' $1; /* $2 */$n',
[sym.loc.r, toRope(sym.name.s)])
app(m.s[cfsVars], ' volatile');
appf(m.s[cfsVars], ' $1;$n', [sym.loc.r])
end
end;
procedure genConstPrototype(sym: PSym);
procedure genConstPrototype(m: BModule; sym: PSym);
begin
useHeader(sym);
fillLoc(sym.loc, locData, sym.typ, mangleName(sym), {@set}[lfOnData]);
useHeader(m, sym);
fillLoc(sym.loc, locData, sym.typ, mangleName(sym), OnUnknown);
if (lfNoDecl in sym.loc.Flags) or
intSetContainsOrIncl(currMod.declaredThings, sym.id) then
intSetContainsOrIncl(m.declaredThings, sym.id) then
exit;
if sym.owner.id <> currMod.module.id then begin
if sym.owner.id <> m.module.id then begin
// else we already have the symbol generated!
assert(sym.loc.r <> nil);
app(currMod.s[cfsData], 'extern ');
appRopeFormat(currMod.s[cfsData], '$1$2 $3; /* $4 */$n',
[constTok, getTypeDesc(sym.loc.t), sym.loc.r, toRope(sym.name.s)])
app(m.s[cfsData], 'extern ');
appf(m.s[cfsData], 'NIM_CONST $1 $2;$n',
[getTypeDesc(m, sym.loc.t), sym.loc.r])
end
end;
procedure genProcPrototype(sym: PSym);
procedure genProcPrototype(m: BModule; sym: PSym);
begin
useHeader(sym);
fillLoc(sym.loc, locProc, sym.typ, mangleName(sym), {@set}[lfOnData]);
useHeader(m, sym);
fillLoc(sym.loc, locProc, sym.typ, mangleName(sym), OnStack);
if lfDynamicLib in sym.loc.Flags then begin
// it is a proc variable!
if (sym.owner.id <> currMod.module.id) and
not intSetContainsOrIncl(currMod.declaredThings, sym.id) then begin
app(currMod.s[cfsVars], 'extern ');
if (sym.owner.id <> m.module.id) and
not intSetContainsOrIncl(m.declaredThings, sym.id) then begin
app(m.s[cfsVars], 'extern ');
// BUGFIX: declareGlobalVar() inlined, because of intSetContainsOrIncl
// check
app(currMod.s[cfsVars], getTypeDesc(sym.loc.t));
appRopeFormat(currMod.s[cfsVars], ' $1; /* $2 */$n',
[sym.loc.r, toRope(sym.name.s)])
app(m.s[cfsVars], getTypeDesc(m, sym.loc.t));
appf(m.s[cfsVars], ' $1;$n', [sym.loc.r])
end
end
else begin
// it is a proc:
if (lfNoDecl in sym.loc.Flags) then exit;
if intSetContainsOrIncl(currMod.declaredThings, sym.id) then exit;
appRopeFormat(currMod.s[cfsProcHeaders], '$1;$n', [genProcHeader(sym)]);
if intSetContainsOrIncl(m.declaredThings, sym.id) then exit;
appf(m.s[cfsProcHeaders], '$1;$n', [genProcHeader(m, sym)]);
if (sym.typ.callConv = ccInline)
and (sym.owner.id <> currMod.module.id) then
genProc(sym) // generate the code again!
// else
// IntSetIncl(currMod.declaredThings, sym.id)
and (sym.owner.id <> m.module.id) then
genProc(m, sym) // generate the code again!
end
end;
function getFileHeader: PRope;
function getFileHeader(const cfilenoext: string): PRope;
begin
result := ropeFormat(
result := ropef(
'/* Generated by the Nimrod Compiler v$1 */$n' +
'/* (c) 2008 Andreas Rumpf */$n' +
'/* Compiled for: $2, $3, $4 */$n',
'/* Compiled for: $2, $3, $4 */$n' +
'/* Command for C compiler:$n $5 */$n',
[toRope(versionAsString), toRope(platform.OS[targetOS].name),
toRope(platform.CPU[targetCPU].name),
toRope(extccomp.CC[extccomp.ccompiler].name)])
toRope(extccomp.CC[extccomp.ccompiler].name),
toRope(getCompileCFileCmd(cfilenoext))]);
case platform.CPU[targetCPU].intSize of
16: appf(result, '$ntypedef short int NI;$n' +
'typedef unsigned short int NU;$n', []);
32: appf(result, '$ntypedef long int NI;$n' +
'typedef unsigned long int NU;$n', []);
64: appf(result, '$ntypedef long long int NI;$n' +
'typedef unsigned long long int NU;$n', []);
else begin end
end
end;
procedure genMainProc(m: BModule);
@ -581,13 +600,13 @@ const
'$1' +
'$2';
PosixMain =
'NS cmdCount;$n' +
'NI cmdCount;$n' +
'char** cmdLine;$n' +
'char** gEnv;$n' +
'int main(int argc, char** args, char** env) {$n' +
' int dummy[8];$n' +
' cmdLine = args;$n' +
' cmdCount = (NS)argc;$n' +
' cmdCount = (NI)argc;$n' +
' gEnv = env;$n' +{&}
CommonMainBody +{&}
' return 0;$n' +
@ -610,7 +629,7 @@ const
var
frmt: TFormatStr;
begin
useMagic('setStackBottom');
useMagic(m, 'setStackBottom');
if (platform.targetOS = osWindows) and
(gGlobalOptions * [optGenGuiApp, optGenDynLib] <> []) then begin
if optGenGuiApp in gGlobalOptions then
@ -622,8 +641,8 @@ begin
else
frmt := PosixMain;
if gBreakpoints <> nil then
useMagic('dbgRegisterBreakpoint');
appRopeFormat(m.s[cfsProcs], frmt, [gBreakpoints, mainModInit])
useMagic(m, 'dbgRegisterBreakpoint');
appf(m.s[cfsProcs], frmt, [gBreakpoints, mainModInit])
end;
procedure genInitCode(m: BModule);
@ -631,16 +650,16 @@ var
initname, prc: PRope;
begin
initname := con(m.module.name.s, toRope('Init'));
appRopeFormat(mainModProcs, 'N_NIMCALL(void, $1)(void);$n',
appf(mainModProcs, 'N_NIMCALL(void, $1)(void);$n',
[initname]);
if not (sfSystemModule in m.module.flags) then
appRopeFormat(mainModInit, '$1();$n', [initname]);
prc := ropeFormat('N_NIMCALL(void, $1)(void) {$n', [initname]);
appf(mainModInit, '$1();$n', [initname]);
prc := ropef('N_NIMCALL(void, $1)(void) {$n', [initname]);
if optStackTrace in m.initProc.options then begin
prepend(m.initProc.s[cpsLocals], toRope('volatile TFrame F;' + tnl));
app(prc, m.initProc.s[cpsLocals]);
app(prc, m.s[cfsTypeInit1]);
appRopeFormat(prc,
appf(prc,
'F.len = 0;$n' + // IMPORTANT: else the debugger crashes!
'F.procname = $1;$n' +
'F.prev = framePtr;$n' +
@ -666,12 +685,12 @@ begin
app(m.s[cfsProcs], prc)
end;
function genModule(m: BModule): PRope;
function genModule(m: BModule; const cfilenoext: string): PRope;
var
i: TCFileSection;
begin
result := getFileHeader();
generateHeaders();
result := getFileHeader(cfilenoext);
generateHeaders(m);
for i := low(TCFileSection) to cfsProcs do app(result, m.s[i])
end;
@ -688,11 +707,10 @@ begin
initIdTable(result.typeCache);
initIdTable(result.forwTypeCache);
result.module := module;
if gCmd <> cmdCompileToCpp then
constTok := toRope('const ');
intSetInit(result.typeInfoMarker);
result.initProc := newProc(nil);
result.initProc := newProc(nil, result);
result.initProc.options := gOptions;
{@emit result.typeStack := [];}
end;
function shouldRecompile(code: PRope; const cfile, cfilenoext: string): bool;
@ -717,28 +735,27 @@ var
code: PRope;
begin
m := BModule(b);
currMod := m;
currMod.initProc.options := gOptions;
genStmts(currMod.initProc, n);
m.initProc.options := gOptions;
genStmts(m.initProc, n);
// generate code for the init statements of the module:
genInitCode(m);
finishTypeDescriptions(m);
if sfMainModule in m.module.flags then begin
// generate mapping file (if requested):
if gMapping <> nil then
WriteRope(gMapping, ChangeFileExt(cfile + '_map', 'txt'));
// generate main file:
app(currMod.s[cfsProcHeaders], mainModProcs);
genMainProc(currMod);
app(m.s[cfsProcHeaders], mainModProcs);
genMainProc(m);
end;
cfile := completeCFilePath(m.cfilename);
cfilenoext := changeFileExt(cfile, '');
code := genModule(m);
code := genModule(m, cfilenoext);
if shouldRecompile(code, changeFileExt(cfile, cExt), cfilenoext) then begin
addFileToCompile(cfilenoext); // is to compile
end;
addFileToLink(cfilenoext);
currMod := nil // free the memory
end;
function CBackend(b: PBackend; module: PSym; const filename: string): PBackend;
@ -749,7 +766,6 @@ begin
g.backendCreator := CBackend;
g.eventMask := {@set}[eAfterModule];
g.afterModuleEvent := finishModule;
currMod := g;
result := g;
end;

View file

@ -7,10 +7,10 @@
// distribution, for details about the copyright.
//
// This module handles the parsing of command line arguments.
unit commands;
// This module handles the parsing of command line arguments.
interface
{$include 'config.inc'}
@ -41,16 +41,14 @@ uses
const
{$ifdef fpc}
compileDate = {$I %date%};
compileTime = {$I %time%};
{$else}
compileDate = '2008-0-0';
compileTime = '00:00:00';
{$endif}
{@emit}
const
HelpMessage = 'Nimrod Compiler Version $1 (' +{&}
compileDate +{&} ' ' +{&} compileTime +{&} ') [$2: $3]' +{&} nl +{&}
compileDate +{&} ') [$2: $3]' +{&} nl +{&}
'Copyright (c) 2004-2008 by Andreas Rumpf' +{&} nl;
const
@ -66,7 +64,8 @@ const
+{&} ' compile compile project with default code generator (C)' +{&} nl
+{&} ' compile_to_c compile project with C code generator' +{&} nl
+{&} ' compile_to_cpp compile project with C++ code generator' +{&} nl
+{&} ' doc generate the documentation for inputfile; ' +{&} nl
+{&} ' compile_to_ecmascript compile project to ECMAScript code (experimental)' +{&} nl
+{&} ' doc generate the documentation for inputfile;' +{&} nl
+{&} ' with --run switch opens it with $BROWSER' +{&} nl
+{&} 'Arguments:' +{&} nl
+{&} ' arguments are passed to the program being run (if --run option is selected)' +{&} nl
@ -80,6 +79,8 @@ const
+{&} ' --line_trace:on|off code generation for line trace ON|OFF' +{&} nl
+{&} ' --debugger:on|off turn Embedded Nimrod Debugger ON|OFF' +{&} nl
+{&} ' -x, --checks:on|off code generation for all runtime checks ON|OFF' +{&} nl
+{&} ' --obj_checks:on|off code generation for obj conversion checks ON|OFF' +{&} nl
+{&} ' --field_checks:on|off code generation for case record fields ON|OFF' +{&} nl
+{&} ' --range_checks:on|off code generation for range checks ON|OFF' +{&} nl
+{&} ' --bound_checks:on|off code generation for bound checks ON|OFF' +{&} nl
+{&} ' --overflow_checks:on|off code generation for over-/underflow checks ON|OFF' +{&} nl
@ -174,17 +175,8 @@ const
;
function getCommandLineDesc: string;
var
v: string;
begin
// the Pascal version number gets a little star ('*'), the Nimrod version
// does not! This helps distinguishing the different builds.
{@ignore}
v := VersionAsString +{&} '*';
{@emit
v := VersionAsString
}
result := format(HelpMessage, [v, platform.os[hostOS].name,
result := format(HelpMessage, [VersionAsString, platform.os[hostOS].name,
cpu[hostCPU].name]) +{&} Usage
end;
@ -210,6 +202,7 @@ begin
cpu[hostCPU].name]) +{&} AdvancedUsage);
advHelpWritten := true;
helpWritten := true;
halt(0);
end
end;
@ -423,7 +416,7 @@ begin
ProcessOnOffSwitch({@set}[optHints], arg, pass, info);
wCheckpoints:
ProcessOnOffSwitch({@set}[optCheckpoints], arg, pass, info);
wStackTrace, wS:
wStackTrace:
ProcessOnOffSwitch({@set}[optStackTrace], arg, pass, info);
wLineTrace:
ProcessOnOffSwitch({@set}[optLineTrace], arg, pass, info);
@ -436,6 +429,10 @@ begin
end;
wChecks, wX:
ProcessOnOffSwitch(checksOptions, arg, pass, info);
wObjChecks:
ProcessOnOffSwitch({@set}[optObjCheck], arg, pass, info);
wFieldChecks:
ProcessOnOffSwitch({@set}[optFieldCheck], arg, pass, info);
wRangeChecks:
ProcessOnOffSwitch({@set}[optRangeCheck], arg, pass, info);
wBoundChecks:
@ -485,6 +482,10 @@ begin
liMessage(info, errGuiConsoleOrLibExpectedButXFound, arg)
end
end;
wListDef: begin
if pass in {@set}[passCmd2, passPP] then
condsyms.listSymbols();
end;
wPassC, wT: begin
expectArg(switch, arg, pass, info);
if pass in {@set}[passCmd2, passPP] then

View file

@ -19,7 +19,7 @@ type
TCrc32 = int32;
const
InitCrc32 = TCrc32($ffffffff);
InitCrc32 = TCrc32(-1);
function updateCrc32(val: Byte; crc: TCrc32): TCrc32; overload;
function updateCrc32(val: Char; crc: TCrc32): TCrc32; overload;

View file

@ -40,6 +40,7 @@ type
modDesc: PRope; // module description
dependsOn: PRope; // dependencies
id: int; // for generating IDs
splitAfter: int; // split to long entries in the TOC
tocPart: array of TTocEntry;
hasToc: bool;
toc, section: TSections;
@ -106,6 +107,8 @@ begin
end;
function newDocumentor(const filename: string): PDoc;
var
s: string;
begin
new(result);
{@ignore}
@ -115,6 +118,10 @@ begin
}
result.filename := filename;
result.id := 100;
result.splitAfter := 25;
s := getConfigVar('split.item.toc');
if s <> '' then
result.splitAfter := parseInt(s);
end;
function getVarIdx(const varnames: array of string; const id: string): int;
@ -209,12 +216,16 @@ begin
end
end;
function toXml(const s: string): string;
function toXml(const s: string; splitAfter: int = -1): string;
var
i: int;
begin
result := '';
for i := strStart to length(s)+strStart-1 do addXmlChar(result, s[i])
for i := strStart to length(s)+strStart-1 do begin
if (splitAfter >= 0) and ((i-strStart+1) mod splitAfter = 0) then
addChar(result, ' ');
addXmlChar(result, s[i])
end
end;
function renderRstToHtml(d: PDoc; n: PRstNode): PRope; forward;
@ -226,8 +237,8 @@ var
begin
result := nil;
for i := 0 to rsonsLen(n)-1 do
appRopeFormat(result, inner, [renderRstToHtml(d, n.sons[i])]);
result := ropeFormat(outer, [result]);
appf(result, inner, [renderRstToHtml(d, n.sons[i])]);
result := ropef(outer, [result]);
end;
procedure setIndexForSourceTerm(d: PDoc; name: PRstNode; id: int);
@ -249,7 +260,7 @@ var
a, h: PRstNode;
begin
inc(d.id);
result := ropeFormat('<em id="$1">$2</em>',
result := ropef('<em id="$1">$2</em>',
[toRope(d.id), renderAux(d, n)]);
h := newRstNode(rnHyperlink);
a := newRstNode(rnLeaf, d.indexValFilename +{&} '#' +{&} toString(d.id));
@ -277,11 +288,13 @@ var
begin
if n = nil then begin result := nil; exit end;
result := genComment(d, n);
if result = nil then
for i := 0 to sonsLen(n)-1 do begin
result := genRecComment(d, n.sons[i]);
if result <> nil then exit
end
if result = nil then begin
if not (n.kind in [nkEmpty..nkNilLit]) then
for i := 0 to sonsLen(n)-1 do begin
result := genRecComment(d, n.sons[i]);
if result <> nil then exit
end
end
else
n.comment := snil
end;
@ -303,14 +316,14 @@ begin
result := isVisible(n.sons[0]);
end;
function getName(n: PNode): string;
function getName(n: PNode; splitAfter: int = -1): string;
begin
case n.kind of
nkPostfix: result := getName(n.sons[1]);
nkPragmaExpr: result := getName(n.sons[0]);
nkSym: result := toXML(n.sym.name.s);
nkIdent: result := toXML(n.ident.s);
nkAccQuoted: result := '`' +{&} getName(n.sons[0]) +{&} '`';
nkPostfix: result := getName(n.sons[1], splitAfter);
nkPragmaExpr: result := getName(n.sons[0], splitAfter);
nkSym: result := toXML(n.sym.name.s, splitAfter);
nkIdent: result := toXML(n.ident.s, splitAfter);
nkAccQuoted: result := '`' +{&} getName(n.sons[0], splitAfter) +{&} '`';
else begin
internalError(n.info, 'getName()');
result := ''
@ -355,49 +368,49 @@ begin
case kind of
tkEof: break;
tkComment:
appRopeFormat(result, '<span class="Comment">$1</span>',
appf(result, '<span class="Comment">$1</span>',
[toRope(toXml(literal))]);
tokKeywordLow..tokKeywordHigh:
appRopeFormat(result, '<span class="Keyword">$1</span>',
appf(result, '<span class="Keyword">$1</span>',
[toRope(literal)]);
tkOpr, tkHat:
appRopeFormat(result, '<span class="Operator">$1</span>',
appf(result, '<span class="Operator">$1</span>',
[toRope(toXml(literal))]);
tkStrLit..tkTripleStrLit:
appRopeFormat(result, '<span class="StringLit">$1</span>',
appf(result, '<span class="StringLit">$1</span>',
[toRope(toXml(literal))]);
tkCharLit, tkRCharLit:
appRopeFormat(result, '<span class="CharLit">$1</span>',
tkCharLit:
appf(result, '<span class="CharLit">$1</span>',
[toRope(toXml(literal))]);
tkIntLit..tkInt64Lit:
appRopeFormat(result, '<span class="DecNumber">$1</span>',
appf(result, '<span class="DecNumber">$1</span>',
[toRope(literal)]);
tkFloatLit..tkFloat64Lit:
appRopeFormat(result, '<span class="FloatNumber">$1</span>',
appf(result, '<span class="FloatNumber">$1</span>',
[toRope(literal)]);
tkSymbol:
appRopeFormat(result, '<span class="Identifier">$1</span>',
appf(result, '<span class="Identifier">$1</span>',
[toRope(literal)]);
tkInd, tkSad, tkDed, tkSpaces:
app(result, literal);
//appRopeFormat(result, '<span class="Whitespace">$1</span>',
//appf(result, '<span class="Whitespace">$1</span>',
// [toRope(literal)]);
tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi,
tkParDotLe, tkParDotRi, tkComma, tkSemiColon, tkColon,
tkEquals, tkDot, tkDotDot, tkAccent:
appRopeFormat(result, '<span class="Other">$1</span>',
appf(result, '<span class="Other">$1</span>',
[toRope(literal)]);
else InternalError(n.info, 'docgen.genThing(' + toktypeToStr[kind] + ')');
end
end;
inc(d.id);
app(d.section[k], ropeFormatNamedVars(getConfigVar('doc.item'),
['name', 'header', 'desc', 'itemID'],
[name, result, comm, toRope(d.id)]));
['name', 'header', 'desc', 'itemID'],
[name, result, comm, toRope(d.id)]));
app(d.toc[k], ropeFormatNamedVars(getConfigVar('doc.item.toc'),
['name', 'header', 'desc', 'itemID'],
[name, result, comm, toRope(d.id)]));
['name', 'header', 'desc', 'itemID'],
[toRope(getName(nameNode, d.splitAfter)), result, comm, toRope(d.id)]));
setIndexForSourceTerm(d, getRstName(nameNode), d.id);
end;
@ -416,12 +429,12 @@ begin
d.tocPart[len].refname := refname;
d.tocPart[len].n := n;
d.tocPart[len].header := result;
result := ropeFormat('<h$1><a class="toc-backref" id="$2" href="#$2_toc">$3'+
result := ropef('<h$1><a class="toc-backref" id="$2" href="#$2_toc">$3'+
'</a></h$1>',
[toRope(n.level), d.tocPart[len].refname, result]);
end
else
result := ropeFormat('<h$1 id="$2">$3</h$1>',
result := ropef('<h$1 id="$2">$3</h$1>',
[toRope(n.level), refname, result]);
end;
@ -437,7 +450,7 @@ begin
if d.meta[metaTitle] = nil then d.meta[metaTitle] := t
else if d.meta[metaSubtitle] = nil then d.meta[metaSubtitle] := t
else
result := ropeFormat('<h$1 id="$2"><center>$3</center></h$1>',
result := ropef('<h$1 id="$2"><center>$3</center></h$1>',
[toRope(n.level), toRope(rstnodeToRefname(n)), t]);
end;
@ -469,32 +482,32 @@ begin
rnHeadline: begin
result := renderRstSons(d, n);
L := ropeLen(result);
result := ropeFormat('$n$1$2$n$1$3', [ind, result,
result := ropef('$n$1$2$n$1$3', [ind, result,
toRope(repeatChar(L, lvlToChar[n.level]))]);
end;
rnOverline: begin
result := renderRstSons(d, n);
L := ropeLen(result);
result := ropeFormat('$n$1$3$n$1$2$n$1$3', [ind, result,
result := ropef('$n$1$3$n$1$2$n$1$3', [ind, result,
toRope(repeatChar(L, lvlToChar[n.level]))]);
end;
rnTransition:
result := ropeFormat('$n$n$1$2$n$n',
result := ropef('$n$n$1$2$n$n',
[ind, toRope(repeatChar(78-d.indent, '-'))]);
rnParagraph: begin
result := renderRstSons(d, n);
result := ropeFormat('$n$n$1$2', [ind, result]);
result := ropef('$n$n$1$2', [ind, result]);
end;
rnBulletItem: begin
inc(d.indent, 2);
result := renderRstSons(d, n);
if result <> nil then result := ropeFormat('$n$1* $2', [ind, result]);
if result <> nil then result := ropef('$n$1* $2', [ind, result]);
dec(d.indent, 2);
end;
rnEnumItem: begin
inc(d.indent, 4);
result := renderRstSons(d, n);
if result <> nil then result := ropeFormat('$n$1(#) $2', [ind, result]);
if result <> nil then result := ropef('$n$1(#) $2', [ind, result]);
dec(d.indent, 4);
end;
rnOptionList, rnFieldList, rnDefList, rnDefItem, rnLineBlock, rnFieldName,
@ -502,27 +515,27 @@ begin
result := renderRstSons(d, n);
rnDefName: begin
result := renderRstSons(d, n);
result := ropeFormat('$n$n$1$2', [ind, result]);
result := ropef('$n$n$1$2', [ind, result]);
end;
rnDefBody: begin
inc(d.indent, 2);
result := renderRstSons(d, n);
if n.sons[0].kind <> rnBulletList then
result := ropeFormat('$n$1 $2', [ind, result]);
result := ropef('$n$1 $2', [ind, result]);
dec(d.indent, 2);
end;
rnField: begin
result := renderRstToRst(d, n.sons[0]);
L := max(ropeLen(result)+3, 30);
inc(d.indent, L);
result := ropeFormat('$n$1:$2:$3$4', [
result := ropef('$n$1:$2:$3$4', [
ind, result, toRope(repeatChar(L-ropeLen(result)-2)),
renderRstToRst(d, n.sons[1])]);
dec(d.indent, L);
end;
rnLineBlockItem: begin
result := renderRstSons(d, n);
result := ropeFormat('$n$1| $2', [ind, result]);
result := ropef('$n$1| $2', [ind, result]);
end;
rnBlockQuote: begin
inc(d.indent, 2);
@ -531,44 +544,44 @@ begin
end;
rnRef: begin
result := renderRstSons(d, n);
result := ropeFormat('`$1`_', [result]);
result := ropef('`$1`_', [result]);
end;
rnHyperlink: begin
result := ropeFormat('`$1 <$2>`_', [renderRstToRst(d, n.sons[0]),
result := ropef('`$1 <$2>`_', [renderRstToRst(d, n.sons[0]),
renderRstToRst(d, n.sons[1])]);
end;
rnGeneralRole: begin
result := renderRstToRst(d, n.sons[0]);
result := ropeFormat('`$1`:$2:', [result, renderRstToRst(d, n.sons[1])]);
result := ropef('`$1`:$2:', [result, renderRstToRst(d, n.sons[1])]);
end;
rnSub: begin
result := renderRstSons(d, n);
result := ropeFormat('`$1`:sub:', [result]);
result := ropef('`$1`:sub:', [result]);
end;
rnSup: begin
result := renderRstSons(d, n);
result := ropeFormat('`$1`:sup:', [result]);
result := ropef('`$1`:sup:', [result]);
end;
rnIdx: begin
result := renderRstSons(d, n);
result := ropeFormat('`$1`:idx:', [result]);
result := ropef('`$1`:idx:', [result]);
end;
rnEmphasis: begin
result := renderRstSons(d, n);
result := ropeFormat('*$1*', [result]);
result := ropef('*$1*', [result]);
end;
rnStrongEmphasis: begin
result := renderRstSons(d, n);
result := ropeFormat('**$1**', [result]);
result := ropef('**$1**', [result]);
end;
rnInterpretedText: begin
result := renderRstSons(d, n);
result := ropeFormat('`$1`', [result]);
result := ropef('`$1`', [result]);
end;
rnInlineLiteral: begin
inc(d.verbatim);
result := renderRstSons(d, n);
result := ropeFormat('``$1``', [result]);
result := ropef('``$1``', [result]);
dec(d.verbatim);
end;
rnLeaf: begin
@ -582,10 +595,10 @@ begin
if n.sons[2] <> nil then
result := renderRstSons(d, n.sons[2]);
dec(d.indent, 3);
result := ropeFormat('$n$n$1.. index::$n$2', [ind, result]);
result := ropef('$n$n$1.. index::$n$2', [ind, result]);
end;
rnContents: begin
result := ropeFormat('$n$n$1.. contents::', [ind]);
result := ropef('$n$n$1.. contents::', [ind]);
end;
else rawMessage(errCannotRenderX, rstnodeKindToStr[n.kind]);
end;
@ -593,7 +606,7 @@ end;
function renderTocEntry(d: PDoc; const e: TTocEntry): PRope;
begin
result := ropeFormat('<li><a class="reference" id="$1_toc" href="#$1">$2' +
result := ropef('<li><a class="reference" id="$1_toc" href="#$1">$2' +
'</a></li>$n', [e.refname, e.header]);
end;
@ -614,24 +627,24 @@ begin
break
end;
if lvl > 1 then
result := ropeFormat('<ul class="simple">$1</ul>', [result]);
result := ropef('<ul class="simple">$1</ul>', [result]);
end;
function renderImage(d: PDoc; n: PRstNode): PRope;
var
s: string;
begin
result := ropeFormat('<img src="$1"', [toRope(getArgument(n))]);
result := ropef('<img src="$1"', [toRope(getArgument(n))]);
s := getFieldValue(n, 'height');
if s <> '' then appRopeFormat(result, ' height="$1"', [toRope(s)]);
if s <> '' then appf(result, ' height="$1"', [toRope(s)]);
s := getFieldValue(n, 'width');
if s <> '' then appRopeFormat(result, ' width="$1"', [toRope(s)]);
if s <> '' then appf(result, ' width="$1"', [toRope(s)]);
s := getFieldValue(n, 'scale');
if s <> '' then appRopeFormat(result, ' scale="$1"', [toRope(s)]);
if s <> '' then appf(result, ' scale="$1"', [toRope(s)]);
s := getFieldValue(n, 'alt');
if s <> '' then appRopeFormat(result, ' alt="$1"', [toRope(s)]);
if s <> '' then appf(result, ' alt="$1"', [toRope(s)]);
s := getFieldValue(n, 'align');
if s <> '' then appRopeFormat(result, ' align="$1"', [toRope(s)]);
if s <> '' then appf(result, ' align="$1"', [toRope(s)]);
app(result, ' />');
if rsonsLen(n) >= 3 then app(result, renderRstToHtml(d, n.sons[2]))
end;
@ -644,14 +657,14 @@ var
lang: TSourceLanguage;
begin
m := n.sons[2].sons[0];
assert(m.kind = rnLeaf);
if (m.kind <> rnLeaf) then InternalError('renderCodeBlock');
result := nil;
langstr := strip(getArgument(n));
if langstr = '' then lang := langNimrod // default language
else lang := getSourceLanguage(langstr);
if lang = langNone then begin
rawMessage(warnLanguageXNotSupported, langstr);
result := ropeFormat('<pre>$1</pre>', [toRope(m.text)])
result := ropef('<pre>$1</pre>', [toRope(m.text)])
end
else begin
initGeneralTokenizer(g, m.text);
@ -660,15 +673,17 @@ begin
case g.kind of
gtEof: break;
gtNone, gtWhitespace:
app(result, ncopy(m.text, g.start+strStart, g.len+g.start));
app(result, ncopy(m.text, g.start+strStart,
g.len+g.start-1+strStart));
else
appRopeFormat(result, '<span class="$2">$1</span>',
[toRope(ncopy(m.text, g.start+strStart, g.len+g.start)),
appf(result, '<span class="$2">$1</span>',
[toRope(ncopy(m.text, g.start+strStart,
g.len+g.start-1+strStart)),
toRope(tokenClassToStr[g.kind])]);
end;
end;
deinitGeneralTokenizer(g);
if result <> nil then result := ropeFormat('<pre>$1</pre>', [result]);
if result <> nil then result := ropef('<pre>$1</pre>', [result]);
end
end;
@ -719,10 +734,10 @@ begin
rnDescription: outer := '<td align="left">$1</td>$n';
rnOption,
rnOptionString,
rnOptionArgument: assert(false);
rnOptionArgument: InternalError('renderRstToHtml');
rnLiteralBlock: outer := '<pre>$1</pre>'+nl;
rnQuotedLiteralBlock: assert(false);
rnQuotedLiteralBlock: InternalError('renderRstToHtml');
rnLineBlock: outer := '<p>$1</p>';
rnLineBlockItem: outer := '$1<br />';
@ -735,19 +750,19 @@ begin
rnTableDataCell: outer := '<td>$1</td>';
rnTableHeaderCell: outer := '<th>$1</th>';
rnLabel: assert(false); // used for footnotes and other things
rnFootnote: assert(false); // a footnote
rnLabel: InternalError('renderRstToHtml'); // used for footnotes and other
rnFootnote: InternalError('renderRstToHtml'); // a footnote
rnCitation: assert(false); // similar to footnote
rnCitation: InternalError('renderRstToHtml'); // similar to footnote
rnRef: begin
result := ropeFormat('<a class="reference external" href="#$2">$1</a>',
result := ropef('<a class="reference external" href="#$2">$1</a>',
[renderAux(d, n), toRope(rstnodeToRefname(n))]);
exit
end;
rnStandaloneHyperlink:
outer := '<a class="reference external" href="$1">$1</a>';
rnHyperlink: begin
result := ropeFormat('<a class="reference external" href="$2">$1</a>',
result := ropef('<a class="reference external" href="$2">$1</a>',
[renderRstToHtml(d, n.sons[0]),
renderRstToHtml(d, n.sons[1])]);
exit
@ -766,7 +781,7 @@ begin
// Inline markup:
rnGeneralRole: begin
result := ropeFormat('<span class="$2">$1</span>',
result := ropef('<span class="$2">$1</span>',
[renderRstToHtml(d, n.sons[0]),
renderRstToHtml(d, n.sons[1])]);
exit
@ -798,7 +813,7 @@ begin
d.meta[metaTitle] := renderRstToHtml(d, n.sons[0]);
exit
end;
else assert(false);
else InternalError('renderRstToHtml');
end;
result := renderAux(d, n, outer, inner);
end;
@ -809,11 +824,12 @@ var
begin
if n = nil then exit;
case n.kind of
nkCommentStmt: app(d.modDesc, genComment(d, n));
nkProcDef: genItem(d, n, n.sons[namePos], skProc);
nkIteratorDef: genItem(d, n, n.sons[namePos], skIterator);
nkMacroDef: genItem(d, n, n.sons[namePos], skMacro);
nkTemplateDef: genItem(d, n, n.sons[namePos], skTemplate);
nkCommentStmt: app(d.modDesc, genComment(d, n));
nkProcDef: genItem(d, n, n.sons[namePos], skProc);
nkIteratorDef: genItem(d, n, n.sons[namePos], skIterator);
nkMacroDef: genItem(d, n, n.sons[namePos], skMacro);
nkTemplateDef: genItem(d, n, n.sons[namePos], skTemplate);
nkConverterDef: genItem(d, n, n.sons[namePos], skConverter);
nkVarSection: begin
for i := 0 to sonsLen(n)-1 do
genItem(d, n.sons[i], n.sons[i].sons[0], skVar);
@ -860,13 +876,15 @@ var
begin
j := 0;
toc := renderTocEntries(d, j, 1);
code := nil;
content := nil;
title := nil;
for i := low(TSymKind) to high(TSymKind) do begin
genSection(d, i);
app(toc, d.toc[i]);
end;
if toc <> nil then
toc := ropeFormatNamedVars(getConfigVar('doc.toc'), ['content'], [toc]);
code := nil;
for i := low(TSymKind) to high(TSymKind) do
app(code, d.section[i]);
if d.meta[metaTitle] <> nil then
@ -918,13 +936,16 @@ var
filen: string;
d: PDoc;
rst: PRstNode;
code: PRope;
begin
filen := appendFileExt(filename, 'txt');
d := newDocumentor(filen);
initIndexFile(d);
rst := rstParse(readFile(filen), false, filen, 0, 1, d.hasToc);
d.modDesc := renderRstToHtml(d, rst);
writeRope(genHtmlFile(d), getOutFile(filename, HtmlExt));
code := genHtmlFile(d);
assert(ropeInvariant(code));
writeRope(code, getOutFile(filename, HtmlExt));
generateIndex(d);
end;

1869
nim/ecmasgen.pas Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -15,7 +15,9 @@ interface
{$include 'config.inc'}
uses
nimconf, msgs; // some things are read in from the configuration file
nsystem, nimconf, msgs;
// some things are read in from the configuration file
type
TSystemCC = (ccNone, ccGcc, ccLLVM_Gcc, ccLcc, ccBcc, ccDmc, ccWcc, ccVcc,
@ -27,15 +29,17 @@ type
hasCpp // CC is/contains a C++ compiler
);
TInfoCCProps = set of TInfoCCProp;
TInfoCC = record
TInfoCC = record{@tuple}
name: string; // the short name of the compiler
objExt: string; // the compiler's object file extenstion
optSpeed: string; // the options for optimization for speed
optSize: string; // the options for optimization for size
compile: string; // the compile command template
compilerExe: string; // the compiler's executable
compileTmpl: string; // the compile command template
buildGui: string; // command to build a GUI application
buildDll: string; // command to build a shared library
link: string; // command to link files to produce an executable
linkerExe: string; // the linker's executable
linkTmpl: string; // command to link files to produce an executable
includeCmd: string; // command to add an include directory path
debug: string; // flags for debug build
pic: string; // command for position independent code
@ -50,10 +54,12 @@ const
objExt: 'o'+'';
optSpeed: ' -O3 -ffast-math ';
optSize: ' -Os -ffast-math ';
compile: 'gcc -c $options $include -o $objfile $file';
compilerExe: 'gcc';
compileTmpl: '-c $options $include -o $objfile $file';
buildGui: ' -mwindows';
buildDll: ' -mdll';
link: 'gcc $options $buildgui $builddll -o $exefile $objfiles';
linkerExe: 'gcc';
linkTmpl: '$options $buildgui $builddll -o $exefile $objfiles';
includeCmd: ' -I';
debug: '';
pic: '-fPIC';
@ -65,10 +71,12 @@ const
objExt: 'o'+'';
optSpeed: ' -O3 -ffast-math ';
optSize: ' -Os -ffast-math ';
compile: 'llvm-gcc -c $options $include -o $objfile $file';
compilerExe: 'llvm-gcc';
compileTmpl: '-c $options $include -o $objfile $file';
buildGui: ' -mwindows';
buildDll: ' -mdll';
link: 'llvm-gcc $options $buildgui $builddll -o $exefile $objfiles';
linkerExe: 'llvm-gcc';
linkTmpl: '$options $buildgui $builddll -o $exefile $objfiles';
includeCmd: ' -I';
debug: '';
pic: '-fPIC';
@ -80,10 +88,12 @@ const
objExt: 'obj';
optSpeed: ' -O -p6 ';
optSize: ' -O -p6 ';
compile: 'lcc -e1 $options $include -Fo$objfile $file';
compilerExe: 'lcc';
compileTmpl: '-e1 $options $include -Fo$objfile $file';
buildGui: ' -subsystem windows';
buildDll: ' -dll';
link: 'lcclnk $options $buildgui $builddll -O $exefile $objfiles';
linkerExe: 'lcclnk';
linkTmpl: '$options $buildgui $builddll -O $exefile $objfiles';
includeCmd: ' -I';
debug: ' -g5 ';
pic: '';
@ -95,10 +105,12 @@ const
objExt: 'obj';
optSpeed: ' -O2 -6 ';
optSize: ' -O1 -6 ';
compile: 'bcc32 -c $options $include -o$objfile $file';
compilerExe: 'bcc32';
compileTmpl: '-c $options $include -o$objfile $file';
buildGui: ' -tW';
buildDll: ' -tWD';
link: 'bcc32 $options $buildgui $builddll -e$exefile $objfiles';
linkerExe: 'bcc32';
linkTmpl: '$options $buildgui $builddll -e$exefile $objfiles';
includeCmd: ' -I';
debug: '';
pic: '';
@ -110,10 +122,12 @@ const
objExt: 'obj';
optSpeed: ' -ff -o -6 ';
optSize: ' -ff -o -6 ';
compile: 'dmc -c $options $include -o$objfile $file';
compilerExe: 'dmc';
compileTmpl: '-c $options $include -o$objfile $file';
buildGui: ' -L/exet:nt/su:windows';
buildDll: ' -WD';
link: 'dmc $options $buildgui $builddll -o$exefile $objfiles';
linkerExe: 'dmc';
linkTmpl: '$options $buildgui $builddll -o$exefile $objfiles';
includeCmd: ' -I';
debug: ' -g ';
pic: '';
@ -125,10 +139,12 @@ const
objExt: 'obj';
optSpeed: ' -ox -on -6 -d0 -fp6 -zW ';
optSize: '';
compile: 'wcl386 -c $options $include -fo=$objfile $file';
compilerExe: 'wcl386';
compileTmpl: '-c $options $include -fo=$objfile $file';
buildGui: ' -bw';
buildDll: ' -bd';
link: 'wcl386 $options $buildgui $builddll -fe=$exefile $objfiles ';
linkerExe: 'wcl386';
linkTmpl: '$options $buildgui $builddll -fe=$exefile $objfiles ';
includeCmd: ' -i=';
debug: ' -d2 ';
pic: '';
@ -140,10 +156,12 @@ const
objExt: 'obj';
optSpeed: ' /Ogityb2 /G7 /arch:SSE2 ';
optSize: ' /O1 /G7 ';
compile: 'cl /c $options $include /Fo$objfile $file';
compilerExe: 'cl';
compileTmpl: '/c $options $include /Fo$objfile $file';
buildGui: ' /link /SUBSYSTEM:WINDOWS ';
buildDll: ' /LD';
link: 'cl $options $builddll /Fe$exefile $objfiles $buildgui';
linkerExe: 'cl';
linkTmpl: '$options $builddll /Fe$exefile $objfiles $buildgui';
includeCmd: ' /I';
debug: ' /GZ /Zi ';
pic: '';
@ -155,10 +173,12 @@ const
objExt: 'o'+'';
optSpeed: '';
optSize: '';
compile: 'tcc -c $options $include -o $objfile $file';
compilerExe: 'tcc';
compileTmpl: '-c $options $include -o $objfile $file';
buildGui: 'UNAVAILABLE!';
buildDll: ' -shared';
link: 'tcc -o $exefile $options $buildgui $builddll $objfiles';
linkerExe: 'tcc';
linkTmpl: '-o $exefile $options $buildgui $builddll $objfiles';
includeCmd: ' -I';
debug: ' -g ';
pic: '';
@ -170,10 +190,12 @@ const
objExt: 'obj';
optSpeed: ' -Ox ';
optSize: ' -Os ';
compile: 'cc -c $options $include -Fo$objfile $file';
compilerExe: 'cc';
compileTmpl: '-c $options $include -Fo$objfile $file';
buildGui: ' -SUBSYSTEM:WINDOWS';
buildDll: ' -DLL';
link: 'cc $options $buildgui $builddll -OUT:$exefile $objfiles';
linkerExe: 'cc';
linkTmpl: '$options $buildgui $builddll -OUT:$exefile $objfiles';
includeCmd: ' -I';
debug: ' -Zi ';
pic: '';
@ -185,10 +207,12 @@ const
objExt: 'o'+'';
optSpeed: ' -O3 ';
optSize: ' -O1 ';
compile: 'cc -c $options $include -o $objfile $file';
compilerExe: 'cc';
compileTmpl: '-c $options $include -o $objfile $file';
buildGui: '';
buildDll: ' -shared ';
link: 'cc -o $exefile $options $buildgui $builddll $objfiles';
linkerExe: 'cc';
linkTmpl: '-o $exefile $options $buildgui $builddll $objfiles';
includeCmd: ' -I';
debug: '';
pic: '';
@ -199,10 +223,12 @@ const
objExt: 'o'+'';
optSpeed: ' -O3 ';
optSize: ' -Os ';
compile: 'icc -c $options $include -o $objfile $file';
compilerExe: 'icc';
compileTmpl: '-c $options $include -o $objfile $file';
buildGui: ' -mwindows';
buildDll: ' -mdll';
link: 'icc $options $buildgui $builddll -o $exefile $objfiles';
linkerExe: 'icc';
linkTmpl: '$options $buildgui $builddll -o $exefile $objfiles';
includeCmd: ' -I';
debug: '';
pic: '-fPIC';
@ -213,10 +239,12 @@ const
objExt: 'o'+'';
optSpeed: ' -O3 -ffast-math ';
optSize: ' -Os -ffast-math ';
compile: 'g++ -c $options $include -o $objfile $file';
compilerExe: 'g++';
compileTmpl: '-c $options $include -o $objfile $file';
buildGui: ' -mwindows';
buildDll: ' -mdll';
link: 'g++ $options $buildgui $builddll -o $exefile $objfiles';
linkerExe: 'g++';
linkTmpl: '$options $buildgui $builddll -o $exefile $objfiles';
includeCmd: ' -I';
debug: ' -g ';
pic: '-fPIC';
@ -238,6 +266,9 @@ var
function completeCFilePath(const cfile: string;
createSubDir: Boolean = true): string;
function getCompileCFileCmd(const cfilename: string;
isExternal: bool = false): string;
procedure addFileToCompile(const filename: string);
procedure addExternalFileToCompile(const filename: string);
procedure addFileToLink(const filename: string);
@ -260,7 +291,7 @@ procedure setCC(const ccname: string);
implementation
uses
nsystem, charsets,
charsets,
lists, options, ropes, nos, strutils, platform, condsyms;
var
@ -389,16 +420,13 @@ begin
result := cc[c].optSize // use default settings from this file
end;
procedure CompileCFile(const list: TLinkedList;
var script: PRope; isExternal: Boolean);
function getCompileCFileCmd(const cfilename: string;
isExternal: bool = false): string;
var
it: PStrEntry;
compileCmd, cfile, objfile, options, includeCmd, compilePattern: string;
cfile, objfile, options, includeCmd, compilePattern: string;
c: TSystemCC; // an alias to ccompiler
begin
c := ccompiler;
it := PStrEntry(list.head);
options := compileOptions;
if optCDebug in gGlobalOptions then addStr(options, ' ' + getDebug(c));
if optOptimizeSpeed in gOptions then addStr(options, ' ' + getOptSpeed(c))
@ -413,31 +441,43 @@ begin
includeCmd := cc[c].includeCmd; // this is more complex than needed, but
// a workaround of a FPC bug...
addStr(includeCmd, libpath);
compilePattern := JoinPath(ccompilerpath, cc[c].compile);
compilePattern := quoteIfSpaceExists(
JoinPath(ccompilerpath, cc[c].compilerExe));
end
else begin
includeCmd := '';
compilePattern := cc[c].compile
compilePattern := cc[c].compilerExe
end;
if targetOS = hostOS then
cfile := cfilename
else
cfile := extractFileName(cfilename);
if not isExternal or (targetOS <> hostOS) then
objfile := toObjFile(cfile)
else
objfile := completeCFilePath(toObjFile(cfile));
result := compilePattern +{&} ' ' +{&} format(cc[c].compileTmpl,
['file', AppendFileExt(cfile, cExt),
'objfile', objfile,
'options', options,
'include', includeCmd,
'nimrod', getPrefixDir(),
'lib', libpath
]);
end;
procedure CompileCFile(const list: TLinkedList;
var script: PRope; isExternal: Boolean);
var
it: PStrEntry;
compileCmd: string;
begin
it := PStrEntry(list.head);
while it <> nil do begin
// call the C compiler for the .c file:
if targetOS = hostOS then
cfile := it.data
else
cfile := extractFileName(it.data);
if not isExternal or (targetOS <> hostOS) then
objfile := toObjFile(cfile)
else
objfile := completeCFilePath(toObjFile(cfile));
compileCmd := format(compilePattern,
['file', AppendFileExt(cfile, cExt),
'objfile', objfile,
'options', options,
'include', includeCmd
]);
compileCmd := getCompileCFileCmd(it.data, isExternal);
if not (optCompileOnly in gGlobalOptions) then
execExternalProgram(compileCmd);
if (optGenScript in gGlobalOptions) then begin
@ -469,9 +509,9 @@ begin
if not (optNoLinking in gGlobalOptions) then begin
// call the linker:
if (hostOS <> targetOS) then
linkCmd := cc[c].link
linkCmd := cc[c].linkerExe
else
linkCmd := JoinPath(ccompilerpath, cc[c].link);
linkCmd := quoteIfSpaceExists(JoinPath(ccompilerpath, cc[c].linkerExe));
if optGenDynLib in gGlobalOptions then
buildDll := cc[c].buildDll
@ -506,12 +546,14 @@ begin
it := PStrEntry(it.next);
end;
linkCmd := format(linkCmd, [
linkCmd := linkCmd +{&} ' ' +{&} format(cc[c].linkTmpl, [
'builddll', builddll,
'buildgui', buildgui,
'options', linkOptions,
'objfiles', objfiles,
'exefile', exefile
'exefile', exefile,
'nimrod', getPrefixDir(),
'lib', libpath
]);
if not (optCompileOnly in gGlobalOptions) then
execExternalProgram(linkCmd);

View file

@ -1,175 +0,0 @@
//
//
// The Nimrod Compiler
// (c) Copyright 2008 Andreas Rumpf
//
// See the file "copying.txt", included in this
// distribution, for details about the copyright.
//
unit genhelp;
// This module contains some helper routines used by the different
// code generators.
interface
{$include 'config.inc'}
uses
nsystem,
ast, astalgo, trees, msgs, options, platform;
function hasSideEffect(t: PNode): Boolean;
function ReturnsNewThing(op: PNode): Boolean;
function containsGarbageCollectedRef(typ: PType): Boolean;
// returns true if typ contains a reference, sequence or string (all the things
// that are garbage-collected)
function containsHiddenPointer(typ: PType): Boolean;
// returns true if typ contains a string, table or sequence (all the things
// that need to be copied deeply)
function containsObject(typ: PType): Boolean;
// Returns true if typ contains an object type directly; then it has to
// be initialized in a complex way that sets up the typeid field.
function isGarbageCollected(typ: PType): Boolean;
function pointerOf(typ: PType): PType;
implementation
function pointerOf(typ: PType): PType;
begin
result := newType(unknownLineInfo, tyPtr);
result.baseType := typ;
result.align := platform.PtrSize;
result.size := platform.PtrSize;
end;
function isGarbageCollected(typ: PType): Boolean;
begin
result := typ.Kind in [tyTable, tyRef, tySequence, tyString]
end;
function ReturnsNewThing(op: PNode): Boolean;
var
s: PSym;
begin
result := false;
if op.kind = nkCall then begin
if op.sons[0].kind = nkSym then begin
s := op.sons[0].sym;
result := (sfReturnsNew in s.flags)
end
end
else if op.typ.Kind = tyArrayConstr then
result := true // array constructor returns a newly allocated thing
end;
function containsHiddenPointer(typ: PType): Boolean;
var
t: PType;
i: int;
begin
t := typ;
result := false;
if t = nil then exit;
case t.Kind of
tySequence, tyString, tyTable: result := true;
tyArray, tyArrayConstr, tyOpenArray:
result := containsHiddenPointer(t.baseType);
tySubtype: result := containsHiddenPointer(typ.baseType);
tyRecord, tyObject: begin
if (t.baseType <> nil) and containsHiddenPointer(t.baseType) then
result := true
else
// walk through all fields:
for i := 0 to seqTableLen(t.symList)-1 do
if containsHiddenPointer(seqTableAt(t.symList, i).typ) then begin
result := true; break
end;
end
else result := false
end
end;
function containsGarbageCollectedRef(typ: PType): Boolean;
var
t: PType;
i: int;
begin
t := typ;
result := false;
if t = nil then exit;
case t.Kind of
tySequence, tyRef, tyString, tyTable: result := true;
tyArray: result := containsGarbageCollectedRef(t.baseType);
tyRecord, tyObject: begin
if (t.baseType <> nil) and containsGarbageCollectedRef(t.baseType) then
result := true
else
// walk through all fields:
for i := 0 to seqTableLen(t.symList)-1 do
if containsGarbageCollectedRef(SeqTableAt(t.symList, i).typ) then
begin
result := true; break
end;
end
else result := false
end
end;
function containsObject(typ: PType): Boolean;
var
t: PType;
i: int;
begin
t := typ;
result := false;
if t = nil then exit;
case t.Kind of
tyArray, tyArrayConstr:
result := containsObject(t.baseType);
tyObject: result := true;
tySubtype: result := containsObject(typ.baseType);
tyRecord: begin
// walk through all fields:
for i := 0 to seqTableLen(t.symList)-1 do
if containsObject(SeqTableAt(t.symList, i).typ) then begin
result := true; break
end;
end
else result := false
end
end;
function hasSideEffect(t: PNode): Boolean;
{var
it: PNode; }
begin
result := t.kind in [nkCall, nkArrayConstr, nkRecordConstr, nkSetConstr]
// assume side effect for operations
{
if t.Kind = nkOperation then begin
// this is for function pointers:
if hasSideEffect(t.left) then begin
result := true; exit
end;
it := t.right;
while it <> nil do begin
if hasSideEffect(it) then begin
result := true; exit
end;
it := it.next
end;
result := true
end;
result := false }
end;
end.

View file

@ -60,7 +60,9 @@ type
function nextPowerOfTwo(x: int): int;
begin
result := x -{%} 1;
result := result or (result shr 32);
// complicated, to make it a nop if sizeof(int) == 4,
// because shifting more than 31 bits is undefined in C
result := result or (result shr ((sizeof(int)-4)* 32));
result := result or (result shr 16);
result := result or (result shr 8);
result := result or (result shr 4);

View file

@ -137,6 +137,11 @@ procedure initGeneralTokenizer(var g: TGeneralTokenizer;
begin
{@ignore} fillChar(g, sizeof(g), 0); {@emit}
g.buf := PChar(buf);
g.kind := low(TTokenClass);
g.start := 0;
g.len := 0;
g.pos := 0;
g.state := low(TTokenClass);
end;
procedure deinitGeneralTokenizer(var g: TGeneralTokenizer);

View file

@ -42,8 +42,9 @@ var
j: int;
etyp: PType; // enumeration type
begin
copy := copySym(s, s.owner);
copy.ast := s.ast; // BUGFIX
//copy := copySym(s, true);
//copy.ast := s.ast;
copy := s; // do not copy symbols when importing!
// check if we have already a symbol of the same name:
check := StrTableGet(c.tab.stack[importTablePos], s.name);
if check <> nil then begin
@ -55,17 +56,17 @@ begin
end;
StrTableAdd(c.tab.stack[importTablePos], copy);
if s.kind = skType then begin
// types are special: we need to copy types but need to
// consider private fields
etyp := s.typ;
if etyp.kind = tyEnum then begin
for j := 0 to sonsLen(etyp.n)-1 do begin
e := etyp.n.sons[j].sym;
assert(e.Kind = skEnumField);
rawImportSymbol(c, e)
if (e.Kind = skEnumField) then rawImportSymbol(c, e)
else InternalError(s.info, 'rawImportSymbol');
end
end
end;
end
else if s.kind = skConverter then
addConverter(c, s);
end;
procedure importSymbol(c: PContext; ident: PNode; fromMod: PSym);
@ -73,18 +74,20 @@ var
s, e: PSym;
it: TIdentIter;
begin
assert(ident.kind = nkIdent);
if (ident.kind <> nkIdent) then InternalError(ident.info, 'importSymbol');
s := StrTableGet(fromMod.tab, ident.ident);
if s = nil then
liMessage(ident.info, errUndeclaredIdentifier, ident.ident.s);
assert(s.Kind in ExportableSymKinds);
if not (s.Kind in ExportableSymKinds) then
InternalError(ident.info, 'importSymbol: 2');
// for an enumeration we have to add all identifiers
case s.Kind of
skProc, skIterator, skMacro, skTemplate: begin
// for a overloadable syms add all overloaded routines
skProc, skIterator, skMacro, skTemplate, skConverter: begin
// for a overloadable syms add all overloaded routines
e := InitIdentIter(it, fromMod.tab, s.name);
while e <> nil do begin
assert(e.name.id = s.Name.id);
if (e.name.id <> s.Name.id) then
InternalError(ident.info, 'importSymbol: 3');
rawImportSymbol(c, e);
e := NextIdentIter(it, fromMod.tab);
end
@ -101,8 +104,11 @@ begin
s := InitTabIter(i, fromMod.tab);
while s <> nil do begin
if s.kind <> skModule then begin
assert(s.Kind in ExportableSymKinds);
rawImportSymbol(c, s); // this is correct!
if s.kind <> skEnumField then begin
if not (s.Kind in ExportableSymKinds) then
InternalError(s.info, 'importAllSymbols');
rawImportSymbol(c, s); // this is correct!
end
end;
s := NextIter(i, fromMod.tab)
end
@ -129,6 +135,7 @@ var
i: int;
begin
result := n;
checkMinSonsLen(n, 2);
m := c.ImportModule(getModuleFile(n.sons[0]), c.b);
n.sons[0] := newSymNode(m);
addDecl(c, m); // add symbol to symbol table of module
@ -140,7 +147,7 @@ var
i: int;
x: PNode;
begin
result := newNode(nkStmtList);
result := newNodeI(nkStmtList, n.info);
for i := 0 to sonsLen(n)-1 do begin
x := c.includeFile(getModuleFile(n.sons[i]));
x := semStmt(c, x);

View file

@ -21,11 +21,12 @@ type
newOwner: PSym;
instantiator: TLineInfo;
end;
PInstClosure = ^TInstantiateClosure;
PInstantiateClosure = ^TInstantiateClosure;
PInstClosure = PInstantiateClosure;
function instantiateTree(var c: TInstantiateClosure; t: PNode): PNode; forward;
function instantiateSym(var c: TInstantiateClosure; sym: PSym): PSym; forward;
function instantiateTree(c: PInstantiateClosure; t: PNode): PNode; forward;
function instantiateSym(c: PInstantiateClosure; sym: PSym): PSym; forward;
function instantiateType(c: PInstantiateClosure; typ: PType): PType; forward;
function containsGenericTypeIter(t: PType; closure: PObject): bool;
begin
@ -37,35 +38,58 @@ begin
result := iterOverType(t, containsGenericTypeIter, nil);
end;
function instantiateTypeMutator(typ: PType; c: PObject): PType;
function instTypeNode(c: PInstantiateClosure; n: PNode): PNode;
var
i: int;
begin
result := PType(idTableGet(PInstClosure(c).mapping, typ));
result := nil;
if n <> nil then begin
result := copyNode(n);
result.typ := instantiateType(c, n.typ);
case n.kind of
nkNone..nkNilLit: begin // a leaf
end;
else begin
for i := 0 to sonsLen(n)-1 do
addSon(result, instTypeNode(c, n.sons[i]));
end
end
end
end;
function instantiateType(c: PInstantiateClosure; typ: PType): PType;
var
i: int;
begin
result := PType(idTableGet(c.mapping, typ));
if result <> nil then exit;
if containsGenericType(typ) then begin
result := copyType(typ, PInstClosure(c).newOwner);
idTablePut(PInstClosure(c).mapping, typ, result)
result := copyType(typ, c.newOwner);
idTablePut(c.mapping, typ, result); // to avoid cycles
for i := 0 to sonsLen(result)-1 do
result.sons[i] := instantiateType(c, result.sons[i]);
if result.n <> nil then
result.n := instTypeNode(c, result.n);
end
else
result := typ;
if result.Kind in GenericTypes then begin
liMessage(PInstClosure(c).instantiator, errCannotInstantiateX,
liMessage(c.instantiator, errCannotInstantiateX,
TypeToString(typ, preferName));
end
else if result.kind = tyVar then begin
if result.sons[0].kind = tyVar then
liMessage(c.instantiator, errVarVarTypeNotAllowed);
end;
end;
function instantiateType(var c: TInstantiateClosure; typ: PType): PType;
begin
result := mutateType(typ, instantiateTypeMutator, {@cast}PObject(addr(c)));
end;
function instantiateSym(var c: TInstantiateClosure; sym: PSym): PSym;
function instantiateSym(c: PInstantiateClosure; sym: PSym): PSym;
begin
if sym = nil then begin result := nil; exit end; // BUGFIX
result := PSym(idTableGet(c.mapping, sym));
if (result = nil) then begin
if (sym.owner.id = c.fn.id) or (sym.id = c.fn.id) then begin
result := copySym(sym, nil);
result := copySym(sym);
if sym.id = c.fn.id then c.newOwner := result;
include(result.flags, sfIsCopy);
idTablePut(c.mapping, sym, result); // BUGFIX
@ -83,7 +107,7 @@ begin
end
end;
function instantiateTree(var c: TInstantiateClosure; t: PNode): PNode;
function instantiateTree(c: PInstantiateClosure; t: PNode): PNode;
var
len, i: int;
begin
@ -124,7 +148,8 @@ begin
q := n.sons[i].sym;
s := newSym(skType, q.name, getCurrOwner(c));
t := PType(IdTableGet(pt, q.typ));
if t = nil then liMessage(n.sons[i].info, errCannotInstantiateX, s.name.s);
if t = nil then
liMessage(n.sons[i].info, errCannotInstantiateX, s.name.s);
assert(t.kind <> tyGenericParam);
s.typ := t;
addDecl(c, s);
@ -138,7 +163,8 @@ var
begin
result := nil;
for i := 0 to sonsLen(c.generics)-1 do begin
assert(c.generics.sons[i].kind = nkExprEqExpr);
if c.generics.sons[i].kind <> nkExprEqExpr then
InternalError(genericSym.info, 'GenericCacheGet');
a := c.generics.sons[i].sons[0].sym;
if genericSym.id = a.id then begin
b := c.generics.sons[i].sons[1].sym;
@ -173,8 +199,8 @@ var
n: PNode;
begin
oldP := c.p; // restore later
result := copySym(fn, getCurrOwner(c));
result.id := getId();
result := copySym(fn);
result.owner := getCurrOwner(c);
n := copyTree(fn.ast);
result.ast := n;
pushOwner(c, result);
@ -202,7 +228,7 @@ begin
addDecl(c, result);
if n.sons[codePos] <> nil then begin
c.p := newProcCon(result);
if result.kind = skProc then begin
if result.kind in [skProc, skConverter] then begin
addResult(c, result.typ.sons[0], n.info);
addResultNode(c, n);
end;
@ -221,8 +247,12 @@ end;
function generateTypeInstance(p: PContext; const pt: TIdTable;
const instantiator: TLineInfo; t: PType): PType;
var
c: TInstantiateClosure;
c: PInstantiateClosure;
begin
new(c);
{@ignore}
fillChar(c^, sizeof(c^), 0);
{@emit}
c.mapping := pt; // making a copy is not necessary
c.fn := nil;
c.instantiator := instantiator;

View file

@ -227,7 +227,7 @@ begin
L.linenumber := 1; // lines start at 1
L.fileOpened := false;
if L.bufLen > 0 then begin
copyMem(L.buf, addr(buffer[strStart]), L.bufLen);
copyMem(L.buf, {@cast}pointer(buffer), L.bufLen);
L.buf[L.bufLen-1] := EndOfFile;
end
else

View file

@ -12,8 +12,7 @@
function getSymRepr(s: PSym): string;
begin
case s.kind of
skProc, skConverter, skIterator:
result := getProcHeader(s);
skProc, skConverter, skIterator: result := getProcHeader(s);
else result := s.name.s
end
end;
@ -24,7 +23,7 @@ var
s: PSym;
begin
// check if all symbols have been used and defined:
assert(tab.tos <= length(tab.stack));
if (tab.tos > length(tab.stack)) then InternalError('CloseScope');
s := InitTabIter(it, tab.stack[tab.tos-1]);
while s <> nil do begin
if sfForward in s.flags then
@ -59,7 +58,8 @@ procedure addOverloadableSymAt(c: PContext; fn: PSym; at: Natural);
var
check: PSym;
begin
assert(fn.kind in OverloadableSyms);
if not (fn.kind in OverloadableSyms) then
InternalError(fn.info, 'addOverloadableSymAt');
check := StrTableGet(c.tab.stack[at], fn.name);
if (check <> nil) and (check.Kind <> fn.kind) then
liMessage(fn.info, errAttemptToRedefine, fn.Name.s);
@ -70,7 +70,7 @@ procedure AddInterfaceDeclAux(c: PContext; sym: PSym);
begin
if (sfInInterface in sym.flags) then begin
// add to interface:
assert(c.module <> nil);
if c.module = nil then InternalError(sym.info, 'AddInterfaceDeclAux');
StrTableAdd(c.module.tab, sym);
end;
if getCurrOwner(c).kind = skModule then
@ -92,12 +92,21 @@ end;
function lookUp(c: PContext; n: PNode): PSym;
// Looks up a symbol. Generates an error in case of nil.
begin
if n.kind = nkAccQuoted then result := lookup(c, n.sons[0])
else begin
assert(n.kind = nkIdent);
result := SymtabGet(c.Tab, n.ident);
if result = nil then liMessage(n.info, errUndeclaredIdentifier, n.ident.s);
include(result.flags, sfUsed);
case n.kind of
nkAccQuoted: result := lookup(c, n.sons[0]);
nkSym: begin
result := SymtabGet(c.Tab, n.sym.name);
if result = nil then
liMessage(n.info, errUndeclaredIdentifier, n.sym.name.s);
include(result.flags, sfUsed);
end;
nkIdent: begin
result := SymtabGet(c.Tab, n.ident);
if result = nil then
liMessage(n.info, errUndeclaredIdentifier, n.ident.s);
include(result.flags, sfUsed);
end
else InternalError(n.info, 'lookUp');
end
end;
@ -115,6 +124,14 @@ begin
and StrTableContains(c.AmbigiousSymbols, result) then
liMessage(n.info, errUseQualifier, n.ident.s)
end;
nkSym: begin
result := SymtabGet(c.Tab, n.sym.name);
if result = nil then
liMessage(n.info, errUndeclaredIdentifier, n.sym.name.s)
else if ambigiousCheck
and StrTableContains(c.AmbigiousSymbols, result) then
liMessage(n.info, errUseQualifier, n.sym.name.s)
end;
nkDotExpr, nkQualified: begin
result := nil;
m := qualifiedLookUp(c, n.sons[0], false);
@ -165,6 +182,15 @@ begin
result := InitIdentIter(o.it, c.tab.stack[o.stackPtr], n.ident);
end;
end;
nkSym: begin
o.stackPtr := c.tab.tos;
o.mode := oimNoQualifier;
while (result = nil) do begin
dec(o.stackPtr);
if o.stackPtr < 0 then break;
result := InitIdentIter(o.it, c.tab.stack[o.stackPtr], n.sym.name);
end;
end;
nkDotExpr, nkQualified: begin
o.mode := oimOtherModule;
o.m := qualifiedLookUp(c, n.sons[0], false);
@ -199,7 +225,8 @@ begin
while (result = nil) do begin
dec(o.stackPtr);
if o.stackPtr < 0 then break;
result := InitIdentIter(o.it, c.tab.stack[o.stackPtr], n.ident);
result := InitIdentIter(o.it, c.tab.stack[o.stackPtr], o.it.name);
// BUGFIX: o.it.name <-> n.ident
end
end
else result := nil;

View file

@ -17,7 +17,8 @@ interface
uses
nsystem, strutils, ast, astalgo, scanner, pnimsyn, rnimsyn, options, msgs,
nos, lists, condsyms, paslex, pasparse, rodgen, ropes, trees,
wordrecg, sem, idents, magicsys, backends, docgen, extccomp, cgen;
wordrecg, sem, idents, magicsys, backends, docgen, extccomp, cgen,
platform, ecmasgen;
procedure MainCommand(const cmd, filename: string);
@ -109,7 +110,9 @@ begin
// compile the module
// XXX: here caching could be implemented
result := compileModule(filename, backend, false, false);
end;
end
else if sfSystemModule in result.flags then
liMessage(result.info, errAttemptToRedefine, result.Name.s);
end;
function CompileModule(const filename: string; backend: PBackend;
@ -131,8 +134,8 @@ begin
openScope(c.tab); // scope for imported symbols
SymTabAdd(c.tab, result);
if not isSystemFile then begin
importAllSymbols(c, magicsys.SystemModule);
SymTabAdd(c.tab, magicsys.SystemModule); // import the "System" identifier
importAllSymbols(c, magicsys.SystemModule);
SymTabAdd(c.tab, newIsMainModuleSym(result, isMainFile));
end
else begin
@ -142,7 +145,6 @@ begin
end;
{@discard} semModule(c, ast);
rawCloseScope(c.tab); // imported symbols; don't check for unused ones!
// XXX: compile the generated generic procs!
msgCompiled(result.name.s);
end;
@ -161,8 +163,8 @@ var
procedure addDependencyAux(importing, imported: PSym);
begin
appRopeFormat(gDotGraph, '$1 -> $2;$n', [toRope(importing.name.s),
toRope(imported.name.s)]);
appf(gDotGraph, '$1 -> $2;$n', [toRope(importing.name.s),
toRope(imported.name.s)]);
// s1 -> s2_4 [label="[0-9]"];
end;
@ -193,7 +195,7 @@ end;
procedure generateDot(const project: string);
begin
writeRope(
ropeFormat('digraph $1 {$n$2}$n', [
ropef('digraph $1 {$n$2}$n', [
toRope(changeFileExt(extractFileName(project), '')), gDotGraph]),
changeFileExt(project, 'dot') );
end;
@ -257,6 +259,14 @@ begin
extccomp.CallCCompiler(changeFileExt(filename, ''));
end;
procedure CommandCompileToEcmaScript(const filename: string);
begin
include(gGlobalOptions, optSafeCode);
setTarget(osEcmaScript, cpuEcmaScript);
initDefines();
compileProject(filename, EcmasBackend(nil, nil, filename));
end;
// --------------------------------------------------------------------------
procedure exSymbols(n: PNode);
@ -279,7 +289,7 @@ begin
for i := 0 to sonsLen(n)-1 do begin
exSymbol(n.sons[i].sons[0]);
if (n.sons[i].sons[2] <> nil) and
(n.sons[i].sons[2].kind in [nkRecordTy, nkObjectTy]) then
(n.sons[i].sons[2].kind = nkObjectTy) then
fixRecordDef(n.sons[i].sons[2])
end
end;
@ -406,6 +416,11 @@ begin
wantFile(filename);
CommandCompileToC(filename);
end;
wCompileToEcmaScript: begin
gCmd := cmdCompileToEcmaScript;
wantFile(filename);
CommandCompileToEcmaScript(filename);
end;
wPretty: begin
// compile means compileToC currently
gCmd := cmdPretty;

View file

@ -74,10 +74,6 @@ type
errTokenExpected,
errStringAfterIncludeExpected,
errRecursiveInclude,
errAtIfExpected,
errAtIfExpectedBeforeElse,
errAtIfExpectedBeforeElif,
errAtEndExpected,
errOnOrOffExpected,
errNoneSpeedOrSizeExpected,
errInvalidPragma,
@ -186,7 +182,7 @@ type
errSizeTooBig,
errSetTooBig,
errBaseTypeMustBeOrdinal,
errInheritanceOnlyWithObjects,
errInheritanceOnlyWithNonFinalObjects,
errInheritanceOnlyWithEnums,
errIllegalRecursionInTypeX,
errCannotInstantiateX,
@ -267,6 +263,20 @@ type
errWhitespaceExpected,
errXisNoValidIndexFile,
errCannotRenderX,
errVarVarTypeNotAllowed,
errIsExpectsTwoArguments,
errIsExpectsObjectTypes,
errXcanNeverBeOfThisSubtype,
errTooManyIterations,
errCannotInterpretNodeX,
errFieldXNotFound,
errInvalidConversionFromTypeX,
errAssertionFailed,
errCannotGenerateCodeForX,
errXNeedsReturnType,
errXRequiresOneArgument,
errUnhandledExceptionX,
errCyclicTree,
errUser,
warnCannotOpenFile,
warnOctalEscape,
@ -291,6 +301,8 @@ type
hintMo2FileInvalid,
hintModuleHasChanged,
hintCannotOpenMo2File,
hintQuitCalled,
hintProcessing,
hintUser);
const
@ -310,7 +322,7 @@ const
'invalid token: $1',
'line too long',
'$1 is not a valid number',
'$1 is too large or too small',
'number $1 out of valid range',
'\n not allowed in character literal',
'closing '']'' expected, but end of file reached',
'missing final ''',
@ -319,10 +331,6 @@ const
'''$1'' expected',
'string after ''include'' expected',
'recursive include file: ''$1''',
'''@if'' expected',
'''@if'' expected before ''@else''',
'''@if'' expected before ''@elif''',
'''@end'' expected',
'''on'' or ''off'' expected',
'''none'', ''speed'' or ''size'' expected',
'invalid pragma',
@ -431,12 +439,12 @@ const
'computing the type''s size produced an overflow',
'set is too large',
'base type of a set must be an ordinal',
'inheritance only works with an object',
'inheritance only works non-final objects',
'inheritance only works with an enum',
'illegal recursion in type ''$1''',
'cannot instantiate: ''$1''',
'expression has no address',
'to an out parameter a variable needs to be passed',
'for a ''var'' type a variable needs to be passed',
'type mismatch',
'type mismatch: got (',
'but expected one of: ',
@ -512,6 +520,20 @@ const
'whitespace expected, got ''$1''',
'''$1'' is no valid index file',
'cannot render reStructuredText element ''$1''',
'type ''var var'' is not allowed',
'''is'' expects two arguments',
'''is'' expects object types',
'''$1'' can never be of this subtype',
'interpretation requires too many iterations',
'cannot interpret node kind ''$1''',
'field ''$1'' cannot be found',
'invalid conversion from type ''$1''',
'assertion failed',
'cannot generate code for ''$1''',
'converter needs return type',
'converter requires one parameter',
'unhandled exception: $1',
'macro returned a cyclic abstract syntax tree',
'$1',
'cannot open ''$1'' [CannotOpenFile]',
'octal escape sequences do not exist; leading zero is ignored [OctalEscape]',
@ -536,6 +558,8 @@ const
'mo2 file ''$1'' is invalid [Mo2FileInvalid]',
'module ''$1'' has been changed [ModuleHasChanged]',
'mo2 file ''$1'' does not exist [CannotOpenMo2File]',
'quit() called [QuitCalled]',
'processing [Processing]',
'$1 [User]'
);
const
@ -556,7 +580,7 @@ const
'User'
);
const
HintsToStr: array [0..9] of string = (
HintsToStr: array [0..11] of string = (
'Success',
'LineTooLong',
'XDeclaredButNotUsed',
@ -566,6 +590,8 @@ const
'Mo2FileInvalid',
'ModuleHasChanged',
'CannotOpenMo2File',
'QuitCalled',
'Processing',
'User'
);
//[[[end]]]
@ -593,12 +619,7 @@ type
fileIndex: int32;
end;
const
UnknownLineInfo: TLineInfo = (
line: -1;
col: -1;
fileIndex: -1;
);
function UnknownLineInfo(): TLineInfo;
var
gNotes: TNoteKinds = [low(TNoteKind)..high(TNoteKind)];
@ -649,6 +670,13 @@ procedure popInfoContext;
implementation
function UnknownLineInfo(): TLineInfo;
begin
result.line := -1;
result.col := -1;
result.fileIndex := -1;
end;
{@ignore}
var
filenames: array of string;
@ -782,12 +810,13 @@ end;
procedure handleError(const msg: TMsgKind);
begin
if (msg >= fatalMin) and (msg <= fatalMax) then begin
assert(false); halt(1)
if optVerbose in gGlobalOptions then assert(false);
halt(1)
end;
if (msg >= errMin) and (msg <= errMax) then begin
inc(gErrorCounter);
if gErrorCounter >= gErrorMax then begin
assert(false); // stack trace for debugging
if optVerbose in gGlobalOptions then assert(false);
halt(1) // one error stops the compiler
end
end
@ -797,7 +826,7 @@ procedure writeContext;
var
i: int;
begin
for i := length(msgContext)-1 downto 0 do begin
for i := 0 to length(msgContext)-1 do begin
MessageOut(Format(posErrorFormat, [toFilename(msgContext[i]),
coordToStr(msgContext[i].line),
coordToStr(msgContext[i].col),

View file

@ -101,7 +101,7 @@ var
procedure doEnd(var L: TLexer; tok: PToken);
begin
if high(condStack) < 0 then lexMessage(L, errAtIfExpected);
if high(condStack) < 0 then lexMessage(L, errTokenExpected, '@if');
ppGetTok(L, tok); // skip 'end'
setLength(condStack, high(condStack))
end;
@ -114,7 +114,7 @@ procedure jumpToDirective(var L: TLexer; tok: PToken; dest: TJumpDest); forward;
procedure doElse(var L: TLexer; tok: PToken);
begin
if high(condStack) < 0 then
lexMessage(L, errAtIfExpectedBeforeElse);
lexMessage(L, errTokenExpected, '@if');
ppGetTok(L, tok);
if tok.tokType = tkColon then ppGetTok(L, tok);
if condStack[high(condStack)] then
@ -126,7 +126,7 @@ var
res: bool;
begin
if high(condStack) < 0 then
lexMessage(L, errAtIfExpectedBeforeElif);
lexMessage(L, errTokenExpected, '@if');
res := EvalppIf(L, tok);
if condStack[high(condStack)] or not res then
jumpToDirective(L, tok, jdElseEndif)
@ -168,7 +168,7 @@ begin
ppGetTok(L, tok)
end
else if tok.tokType = tkEof then
lexMessage(L, errAtEndExpected)
lexMessage(L, errTokenExpected, '@end')
else
ppGetTok(L, tok)
end
@ -303,7 +303,7 @@ begin
while tok.tokType <> tkEof do
parseAssignment(L, tok);
if length(condStack) > 0 then
lexMessage(L, errAtEndExpected);
lexMessage(L, errTokenExpected, '@end');
closeLexer(L)
end
end;

View file

@ -6,7 +6,7 @@
// See the file "copying.txt", included in this
// distribution, for details about the copyright.
//
program nim;
program nimrod;
{$include 'config.inc'}
{@ignore}
@ -18,39 +18,37 @@ program nim;
uses
nsystem,
charsets, sysutils, commands, scanner, condsyms, options, msgs, nversion,
nimconf, ropes, extccomp, strutils, nos, platform, main;
nimconf, ropes, extccomp, strutils, nos, platform, main, parseopt;
var
arguments: string = ''; // the arguments to be passed to the program that
// should be run
cmdLineInfo: TLineInfo;
function ProcessCmdLine(pass: TCmdLinePass): string;
procedure ProcessCmdLine(pass: TCmdLinePass; var command, filename: string);
var
i, paramCounter: int;
param: string;
p: TOptParser;
begin
i := 1;
result := '';
paramCounter := paramCount();
while i <= paramCounter do begin
param := ParamStr(i);
if param[strStart] = '-' then begin
commands.ProcessCommand(param, pass);
p := parseopt.init();
while true do begin
parseopt.next(p);
case p.kind of
cmdEnd: break;
cmdLongOption, cmdShortOption:
ProcessSwitch(p.key, p.val, pass, cmdLineInfo);
cmdArgument: begin
if command = '' then command := p.key
else if filename = '' then begin
filename := unixToNativePath(p.key);
// BUGFIX for portable build scripts
break
end
end
end
else if i > 1 then begin
result := unixToNativePath(param); // BUGFIX for portable build scripts
options.compilerArgs := i;
break // do not process the arguments
end;
Inc(i)
end;
inc(i); // skip program file
// collect the arguments:
if pass = passCmd2 then begin
while i <= paramCounter do begin
arguments := arguments + ' ' +{&} paramStr(i);
inc(i)
end;
arguments := getRestOfCommandLine(p);
if not (optRun in gGlobalOptions) and (arguments <> '') then
rawMessage(errArgsNeedRunOption);
end
@ -58,42 +56,36 @@ end;
procedure HandleCmdLine;
var
inp: string;
command, filename: string;
begin
if paramCount() = 0 then
writeCommandLineUsage()
else begin
// Process command line arguments:
inp := ProcessCmdLine(passCmd1);
if inp <> '' then begin
command := '';
filename := '';
ProcessCmdLine(passCmd1, command, filename);
if filename <> '' then begin
if gCmd = cmdInterpret then DefineSymbol('interpreting');
nimconf.LoadConfig(inp); // load the right config file
nimconf.LoadConfig(filename); // load the right config file
// now process command line arguments again, because some options in the
// command line can overwite the config file's settings
extccomp.initVars();
inp := ProcessCmdLine(passCmd2);
command := '';
filename := '';
ProcessCmdLine(passCmd2, command, filename);
end;
MainCommand(paramStr(1), inp);
MainCommand(command, filename);
if (gCmd <> cmdInterpret) and (msgs.gErrorCounter = 0) then
rawMessage(hintSuccess);
if optRun in gGlobalOptions then
execExternalProgram(changeFileExt(inp, '') +{&} arguments)
execExternalProgram(changeFileExt(filename, '') +{&} ' ' +{&} arguments)
end
end;
{@ignore}
var
Saved8087CW: Word;
{@emit}
begin
{@ignore}
Saved8087CW := Default8087CW;
Set8087CW($133f); // Disable all fpu exceptions
{@emit}
cmdLineInfo := newLineInfo('command line', -1, -1);
condsyms.InitDefines();
HandleCmdLine();
{@ignore}
Set8087CW(Saved8087CW);
{@emit}
halt(options.gExitcode);
end.

View file

@ -49,7 +49,7 @@ function inSet(s: PNode; const elem: PNode): Boolean;
var
i: int;
begin
assert(s.kind in [nkSetConstr, nkConstSetConstr]);
if s.kind <> nkCurly then InternalError(s.info, 'inSet');
for i := 0 to sonsLen(s)-1 do
if s.sons[i].kind = nkRange then begin
if leValue(s.sons[i].sons[0], elem)
@ -95,7 +95,7 @@ function SomeInSet(s: PNode; const a, b: PNode): Boolean;
var
i: int;
begin
assert(s.kind in [nkSetConstr, nkConstSetConstr]);
if s.kind <> nkCurly then InternalError(s.info, 'SomeInSet');
for i := 0 to sonsLen(s)-1 do
if s.sons[i].kind = nkRange then begin
if leValue(s.sons[i].sons[0], b)
@ -142,7 +142,7 @@ var
begin
elemType := settype.sons[0];
first := firstOrd(elemType);
result := newNode(nkConstSetConstr);
result := newNode(nkCurly);
result.typ := settype;
result.info := info;
@ -244,7 +244,7 @@ function SetHasRange(s: PNode): Boolean;
var
i: int;
begin
assert(s.kind in [nkSetConstr, nkConstSetConstr]);
if s.kind <> nkCurly then InternalError(s.info, 'SetHasRange');
for i := 0 to sonsLen(s)-1 do
if s.sons[i].kind = nkRange then begin
result := true; exit

View file

@ -22,8 +22,8 @@ uses
{$ifdef mswindows}
windows,
{$else}
unix,
dos,
unix,
{$endif}
strutils,
nsystem;
@ -83,6 +83,14 @@ function sameFile(const path1, path2: string): boolean;
implementation
function UnixToNativePath(const path: string): string;
begin
if dirSep <> '/' then
result := replaceStr(path, '/', dirSep)
else
result := path;
end;
function expandFilename(filename: string): string;
begin
result := sysutils.expandFilename(filename)
@ -90,16 +98,8 @@ end;
function sameFile(const path1, path2: string): boolean;
begin
result := cmpIgnoreCase(expandFilename(path1),
expandFilename(path2)) = 0;
end;
function UnixToNativePath(const path: string): string;
begin
if dirSep <> '/' then
result := replaceStr(path, '/', dirSep)
else
result := path;
result := cmpIgnoreCase(expandFilename(UnixToNativePath(path1)),
expandFilename(UnixToNativePath(path2))) = 0;
end;
procedure createDir(dir: string);
@ -417,8 +417,9 @@ begin
SI.hStdError := GetStdHandle(STD_ERROR_HANDLE);
SI.hStdInput := GetStdHandle(STD_INPUT_HANDLE);
SI.hStdOutput := GetStdHandle(STD_OUTPUT_HANDLE);
if not Windows.CreateProcess(nil, PChar(cmd), nil, nil, true,
NORMAL_PRIORITY_CLASS, Windows.GetEnvironmentStrings(), nil, SI, ProcInfo)
if not Windows.CreateProcess(nil, PChar(cmd), nil, nil, false,
NORMAL_PRIORITY_CLASS, nil {Windows.GetEnvironmentStrings()},
nil, SI, ProcInfo)
then
result := getLastError()
else begin
@ -435,11 +436,19 @@ begin
end;
{$else}
{$ifdef windows}
function executeProcess(const cmd: string): int;
begin
result := dos.Exec(cmd, '')
end;
//C:\Eigenes\compiler\MinGW\bin;
{$else}
// fpc has a portable function for this
function executeProcess(const cmd: string): int;
begin
result := shell(cmd);
end;
{$endif}
{$endif}
{$ifdef windows}

View file

@ -90,10 +90,11 @@ type
TAddress = longint;
{$endif}
var
NaN: float;
inf: float;
NegInf: float;
{$ifdef fpc}
const
inf = math.Infinity;
NegInf = -inf;
{$else}
{$ifopt Q+}
{$define Q_on}
@ -150,6 +151,10 @@ function shlU(a, b: biggestInt): biggestInt;
function shrU(a, b: biggestInt): biggestInt;
function ltU(a, b: biggestInt): bool;
function leU(a, b: biggestInt): bool;
function toU8(a: biggestInt): byte;
function toU32(a: biggestInt): int32;
function ze64(a: byte): biggestInt;
{@emit}
function alloc(size: int): Pointer;
@ -257,6 +262,23 @@ function leU(a, b: biggestInt): bool;
begin
result := biggestUInt(a) < biggestUInt(b);
end;
function toU8(a: biggestInt): byte;
begin
assert(a >= 0);
assert(a <= 255);
result := a;
end;
function toU32(a: biggestInt): int32;
begin
result := int32(a and $ffffffff);
end;
function ze64(a: byte): biggestInt;
begin
result := a
end;
{@emit}
procedure addChar(var s: string; c: Char);
@ -486,4 +508,21 @@ end;
{$ifdef I_on} {$undef I_on} {$I+} {$endif}
{$ifopt R+} {$R-,Q-} {$define R_on} {$endif}
var
zero: float;
Saved8087CW: Word;
initialization
Saved8087CW := Default8087CW;
Set8087CW($133f); // Disable all fpu exceptions
zero := 0.0;
NaN := 0.0 / zero;
inf := 1.0 / zero;
NegInf := -inf;
finalization
Set8087CW(Saved8087CW);
{$ifdef R_on}
{$R+,Q+}
{$endif}
end.

View file

@ -18,22 +18,32 @@ interface
uses
strutils;
// the Pascal version number gets a little star ('*'), the Nimrod version
// does not! This helps distinguishing the different builds.
{@ignore}
const
VersionStar = '*'+'';
{@emit
const
VersionStar = '';
}
const
MaxSetElements = 1 shl 16; // (2^16) to support unicode character sets?
defaultAsmMarkerSymbol = '!';
//[[[cog
//from koch import NIMROD_VERSION
//cog.outl("VersionAsString = '%s';" % NIMROD_VERSION)
//cog.outl("VersionAsString = '%s'+VersionStar;" % NIMROD_VERSION)
//ver = NIMROD_VERSION.split('.')
//cog.outl('VersionMajor = %s;' % ver[0])
//cog.outl('VersionMinor = %s;' % ver[1])
//cog.outl('VersionPatch = %s;' % ver[2])
//]]]
VersionAsString = '0.5.1';
VersionAsString = '0.6.0'+VersionStar;
VersionMajor = 0;
VersionMinor = 5;
VersionPatch = 1;
VersionMinor = 6;
VersionPatch = 0;
//[[[[end]]]]
implementation

34
nim/optast.pas Normal file
View file

@ -0,0 +1,34 @@
//
//
// The Nimrod Compiler
// (c) Copyright 2008 Andreas Rumpf
//
// See the file "copying.txt", included in this
// distribution, for details about the copyright.
//
unit optast;
// Optimizations that can be done by AST transformations. The code generators
// should work without the optimizer. The optimizer does the following:
// - cross-module constant merging
// - cross-module generic merging
// - lowers set operations to bit operations
// - inlining of procs
// - ``s == ""`` --> ``len(s) == 0``
// - optimization of ``&`` string operator
interface
{$include 'config.inc'}
uses
nsystem, ast, astalgo, strutils, hashes, trees, treetab, platform, magicsys,
options, msgs, crc, idents, lists, types, ropes, nmath, wordrecg, rnimsyn;
implementation
end.

View file

@ -13,12 +13,14 @@ interface
{$include 'config.inc'}
uses
nsystem, nos, lists, strutils;
nsystem, nos, lists, strutils, strtabs;
type
// please make sure we have under 32 options
// (improves code efficiency a lot!)
TOption = (optNone, optRangeCheck,
TOption = (optNone,
optObjCheck,
optFieldCheck, optRangeCheck,
optBoundsCheck, optOverflowCheck, optNilCheck, optAssert, optLineDir,
optWarns, optHints,
optOptimizeSpeed,
@ -56,6 +58,7 @@ type
cmdNone,
cmdCompileToC,
cmdCompileToCpp,
cmdCompileToEcmaScript,
cmdInterpret,
cmdPretty,
cmdDoc,
@ -69,32 +72,27 @@ type
cmdDebugTrans, // debug a transformation pass
cmdRst2html // convert a reStructuredText file to HTML
);
TNumericalBase = (base10, // base10 is listed as the first element,
// so that it is the correct default value
base2,
base8,
base16);
TStringSeq = array of string;
const
ChecksOptions = {@set}[optRangeCheck, optNilCheck, optOverflowCheck,
optBoundsCheck, optAssert];
ChecksOptions = {@set}[optObjCheck, optFieldCheck, optRangeCheck,
optNilCheck, optOverflowCheck, optBoundsCheck,
optAssert];
optionToStr: array [TOption] of string = (
'optNone', 'optRangeCheck',
'optNone', 'optObjCheck', 'optFieldCheck', 'optRangeCheck',
'optBoundsCheck', 'optOverflowCheck', 'optNilCheck', 'optAssert',
'optLineDir', 'optWarns', 'optHints', 'optOptimizeSpeed',
'optOptimizeSize', 'optStackTrace', 'optLineTrace', 'optEmdb',
'optByRef', 'optCheckpoints'
);
var
gOptions: TOptions = {@set}[optRangeCheck, optBoundsCheck, optOverflowCheck,
gOptions: TOptions = {@set}[optObjCheck, optFieldCheck, optRangeCheck,
optBoundsCheck, optOverflowCheck,
optAssert, optWarns, optHints, optLineDir,
optStackTrace, optLineTrace];
gGlobalOptions: TGlobalOptions = {@set}[optRefcGC];
compilerArgs: int;
gExitcode: Byte;
searchPaths: TLinkedList;
outFile: string = '';
@ -124,22 +122,15 @@ function getPrefixDir: string;
// gets the application directory
// additional configuration variables:
type
TPair = record
key, val: string;
end;
TPairs = array of TPair;
TStringSeq = array of string;
var
gConfigVars: TPairs = {@ignore} nil {@emit []};
gConfigVars: PStringTable;
libpath: string = '';
gKeepComments: boolean = true; // whether the parser needs to keep comments
gImplicitMods: TStringSeq = {@ignore} nil {@emit []};
// modules that are to be implicitly imported
procedure setConfigVar(const key, val: string);
function getConfigVar(const key: string): string;
procedure setConfigVar(const key, val: string);
procedure addImplicitMod(const filename: string);
@ -149,6 +140,16 @@ function binaryStrSearch(const x: array of string; const y: string): int;
implementation
function getConfigVar(const key: string): string;
begin
result := strtabs.get(gConfigVars, key);
end;
procedure setConfigVar(const key, val: string);
begin
strtabs.put(gConfigVars, key, val);
end;
function getOutFile(const filename, ext: string): string;
begin
if options.outFile <> '' then result := options.outFile
@ -172,38 +173,6 @@ begin
SplitPath(appdir, result, bin);
end;
function getConfigIdx(const key: string): int;
var
i: int;
begin
for i := 0 to high(gConfigVars) do
if cmpIgnoreStyle(gConfigVars[i].key, key) = 0 then begin
result := i; exit end;
result := -1
end;
function getConfigVar(const key: string): string;
var
i: int;
begin
i := getConfigIdx(key);
if i >= 0 then result := gConfigVars[i].val
else result := ''
end;
procedure setConfigVar(const key, val: string);
var
i: int;
begin
i := getConfigIdx(key);
if i < 0 then begin
i := length(gConfigVars);
setLength(gConfigVars, i+1);
gConfigVars[i].key := key
end;
gConfigVars[i].val := val
end;
function toGeneratedFile(const path, ext: string): string;
var
head, tail: string;
@ -261,4 +230,6 @@ begin
result := -1
end;
initialization
gConfigVars := newStringTable([], modeStyleInsensitive);
end.

414
nim/parsecfg.pas Normal file
View file

@ -0,0 +1,414 @@
//
//
// Nimrod's Runtime Library
// (c) Copyright 2008 Andreas Rumpf
//
// See the file "copying.txt", included in this
// distribution, for details about the copyright.
//
unit parsecfg;
// A HIGH-PERFORMANCE configuration file parser;
// the Nimrod version of this file will become part
// of the standard library.
interface
{$include 'config.inc'}
uses
charsets, nsystem, sysutils, hashes, strutils, lexbase;
type
TCfgEventKind = (
cfgEof, // end of file reached
cfgSectionStart, // a ``[section]`` has been parsed
cfgKeyValuePair, // a ``key=value`` pair has been detected
cfgOption, // a ``--key=value`` command line option
cfgError // an error ocurred during parsing; msg contains the
// error message
);
TCfgEvent = {@ignore} record
kind: TCfgEventKind;
section: string;
key, value: string;
msg: string;
end;
{@emit object(NObject)
case kind: TCfgEventKind of
cfgSection: (section: string);
cfgKeyValuePair, cfgOption: (key, value: string);
cfgError: (msg: string);
end;}
TTokKind = (tkInvalid, tkEof, // order is important here!
tkSymbol, tkEquals, tkColon,
tkBracketLe, tkBracketRi, tkDashDash
);
TToken = record // a token
kind: TTokKind; // the type of the token
literal: string; // the parsed (string) literal
end;
TParserState = (startState, commaState);
TCfgParser = object(TBaseLexer)
tok: TToken;
state: TParserState;
filename: string;
end;
function Open(var c: TCfgParser; const filename: string): bool;
procedure OpenFromBuffer(var c: TCfgParser; const buf: string);
procedure Close(var c: TCfgParser);
function next(var c: TCfgParser): TCfgEvent;
function getColumn(const c: TCfgParser): int;
function getLine(const c: TCfgParser): int;
function getFilename(const c: TCfgParser): string;
implementation
const
SymChars: TCharSet = ['a'..'z', 'A'..'Z', '0'..'9', '_', #128..#255];
// ----------------------------------------------------------------------------
procedure rawGetTok(var c: TCfgParser; var tok: TToken); forward;
function open(var c: TCfgParser; const filename: string): bool;
begin
{@ignore}
FillChar(c, sizeof(c), 0); // work around Delphi/fpc bug
{@emit}
result := initBaseLexer(c, filename);
c.filename := filename;
c.state := startState;
c.tok.kind := tkInvalid;
c.tok.literal := '';
if result then rawGetTok(c, c.tok);
end;
procedure openFromBuffer(var c: TCfgParser; const buf: string);
begin
{@ignore}
FillChar(c, sizeof(c), 0); // work around Delphi/fpc bug
{@emit}
initBaseLexerFromBuffer(c, buf);
c.filename := 'buffer';
c.state := startState;
c.tok.kind := tkInvalid;
c.tok.literal := '';
rawGetTok(c, c.tok);
end;
procedure close(var c: TCfgParser);
begin
deinitBaseLexer(c);
end;
function getColumn(const c: TCfgParser): int;
begin
result := getColNumber(c, c.bufPos)
end;
function getLine(const c: TCfgParser): int;
begin
result := c.linenumber
end;
function getFilename(const c: TCfgParser): string;
begin
result := c.filename
end;
// ----------------------------------------------------------------------------
procedure handleHexChar(var c: TCfgParser; var xi: int);
begin
case c.buf[c.bufpos] of
'0'..'9': begin
xi := (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0'));
inc(c.bufpos);
end;
'a'..'f': begin
xi := (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('a') + 10);
inc(c.bufpos);
end;
'A'..'F': begin
xi := (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10);
inc(c.bufpos);
end;
else begin end // do nothing
end
end;
procedure handleDecChars(var c: TCfgParser; var xi: int);
begin
while c.buf[c.bufpos] in ['0'..'9'] do begin
xi := (xi * 10) + (ord(c.buf[c.bufpos]) - ord('0'));
inc(c.bufpos);
end;
end;
procedure getEscapedChar(var c: TCfgParser; var tok: TToken);
var
xi: int;
begin
inc(c.bufpos); // skip '\'
case c.buf[c.bufpos] of
'n', 'N': begin
tok.literal := tok.literal +{&} nl;
Inc(c.bufpos);
end;
'r', 'R', 'c', 'C': begin addChar(tok.literal, CR); Inc(c.bufpos); end;
'l', 'L': begin addChar(tok.literal, LF); Inc(c.bufpos); end;
'f', 'F': begin addChar(tok.literal, FF); inc(c.bufpos); end;
'e', 'E': begin addChar(tok.literal, ESC); Inc(c.bufpos); end;
'a', 'A': begin addChar(tok.literal, BEL); Inc(c.bufpos); end;
'b', 'B': begin addChar(tok.literal, BACKSPACE); Inc(c.bufpos); end;
'v', 'V': begin addChar(tok.literal, VT); Inc(c.bufpos); end;
't', 'T': begin addChar(tok.literal, Tabulator); Inc(c.bufpos); end;
'''', '"': begin addChar(tok.literal, c.buf[c.bufpos]); Inc(c.bufpos); end;
'\': begin addChar(tok.literal, '\'); Inc(c.bufpos) end;
'x', 'X': begin
inc(c.bufpos);
xi := 0;
handleHexChar(c, xi);
handleHexChar(c, xi);
addChar(tok.literal, Chr(xi));
end;
'0'..'9': begin
xi := 0;
handleDecChars(c, xi);
if (xi <= 255) then
addChar(tok.literal, Chr(xi))
else
tok.kind := tkInvalid
end
else tok.kind := tkInvalid
end
end;
function HandleCRLF(var c: TCfgParser; pos: int): int;
begin
case c.buf[pos] of
CR: result := lexbase.HandleCR(c, pos);
LF: result := lexbase.HandleLF(c, pos);
else result := pos
end
end;
procedure getString(var c: TCfgParser; var tok: TToken; rawMode: Boolean);
var
pos: int;
ch: Char;
buf: PChar;
begin
pos := c.bufPos + 1; // skip "
buf := c.buf; // put `buf` in a register
tok.kind := tkSymbol;
if (buf[pos] = '"') and (buf[pos+1] = '"') then begin
// long string literal:
inc(pos, 2); // skip ""
// skip leading newline:
pos := HandleCRLF(c, pos);
repeat
case buf[pos] of
'"': begin
if (buf[pos+1] = '"') and (buf[pos+2] = '"') then
break;
addChar(tok.literal, '"');
Inc(pos)
end;
CR, LF: begin
pos := HandleCRLF(c, pos);
tok.literal := tok.literal +{&} nl;
end;
lexbase.EndOfFile: begin
tok.kind := tkInvalid;
break
end
else begin
addChar(tok.literal, buf[pos]);
Inc(pos)
end
end
until false;
c.bufpos := pos + 3 // skip the three """
end
else begin // ordinary string literal
repeat
ch := buf[pos];
if ch = '"' then begin
inc(pos); // skip '"'
break
end;
if ch in [CR, LF, lexbase.EndOfFile] then begin
tok.kind := tkInvalid;
break
end;
if (ch = '\') and not rawMode then begin
c.bufPos := pos;
getEscapedChar(c, tok);
pos := c.bufPos;
end
else begin
addChar(tok.literal, ch);
Inc(pos)
end
until false;
c.bufpos := pos;
end
end;
procedure getSymbol(var c: TCfgParser; var tok: TToken);
var
pos: int;
buf: pchar;
begin
pos := c.bufpos;
buf := c.buf;
while true do begin
addChar(tok.literal, buf[pos]);
Inc(pos);
if not (buf[pos] in SymChars) then break;
end;
c.bufpos := pos;
tok.kind := tkSymbol
end;
procedure skip(var c: TCfgParser);
var
buf: PChar;
pos: int;
begin
pos := c.bufpos;
buf := c.buf;
repeat
case buf[pos] of
' ': Inc(pos);
Tabulator: inc(pos);
'#', ';': while not (buf[pos] in [CR, LF, lexbase.EndOfFile]) do inc(pos);
CR, LF: pos := HandleCRLF(c, pos);
else break // EndOfFile also leaves the loop
end
until false;
c.bufpos := pos;
end;
procedure rawGetTok(var c: TCfgParser; var tok: TToken);
begin
tok.kind := tkInvalid;
setLength(tok.literal, 0);
skip(c);
case c.buf[c.bufpos] of
'=': begin
tok.kind := tkEquals;
inc(c.bufpos);
tok.literal := '='+'';
end;
'-': begin
inc(c.bufPos);
if c.buf[c.bufPos] = '-' then inc(c.bufPos);
tok.kind := tkDashDash;
tok.literal := '--';
end;
':': begin
tok.kind := tkColon;
inc(c.bufpos);
tok.literal := ':'+'';
end;
'r', 'R': begin
if c.buf[c.bufPos+1] = '"' then begin
Inc(c.bufPos);
getString(c, tok, true);
end
else
getSymbol(c, tok);
end;
'[': begin
tok.kind := tkBracketLe;
inc(c.bufpos);
tok.literal := '['+'';
end;
']': begin
tok.kind := tkBracketRi;
Inc(c.bufpos);
tok.literal := ']'+'';
end;
'"': getString(c, tok, false);
lexbase.EndOfFile: tok.kind := tkEof;
else getSymbol(c, tok);
end
end;
function errorStr(const c: TCfgParser; const msg: string): string;
begin
result := format('$1($2, $3) Error: $4', [
c.filename, toString(getLine(c)), toString(getColumn(c)),
msg
]);
end;
function getKeyValPair(var c: TCfgParser; kind: TCfgEventKind): TCfgEvent;
begin
if c.tok.kind = tkSymbol then begin
result.kind := kind;
result.key := c.tok.literal;
result.value := '';
rawGetTok(c, c.tok);
if c.tok.kind in [tkEquals, tkColon] then begin
rawGetTok(c, c.tok);
if c.tok.kind = tkSymbol then begin
result.value := c.tok.literal;
end
else begin
result.kind := cfgError;
result.msg := errorStr(c, 'symbol expected, but found: '
+ c.tok.literal);
end;
rawGetTok(c, c.tok);
end
end
else begin
result.kind := cfgError;
result.msg := errorStr(c, 'symbol expected, but found: ' + c.tok.literal);
rawGetTok(c, c.tok);
end;
end;
function next(var c: TCfgParser): TCfgEvent;
begin
case c.tok.kind of
tkEof: result.kind := cfgEof;
tkDashDash: begin
rawGetTok(c, c.tok);
result := getKeyValPair(c, cfgOption);
end;
tkSymbol: begin
result := getKeyValPair(c, cfgKeyValuePair);
end;
tkBracketLe: begin
rawGetTok(c, c.tok);
if c.tok.kind = tkSymbol then begin
result.kind := cfgSectionStart;
result.section := c.tok.literal;
end
else begin
result.kind := cfgError;
result.msg := errorStr(c, 'symbol expected, but found: ' + c.tok.literal);
end;
rawGetTok(c, c.tok);
if c.tok.kind = tkBracketRi then rawGetTok(c, c.tok)
else begin
result.kind := cfgError;
result.msg := errorStr(c, ''']'' expected, but found: ' + c.tok.literal);
end
end;
tkInvalid, tkEquals, tkColon: begin
result.kind := cfgError;
result.msg := errorStr(c, 'invalid token: ' + c.tok.literal);
rawGetTok(c, c.tok);
end
end
end;
end.

153
nim/parseopt.pas Normal file
View file

@ -0,0 +1,153 @@
//
//
// Nimrod's Runtime Library
// (c) Copyright 2008 Andreas Rumpf
//
// See the file "copying.txt", included in this
// distribution, for details about the copyright.
//
unit parseopt;
// A command line parser; the Nimrod version of this file
// will become part of the standard library.
interface
{$include 'config.inc'}
uses
nsystem, charsets, nos, strutils;
type
TCmdLineKind = (
cmdEnd, // end of command line reached
cmdArgument, // argument detected
cmdLongoption, // a long option ``--option`` detected
cmdShortOption // a short option ``-c`` detected
);
TOptParser = object(NObject)
cmd: string;
pos: int;
inShortState: bool;
kind: TCmdLineKind;
key, val: string;
end;
function init(const cmdline: string = ''): TOptParser;
procedure next(var p: TOptParser);
function getRestOfCommandLine(const p: TOptParser): string;
implementation
function init(const cmdline: string = ''): TOptParser;
var
i: int;
begin
result.pos := strStart;
result.inShortState := false;
if cmdline <> '' then
result.cmd := cmdline
else begin
result.cmd := '';
for i := 1 to ParamCount() do
result.cmd := result.cmd +{&} quoteIfSpaceExists(paramStr(i)) +{&} ' ';
{@ignore}
result.cmd := result.cmd + #0;
{@emit}
end;
result.kind := cmdEnd;
result.key := '';
result.val := '';
end;
function parseWord(const s: string; const i: int; var w: string;
const delim: TCharSet = {@set}[#9, ' ', #0]): int;
begin
result := i;
if s[result] = '"' then begin
inc(result);
while not (s[result] in [#0, '"']) do begin
addChar(w, s[result]);
inc(result);
end;
if s[result] = '"' then inc(result)
end
else begin
while not (s[result] in delim) do begin
addChar(w, s[result]);
inc(result);
end
end
end;
procedure handleShortOption(var p: TOptParser);
var
i: int;
begin
i := p.pos;
p.kind := cmdShortOption;
addChar(p.key, p.cmd[i]);
inc(i);
p.inShortState := true;
while p.cmd[i] in [#9, ' '] do begin
inc(i);
p.inShortState := false;
end;
if p.cmd[i] in [':', '='] then begin
inc(i); p.inShortState := false;
while p.cmd[i] in [#9, ' '] do inc(i);
i := parseWord(p.cmd, i, p.val);
end;
if p.cmd[i] = #0 then p.inShortState := false;
p.pos := i;
end;
procedure next(var p: TOptParser);
var
i: int;
begin
i := p.pos;
while p.cmd[i] in [#9, ' '] do inc(i);
p.pos := i;
setLength(p.key, 0);
setLength(p.val, 0);
if p.inShortState then begin
handleShortOption(p); exit
end;
case p.cmd[i] of
#0: p.kind := cmdEnd;
'-': begin
inc(i);
if p.cmd[i] = '-' then begin
p.kind := cmdLongOption;
inc(i);
i := parseWord(p.cmd, i, p.key, {@set}[#0, ' ', #9, ':', '=']);
while p.cmd[i] in [#9, ' '] do inc(i);
if p.cmd[i] in [':', '='] then begin
inc(i);
while p.cmd[i] in [#9, ' '] do inc(i);
p.pos := parseWord(p.cmd, i, p.val);
end
else
p.pos := i;
end
else begin
p.pos := i;
handleShortOption(p)
end
end;
else begin
p.kind := cmdArgument;
p.pos := parseWord(p.cmd, i, p.key);
end
end
end;
function getRestOfCommandLine(const p: TOptParser): string;
begin
result := strip(ncopy(p.cmd, p.pos+strStart, length(p.cmd)-1))
// always -1, because Pascal version uses a trailing zero here
end;
end.

View file

@ -70,6 +70,7 @@ type
pxSymbol, // a symbol
pxIntLit,
pxInt64Lit, // long constant like 0x00000070fffffff or out of int range
pxFloatLit,
pxParLe, pxParRi, pxBracketLe, pxBracketRi,
@ -110,7 +111,8 @@ const
'with', 'xor',
//[[[end]]]
'pxComment', 'pxCommand',
'{&}', '{%}', 'pxStrLit', '[IDENTIFIER]', 'pxIntLit', 'pxFloatLit',
'{&}', '{%}', 'pxStrLit', '[IDENTIFIER]', 'pxIntLit', 'pxInt64Lit',
'pxFloatLit',
'('+'', ')'+'', '['+'', ']'+'',
','+'', ';'+'', ':'+'',
':=', '='+'', '.'+'', '..', '^'+'', '+'+'', '-'+'', '*'+'', '/'+'',
@ -135,7 +137,7 @@ implementation
function pastokToStr(const tok: TPasTok): string;
begin
case tok.xkind of
pxIntLit:
pxIntLit, pxInt64Lit:
result := toString(tok.iNumber);
pxFloatLit:
result := toStringF(tok.fNumber);
@ -271,7 +273,7 @@ end;
procedure getNumber2(var L: TPasLex; var tok: TPasTok);
var
pos: int;
pos, bits: int;
xi: biggestInt;
begin
pos := L.bufpos+1; // skip %
@ -284,6 +286,7 @@ begin
tok.base := base2;
xi := 0;
bits := 0;
while true do begin
case L.buf[pos] of
'A'..'Z', 'a'..'z', '2'..'9', '.': begin
@ -294,23 +297,28 @@ begin
'0', '1': begin
xi := (xi shl 1) or (ord(L.buf[pos]) - ord('0'));
inc(pos);
inc(bits);
end;
else break;
end
end;
tok.iNumber := xi;
tok.xkind := pxIntLit;
if (bits > 32) then //or (xi < low(int32)) or (xi > high(int32)) then
tok.xkind := pxInt64Lit
else
tok.xkind := pxIntLit;
L.bufpos := pos;
end;
procedure getNumber16(var L: TPasLex; var tok: TPasTok);
var
pos: int;
pos, bits: int;
xi: biggestInt;
begin
pos := L.bufpos+1; // skip $
tok.base := base16;
xi := 0;
bits := 0;
while true do begin
case L.buf[pos] of
'G'..'Z', 'g'..'z', '.': begin
@ -321,20 +329,26 @@ begin
'0'..'9': begin
xi := (xi shl 4) or (ord(L.buf[pos]) - ord('0'));
inc(pos);
inc(bits, 4);
end;
'a'..'f': begin
xi := (xi shl 4) or (ord(L.buf[pos]) - ord('a') + 10);
inc(pos);
inc(bits, 4);
end;
'A'..'F': begin
xi := (xi shl 4) or (ord(L.buf[pos]) - ord('A') + 10);
inc(pos);
inc(bits, 4);
end;
else break;
end
end;
tok.iNumber := xi;
tok.xkind := pxIntLit;
if (bits > 32) then // (xi < low(int32)) or (xi > high(int32)) then
tok.xkind := pxInt64Lit
else
tok.xkind := pxIntLit;
L.bufpos := pos;
end;
@ -354,7 +368,10 @@ begin
end
else begin
tok.iNumber := ParseInt(tok.literal);
tok.xkind := pxIntLit;
if (tok.iNumber < low(int32)) or (tok.iNumber > high(int32)) then
tok.xkind := pxInt64Lit
else
tok.xkind := pxIntLit;
end;
except
on EInvalidValue do

View file

@ -322,6 +322,10 @@ begin
result := newNodeP(nkPtrTy, p);
getTok(p); eat(p, pxCurlyDirRi);
end
else if p.tok.ident.id = getIdent('tuple').id then begin
result := newNodeP(nkTupleTy, p);
getTok(p); eat(p, pxCurlyDirRi);
end
else begin
parMessage(p, errUnknownDirective, pasTokToStr(p.tok));
while true do begin
@ -481,6 +485,16 @@ begin
exprListAux(p, elemKind, endTok, sepTok, result);
end;
procedure setBaseFlags(n: PNode; base: TNumericalBase);
begin
case base of
base10: begin end;
base2: include(n.flags, nfBase2);
base8: include(n.flags, nfBase8);
base16: include(n.flags, nfBase16);
end
end;
function identOrLiteral(var p: TPasParser): PNode;
var
a: PNode;
@ -493,12 +507,17 @@ begin
// literals
pxIntLit: begin
result := newIntNodeP(nkIntLit, p.tok.iNumber, p);
result.base := p.tok.base;
setBaseFlags(result, p.tok.base);
getTok(p);
end;
pxInt64Lit: begin
result := newIntNodeP(nkInt64Lit, p.tok.iNumber, p);
setBaseFlags(result, p.tok.base);
getTok(p);
end;
pxFloatLit: begin
result := newFloatNodeP(nkFloatLit, p.tok.fNumber, p);
result.base := p.tok.base;
setBaseFlags(result, p.tok.base);
getTok(p);
end;
pxStrLit: begin
@ -683,8 +702,9 @@ begin
end
else begin end
end;
for i := 0 to sonsLen(n)-1 do
result.sons[i] := fixExpr(n.sons[i])
if not (n.kind in [nkEmpty..nkNilLit]) then
for i := 0 to sonsLen(n)-1 do
result.sons[i] := fixExpr(n.sons[i])
end;
function parseExpr(var p: TPasParser): PNode;
@ -948,6 +968,7 @@ begin
if p.tok.xkind <> pxIf then begin
// ordinary else part:
branch := newNodeP(nkElse, p);
skipCom(p, result); // BUGFIX
addSon(branch, parseStmt(p));
addSon(result, branch);
break
@ -1235,6 +1256,14 @@ begin
noBody := true;
getTok(p); opt(p, pxSemicolon);
end;
wNoConv: begin
// This is a fake for platform module. There is no ``noconv``
// directive in Pascal.
if result = nil then result := newNodeP(nkPragma, p);
addSon(result, newIdentNodeP(getIdent('noconv'), p));
noBody := true;
getTok(p); opt(p, pxSemicolon);
end;
wVarargs: begin
if result = nil then result := newNodeP(nkPragma, p);
addSon(result, newIdentNodeP(getIdent('varargs'), p));
@ -1464,7 +1493,7 @@ begin
nkIdent, nkAccQuoted: begin
a := newNode(nkPostFix);
a.info := n.info;
addSon(a, newIdentNode(getIdent('*'+'')));
addSon(a, newIdentNode(getIdent('*'+''), n.info));
addSon(a, n);
n := a
end;
@ -1486,7 +1515,7 @@ begin
end
end;
nkRecList, nkRecWhen, nkElse, nkOfBranch, nkElifBranch,
nkRecordTy, nkObjectTy: begin
nkObjectTy: begin
for i := 0 to sonsLen(n)-1 do fixRecordDef(n.sons[i])
end;
nkIdentDefs: begin
@ -1497,6 +1526,19 @@ begin
end
end;
procedure parseRecordBody(var p: TPasParser; result: PNode);
var
a: PNode;
begin
skipCom(p, result);
a := parseRecordPart(p);
if result.kind <> nkTupleTy then fixRecordDef(a);
addSon(result, a);
eat(p, pxEnd);
opt(p, pxSemicolon);
skipCom(p, result);
end;
function parseRecordOrObject(var p: TPasParser; kind: TNodeKind): PNode;
var
a: PNode;
@ -1512,19 +1554,14 @@ begin
eat(p, pxParRi);
end
else addSon(result, nil);
skipCom(p, result);
a := parseRecordPart(p);
fixRecordDef(a);
addSon(result, a);
eat(p, pxEnd);
opt(p, pxSemicolon);
skipCom(p, result);
parseRecordBody(p, result);
end;
function parseTypeDesc(var p: TPasParser): PNode;
var
oldcontext: TPasContext;
a, r: PNode;
i: int;
begin
oldcontext := p.context;
p.context := conTypeDesc;
@ -1532,7 +1569,28 @@ begin
case p.tok.xkind of
pxCommand: result := parseCommand(p);
pxProcedure, pxFunction: result := parseRoutineType(p);
pxRecord: result := parseRecordOrObject(p, nkRecordTy);
pxRecord: begin
getTok(p);
if p.tok.xkind = pxCommand then begin
result := parseCommand(p);
if result.kind <> nkTupleTy then
InternalError(result.info, 'parseTypeDesc');
parseRecordBody(p, result);
a := lastSon(result);
// embed nkRecList directly into nkTupleTy
for i := 0 to sonsLen(a)-1 do
if i = 0 then result.sons[sonsLen(result)-1] := a.sons[0]
else addSon(result, a.sons[i]);
end
else begin
result := newNodeP(nkReturnToken, p);
// we use nkReturnToken to signal that this object should be marked as
// final
addSon(result, nil);
addSon(result, nil);
parseRecordBody(p, result);
end;
end;
pxObject: result := parseRecordOrObject(p, nkObjectTy);
pxParLe: result := parseEnum(p);
pxArray: begin
@ -1591,13 +1649,29 @@ begin
end;
function parseTypeDef(var p: TPasParser): PNode;
var
a, e, pragmasNode: PNode;
begin
result := newNodeP(nkTypeDef, p);
addSon(result, identVis(p));
addSon(result, nil); // generic params
if p.tok.xkind = pxEquals then begin
getTok(p); skipCom(p, result);
addSon(result, parseTypeDesc(p));
a := parseTypeDesc(p);
addSon(result, a);
if a.kind = nkReturnToken then begin // a `final` object?
a.kind := nkObjectTy;
if result.sons[0].kind <> nkPragmaExpr then begin
e := newNodeP(nkPragmaExpr, p);
pragmasNode := newNodeP(nkPragma, p);
addSon(e, result.sons[0]);
addSon(e, pragmasNode);
result.sons[0] := e;
end
else
pragmasNode := result.sons[1];
addSon(pragmasNode, newIdentNodeP(getIdent('final'), p));
end
end
else
addSon(result, nil);

View file

@ -13,7 +13,7 @@ unit platform;
// Note: Unfortunately if an OS or CPU is listed here this does not mean that
// Nimrod has been tested on this platform or that the RTL has been ported.
// Feel free to test for your exentric platform! (Windows on I386 and Linux
// on AMD64 have been tested, though.)
// on I386 have been tested, though.)
interface
@ -45,7 +45,8 @@ type
osAtari,
osNetware,
osMacos,
osMacosx
osMacosx,
osEcmaScript
);
type
TInfoOSProp = (
@ -55,7 +56,7 @@ type
);
TInfoOSProps = set of TInfoOSProp;
TInfoOS = record
TInfoOS = record{@tuple}
name: string;
parDir: string;
dllExt: string;
@ -360,6 +361,22 @@ const
exeExt: '';
extSep: '.'+'';
props: {@set}[ospNeedsPIC, ospPosix];
),
(
name: 'EcmaScript';
parDir: '..';
dllExt: '.so';
altDirSep: '/'+'';
dllPrefix: 'lib';
objExt: '.o';
newLine: #10+'';
pathSep: ':'+'';
dirSep: '/'+'';
scriptExt: '.sh';
curDir: '.'+'';
exeExt: '';
extSep: '.'+'';
props: {@set}[];
)
);
type
@ -377,11 +394,12 @@ type
cpuIa64,
cpuAmd64,
cpuMips,
cpuArm
cpuArm,
cpuEcmaScript
);
type
TEndian = (littleEndian, bigEndian);
TInfoCPU = record
TInfoCPU = record{@tuple}
name: string;
intSize: int;
endian: TEndian;
@ -460,6 +478,13 @@ const
endian: littleEndian;
floatSize: 64;
bit: 32;
),
(
name: 'ecmascript';
intSize: 32;
endian: bigEndian;
floatSize: 64;
bit: 32;
)
);
@ -517,9 +542,9 @@ end;
// this is Ok for the Pascal version, but the Nimrod version needs a different
// mechanism
{@emit
procedure nimCPU(): cstring; importc;}
procedure nimCPU(): cstring; importc; noconv;}
{@emit
procedure nimOS(): cstring; importc;}
procedure nimOS(): cstring; importc; noconv;}
{@ignore}
initialization

View file

@ -240,6 +240,9 @@ begin
end;
function parseSymbol(var p: TParser): PNode;
var
s: string;
id: PIdent;
begin
case p.tok.tokType of
tkSymbol: begin
@ -251,9 +254,31 @@ begin
getTok(p);
case p.tok.tokType of
tkBracketLe: begin
addSon(result, newIdentNodeP(getIdent('[]'), p));
s := '['+'';
getTok(p);
if (p.tok.tokType = tkOpr) and (p.tok.ident.s = '$'+'') then begin
s := s + '$..';
getTok(p);
eat(p, tkDotDot);
if (p.tok.tokType = tkOpr) and (p.tok.ident.s = '$'+'') then begin
s := s + '$'+'';
getTok(p);
end;
end
else if p.tok.tokType = tkDotDot then begin
s := s + '..';
getTok(p);
if (p.tok.tokType = tkOpr) and (p.tok.ident.s = '$'+'') then begin
s := s + '$'+'';
getTok(p);
end;
end;
eat(p, tkBracketRi);
s := s + ']'+'';
if p.tok.tokType = tkEquals then begin
s := s + '='; getTok(p);
end;
addSon(result, newIdentNodeP(getIdent(s), p));
end;
tkParLe: begin
addSon(result, newIdentNodeP(getIdent('()'), p));
@ -261,8 +286,14 @@ begin
eat(p, tkParRi);
end;
tokKeywordLow..tokKeywordHigh, tkSymbol, tkOpr: begin
addSon(result, newIdentNodeP(p.tok.ident, p));
id := p.tok.ident;
getTok(p);
if p.tok.tokType = tkEquals then begin
addSon(result, newIdentNodeP(getIdent(id.s + '='), p));
getTok(p);
end
else
addSon(result, newIdentNodeP(id, p));
end;
else begin
parMessage(p, errIdentifierExpected, tokToStr(p.tok));
@ -350,7 +381,7 @@ var
begin
case p.tok.tokType of
tkDotDot: result := dotdotExpr(p);
tkVar, tkRef, tkPtr, tkProc, tkType: result := parseTypeDescK(p);
tkVar, tkRef, tkPtr, tkProc, tkTuple, tkType: result := parseTypeDescK(p);
else begin
a := parseExpr(p);
case p.tok.tokType of
@ -519,6 +550,16 @@ begin
eat(p, tkParRi);
end;
procedure setBaseFlags(n: PNode; base: TNumericalBase);
begin
case base of
base10: begin end;
base2: include(n.flags, nfBase2);
base8: include(n.flags, nfBase8);
base16: include(n.flags, nfBase16);
end
end;
function identOrLiteral(var p: TParser): PNode;
begin
case p.tok.tokType of
@ -530,42 +571,42 @@ begin
// literals
tkIntLit: begin
result := newIntNodeP(nkIntLit, p.tok.iNumber, p);
result.base := p.tok.base;
setBaseFlags(result, p.tok.base);
getTok(p);
end;
tkInt8Lit: begin
result := newIntNodeP(nkInt8Lit, p.tok.iNumber, p);
result.base := p.tok.base;
setBaseFlags(result, p.tok.base);
getTok(p);
end;
tkInt16Lit: begin
result := newIntNodeP(nkInt16Lit, p.tok.iNumber, p);
result.base := p.tok.base;
setBaseFlags(result, p.tok.base);
getTok(p);
end;
tkInt32Lit: begin
result := newIntNodeP(nkInt32Lit, p.tok.iNumber, p);
result.base := p.tok.base;
setBaseFlags(result, p.tok.base);
getTok(p);
end;
tkInt64Lit: begin
result := newIntNodeP(nkInt64Lit, p.tok.iNumber, p);
result.base := p.tok.base;
setBaseFlags(result, p.tok.base);
getTok(p);
end;
tkFloatLit: begin
result := newFloatNodeP(nkFloatLit, p.tok.fNumber, p);
result.base := p.tok.base;
setBaseFlags(result, p.tok.base);
getTok(p);
end;
tkFloat32Lit: begin
result := newFloatNodeP(nkFloat32Lit, p.tok.fNumber, p);
result.base := p.tok.base;
setBaseFlags(result, p.tok.base);
getTok(p);
end;
tkFloat64Lit: begin
result := newFloatNodeP(nkFloat64Lit, p.tok.fNumber, p);
result.base := p.tok.base;
setBaseFlags(result, p.tok.base);
getTok(p);
end;
tkStrLit: begin
@ -584,10 +625,6 @@ begin
result := newIntNodeP(nkCharLit, ord(p.tok.literal[strStart]), p);
getTok(p);
end;
tkRCharLit: begin
result := newIntNodeP(nkRCharLit, ord(p.tok.literal[strStart]), p);
getTok(p);
end;
tkNil: begin
result := newNodeP(nkNilLit, p);
getTok(p);
@ -598,8 +635,7 @@ begin
tkColon);
end;
tkCurlyLe: begin // {} constructor
result := exprColonEqExprList(p, nkCurly, nkRange, tkCurlyRi,
tkDotDot);
result := exprColonEqExprList(p, nkCurly, nkRange, tkCurlyRi, tkDotDot);
end;
tkBracketLe: begin // [] constructor
result := exprColonEqExprList(p, nkBracket, nkExprColonExpr, tkBracketRi,
@ -1278,6 +1314,8 @@ begin
end;
function parseTypeDescK(var p: TParser): PNode;
var
a: PNode;
begin
case p.tok.tokType of
tkVar: result := parseTypeDescKAux(p, nkVarTy);
@ -1298,7 +1336,25 @@ begin
addSon(result, parsePragma(p))
else
addSon(result, nil);
end
end;
tkTuple: begin
result := newNodeP(nkTupleTy, p);
getTok(p);
eat(p, tkBracketLe);
optInd(p, result);
while true do begin
case p.tok.tokType of
tkSymbol, tkAccent: a := parseIdentColonEquals(p, false);
tkBracketRi: begin getTok(p); break end;
else begin parMessage(p, errTokenExpected, ']'+''); break; end;
end;
optInd(p, a);
if p.tok.tokType = tkComma then begin
getTok(p); optInd(p, a)
end;
addSon(result, a);
end;
end;
else begin
InternalError(parLineInfo(p), 'pnimsyn.parseTypeDescK');
result := nil
@ -1309,7 +1365,7 @@ end;
function parseTypeDesc(var p: TParser): PNode;
begin
case p.tok.tokType of
tkVar, tkRef, tkPtr, tkProc, tkType:
tkVar, tkRef, tkPtr, tkProc, tkType, tkTuple:
result := parseTypeDescK(p);
else result := primary(p)
end
@ -1599,7 +1655,7 @@ begin
if kind = nkObjectTy then
addSon(result, a)
else
parMessage(p, errInheritanceOnlyWithObjects);
parMessage(p, errInheritanceOnlyWithNonFinalObjects);
end
else addSon(result, nil);
skipComment(p, result);
@ -1617,7 +1673,6 @@ begin
if p.tok.tokType = tkEquals then begin
getTok(p); optInd(p, result);
case p.tok.tokType of
tkRecord: a := parseRecordOrObject(p, nkRecordTy);
tkObject: a := parseRecordOrObject(p, nkObjectTy);
tkEnum: a := parseEnum(p);
else a := parseTypeDesc(p);
@ -1660,22 +1715,23 @@ end;
function complexOrSimpleStmt(var p: TParser): PNode;
begin
case p.tok.tokType of
tkIf: result := parseIfOrWhen(p, nkIfStmt);
tkWhile: result := parseWhile(p);
tkCase: result := parseCase(p);
tkTry: result := parseTry(p);
tkFor: result := parseFor(p);
tkBlock: result := parseBlock(p);
tkAsm: result := parseAsm(p);
tkProc: result := parseRoutine(p, nkProcDef);
tkIterator: result := parseRoutine(p, nkIteratorDef);
tkMacro: result := parseRoutine(p, nkMacroDef);
tkTemplate: result := parseRoutine(p, nkTemplateDef);
tkType: result := parseSection(p, nkTypeSection, parseTypeDef);
tkConst: result := parseSection(p, nkConstSection, parseConstant);
tkWhen: result := parseIfOrWhen(p, nkWhenStmt);
tkVar: result := parseSection(p, nkVarSection, parseVariable);
else result := simpleStmt(p);
tkIf: result := parseIfOrWhen(p, nkIfStmt);
tkWhile: result := parseWhile(p);
tkCase: result := parseCase(p);
tkTry: result := parseTry(p);
tkFor: result := parseFor(p);
tkBlock: result := parseBlock(p);
tkAsm: result := parseAsm(p);
tkProc: result := parseRoutine(p, nkProcDef);
tkIterator: result := parseRoutine(p, nkIteratorDef);
tkMacro: result := parseRoutine(p, nkMacroDef);
tkTemplate: result := parseRoutine(p, nkTemplateDef);
tkConverter: result := parseRoutine(p, nkConverterDef);
tkType: result := parseSection(p, nkTypeSection, parseTypeDef);
tkConst: result := parseSection(p, nkConstSection, parseConstant);
tkWhen: result := parseIfOrWhen(p, nkWhenStmt);
tkVar: result := parseSection(p, nkVarSection, parseVariable);
else result := simpleStmt(p);
end
end;

View file

@ -26,10 +26,9 @@ begin
if (it.kind = nkExprColonExpr) and (it.sons[0].kind = nkIdent) then begin
case whichKeyword(it.sons[0].ident) of
wAsmQuote: begin
case it.sons[1].kind of
nkCharLit, nkRCharLit: result := chr(int(it.sons[1].intVal));
else invalidPragma(it)
end
if it.sons[1].kind = nkCharLit then
result := chr(int(it.sons[1].intVal))
else invalidPragma(it)
end
else
invalidPragma(it)
@ -246,6 +245,8 @@ begin
sw := whichKeyword(n.sons[0].ident);
case sw of
wChecks: OnOff(c, n, checksOptions);
wObjChecks: OnOff(c, n, {@set}[optObjCheck]);
wFieldchecks: OnOff(c, n, {@set}[optFieldCheck]);
wRangechecks: OnOff(c, n, {@set}[optRangeCheck]);
wBoundchecks: OnOff(c, n, {@set}[optBoundsCheck]);
wOverflowchecks: OnOff(c, n, {@set}[optOverflowCheck]);
@ -373,12 +374,12 @@ begin
end
end;
procedure Breakpoint(c: PContext; n: PNode);
procedure PragmaBreakpoint(c: PContext; n: PNode);
begin
{@discard} getOptionalStr(c, n, '');
end;
procedure Checkpoint(c: PContext; n: PNode);
procedure PragmaCheckpoint(c: PContext; n: PNode);
// checkpoints can be used to debug the compiler; they are not documented
var
info: TLineInfo;
@ -427,7 +428,10 @@ begin
liMessage(it.info, errPowerOfTwoExpected);
end;
wNodecl: begin noVal(it); Include(sym.loc.Flags, lfNoDecl); end;
wPure: begin noVal(it); include(sym.flags, sfPure); end;
wPure: begin
noVal(it);
if sym <> nil then include(sym.flags, sfPure);
end;
wVolatile: begin noVal(it); Include(sym.flags, sfVolatile); end;
wRegister: begin noVal(it); include(sym.flags, sfRegister); end;
wMagic: processMagic(c, it, sym);
@ -444,7 +448,6 @@ begin
wNosideeffect: begin noVal(it); Include(sym.flags, sfNoSideEffect); end;
wNoReturn: begin noVal(it); Include(sym.flags, sfNoReturn); end;
wDynLib: processDynLib(c, it, sym);
wReturnsNew: begin noVal(it); Include(sym.flags, sfReturnsNew); end;
wCompilerProc: begin
noVal(it); // compilerproc may not get a string!
makeExternExport(sym, sym.name.s);
@ -464,6 +467,14 @@ begin
noVal(it);
include(sym.typ.flags, tfVarargs);
end;
wFinal: begin
noVal(it);
include(sym.typ.flags, tfFinal);
end;
wTypeCheck: begin
noVal(it);
include(sym.flags, sfTypeCheck);
end;
// statement pragmas:
wHint: liMessage(it.info, hintUser, expectStrLit(c, it));
@ -478,6 +489,9 @@ begin
wCompile: processCompile(c, it);
wLink: processCommonLink(c, it, linkNormal);
wLinkSys: processCommonLink(c, it, linkSys);
wPassL: extccomp.addLinkOption(expectStrLit(c, it));
wPassC: extccomp.addCompileOption(expectStrLit(c, it));
// fixupSystem not even documented:
wFixupSystem: begin
if c.module = magicSys.SystemModule then
@ -485,12 +499,13 @@ begin
else
invalidPragma(it)
end;
wBreakpoint: Breakpoint(c, it);
wCheckpoint: Checkpoint(c, it);
wBreakpoint: PragmaBreakpoint(c, it);
wCheckpoint: PragmaCheckpoint(c, it);
wPush: begin processPush(c, n, i+1); break end;
wPop: processPop(c, it);
wChecks, wRangechecks, wBoundchecks, wOverflowchecks, wNilchecks,
wChecks, wObjChecks, wFieldChecks,
wRangechecks, wBoundchecks, wOverflowchecks, wNilchecks,
wAssertions, wWarnings, wHints, wLinedir, wStacktrace,
wLinetrace, wOptimization, wByRef, wCallConv, wDebugger:
processOption(c, it);
@ -528,20 +543,28 @@ begin
wCppMethod, wDeprecated, wVarargs]);
end;
procedure pragmaMacro(c: PContext; s: PSym; n: PNode);
begin
pragma(c, s, n, {@set}[FirstCallConv..LastCallConv,
wImportc, wExportc, wNostatic, wNodecl, wMagic, wNosideEffect,
wCompilerProc, wDeprecated, wTypeCheck]);
end;
procedure pragmaIterator(c: PContext; s: PSym; n: PNode);
begin
pragma(c, s, n, {@set}[FirstCallConv..LastCallConv,
wImportc, wExportc, wNodecl, wMagic, wDeprecated]);
end;
procedure pragmaStmt(c: PContext; n: PNode);
procedure pragmaStmt(c: PContext; s: PSym; n: PNode);
begin
pragma(c, nil, n, {@set}[wChecks, wRangechecks, wBoundchecks,
wOverflowchecks, wNilchecks, wAssertions, wWarnings,
pragma(c, s, n, {@set}[wChecks, wObjChecks, wFieldChecks, wRangechecks,
wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings,
wHints, wLinedir, wStacktrace, wLinetrace, wOptimization,
wHint, wWarning, wError, wFatal, wDefine, wUndef,
wCompile, wLink, wLinkSys,
wPush, wPop, wFixupSystem, wBreakpoint, wCheckpoint]);
wCompile, wLink, wLinkSys, wPure,
wPush, wPop, wFixupSystem, wBreakpoint, wCheckpoint,
wPassL, wPassC]);
end;
procedure pragmaLambda(c: PContext; s: PSym; n: PNode);
@ -554,7 +577,7 @@ end;
procedure pragmaType(c: PContext; s: PSym; n: PNode);
begin
pragma(c, s, n, {@set}[wImportc, wExportc, wDeprecated, wMagic,
wNodecl, wPure, wHeader, wCompilerProc]);
wNodecl, wPure, wHeader, wCompilerProc, wFinal]);
end;
procedure pragmaField(c: PContext; s: PSym; n: PNode);

Some files were not shown because too many files have changed in this diff Show more