version 0.7.4

This commit is contained in:
Andreas Rumpf 2009-01-07 17:03:25 +01:00
commit 439aa2d04d
114 changed files with 13664 additions and 10110 deletions

View file

@ -3,7 +3,7 @@
# Feel free to edit the templates as you need. # Feel free to edit the templates as you need.
split.item.toc = "20" split.item.toc = "20"
# too long entries in the table of contents get truncated # too long entries in the table of contents wrap around
# after this number of characters # after this number of characters
doc.section = """ doc.section = """
@ -136,6 +136,10 @@ pre, span.tok {
background-color:#F9F9F9; background-color:#F9F9F9;
border:1px dotted #2F6FAB; border:1px dotted #2F6FAB;
color:black; color:black;
}
span.red {
color: #A80000;
} }
/* /*

View file

@ -1,100 +1,95 @@
# Configuration file for the Nimrod Compiler. # Configuration file for the Nimrod Compiler.
# (c) 2008 Andreas Rumpf # (c) 2008 Andreas Rumpf
# Feel free to edit the default values as you need. # Feel free to edit the default values as you need.
# You may set environment variables with # You may set environment variables with
# @putenv "key" "val" # @putenv "key" "val"
# Environment variables cannot be used in the options, however! # Environment variables cannot be used in the options, however!
cc = @if windows: llvm_gcc @else: gcc @end cc = @if windows: llvm_gcc @else: gcc @end
lib="$nimrod/lib" lib="$nimrod/lib"
path="$lib/base" path="$lib/base"
path="$lib/base/gtk" path="$lib/base/gtk"
path="$lib/base/cairo" path="$lib/base/cairo"
path="$lib/base/x11" path="$lib/base/x11"
path="$lib/base/sdl" path="$lib/base/sdl"
path="$lib/base/opengl" path="$lib/base/opengl"
path="$lib/base/zip" path="$lib/base/zip"
path="$lib/windows" path="$lib/windows"
path="$lib/posix" path="$lib/posix"
path="$lib/ecmas" path="$lib/ecmas"
path="$lib/extra" path="$lib/extra"
@if release: @if release:
obj_checks:off obj_checks:off
field_checks:off field_checks:off
range_checks:off range_checks:off
bound_checks:off bound_checks:off
overflow_checks:off overflow_checks:off
assertions:off assertions:off
stacktrace:off stacktrace:off
debugger:off debugger:off
line_dir:off line_dir:off
opt:speed opt:speed
@end dead_code_elim:on
@end
# additional options always passed to the compiler:
--verbosity: "1" # additional options always passed to the compiler:
--verbosity: "1"
hint[LineTooLong]=off
#hint[XDeclaredButNotUsed]=off hint[LineTooLong]=off
#hint[XDeclaredButNotUsed]=off
@if unix:
@if not bsd: passl= "-ldl" @end @if unix:
@end @if not bsd: passl= "-ldl" @end
@end
@if icc:
passl = "-cxxlib" @if icc:
passc = "-cxxlib" passl = "-cxxlib"
@end passc = "-cxxlib"
@end
# Configuration for the LLVM GCC compiler:
@if windows: # Configuration for the LLVM GCC compiler:
llvm_gcc.path = r"$nimrod\dist\llvm-gcc4.2\bin" llvm_gcc.options.debug = "-g"
@elif macosx: llvm_gcc.options.always = "-w"
llvm_gcc.path = llvm_gcc.options.speed = "-O2"
r"/Users/andreasrumpf/download/C/llvm-gcc4.2-2.3-x86-darwin8/bin" llvm_gcc.options.size = "-Os"
@end
llvm_gcc.options.debug = "-g" # Configuration for the Visual C/C++ compiler:
llvm_gcc.options.always = "-w" @if vcc:
llvm_gcc.options.speed = "-O2" passl: r"/F33554432" # set the stack size to 8 MB
llvm_gcc.options.size = "-Os" @end
vcc.options.debug = "/RTC1 /ZI"
# Configuration for the Visual C/C++ compiler: vcc.options.always = "/nologo"
@if vcc: vcc.options.speed = "/Ox /arch:SSE2"
passl: r"/F33554432" # set the stack size to 8 MB vcc.options.size = "/O1"
@end
vcc.options.debug = "/RTC1 /ZI" # Configuration for the GNU C/C++ compiler:
vcc.options.always = "/nologo" @if windows:
vcc.options.speed = "/Ox /arch:SSE2" gcc.path = r"C:\eigenes\compiler\mingw\bin"
vcc.options.size = "/O1" @end
#gcc.exe = "gcc-4.1"
# Configuration for the GNU C/C++ compiler: #gcc.linkerExe = "gcc-4.1"
@if windows: gcc.options.debug = "-g"
gcc.path = r"C:\eigenes\compiler\mingw\bin" @if macosx:
@end gcc.options.always = "-w -fasm-blocks"
#gcc.exe = "gcc-4.1" @else:
#gcc.linkerExe = "gcc-4.1" gcc.options.always = "-w"
gcc.options.debug = "-g" @end
@if macosx: gcc.options.speed = "-O3 -fno-strict-aliasing"
gcc.options.always = "-w -fasm-blocks" gcc.options.size = "-Os"
@else:
gcc.options.always = "-w" # Configuration for the Digital Mars C/C++ compiler:
@end @if windows:
gcc.options.speed = "-O3 -fno-strict-aliasing" dmc.path = r"C:\eigenes\compiler\d\dm\bin"
gcc.options.size = "-Os" @end
# Configuration for the Digital Mars C/C++ compiler: # Configuration for the Tiny C Compiler:
@if windows: @if windows:
dmc.path = r"C:\eigenes\compiler\d\dm\bin" tcc.path = r"C:\Eigenes\compiler\tcc-0.9.23\tcc"
@end tcc.options.always = r"-IC:\Eigenes\compiler\tcc-0.9.23\include " &
r"-IC:\Eigenes\compiler\tcc-0.9.23\include\winapi"
# Configuration for the Tiny C Compiler: @end
@if windows: tcc.options.always = "-w"
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.always = "-w"

View file

@ -1,18 +1,18 @@
======================================================= =======================================================
The Nimrod Compiler The Nimrod Compiler
Copyright (C) 2004-2008 Andreas Rumpf Copyright (C) 2004-2009 Andreas Rumpf
======================================================= =======================================================
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2 as published by the Free Software Foundation; version 2
of the License. of the License.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

View file

@ -1,5 +1,5 @@
Advanced commands:: Advanced commands::
pas convert a Pascal file to Nimrod standard syntax pas convert a Pascal file to Nimrod syntax
pretty pretty print the inputfile pretty pretty print the inputfile
gen_depend generate a DOT file containing the gen_depend generate a DOT file containing the
module dependency graph module dependency graph

View file

@ -41,6 +41,7 @@
'sfCompileTime', # proc can be evaluated at compile time 'sfCompileTime', # proc can be evaluated at compile time
'sfThreadVar', # variable is a thread variable 'sfThreadVar', # variable is a thread variable
'sfMerge', # proc can be merged with itself 'sfMerge', # proc can be merged with itself
'sfDeadCodeElim', # dead code elimination for the module is turned on
], ],
'TypeFlag': [ 'TypeFlag': [
@ -116,7 +117,7 @@
# end of atoms # end of atoms
'nkDotCall', # used to temporarily flag a nkCall node; this is used 'nkDotCall', # used to temporarily flag a nkCall node; this is used
# for transforming ``s.len`` to ``len(s)`` # for transforming ``s.len`` to ``len(s)``
'nkCommand', # a call like ``p 2 4`` without parenthesis 'nkCommand', # a call like ``p 2, 4`` without parenthesis
'nkCall', # a call like p(x, y) or an operation like +(a, b) 'nkCall', # a call like p(x, y) or an operation like +(a, b)
'nkGenericCall', # a call with given type parameters 'nkGenericCall', # a call with given type parameters
'nkExplicitTypeListCall', # a call with given explicit typelist 'nkExplicitTypeListCall', # a call with given explicit typelist
@ -125,6 +126,7 @@
'nkIdentDefs', # a definition like `a, b: typeDesc = expr` 'nkIdentDefs', # a definition like `a, b: typeDesc = expr`
# either typeDesc or expr may be nil; used in # either typeDesc or expr may be nil; used in
# formal parameters, var statements, etc. # formal parameters, var statements, etc.
'nkVarTuple', # a ``var (a, b) = expr`` construct
'nkInfix', # a call like (a + b) 'nkInfix', # a call like (a + b)
'nkPrefix', # a call like !a 'nkPrefix', # a call like !a
'nkPostfix', # something like a! (also used for visibility) 'nkPostfix', # something like a! (also used for visibility)
@ -166,6 +168,7 @@
# end of expressions # end of expressions
'nkAsgn', # a = b 'nkAsgn', # a = b
'nkFastAsgn', # internal node for a fast ``a = b`` (no string copy)
'nkDefaultTypeParam', # `ident = typeDesc` in generic parameters 'nkDefaultTypeParam', # `ident = typeDesc` in generic parameters
'nkGenericParams', # generic parameters 'nkGenericParams', # generic parameters
'nkFormalParams', # formal parameters 'nkFormalParams', # formal parameters

View file

@ -24,6 +24,7 @@ Options:
--bound_checks:on|off code generation for bound 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 --overflow_checks:on|off code generation for over-/underflow checks ON|OFF
-a, --assertions:on|off code generation for assertions ON|OFF -a, --assertions:on|off code generation for assertions ON|OFF
--dead_code_elim:on|off whole program dead code elimination ON|OFF
--opt:none|speed|size optimize not at all or for speed|size --opt:none|speed|size optimize not at all or for speed|size
--app:console|gui|lib generate a console|GUI application or a shared lib --app:console|gui|lib generate a console|GUI application or a shared lib
-r, --run run the compiled program with given arguments -r, --run run the compiled program with given arguments

View file

@ -140,6 +140,7 @@
'FloatToStr', 'FloatToStr',
'CStrToStr', 'CStrToStr',
'StrToStr', 'StrToStr',
'EnumToStr',
# special ones: # special ones:
'And', 'And',
@ -209,6 +210,8 @@
'NimrodMinor', 'NimrodMinor',
'NimrodPatch', 'NimrodPatch',
'CpuEndian', 'CpuEndian',
'HostOS',
'HostCPU',
'NaN', 'NaN',
'Inf', 'Inf',
'NegInf', 'NegInf',

View file

@ -142,7 +142,7 @@
'selector must be of an ordinal type'}, 'selector must be of an ordinal type'},
{'errOrdXMustNotBeNegative': 'ord($1) must not be negative'}, {'errOrdXMustNotBeNegative': 'ord($1) must not be negative'},
{'errLenXinvalid': 'len($1) must be less than 32768'}, {'errLenXinvalid': 'len($1) must be less than 32768'},
{'errWrongNumberOfLoopVariables': 'wrong number of loop variables'}, {'errWrongNumberOfVariables': 'wrong number of variables'},
{'errExprCannotBeRaised': 'only objects can be raised'}, {'errExprCannotBeRaised': 'only objects can be raised'},
{'errBreakOnlyInLoop': "'break' only allowed in loop construct"}, {'errBreakOnlyInLoop': "'break' only allowed in loop construct"},
{'errTypeXhasUnknownSize': "type '$1' has unknown size"}, {'errTypeXhasUnknownSize': "type '$1' has unknown size"},

View file

@ -1,38 +0,0 @@
#! /bin/sh
#
# Nimrod deinstallation script
# (c) 2008 Andreas Rumpf
#
if [ $# -eq 1 ] ; then
case $1 in
"/usr/bin")
rm -rf /usr/lib/nimrod
rm -rf /usr/share/nimrod/doc
rm -f /usr/bin/nimrod
rm -f /etc/nimrod.cfg
rm -f /etc/nimdoc.cfg || exit 1
;;
"/usr/local/bin")
rm -rf /usr/local/lib/nimrod
rm -rf /usr/local/share/nimrod/doc
rm -f /usr/local/bin/nimrod
rm -f /etc/nimrod.cfg
rm -f /etc/nimdoc.cfg || exit 1
;;
*)
rm -rf $1/nimrod || exit 1
;;
esac
echo "deinstallation successful"
else
echo "Nimrod deinstallation script"
echo "Usage: [sudo] sh deinstall.sh DIR"
echo "Where DIR may be:"
echo " /usr/bin"
echo " /usr/local/bin"
echo " /opt"
echo " <some other dir> (treated like '/opt')"
exit 1
fi

View file

@ -3,25 +3,28 @@
The documentation consists of several documents: The documentation consists of several documents:
- | `First steps after installation <steps.html>`_ - | `Nimrod tutorial (part I) <tut1.html>`_
| Read this after installation for a quick introduction. | The Nimrod tutorial part one deals with the basics.
- | `Nimrod tutorial (part II) <tut2.html>`_
| The Nimrod tutorial part two deals with the advanced language constructs.
- | `Nimrod manual <manual.html>`_ - | `Nimrod manual <manual.html>`_
| Read this to get to know the Nimrod programming system. | The Nimrod manual is a draft that will evolve into a proper specification.
- | `User guide for the Nimrod Compiler <nimrodc.html>`_ - | `User guide for the Nimrod Compiler <nimrodc.html>`_
| The user guide lists command line arguments, Nimrodc's special features, etc. | The user guide lists command line arguments, special features of the
compiler, etc.
- | `User guide for the Embedded Nimrod Debugger <endb.html>`_ - | `User guide for the Embedded Nimrod Debugger <endb.html>`_
| This document describes how to use the Embedded debugger. The embedded | This document describes how to use the Embedded Debugger.
debugger currently has no GUI. Please help!
- | `Nimrod library documentation <lib.html>`_ - | `Nimrod library documentation <lib.html>`_
| This document describes Nimrod's standard library. | This document describes Nimrod's standard library.
- | `Nimrod internal documentation <intern.html>`_ - | `Nimrod internal documentation <intern.html>`_
| The internal documentation describes how the compiler is implemented. Read | The internal documentation describes how the compiler is implemented. Read
this if you want to hack the compiler or develop advanced macros. this if you want to hack the compiler.
- | `Index <theindex.html>`_ - | `Index <theindex.html>`_
| The generated index. Often the quickest way to find the piece of | The generated index. Often the quickest way to find the piece of

View file

@ -1,41 +1,54 @@
Short description of Nimrod's modules Short description of Nimrod's modules
------------------------------------- -------------------------------------
============== ========================================================== ============== ==========================================================
Module Description Module Description
============== ========================================================== ============== ==========================================================
lexbase buffer handling of the lexical analyser nimrod main module: parses the command line and calls
scanner lexical analyser ```main.MainCommand``
main implements the top-level command dispatching
ast type definitions of the abstract syntax tree (AST) and lexbase buffer handling of the lexical analyser
node constructors scanner lexical analyser
astalgo algorithms for containers of AST nodes; converting the pnimsyn Nimrod's parser
AST to YAML; the symbol table rnimsyn Nimrod code renderer (AST back to its textual form)
passes implement the passes managemer for passes over the AST
trees few algorithms for nodes; this module is less important paslex lexer for Pascal
types module for traversing type graphs; also contain several pasparse parser for Pascal; Pascal's advanced OO features are not
helpers for dealing with types supported
sigmatch contains the matching algorithm that is used for proc options contains global and local compiler options
calls ast type definitions of the abstract syntax tree (AST) and
semexprs contains the semantic checking phase for expressions node constructors
semstmts contains the semantic checking phase for statements astalgo algorithms for containers of AST nodes; converting the
semtypes contains the semantic checking phase for types AST to YAML; the symbol table
passes implement the passes managemer for passes over the AST
idents implements a general mapping from identifiers to an internal trees few algorithms for nodes; this module is less important
representation (``PIdent``) that is used, so that a simple types module for traversing type graphs; also contain several
id-comparison suffices to say whether two Nimrod identifiers helpers for dealing with types
are equivalent
sigmatch contains the matching algorithm that is used for proc
ropes implements long strings using represented as trees for calls
lazy evaluation; used mainly by the code generators semexprs contains the semantic checking phase for expressions
semstmts contains the semantic checking phase for statements
ccgobj contains type definitions neeeded for C code generation semtypes contains the semantic checking phase for types
and some helpers semfold contains code to deal with constant folding
ccgutils contains helpers for the C code generator evals contains an AST interpreter for compile time evaluation
ccgtypes the generator for C types pragmas semantic checking of pragmas
ccgstmts the generator for statements
ccgexprs the generator for expressions idents implements a general mapping from identifiers to an internal
extccomp this module calls the C compiler and linker; interesting representation (``PIdent``) that is used, so that a simple
if you want to add support for a new C compiler id-comparison suffices to say whether two Nimrod identifiers
============== ========================================================== are equivalent
ropes implements long strings represented as trees for
lazy evaluation; used mainly by the code generators
transf transformations on the AST that need to be done before
code generation
cgen main file of the C code generator
ccgutils contains helpers for the C code generator
ccgtypes the generator for C types
ccgstmts the generator for statements
ccgexprs the generator for expressions
extccomp this module calls the C compiler and linker; interesting
if you want to add support for a new C compiler
============== ==========================================================

View file

@ -1,45 +1,43 @@
module ::= ([COMMENT] [SAD] stmt)* module ::= ([COMMENT] [SAD] stmt)*
comma ::= ',' [COMMENT] [IND] comma ::= ',' [COMMENT] [IND]
operator ::= OP0 | OR | XOR | AND | OP3 | OP4 | OP5 | IS | ISNOT | IN | NOTIN operator ::= OP0 | OR | XOR | AND | OP3 | OP4 | OP5 | OP6 | OP7
| OP6 | DIV | MOD | SHL | SHR | OP7 | NOT | 'is' | 'isnot' | 'in' | 'notin'
| 'div' | 'mod' | 'shl' | 'shr' | 'not'
prefixOperator ::= OP0 | OP3 | OP4 | OP5 | OP6 | OP7 | NOT prefixOperator ::= OP0 | OP3 | OP4 | OP5 | OP6 | OP7 | 'not'
optInd ::= [COMMENT] [IND] optInd ::= [COMMENT] [IND]
lowestExpr ::= orExpr ( OP0 optInd orExpr )* lowestExpr ::= orExpr (OP0 optInd orExpr)*
orExpr ::= andExpr ( OR | XOR optInd andExpr )* orExpr ::= andExpr (OR | 'xor' optInd andExpr)*
andExpr ::= cmpExpr ( AND optInd cmpExpr )* andExpr ::= cmpExpr ('and' optInd cmpExpr)*
cmpExpr ::= ampExpr ( OP3 | IS | ISNOT | IN | NOTIN optInd ampExpr )* cmpExpr ::= ampExpr (OP3 | 'is' | 'isnot' | 'in' | 'notin' optInd ampExpr)*
ampExpr ::= plusExpr ( OP4 optInd plusExpr )* ampExpr ::= plusExpr (OP4 optInd plusExpr)*
plusExpr ::= mulExpr ( OP5 optInd mulExpr )* plusExpr ::= mulExpr (OP5 optInd mulExpr)*
mulExpr ::= dollarExpr ( OP6 | DIV | MOD | SHL | SHR optInd dollarExpr )* mulExpr ::= dollarExpr (OP6 | 'div' | 'mod' | 'shl' | 'shr' optInd dollarExpr)*
dollarExpr ::= primary ( OP7 optInd primary )* dollarExpr ::= primary (OP7 optInd primary)*
namedTypeOrExpr ::= namedTypeOrExpr ::=
DOTDOT [expr] '..' [expr]
| expr [EQUALS (expr [DOTDOT expr] | typeDescK | DOTDOT [expr] ) | expr ['=' (expr ['..' expr] | typeDescK | '..' [expr]) | '..' [expr]]
| DOTDOT [expr]]
| typeDescK | typeDescK
castExpr ::= CAST BRACKET_LE optInd typeDesc BRACKERT_RI castExpr ::= 'cast' '[' optInd typeDesc [SAD] ']' '(' optInd expr [SAD] ')'
PAR_LE optInd expr PAR_RI addrExpr ::= 'addr' '(' optInd expr ')'
addrExpr ::= ADDR PAR_LE optInd expr PAR_RI symbol ::= '`' (KEYWORD | IDENT | operator | '(' ')'
symbol ::= ACC (KEYWORD | IDENT | operator | PAR_LE PAR_RI | '[' ']' | '=' | literal)+ '`'
| BRACKET_LE BRACKET_RI | EQUALS | literal )+ ACC
| IDENT | IDENT
primary ::= ( prefixOperator optInd )* ( symbol | constructor | primary ::= (prefixOperator optInd)* (symbol | constructor |
| castExpr | addrExpr ) ( | castExpr | addrExpr) (
DOT optInd symbol '.' optInd symbol
#| CURLY_LE namedTypeDescList CURLY_RI | '(' optInd namedExprList [SAD] ')'
| PAR_LE optInd namedExprList PAR_RI | '[' optInd
| BRACKET_LE optInd [namedTypeOrExpr (comma namedTypeOrExpr)* [comma]]
[ namedTypeOrExpr (comma namedTypeOrExpr)* [comma] ] [SAD] ']'
BRACKET_RI | '^'
| CIRCUM | pragma)*
| pragma )*
literal ::= INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT literal ::= INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
| FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
@ -48,48 +46,42 @@ literal ::= INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
| NIL | NIL
constructor ::= literal constructor ::= literal
| BRACKET_LE optInd colonExprList BRACKET_RI # []-Constructor | '[' optInd colonExprList [SAD] ']'
| CURLY_LE optInd sliceExprList CURLY_RI # {}-Constructor | '{' optInd sliceExprList [SAD] '}'
| PAR_LE optInd colonExprList PAR_RI # ()-Constructor | '(' optInd colonExprList [SAD] ')'
exprList ::= [ expr (comma expr)* [comma] ] colonExpr ::= expr [':' expr]
colonExprList ::= [colonExpr (comma colonExpr)* [comma]]
colonExpr ::= expr [COLON expr] namedExpr ::= expr ['=' expr]
colonExprList ::= [ colonExpr (comma colonExpr)* [comma] ] namedExprList ::= [namedExpr (comma namedExpr)* [comma]]
namedExpr ::= expr [EQUALS expr] # actually this is symbol EQUALS expr|expr sliceExpr ::= expr ['..' expr]
namedExprList ::= [ namedExpr (comma namedExpr)* [comma] ] sliceExprList ::= [sliceExpr (comma sliceExpr)* [comma]]
sliceExpr ::= expr [ DOTDOT expr ] anonymousProc ::= 'lambda' paramList [pragma] '=' stmt
sliceExprList ::= [ sliceExpr (comma sliceExpr)* [comma] ]
anonymousProc ::= LAMBDA paramList [pragma] EQUALS stmt
expr ::= lowestExpr expr ::= lowestExpr
| anonymousProc | anonymousProc
| IF expr COLON expr | 'if' expr ':' expr ('elif' expr ':' expr)* 'else' ':' expr
(ELIF expr COLON expr)*
ELSE COLON expr
namedTypeDesc ::= typeDescK | expr [EQUALS (typeDescK | expr)] namedTypeDesc ::= typeDescK | expr ['=' (typeDescK | expr)]
namedTypeDescList ::= [ namedTypeDesc (comma namedTypeDesc)* [comma] ] namedTypeDescList ::= [namedTypeDesc (comma namedTypeDesc)* [comma]]
qualifiedIdent ::= symbol [ DOT symbol ] qualifiedIdent ::= symbol ['.' symbol]
typeDescK ::= VAR typeDesc typeDescK ::= 'var' typeDesc
| REF typeDesc | 'ref' typeDesc
| PTR typeDesc | 'ptr' typeDesc
| TYPE expr | 'type' expr
| TUPLE tupleDesc | 'tuple' tupleDesc
| PROC paramList [pragma] | 'proc' paramList [pragma]
typeDesc ::= typeDescK | primary typeDesc ::= typeDescK | primary
optSemicolon ::= [SEMICOLON] macroStmt ::= ':' [stmt] ('of' [sliceExprList] ':' stmt
|'elif' expr ':' stmt
macroStmt ::= COLON [stmt] (OF [sliceExprList] COLON stmt |'except' exceptList ':' stmt )*
| ELIF expr COLON stmt ['else' ':' stmt]
| EXCEPT exceptList COLON stmt )*
[ELSE COLON stmt]
simpleStmt ::= returnStmt simpleStmt ::= returnStmt
| yieldStmt | yieldStmt
@ -107,88 +99,91 @@ complexStmt ::= ifStmt | whileStmt | caseStmt | tryStmt | forStmt
| procDecl | iteratorDecl | macroDecl | templateDecl | procDecl | iteratorDecl | macroDecl | templateDecl
| constSection | typeSection | whenStmt | varSection | constSection | typeSection | whenStmt | varSection
indPush ::= IND # push indPush ::= IND # and push indentation onto the stack
indPop ::= # pop indentation from the stack
stmt ::= simpleStmt [SAD] stmt ::= simpleStmt [SAD]
| indPush (complexStmt | simpleStmt) | indPush (complexStmt | simpleStmt)
([SAD] (complexStmt | simpleStmt) )* ([SAD] (complexStmt | simpleStmt))*
DED DED indPop
exprStmt ::= lowestExpr [EQUALS expr | [expr (comma expr)* [comma]] [macroStmt]] exprStmt ::= lowestExpr ['=' expr | [expr (comma expr)*] [macroStmt]]
returnStmt ::= RETURN [expr] returnStmt ::= 'return' [expr]
yieldStmt ::= YIELD expr yieldStmt ::= 'yield' expr
discardStmt ::= DISCARD expr discardStmt ::= 'discard' expr
raiseStmt ::= RAISE [expr] raiseStmt ::= 'raise' [expr]
breakStmt ::= BREAK [symbol] breakStmt ::= 'break' [symbol]
continueStmt ::= CONTINUE continueStmt ::= 'continue'
ifStmt ::= IF expr COLON stmt (ELIF expr COLON stmt)* [ELSE COLON stmt] ifStmt ::= 'if' expr ':' stmt ('elif' expr ':' stmt)* ['else' ':' stmt]
whenStmt ::= WHEN expr COLON stmt (ELIF expr COLON stmt)* [ELSE COLON stmt] whenStmt ::= 'when' expr ':' stmt ('elif' expr ':' stmt)* ['else' ':' stmt]
caseStmt ::= CASE expr (OF sliceExprList COLON stmt)* caseStmt ::= 'case' expr [':'] ('of' sliceExprList ':' stmt)*
(ELIF expr COLON stmt)* ('elif' expr ':' stmt)*
[ELSE COLON stmt] ['else' ':' stmt]
whileStmt ::= WHILE expr COLON stmt whileStmt ::= 'while' expr ':' stmt
forStmt ::= FOR symbol (comma symbol)* [comma] IN expr [DOTDOT expr] COLON stmt forStmt ::= 'for' symbol (comma symbol)* 'in' expr ['..' expr] ':' stmt
exceptList ::= [qualifiedIdent (comma qualifiedIdent)* [comma]] exceptList ::= [qualifiedIdent (comma qualifiedIdent)*]
tryStmt ::= TRY COLON stmt tryStmt ::= 'try' ':' stmt
(EXCEPT exceptList COLON stmt)* ('except' exceptList ':' stmt)*
[FINALLY COLON stmt] ['finally' ':' stmt]
asmStmt ::= ASM [pragma] (STR_LIT | RSTR_LIT | TRIPLESTR_LIT) asmStmt ::= 'asm' [pragma] (STR_LIT | RSTR_LIT | TRIPLESTR_LIT)
blockStmt ::= BLOCK [symbol] COLON stmt blockStmt ::= 'block' [symbol] ':' stmt
filename ::= symbol | STR_LIT | RSTR_LIT | TRIPLESTR_LIT filename ::= symbol | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
importStmt ::= IMPORT filename (comma filename)* [comma] importStmt ::= 'import' filename (comma filename)*
includeStmt ::= INCLUDE filename (comma filename)* [comma] includeStmt ::= 'include' filename (comma filename)*
fromStmt ::= FROM filename IMPORT symbol (comma symbol)* [comma] fromStmt ::= 'from' filename 'import' symbol (comma symbol)*
pragma ::= CURLYDOT_LE colonExprList (CURLYDOT_RI | CURLY_RI) pragma ::= '{.' optInd (colonExpr [comma])* [SAD] ('.}' | '}')
param ::= symbol (comma symbol)* [comma] COLON typeDesc param ::= symbol (comma symbol)* ':' typeDesc
paramList ::= [PAR_LE [param (comma param)* [comma]] PAR_RI] [COLON typeDesc] paramList ::= ['(' [param (comma param)*] [SAD] ')'] [':' typeDesc]
genericParams ::= BRACKET_LE (symbol [EQUALS typeDesc] )* BRACKET_RI genericParam ::= symbol [':' typeDesc]
genericParams ::= '[' genericParam (comma genericParam)* [SAD] ']'
procDecl ::= PROC symbol ["*"] [genericParams] procDecl ::= 'proc' symbol ['*'] [genericParams] paramList [pragma]
paramList [pragma] ['=' stmt]
[EQUALS stmt] macroDecl ::= 'macro' symbol ['*'] [genericParams] paramList [pragma]
macroDecl ::= MACRO symbol ["*"] [genericParams] paramList [pragma] ['=' stmt]
[EQUALS stmt] iteratorDecl ::= 'iterator' symbol ['*'] [genericParams] paramList [pragma]
iteratorDecl ::= ITERATOR symbol ["*"] [genericParams] paramList [pragma] ['=' stmt]
[EQUALS stmt] templateDecl ::= 'template' symbol ['*'] [genericParams] paramList [pragma]
templateDecl ::= TEMPLATE symbol ["*"] [genericParams] paramList [pragma] ['=' stmt]
[EQUALS stmt]
colonAndEquals ::= [COLON typeDesc] EQUALS expr colonAndEquals ::= [':' typeDesc] '=' expr
constDecl ::= symbol ["*"] [pragma] colonAndEquals [COMMENT | IND COMMENT] constDecl ::= symbol ['*'] [pragma] colonAndEquals [COMMENT | IND COMMENT]
| COMMENT | COMMENT
constSection ::= CONST indPush constDecl (SAD constDecl)* DED constSection ::= 'const' indPush constDecl (SAD constDecl)* DED indPop
typeDef ::= typeDesc | objectDef | enumDef typeDef ::= typeDesc | objectDef | enumDef
objectField ::= symbol ["*"] [pragma] objectField ::= symbol ['*'] [pragma]
objectIdentPart ::= objectIdentPart ::=
objectField (comma objectField)* [comma] COLON typeDesc [COMMENT|IND COMMENT] objectField (comma objectField)* ':' typeDesc [COMMENT|IND COMMENT]
objectWhen ::= WHEN expr COLON [COMMENT] objectPart objectWhen ::= 'when' expr ':' [COMMENT] objectPart
(ELIF expr COLON [COMMENT] objectPart)* ('elif' expr ':' [COMMENT] objectPart)*
[ELSE COLON [COMMENT] objectPart] ['else' ':' [COMMENT] objectPart]
objectCase ::= CASE expr COLON typeDesc [COMMENT] objectCase ::= 'case' expr ':' typeDesc [COMMENT]
(OF sliceExprList COLON [COMMENT] objectPart)* ('of' sliceExprList ':' [COMMENT] objectPart)*
[ELSE COLON [COMMENT] objectPart] ['else' ':' [COMMENT] objectPart]
objectPart ::= objectWhen | objectCase | objectIdentPart | NIL objectPart ::= objectWhen | objectCase | objectIdentPart | 'nil'
| indPush objectPart (SAD objectPart)* DED | indPush objectPart (SAD objectPart)* DED indPop
tupleDesc ::= BRACKET_LE optInd [param (comma param)* [comma]] BRACKET_RI tupleDesc ::= '[' optInd [param (comma param)*] [SAD] ']'
objectDef ::= OBJECT [pragma] [OF typeDesc] objectPart objectDef ::= 'object' [pragma] ['of' typeDesc] objectPart
enumField ::= symbol [EQUALS expr] enumField ::= symbol ['=' expr]
enumDef ::= ENUM [OF typeDesc] (enumField [comma | COMMENT | IND COMMENT])+ enumDef ::= 'enum' ['of' typeDesc] (enumField [comma] [COMMENT | IND COMMENT])+
typeDecl ::= COMMENT typeDecl ::= COMMENT
| symbol ["*"] [genericParams] [EQUALS typeDef] [COMMENT | IND COMMENT] | symbol ['*'] [genericParams] ['=' typeDef] [COMMENT | IND COMMENT]
typeSection ::= TYPE indPush typeDecl (SAD typeDecl)* DED typeSection ::= 'type' indPush typeDecl (SAD typeDecl)* DED indPop
colonOrEquals ::= COLON typeDesc [EQUALS expr] | EQUALS expr colonOrEquals ::= ':' typeDesc ['=' expr] | '=' expr
varField ::= symbol ["*"] [pragma] varField ::= symbol ['*'] [pragma]
varPart ::= symbol (comma symbol)* [comma] colonOrEquals [COMMENT | IND COMMENT] varPart ::= symbol (comma symbol)* colonOrEquals [COMMENT | IND COMMENT]
varSection ::= VAR (varPart varSection ::= 'var' (varPart
| indPush (COMMENT|varPart) (SAD (COMMENT|varPart))* DED) | indPush (COMMENT|varPart)
(SAD (COMMENT|varPart))* DED indPop)

View file

@ -34,7 +34,6 @@ Path Purpose
on it! on it!
``web`` website of Nimrod; generated by ``koch.py`` ``web`` website of Nimrod; generated by ``koch.py``
from the ``*.txt`` and ``*.tmpl`` files from the ``*.txt`` and ``*.tmpl`` files
``koch`` the Koch Build System (written for Nimrod)
``obj`` generated ``*.obj`` files go into here ``obj`` generated ``*.obj`` files go into here
============ ============================================== ============ ==============================================
@ -45,44 +44,76 @@ Bootstrapping the compiler
The compiler is written in a subset of Pascal with special annotations so The compiler is written in a subset of Pascal with special annotations so
that it can be translated to Nimrod code automatically. This conversion is that it can be translated to Nimrod code automatically. This conversion is
done by Nimrod itself via the undocumented ``boot`` command. Thus both Nimrod done by Nimrod itself via the undocumented ``boot`` command. Thus both Nimrod
and Free Pascal can compile the Nimrod compiler. and Free Pascal can compile the Nimrod compiler. However, the Pascal version
has no garbage collector and leaks memory like crazy! So the Pascal version
should only be used for bootstrapping.
Requirements for bootstrapping: Requirements for bootstrapping:
- Free Pascal (I used version 2.2) [optional] - Python (should work with version 1.5 or higher) (optional)
- Python (should work with version 1.5 or higher) - supported C compiler
- C compiler -- one of: Compiling the compiler is a simple matter of running::
* win32-lcc (currently broken) koch.py boot
* Borland C++ (tested with 5.5; currently broken)
* Microsoft C++
* Digital Mars C++
* Watcom C++ (currently broken)
* GCC
* Intel C++
* Pelles C (currently broken)
* llvm-gcc
| Compiling the compiler is a simple matter of running: For a release version use::
| ``koch.py boot``
| Or you can compile by hand, this is not difficult.
If you want to debug the compiler, use the command:: koch.py boot -d:release
koch.py boot --debugger:on The ``koch.py`` script is Nimrod's maintainance script. It is a replacement for
make and shell scripting with the advantage that it is much more portable.
The ``koch.py`` script is Nimrod's maintainance script: Everything that has If you don't have Python, there is a ``boot`` Nimrod program which does roughly
been automated is accessible with it. It is a replacement for make and shell the same::
scripting with the advantage that it is more portable.
nimrod cc boot.nim
./boot [-d:release]
Coding standards Pascal annotations
================ ==================
There are some annotations that the Pascal sources use so that they can
be converted to Nimrod automatically:
The compiler is written in a subset of Pascal with special annotations so ``{@discard} <expr>``
that it can be translated to Nimrod code automatically. As a general rule, Tells the compiler that a ``discard`` statement is needed for Nimrod
Pascal code that does not translate to Nimrod automatically is forbidden. here.
``{@cast}typ(expr)``
Tells the compiler that the Pascal conversion is a ``cast`` in Nimrod.
``{@emit <code>}``
Emits ``<code>``. The code fragment needs to be in Pascal syntax.
``{@ignore} <codeA> {@emit <codeB>}``
Ignores ``<codeA>`` and instead emits ``<codeB>`` which needs to be in
Pascal syntax. An empty ``{@emit}`` is possible too (it then only closes
the ``<codeA>`` part).
``record {@tuple}``
Is used to tell the compiler that the record type should be transformed
to a Nimrod tuple type.
``^ {@ptr}``
Is used to tell the compiler that the pointer type should be transformed
to a Nimrod ``ptr`` type. The default is a ``ref`` type.
``'a' + ''``
The idiom ``+''`` is used to tell the compiler that it is a string
literal and not a character literal. (Pascal does not distinguish between
character literals and string literals of length 1.)
``+{&}``
This tells the compiler that Pascal's ``+`` here is a string concatenation
and thus should be converted to ``&``. Note that this is not needed if
any of the operands is a string literal because the compiler then can
figure this out by itself.
``{@set}['a', 'b', 'c']``
Tells the compiler that Pascal's ``[]`` constructor is a set and not an
array. This is only needed if the compiler cannot figure this out for
itself.
Porting to new platforms Porting to new platforms
@ -99,7 +130,7 @@ check that the OS, System modules work and recompile Nimrod.
The only case where things aren't as easy is when the garbage The only case where things aren't as easy is when the garbage
collector needs some assembler tweaking to work. The standard collector needs some assembler tweaking to work. The standard
version of the GC uses C's ``setjmp`` function to store all registers version of the GC uses C's ``setjmp`` function to store all registers
on the hardware stack. It may be that the new platform needs to on the hardware stack. It may be necessary that the new platform needs to
replace this generic code by some assembler code. replace this generic code by some assembler code.
@ -132,11 +163,11 @@ The Garbage Collector
Introduction Introduction
------------ ------------
We use the term *cell* here to refer to everything that is traced I use the term *cell* here to refer to everything that is traced
(sequences, refs, strings). (sequences, refs, strings).
This section describes how the new GC works. This section describes how the new GC works.
The basic algorithm is *Deferrent reference counting* with cycle detection. The basic algorithm is *Deferrent Reference Counting* with cycle detection.
References in the stack are not counted for better performance and easier C References in the stack are not counted for better performance and easier C
code generation. code generation.
@ -170,7 +201,7 @@ modifying a ``TCellSet`` during traversation leads to undefined behaviour.
iterator elements(s: TCellSet): (elem: PCell) iterator elements(s: TCellSet): (elem: PCell)
All the operations have to be perform efficiently. Because a Cellset can All the operations have to perform efficiently. Because a Cellset can
become huge a hash table alone is not suitable for this. become huge a hash table alone is not suitable for this.
We use a mixture of bitset and hash table for this. The hash table maps *pages* We use a mixture of bitset and hash table for this. The hash table maps *pages*
@ -246,16 +277,10 @@ This syntax tree is the interface between the parser and the code generator.
It is essential to understand most of the compiler's code. It is essential to understand most of the compiler's code.
In order to compile Nimrod correctly, type-checking has to be seperated from In order to compile Nimrod correctly, type-checking has to be seperated from
parsing. Otherwise generics would not work. Code generation is done for a parsing. Otherwise generics would not work.
whole module only after it has been checked for semantics.
.. include:: filelist.txt .. include:: filelist.txt
The first command line argument selects the backend. Thus the backend is
responsible for calling the parser and semantic checker. However, when
compiling ``import`` or ``include`` statements, the semantic checker needs to
call the backend, this is done by embedding a PBackend into a TContext.
The syntax tree The syntax tree
--------------- ---------------
@ -265,7 +290,7 @@ may contain cycles. The AST changes its shape after semantic checking. This
is needed to make life easier for the code generators. See the "ast" module is needed to make life easier for the code generators. See the "ast" module
for the type definitions. for the type definitions.
We use the notation ``nodeKind(fields, [sons])`` for describing I use the notation ``nodeKind(fields, [sons])`` for describing
nodes. ``nodeKind[sons]`` is a short-cut for ``nodeKind([sons])``. nodes. ``nodeKind[sons]`` is a short-cut for ``nodeKind([sons])``.
XXX: Description of the language's syntax and the corresponding trees. XXX: Description of the language's syntax and the corresponding trees.
@ -273,12 +298,16 @@ XXX: Description of the language's syntax and the corresponding trees.
How the RTL is compiled How the RTL is compiled
======================= =======================
The system module contains the part of the RTL which needs support by The ``system`` module contains the part of the RTL which needs support by
compiler magic (and the stuff that needs to be in it because the spec compiler magic (and the stuff that needs to be in it because the spec
says so). The C code generator generates the C code for it just like any other says so). The C code generator generates the C code for it just like any other
module. However, calls to some procedures like ``addInt`` are inserted by module. However, calls to some procedures like ``addInt`` are inserted by
the CCG. Therefore the module ``magicsys`` contains a table the CCG. Therefore the module ``magicsys`` contains a table (``compilerprocs``)
(``compilerprocs``) with all symbols that are marked as ``compilerproc``. with all symbols that are marked as ``compilerproc``. ``compilerprocs`` are
needed by the code generator. A ``magic`` proc is not the same as a
``compilerproc``: A ``magic`` is a proc that needs compiler magic for its
semantic checking, a ``compilerproc`` is a proc that is used by the code
generator.
@ -290,77 +319,3 @@ underlying C compiler already does all the hard work for us. The problem is the
common runtime library, especially the memory manager. Note that Borland's common runtime library, especially the memory manager. Note that Borland's
Delphi had exactly the same problem. The workaround is to not link the GC with Delphi had exactly the same problem. The workaround is to not link the GC with
the Dll and provide an extra runtime dll that needs to be initialized. the Dll and provide an extra runtime dll that needs to be initialized.
How to implement closures
=========================
A closure is a record of a proc pointer and a context ref. The context ref
points to a garbage collected record that contains the needed variables.
An example:
.. code-block:: Nimrod
type
TListRec = record
data: string
next: ref TListRec
proc forEach(head: ref TListRec, visitor: proc (s: string) {.closure.}) =
var it = head
while it != nil:
visit(it.data)
it = it.next
proc sayHello() =
var L = new List(["hallo", "Andreas"])
var temp = "jup\xff"
forEach(L, lambda(s: string) =
io.write(temp)
io.write(s)
)
This should become the following in C:
.. code-block:: C
typedef struct ... /* List type */
typedef struct closure {
void (*PrcPart)(string, void*);
void* ClPart;
}
typedef struct Tcl_data {
string temp; // all accessed variables are put in here!
}
void forEach(TListRec* head, const closure visitor) {
TListRec* it = head;
while (it != NIM_NULL) {
visitor.prc(it->data, visitor->cl_data);
it = it->next;
}
}
void printStr(string s, void* cl_data) {
Tcl_data* x = (Tcl_data*) cl_data;
io_write(x->temp);
io_write(s);
}
void sayhello() {
Tcl_data* data = new(...);
asgnRef(&data->temp, "jup\xff");
...
closure cl;
cl.prc = printStr;
cl.cl_data = data;
foreach(L, cl);
}
What about nested closure? - There's not much difference: Just put all used
variables in the data record.

File diff suppressed because it is too large Load diff

View file

@ -12,7 +12,7 @@ Introduction
This document describes the usage of the *Nimrod compiler* This document describes the usage of the *Nimrod compiler*
on the different supported platforms. It is not a definition of the Nimrod on the different supported platforms. It is not a definition of the Nimrod
programming system (therefore is the Nimrod manual). programming language (therefore is the manual).
Nimrod is free software; it is licensed under the Nimrod is free software; it is licensed under the
`GNU General Public License <gpl.html>`_. `GNU General Public License <gpl.html>`_.
@ -41,7 +41,7 @@ looks for it in the following directories (in this order):
2. ``$nimrod/config/nimrod.cfg`` (UNIX, Windows) 2. ``$nimrod/config/nimrod.cfg`` (UNIX, Windows)
3. ``/etc/nimrod.cfg`` (UNIX) 3. ``/etc/nimrod.cfg`` (UNIX)
The search stops as soon as a configuration file has been found. The reading The search stops as soon as a configuration file has been found. The reading
of ``nimrod.cfg`` can be suppressed by the ``--skip_cfg`` command line option. of ``nimrod.cfg`` can be suppressed by the ``--skip_cfg`` command line option.
Configuration settings can be overwritten in a project specific Configuration settings can be overwritten in a project specific
configuration file that is read automatically. This specific file has to configuration file that is read automatically. This specific file has to
@ -54,21 +54,13 @@ Command line settings have priority over configuration file settings.
Nimrod's directory structure Nimrod's directory structure
---------------------------- ----------------------------
The generated files that Nimrod produces all go into a subdirectory called The generated files that Nimrod produces all go into a subdirectory called
``nimcache`` in your project directory. This makes it easy to delete all ``nimcache`` in your project directory. This makes it easy to delete all
generated files. generated files.
However, the generated C code is not platform independant. C code generated for However, the generated C code is not platform independant. C code generated for
Linux does not compile on Windows, for instance. The comment on top of the Linux does not compile on Windows, for instance. The comment on top of the
C file lists the OS, CPU and CC the file has been compiled for. C file lists the OS, CPU and CC the file has been compiled for.
The library lies in ``lib``. Directly in the library directory are essential
Nimrod modules like the ``system`` and ``os`` modules. Under ``lib/base``
are additional specialized libraries or interfaces to foreign libraries which
are included in the standard distribution. The ``lib/extra`` directory is
initially empty. Third party libraries should go there. In the default
configuration the compiler always searches for libraries in ``lib``,
``lib/base`` and ``lib/extra``.
Additional Features Additional Features
=================== ===================
@ -86,8 +78,8 @@ available.
Importc Pragma Importc Pragma
~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~
The `importc`:idx: pragma provides a means to import a type, a variable, or a The `importc`:idx: pragma provides a means to import a type, a variable, or a
procedure from C. The optional argument is a string containing the C procedure from C. The optional argument is a string containing the C
identifier. If the argument is missing, the C name is the Nimrod identifier. If the argument is missing, the C name is the Nimrod
identifier *exactly as spelled*: identifier *exactly as spelled*:
.. code-block:: .. code-block::
@ -97,8 +89,8 @@ identifier *exactly as spelled*:
Exportc Pragma Exportc Pragma
~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~
The `exportc`:idx: pragma provides a means to export a type, a variable, or a The `exportc`:idx: pragma provides a means to export a type, a variable, or a
procedure to C. The optional argument is a string containing the C procedure to C. The optional argument is a string containing the C
identifier. If the argument is missing, the C name is the Nimrod identifier. If the argument is missing, the C name is the Nimrod
identifier *exactly as spelled*: identifier *exactly as spelled*:
.. code-block:: Nimrod .. code-block:: Nimrod
@ -109,7 +101,7 @@ Dynlib Pragma
~~~~~~~~~~~~~ ~~~~~~~~~~~~~
With the `dynlib`:idx: pragma a procedure or a variable can be imported from With the `dynlib`:idx: pragma a procedure or a variable can be imported from
a dynamic library (``.dll`` files for Windows, ``lib*.so`` files for UNIX). The a dynamic library (``.dll`` files for Windows, ``lib*.so`` files for UNIX). The
non-optional argument has to be the name of the dynamic library: non-optional argument has to be the name of the dynamic library:
.. code-block:: Nimrod .. code-block:: Nimrod
proc gtk_image_new(): PGtkWidget {.cdecl, dynlib: "libgtk-x11-2.0.so", importc.} proc gtk_image_new(): PGtkWidget {.cdecl, dynlib: "libgtk-x11-2.0.so", importc.}
@ -128,8 +120,8 @@ the C code. Thus it makes the following possible, for example:
.. code-block:: Nimrod .. code-block:: Nimrod
var var
EOF {.importc: "EOF", no_decl.}: cint # pretend EOF was a variable, as EACCES {.importc, no_decl.}: cint # pretend EACCES was a variable, as
# Nimrod does not know its value # Nimrod does not know its value
However, the ``header`` pragma is often the better alternative. However, the ``header`` pragma is often the better alternative.
@ -164,14 +156,6 @@ strings automatically:
printf("hallo %s", "world") # "world" will be passed as C string printf("hallo %s", "world") # "world" will be passed as C string
No_static Pragma
~~~~~~~~~~~~~~~~
The `no_static`:idx: pragma can be applied to almost any symbol and specifies
that it shall not be declared ``static`` in the generated C code. Note that
symbols in the interface part of a module never get declared ``static``, so
only in very special cases this pragma is necessary.
Line_dir Option Line_dir Option
~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~
The `line_dir`:idx: option can be turned on or off. If on the generated C code The `line_dir`:idx: option can be turned on or off. If on the generated C code
@ -216,14 +200,14 @@ The `register`:idx: pragma is for variables only. It declares the variable as
in a hardware register for faster access. C compilers usually ignore this in a hardware register for faster access. C compilers usually ignore this
though and for good reason: Often they do a better job without it anyway. though and for good reason: Often they do a better job without it anyway.
In highly specific cases (a dispatch loop of an bytecode interpreter for In highly specific cases (a dispatch loop of an bytecode interpreter for
example) it may provide benefits, though. example) it may provide benefits, though.
Acyclic Pragma Acyclic Pragma
~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~
The `acyclic`:idx: pragma can be used for object types to mark them as acyclic The `acyclic`:idx: pragma can be used for object types to mark them as acyclic
even though they seem to be cyclic. This is an **optimization** for the garbage even though they seem to be cyclic. This is an **optimization** for the garbage
collector to not consider objects of this type as part of a cycle:: collector to not consider objects of this type as part of a cycle::
type type
@ -231,15 +215,31 @@ collector to not consider objects of this type as part of a cycle::
TNode {.acyclic, final.} = object TNode {.acyclic, final.} = object
left, right: PNode left, right: PNode
data: string data: string
In the example a tree structure is declared with the ``TNode`` type. Note that In the example a tree structure is declared with the ``TNode`` type. Note that
the type definition is recursive thus the GC has to assume that objects of the type definition is recursive thus the GC has to assume that objects of
this type may form a cyclic graph. The ``acyclic`` pragma passes the this type may form a cyclic graph. The ``acyclic`` pragma passes the
information that this cannot happen to the GC. If the programmer uses the information that this cannot happen to the GC. If the programmer uses the
``acyclic`` pragma for data types that are in reality cyclic, the GC may leak ``acyclic`` pragma for data types that are in reality cyclic, the GC may leak
memory, but nothing worse happens. memory, but nothing worse happens.
Dead_code_elim Pragma
~~~~~~~~~~~~~~~~~~~~~
The `dead_code_elim`:idx: pragma only applies to whole modules: It tells the
compiler to active (or deactivate) dead code elimination for the module the
pragma appers in.
The ``--dead_code_elim:on`` command line switch has the same effect as marking
any module with ``{.dead_code_elim:on}``. However, for some modules such as
the GTK wrapper it makes sense to *always* turn on dead code elimination -
no matter if it is globally active or not.
Example:
.. code-block:: nimrod
{.dead_code_elim: on.}
Disabling certain messages Disabling certain messages
-------------------------- --------------------------
@ -280,8 +280,8 @@ However, sometimes one has to optimize. Do it in the following order:
This section can only help you with the last item. Note that rewriting parts This section can only help you with the last item. Note that rewriting parts
of your program in C is *never* necessary to speed up your program, because of your program in C is *never* necessary to speed up your program, because
everything that can be done in C can be done in Nimrod. Rewriting parts in everything that can be done in C can be done in Nimrod.
assembler *might*.
Optimizing string handling Optimizing string handling
-------------------------- --------------------------

View file

@ -18,8 +18,7 @@ compatible to the original implementation as one would like.
Even though Nimrod's |rst| parser does not parse all constructs, it is pretty Even though Nimrod's |rst| parser does not parse all constructs, it is pretty
usable. The missing features can easily be circumvented. An indication of this usable. The missing features can easily be circumvented. An indication of this
fact is that Nimrod's fact is that Nimrod's *whole* documentation itself (including this document) is
*whole* documentation itself (including this document) is
processed by Nimrod's |rst| parser. (Which is an order of magnitude faster than processed by Nimrod's |rst| parser. (Which is an order of magnitude faster than
Docutils' parser.) Docutils' parser.)

File diff suppressed because it is too large Load diff

1382
doc/tut1.txt Normal file

File diff suppressed because it is too large Load diff

718
doc/tut2.txt Normal file
View file

@ -0,0 +1,718 @@
=============================
The Nimrod Tutorial (Part II)
=============================
:Author: Andreas Rumpf
:Version: |nimrodversion|
.. contents::
Introduction
============
"With great power comes great responsibility." -- Spider-man
This document is a tutorial for the advanced constructs of the *Nimrod*
programming language.
Pragmas
=======
Pragmas are Nimrod's method to give the compiler additional information/
commands without introducing a massive number of new keywords. Pragmas are
processed during semantic checking. Pragmas are enclosed in the
special ``{.`` and ``.}`` curly dot brackets. This tutorial does not cover
pragmas. See the `manual <manual.html>`_ or `user guide <nimrodc.html>`_ for
a description of the available pragmas.
Object Oriented Programming
===========================
While Nimrod's support for object oriented programming (OOP) is minimalistic,
powerful OOP technics can be used. OOP is seen as *one* way to design a
program, not *the only* way. Often a procedural approach leads to simpler
and more efficient code.
Objects
-------
Like tuples, objects are a means to pack different values together in a
structured way. However, objects provide many features that tuples do not:
They provide inheritance and information hiding. Because objects encapsulate
data, the ``()`` tuple constructor cannot be used to construct objects. So
the order of the object's fields is not as important as it is for tuples. The
programmer should provide a proc to initialize the object (this is called
a *constructor*).
Objects have access to their type at runtime. There is an
``is`` operator that can be used to check the object's type:
.. code-block:: nimrod
type
TPerson = object of TObject
name*: string # the * means that `name` is accessible from other modules
age: int # no * means that the field is hidden from other modules
TStudent = object of TPerson # TStudent inherits from TPerson
id: int # with an id field
var
student: TStudent
person: TPerson
assert(student is TStudent) # is true
Object fields that should be visible from outside the defining module, have to
be marked by ``*``. In contrast to tuples, different object types are
never *equivalent*. New object types can only be defined within a type
section.
Inheritance is done with the ``object of`` syntax. Multiple inheritance is
currently not supported. If an object type has no suitable ancestor, ``TObject``
should be used as its ancestor, but this is only a convention.
Note that aggregation (*has-a* relation) is often preferable to inheritance
(*is-a* relation) for simple code reuse. Since objects are value types in
Nimrod, aggregation is as efficient as inheritance.
Mutually recursive types
------------------------
Objects, tuples and references can model quite complex data structures which
depend on each other. This is called *mutually recursive types*. In Nimrod
these types need to be declared within a single type section. Anything else
would require arbitrary symbol lookahead which slows down compilation.
Example:
.. code-block:: nimrod
type
PNode = ref TNode # a traced reference to a TNode
TNode = object
le, ri: PNode # left and right subtrees
sym: ref TSym # leaves contain a reference to a TSym
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
Type conversions
----------------
Nimrod distinguishes between `type casts`:idx: and `type conversions`:idx:.
Casts are done with the ``cast`` operator and force the compiler to
interpret a bit pattern to be of another type.
Type conversions are a much more polite way to convert a type into another:
They preserve the abstract *value*, not necessarily the *bit-pattern*. If a
type conversion is not possible, the compiler complains or an exception is
raised.
The syntax for type conversions is ``destination_type(expression_to_convert)``
(like an ordinary call):
.. code-block:: nimrod
proc getID(x: TPerson): int =
return TStudent(x).id
The ``EInvalidObjectConversion`` exception is raised if ``x`` is not a
``TStudent``.
Object variants
---------------
Often an object hierarchy is overkill in certain situations where simple
`variant`:idx: types are needed.
An example:
.. code-block:: nimrod
# This is an example how an abstract syntax tree could be modelled in Nimrod
type
TNodeKind = enum # the different node types
nkInt, # a leaf with an integer value
nkFloat, # a leaf with a float value
nkString, # a leaf with a string value
nkAdd, # an addition
nkSub, # a subtraction
nkIf # an if statement
PNode = ref TNode
TNode = object
case kind: TNodeKind # the ``kind`` field is the discriminator
of nkInt: intVal: int
of nkFloat: floavVal: float
of nkString: strVal: string
of nkAdd, nkSub:
leftOp, rightOp: PNode
of nkIf:
condition, thenPart, elsePart: PNode
var
n: PNode
new(n) # creates a new node
n.kind = nkFloat
n.floatVal = 0.0 # valid, because ``n.kind==nkFloat``
# the following statement raises an `EInvalidField` exception, because
# n.kind's value does not fit:
n.strVal = ""
As can been seen from the example, an advantage to an object hierarchy is that
no conversion between different object types is needed. Yet, access to invalid
object fields raises an exception.
Methods
-------
In ordinary object oriented languages, procedures (also called *methods*) are
bound to a class. This has disadvantages:
* Adding a method to a class the programmer has no control over is
impossible or needs ugly workarounds.
* Often it is unclear where the procedure should belong to: Is
``join`` a string method or an array method? Should the complex
``vertexCover`` algorithm really be a method of the ``graph`` class?
Nimrod avoids these problems by not distinguishing between methods and
procedures. Methods are just ordinary procedures. However, there is a special
syntactic sugar for calling procedures: The syntax ``obj.method(args)`` can be
used instead of ``method(obj, args)``. If there are no remaining arguments, the
parentheses can be omitted: ``obj.len`` (instead of ``len(obj)``).
This `method call syntax`:idx: is not restricted to objects, it can be used
for any type:
.. code-block:: nimrod
echo("abc".len) # is the same as echo(len("abc"))
echo("abc".toUpper())
echo({'a', 'b', 'c'}.card)
stdout.writeln("Hallo") # the same as write(stdout, "Hallo")
If it gives you warm fuzzy feelings, you can even write ``1.`+`(2)`` instead of
``1 + 2`` and claim that Nimrod is a pure object oriented language. (That
would not even be lying: *pure OO* has no meaning anyway. :-)
Properties
----------
As the above example shows, Nimrod has no need for *get-properties*:
Ordinary get-procedures that are called with the *method call syntax* achieve
the same. But setting a value is different; for this a special setter syntax
is needed:
.. code-block:: nimrod
type
TSocket* = object of TObject
FHost: int # cannot be accessed from the outside of the module
# the `F` prefix is a convention to avoid clashes since
# the accessors are named `host`
proc `host=`*(s: var TSocket, value: int) {.inline.} =
## setter of hostAddr
s.FHost = value
proc host*(s: TSocket): int {.inline.} =
## getter of hostAddr
return s.FHost
var
s: TSocket
s.host = 34 # same as `host=`(s, 34)
(The example also shows ``inline`` procedures.)
The ``[]`` array access operator can be overloaded to provide
`array properties`:idx:\ :
.. code-block:: nimrod
type
TVector* = object
x, y, z: float
proc `[]=`* (v: var TVector, i: int, value: float) =
# setter
case i
of 0: v.x = value
of 1: v.y = value
of 2: v.z = value
else: assert(false)
proc `[]`* (v: TVector, i: int): float =
# getter
case i
of 0: result = v.x
of 1: result = v.y
of 2: result = v.z
else: assert(false)
The example is silly, since a vector is better modelled by a tuple which
already provides ``v[]`` access.
Dynamic binding
---------------
In Nimrod procedural types are used to implement dynamic binding. The following
example also shows some more conventions: The ``self`` or ``this`` object
is named ``my`` (because it is shorter than the alternatives), each class
provides a constructor, etc.
.. code-block:: nimrod
type
TFigure = object of TObject # abstract base class:
draw: proc (my: var TFigure) # concrete classes implement this proc
proc init(f: var TFigure) =
f.draw = nil
type
TCircle = object of TFigure
radius: int
proc drawCircle(my: var TCircle) = echo("o " & $my.radius)
proc init(my: var TCircle) =
init(TFigure(my)) # call base constructor
my.radius = 5
my.draw = drawCircle
type
TRectangle = object of TFigure
width, height: int
proc drawRectangle(my: var TRectangle) = echo("[]")
proc init(my: var TRectangle) =
init(TFigure(my)) # call base constructor
my.width = 5
my.height = 10
my.draw = drawRectangle
# now use these classes:
var
r: TRectangle
c: TCircle
init(r)
init(c)
r.draw(r)
c.draw(c)
The last line shows the syntactical difference between static and dynamic
binding: The ``r.draw(r)`` dynamic call refers to ``r`` twice. This difference
is not necessarily bad. But if you want to eliminate the somewhat redundant
``r``, it can be done by using *closures*:
.. code-block:: nimrod
type
TFigure = object of TObject # abstract base class:
draw: proc () {.closure.} # concrete classes implement this proc
proc init(f: var TFigure) =
f.draw = nil
type
TCircle = object of TFigure
radius: int
proc init(me: var TCircle) =
init(TFigure(me)) # call base constructor
me.radius = 5
me.draw = lambda () =
echo("o " & $me.radius)
type
TRectangle = object of TFigure
width, height: int
proc init(me: var TRectangle) =
init(TFigure(me)) # call base constructor
me.width = 5
me.height = 10
me.draw = lambda () =
echo("[]")
# now use these classes:
var
r: TRectangle
c: TCircle
init(r)
init(c)
r.draw()
c.draw()
The example also introduces `lambda`:idx: expressions: A ``lambda`` expression
defines a new proc with the ``closure`` calling convention on the fly.
`Version 0.7.4: Closures and lambda expressions are not implemented.`:red:
Exceptions
==========
In Nimrod `exceptions`:idx: are objects. By convention, exception types are
prefixed with an 'E', not 'T'. The ``system`` module defines an exception
hierarchy that you should stick to. Reusing an existing exception type is
often better than defining a new exception type: It avoids a proliferation of
types.
Exceptions should be allocated on the heap because their lifetime is unknown.
A convention is that exceptions should be raised in *exceptional* cases:
For example, if a file cannot be opened, this should not raise an exception
since this is quite common (the file may have been deleted).
Raise statement
---------------
Raising an exception is done with the ``raise`` statement:
.. code-block:: nimrod
var
e: ref EOS
new(e)
e.msg = "the request to the OS failed"
raise e
If the ``raise`` keyword is not followed by an expression, the last exception
is *re-raised*.
Try statement
-------------
The `try`:idx: statement handles exceptions:
.. code-block:: nimrod
# read the first two lines of a text file that should contain numbers
# and tries to add them
var
f: TFile
if openFile(f, "numbers.txt"):
try:
var a = readLine(f)
var b = readLine(f)
echo("sum: " & $(parseInt(a) + parseInt(b)))
except EOverflow:
echo("overflow!")
except EInvalidValue:
echo("could not convert string to integer")
except EIO:
echo("IO error!")
except:
echo("Unknown exception!")
# reraise the unknown exception:
raise
finally:
closeFile(f)
The statements after the ``try`` are executed unless an exception is
raised. Then the appropriate ``except`` part is executed.
The empty ``except`` part is executed if there is an exception that is
not explicitely listed. It is similiar to an ``else`` part in ``if``
statements.
If there is a ``finally`` part, it is always executed after the
exception handlers.
The exception is *consumed* in an ``except`` part. If an exception is not
handled, it is propagated through the call stack. This means that often
the rest of the procedure - that is not within a ``finally`` clause -
is not executed (if an exception occurs).
Generics
========
`Version 0.7.4: Complex generic types like in the example do not work.`:red:
`Generics`:idx: are Nimrod's means to parametrize procs, iterators or types
with `type parameters`:idx:. They are most useful for efficient type safe
containers:
.. code-block:: nimrod
type
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
PBinaryTree*[T] = ref TBinaryTree[T] # type that is exported
proc newNode*[T](data: T): PBinaryTree[T] =
# constructor for a node
new(result)
result.dat = data
proc add*[T](root: var PBinaryTree[T], n: PBinaryTree[T]) =
# insert a node into the tree
if root == nil:
root = n
else:
var it = root
while it != nil:
# compare the data items; uses the generic ``cmd`` proc that works for
# any type that has a ``==`` and ``<`` operator
var c = cmp(it.data, n.data)
if c < 0:
if it.le == nil:
it.le = n
return
it = it.le
else:
if it.ri == nil:
it.ri = n
return
it = it.ri
proc add*[T](root: var PBinaryTree[T], data: T) =
# convenience proc:
add(root, newNode(data))
iterator preorder*[T](root: PBinaryTree[T]): T =
# Preorder traversal of a binary tree.
# Since recursive iterators are not yet implemented,
# this uses an explicit stack (which is more efficient anyway):
var stack: seq[PBinaryTree[T]] = @[root]
while stack.len > 0:
var n = stack[stack.len-1]
setLen(stack, stack.len-1) # pop `n` of the stack
while n != nil:
yield n
add(stack, n.ri) # push right subtree onto the stack
n = n.le # and follow the left pointer
var
root: PBinaryTree[string] # instantiate a PBinaryTree with ``string``
add(root, newNode("hallo")) # instantiates generic procs ``newNode`` and ``add``
add(root, "world") # instantiates the second ``add`` proc
for str in preorder(root):
stdout.writeln(str)
The example shows a generic binary tree. Depending on context, the brackets are
used either to introduce type parameters or to instantiate a generic proc,
iterator or type. As the example shows, generics work with overloading: The
best match of ``add`` is used. The built-in ``add`` procedure for sequences
is not hidden and used in the ``preorder`` iterator.
Templates
=========
Templates are a simple substitution mechanism that operates on Nimrod's
abstract syntax trees. Templates are processed in the semantic pass of the
compiler. They integrate well with the rest of the language and share none
of C's preprocessor macros flaws. However, they may lead to code that is harder
to understand and maintain. So one should use them sparingly.
To *invoke* a template, call it like a procedure.
Example:
.. code-block:: nimrod
template `!=` (a, b: expr): expr =
# this definition exists in the System module
not (a == b)
assert(5 != 6) # the compiler rewrites that to: assert(not (5 == 6))
The ``!=``, ``>``, ``>=``, ``in``, ``notin``, ``isnot`` operators are in fact
templates: This has the benefit that if you overload the ``==`` operator,
the ``!=`` operator is available automatically and does the right thing.
``a > b`` is transformed into ``b < a``.
``a in b`` is transformed into ``contains(b, a)``.
``notin`` and ``isnot`` have the obvious meanings.
Templates are especially useful for lazy evaluation purposes. Consider a
simple proc for logging:
.. code-block:: nimrod
const
debug = True
proc log(msg: string) {.inline.} =
if debug:
stdout.writeln(msg)
var
x = 4
log("x has the value: " & $x)
This code has a shortcoming: If ``debug`` is set to false someday, the quite
expensive ``$`` and ``&`` operations are still performed! (The argument
evaluation for procedures is said to be *eager*).
Turning the ``log`` proc into a template solves this problem in an elegant way:
.. code-block:: nimrod
const
debug = True
template log(msg: expr): stmt =
if debug:
stdout.writeln(msg)
var
x = 4
log("x has the value: " & $x)
The "types" of templates can be the symbols ``expr`` (stands for *expression*),
``stmt`` (stands for *statement*) or ``typedesc`` (stands for *type
description*). These are no real types, they just help the compiler parsing.
The template body does not open a new scope. To open a new scope
use a ``block`` statement:
.. code-block:: nimrod
template declareInScope(x: expr, t: typeDesc): stmt =
var x: t
template declareInNewScope(x: expr, t: typeDesc): stmt =
# open a new scope:
block:
var x: t
declareInScope(a, int)
a = 42 # works, `a` is known here
declareInNewScope(b, int)
b = 42 # does not work, `b` is unknown
Macros
======
If the template mechanism scares you, you will be pleased to hear that
templates are not really necessary: Macros can do anything that templates can
do and much more. Macros are harder to write than templates and even harder
to get right :-). Now that you have been warned, lets see what a macro *is*.
Macros enable advanced compile-time code tranformations, but they
cannot change Nimrod's syntax. However, this is no real restriction because
Nimrod's syntax is flexible enough anyway.
`Macros`:idx: can be used to implement `domain specific languages`:idx:.
To write macros, one needs to know how the Nimrod concrete syntax is converted
to an abstract syntax tree (AST). (Unfortunately the AST is not documented yet.)
There are two ways to invoke a macro:
(1) invoking a macro like a procedure call (`expression macros`:idx:)
(2) invoking a macro with the special ``macrostmt`` syntax (`statement macros`:idx:)
Expression Macros
-----------------
The following example implements a powerful ``debug`` command that accepts a
variable number of arguments (this cannot be done with templates):
.. code-block:: nimrod
# to work with Nimrod syntax trees, we need an API that is defined in the
# ``macros`` module:
import macros
macro debug(n: expr): stmt =
# `n` is a Nimrod AST that contains the whole macro expression
# this macro returns a list of statements:
result = newNimNode(nnkStmtList, n)
# iterate over any argument that is passed to this macro:
for i in 1..n.len-1:
# add a call to the statement list that writes the expression;
# `toStrLit` converts an AST to its string representation:
result.add(newCall("write", newIdentNode("stdout"), toStrLit(n[i])))
# add a call to the statement list that writes ": "
result.add(newCall("write", newIdentNode("stdout"), newStrLitNode(": ")))
# add a call to the statement list that writes the expressions value:
result.add(newCall("writeln", newIdentNode("stdout"), n[i]))
var
a: array[0..10, int]
x = "some string"
a[0] = 42
a[1] = 45
debug(a[0], a[1], x)
The macro call expands to:
.. code-block:: nimrod
write(stdout, "a[0]")
write(stdout, ": ")
writeln(stdout, a[0])
write(stdout, "a[1]")
write(stdout, ": ")
writeln(stdout, a[1])
write(stdout, "x")
write(stdout, ": ")
writeln(stdout, x)
Lets return to the dynamic binding ``r.draw(r)`` notational "problem". Apart
from closures, there is another "solution": Define an infix ``!`` macro
operator which hides it:
.. code-block::
macro `!` (n: expr): expr =
result = newNimNode(nnkCall, n)
var dot = newNimNode(nnkDotExpr, n)
dot.add(n[1]) # obj
if n[2].kind == nnkCall:
# transforms ``obj!method(arg1, arg2, ...)`` to
# ``(obj.method)(obj, arg1, arg2, ...)``
dot.add(n[2][0]) # method
result.add(dot)
result.add(n[1]) # obj
for i in 1..n[2].len-1:
result.add(n[2][i])
else:
# transforms ``obj!method`` to
# ``(obj.method)(obj)``
dot.add(n[2]) # method
result.add(dot)
result.add(n[1]) # obj
r!draw(a, b, c) # will be transfomed into ``r.draw(r, a, b, c)``
Great! 20 lines of complex code to safe a few keystrokes! Obviously, this is
exactly you should not do! (But it makes a cool example.)
Statement Macros
----------------
Statement macros are defined just as expression macros. However, they are
invoked by an expression following a colon.
The following example outlines a macro that generates a lexical analyser from
regular expressions:
.. code-block:: nimrod
macro case_token(n: stmt): stmt =
# creates a lexical analyser from regular expressions
# ... (implementation is an exercise for the reader :-)
nil
case_token: # this colon tells the parser it is a macro statement
of r"[A-Za-z_]+[A-Za-z_0-9]*":
return tkIdentifier
of r"0-9+":
return tkInteger
of r"[\+\-\*\?]+":
return tkOperator
else:
return tkUnknown

View file

@ -1,215 +0,0 @@
===========================================
Tutorial of the Nimrod Programming Language
===========================================
:Author: Andreas Rumpf
Motivation
==========
Why yet another programming language?
Look at the trends behind all the new programming languages:
* They try to be dynamic: Dynamic typing, dynamic method binding, etc.
In my opinion the most things the dynamic features buy could be achieved
with static means in a more efficient and *understandable* way.
* They depend on big runtime environments which you need to
ship with your program as each new version of these may break compability
in subtle ways or you use recently added features - thus forcing your
users to update their runtime environment. Compiled programs where the
executable contains all needed code are simply the better solution.
* They are unsuitable for systems programming: Do you really want to
write an operating system, a device driver or an interpreter in a language
that is just-in-time compiled (or interpreted)?
So what lacks are *good* systems programming languages. Nimrod is such a
language. It offers the following features:
* It is readable: It reads from left to right (unlike the C-syntax
languages).
* It is strongly and statically typed: This enables the compiler to find
more errors. Static typing also makes programs more *readable*.
* It is compiled. (Currently this is done via compilation to C.)
* It is garbage collected. Big systems need garbage collection. Manuell
memory management is also supported through *untraced pointers*.
* It scales because high level features are also available: It has built-in
bit sets, strings, enumerations, objects, arrays and dynamically resizeable
arrays (called *sequences*).
* It has high performance: The current implementation compiles to C
and uses a Deutsch-Bobrow garbage collector together with Christoper's
partial mark-sweep garbage collector leading to excellent execution
speed and a small memory footprint.
* It has real modules with proper interfaces and supports separate
compilation.
* It is portable: It compiles to C and platform specific features have
been separated and documented. So even if your platform is not supported
porting should be easy.
* It is flexible: Although primilarily a procedural language, generic,
functional and object-oriented programming is also supported.
* It is easy to learn, easy to use and leads to elegant programs.
* You can link an embedded debugger to your program (ENDB). ENDB is
very easy to use - there is no need to clutter your code with
``echo`` statements for proper debugging.
Introduction
============
This document is a tutorial for the programming language *Nimrod*. It should
be a readable quick tour through the language instead of a dry specification
(which can be found `here <manual.html>`_). This tutorial assumes that
the reader already knows some other programming language such as Pascal. Thus
it is detailed in cases where Nimrod differs from other programming languages
and kept short where Nimrod is more or less the same.
A quick tour through the language
=================================
The first program
-----------------
We start the tour with a modified "hallo world" program:
.. code-block:: Nimrod
# This is a comment
# Standard IO-routines are always accessible
write(stdout, "What's your name? ")
var name: string = readLine(stdin)
write(stdout, "Hi, " & name & "!\n")
Save this code to the file "greeting.nim". Now compile and run it::
nimrod compile --run greeting.nim
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 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
starts. Indentation is Nimrod's way of grouping statements. String literals
are enclosed in double quotes. The ``var`` statement declares a new variable
named ``name`` of type ``string`` with the value that is returned by the
``readline`` procedure. Since the compiler knows that ``readline`` returns
a string, you can leave out the type in the declaration. So this will work too:
.. code-block:: Nimrod
var name = readline(stdin)
Note that this is the only form of type inference that exists in Nimrod:
This is because it yields a good compromise between brevity and readability.
The ``&`` operator concates strings together. ``\n`` stands for the
new line character(s). On several operating systems ``\n`` is represented by
*two* characters: Linefeed and Carriage Return. That is why
*character literals* cannot contain ``\n``. But since Nimrod handles strings
so well, this is a nonissue.
The "hallo world" program contains several identifiers that are already
known to the compiler: ``write``, ``stdout``, ``readLine``, etc. These
built-in items are declared in the system_ module which is implicitly
imported by any other module.
Lexical elements
----------------
Let us look into Nimrod's lexical elements in more detail: Like other
programming languages Nimrod consists of identifiers, keywords, comments,
operators, and other punctation marks. Case is *insignificant* in Nimrod and
even underscores are ignored: ``This_is_an_identifier`` and this is the same
identifier ``ThisIsAnIdentifier``. This feature enables one to use other
peoples code without bothering about a naming convention that one does not
like.
String literals are enclosed in double quotes, character literals in single
quotes. There exist also *raw* string and character literals:
.. code-block:: Nimrod
r"C:\program files\nim"
In raw literals the backslash is not an escape character, so they fit
the principle *what you see is what you get*. *Long string literals*
are also available (``""" ... """``); they can span over multiple lines
and the ``\`` is not an escape character either. They are very useful
for embedding SQL code templates for example.
Comments start with ``#`` and run till the end of the line. (Well this is not
quite true, but you should read the manual for a proper explanation.)
... XXX number literals
The usual statements - if, while, for, case
-------------------------------------------
In Nimrod indentation is used to group statements.
An example showing the most common statement types:
.. code-block:: Nimrod
var name = readLine(stdin)
if name == "Andreas":
echo("What a nice name!")
elif name == "":
echo("Don't you have a name?")
else:
echo("Boring name...")
for i in 0..length(name)-1:
if name[i] == 'm':
echo("hey, there is an *m* in your name!")
echo("Please give your password: \n")
var pw = readLine(stdin)
while pw != "12345":
echo("Wrong password! Next try: \n")
pw = readLine(stdin)
echo("""Login complete!
What do you want to do?
delete-everything
restart-computer
go-for-a-walk
""")
case readline(stdin)
of "delete-everything", "restart-computer":
echo("permission denied")
of "go-for-a-walk": echo("please yourself")
else: echo("unknown command")
..
Types
-----
Nimrod has a rich type system. This tutorial only gives a few examples. Read
the `manual <manual.html>`_ for further information:
.. code-block:: Nimrod
type
TMyRecord = object
x, y: int
Procedures
----------
Procedures are subroutines. They are declared in this way:
.. code-block:: Nimrod
proc findSubStr(sub: string,
.. _strutils: strutils.html
.. _system: system.html

View file

@ -1,126 +0,0 @@
#! /bin/sh
#
# Nimrod installation script
# (c) 2008 Andreas Rumpf
#
if [ $# -eq 1 ] ; then
if test -f bin/nimrod
then
echo "Nimrod already built -- skipping this phase"
else
echo "building Nimrod..."
sh ./build.sh || exit 1
echo "...done"
fi
case $1 in
"/usr/bin")
configdir=/etc
libdir=/usr/lib/nimrod
mkdir -p /usr/lib/nimrod
mkdir -p /usr/share/nimrod/doc
cp bin/nimrod /usr/bin/nimrod
cp config/nimdoc.cfg /etc/nimdoc.cfg
cp -r -p lib /usr/lib/nimrod
cp -r -p doc /usr/share/nimrod/doc
;;
"/usr/local/bin")
configdir=/etc
libdir=/usr/local/lib/nimrod
mkdir -p /usr/local/lib/nimrod
mkdir -p /usr/local/share/nimrod/doc
cp bin/nimrod /usr/local/bin/nimrod
cp config/nimdoc.cfg /etc/nimdoc.cfg
cp -r -p lib /usr/local/lib/nimrod
cp -r -p doc /usr/local/share/nimrod/doc
;;
*)
configdir="$1/nimrod/config"
libdir="$1/nimrod/lib"
mkdir -p $1/nimrod
mkdir -p $1/nimrod/bin
mkdir -p $1/nimrod/config
mkdir -p $1/nimrod/lib
mkdir -p $1/nimrod/doc
cp bin/nimrod $1/nimrod/bin/nimrod
cp config/nimdoc.cfg $1/nimrod/config/nimdoc.cfg
cp -r -p lib $1/nimrod
cp -r -p doc $1/nimrod
;;
esac
# write the configuration file
cat >$configdir/nimrod.cfg <<EOF
# Configuration file for the Nimrod Compiler.
# Feel free to edit the default values as you need.
cc = gcc
lib=$libdir
path="\$lib/base"
path="\$lib/base/gtk"
path="\$lib/base/cairo"
path="\$lib/base/x11"
path="\$lib/base/sdl"
path="\$lib/base/opengl"
path="\$lib/base/zip"
path="\$lib/windows"
path="\$lib/posix"
path="\$lib/ecmas"
path="\$lib/extra"
@if release:
obj_checks:off
field_checks:off
range_checks:off
bound_checks:off
overflow_checks:off
assertions:off
stacktrace:off
debugger:off
line_dir:off
opt:speed
@end
# additional options always passed to the compiler:
--verbosity: "1"
hint[LineTooLong]=off
@if unix and not bsd:
passl= "-ldl"
@end
@if icc:
passl = "-cxxlib"
passc = "-cxxlib"
@end
# Configuration for the GNU C/C++ compiler:
#gcc.exe = "gcc-4.3"
#gcc.linkerExe = "gcc-4.3"
gcc.options.debug = "-g"
@if macosx:
gcc.options.always = "-w -fasm-blocks"
@else:
gcc.options.always = "-w"
@end
gcc.options.speed = "-O3 -fno-strict-aliasing"
gcc.options.size = "-Os"
EOF
echo "installation successful"
else
echo "Nimrod installation script"
echo "Usage: [sudo] sh install.h DIR"
echo "Where DIR may be:"
echo " /usr/bin"
echo " /usr/local/bin"
echo " /opt"
echo " <some other dir> (treated like '/opt')"
echo "To deinstall, use the command:"
echo "sh deinstall.sh DIR"
exit 1
fi

View file

@ -1,66 +1,66 @@
Installation Installation
============ ============
Installation on Linux/UNIX Installation on Linux/UNIX
-------------------------- --------------------------
Note: Note:
A C compiler is required - knowledge of C is not! A C compiler is required - knowledge of C is not!
The GNU C Compiler is fully supported, other compilers may work. The C compiler 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 few Linux should be in your ``$PATH`` (most likely the case). Note that some few Linux
distributions do not ship with a GCC compiler preinstalled - then you have to distributions do not ship with a GCC compiler preinstalled - then you have to
install it. install it.
Install Nimrod by downloading the appropriate ``.zip`` file and extracting it Install Nimrod by downloading the appropriate ``.zip`` file and extracting it
to a directory of your choice. The Nimrod Compiler will stay in this to a directory of your choice. The Nimrod Compiler will stay in this
directory (unless you copy it somewhere else). The compiler does not need directory (unless you copy it somewhere else). The compiler does not need
write access to its directory anymore, so copying the nimrod folder to ``/opt`` write access to its directory anymore, so copying the nimrod folder to ``/opt``
does work. does work.
Then run the following command:: Then run the following command::
sh build.sh sh build.sh
Unlike other software, Nimrod does not distribute its files over the whole file 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 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`` its folder. The disadvantage is that you have to add it to your ``PATH``
manually. An 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 [sudo] ln -s $your_install_dir/bin/nimrod /usr/bin/nimrod
Installation on the Macintosh Installation on the Macintosh
----------------------------- -----------------------------
Only MacOS X is supported. Only MacOS X is supported.
Since MacOS X is UNIX based too, it works like the installation on Linux. 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 need to install Apple's developer's tools for the GNU Compiler Collection
though. though.
Installation on Windows Installation on Windows
----------------------- -----------------------
Install Nimrod by downloading and running Install Nimrod by downloading and running
the ``nimrod_$version.exe`` file. As default, the ``LLVM-GCC`` the ``nimrod_$version.exe`` file. As default, the ``LLVM-GCC``
compiler is used that is bundled with this installer. You can change compiler is used that is bundled with this installer. You can change
the configuration file to use another C compiler. the configuration file to use another C compiler.
Currently, the following C compilers are supported under Windows: Currently, the following C compilers are supported under Windows:
- | Microsoft's Visual C++ - | Microsoft's Visual C++
| http://msdn.microsoft.com/visualc | http://msdn.microsoft.com/visualc
| (You need the SDK too - but not the full one: Essential are only | (You need the SDK too - but not the full one: Essential are only
the win32api header files and import libraries.) the win32api header files and import libraries.)
- | Gnu C Compiler (the mingw version; the cygwin version has not been tested!) - | Gnu C Compiler (the mingw version; the cygwin version has not been tested!)
| http://www.mingw.org/download.shtml | http://www.mingw.org/download.shtml
- | LLVM with GNU C/C++ frontend - | LLVM with GNU C/C++ frontend
| http://llvm.org/releases/download.html#2.2 | http://llvm.org/releases/download.html#2.2
- | Digital Mars C++ - | Digital Mars C++
| http://www.digitalmars.com/download/freecompiler.html | http://www.digitalmars.com/download/freecompiler.html
For better compile times I recommend Digital Mars C++ -- it is easy to install For better compile times I recommend Digital Mars C++ -- it is easy to install
and a small package. and a small package.

81
koch.py
View file

@ -18,7 +18,7 @@ False = 0 == 1
# --------------------- constants ---------------------------------------- # --------------------- constants ----------------------------------------
NIMROD_VERSION = '0.7.2' NIMROD_VERSION = '0.7.4'
# This string contains Nimrod's version. It is the only place # This string contains Nimrod's version. It is the only place
# where the version needs to be updated. The rest is done by # where the version needs to be updated. The rest is done by
# the build process automatically. It is replaced **everywhere** # the build process automatically. It is replaced **everywhere**
@ -35,8 +35,6 @@ force = False
GENERATE_DIFF = False GENERATE_DIFF = False
# if set, a diff.log file is generated when bootstrapping # if set, a diff.log file is generated when bootstrapping
# this uses quite a good amount of RAM (ca. 12 MB), so it should not be done
# on underpowered systems.
USE_FPC = True USE_FPC = True
@ -45,31 +43,6 @@ BOOTCMD = "%s cc --compile:build/platdef.c %s rod/nimrod.nim"
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
DOC = split("""endb intern lib manual nimrodc steps overview""")
SRCDOC = split("""system os strutils base/regexprs math complex times
parseopt hashes strtabs lexbase parsecfg base/dialogs
posix/posix
streams base/odbcsql
base/zip/zipfiles base/zip/zlib base/zip/libzip
""")
ADD_SRCDOC = split("""
base/cairo/cairo base/cairo/cairoft
base/cairo/cairowin32 base/cairo/cairoxlib
base/gtk/atk base/gtk/gdk2 base/gtk/gdk2pixbuf
base/gtk/gdkglext base/gtk/glib2 base/gtk/gtk2
base/gtk/gtkglext base/gtk/gtkhtml base/gtk/libglade2
base/gtk/pango base/gtk/pangoutils
windows/windows windows/mmsystem windows/nb30
windows/ole2 windows/shellapi windows/shfolder
base/x11/*.nim
base/opengl/*.nim
base/sdl/*.nim
base/lua/*.nim
""")
# --------------------------------------------------------------------------
def Error(msg): sys.exit("[Koch] *** ERROR: " + msg) def Error(msg): sys.exit("[Koch] *** ERROR: " + msg)
def Warn(msg): print "[Koch] *** WARNING: " + msg def Warn(msg): print "[Koch] *** WARNING: " + msg
def Echo(msg): print "[Koch] " + msg def Echo(msg): print "[Koch] " + msg
@ -140,7 +113,7 @@ BaseDir = _baseDir
def Path(a): def Path(a):
# Gets a UNIX like path and converts it to a path on this platform. # Gets a UNIX like path and converts it to a path on this platform.
# With UNIX like, I mean: slashes, not backslashes, only relative # With UNIX like, I mean: slashes, not backslashes, only relative
# paths ('../etc' can be used) # paths ('../etc') can be used
result = a result = a
if os.sep != "/": result = replace(result, "/", os.sep) if os.sep != "/": result = replace(result, "/", os.sep)
if os.pardir != "..": result = replace(result, "..", os.pardir) if os.pardir != "..": result = replace(result, "..", os.pardir)
@ -401,12 +374,12 @@ Options:
Possible Commands: Possible Commands:
nim builds the Pascal version of Nimrod nim builds the Pascal version of Nimrod
rod [options] builds the Nimrod version of Nimrod (with options) rod [options] builds the Nimrod version of Nimrod (with options)
doc builds the documentation in HTML
clean cleans Nimrod project; removes generated files clean cleans Nimrod project; removes generated files
boot [options] bootstraps with given command line options boot [options] bootstraps with given command line options
rodsrc generates Nimrod version from Pascal version rodsrc generates Nimrod version from Pascal version
web generates the website web generates the website
profile profile the Nimrod compiler profile profile the Nimrod compiler
csource build the C sources for installation
zip build the installation ZIP package zip build the installation ZIP package
inno build the Inno Setup installer inno build the Inno Setup installer
""" % (NIMROD_VERSION + ' ' * (44-len(NIMROD_VERSION)), sys.version) """ % (NIMROD_VERSION + ' ' * (44-len(NIMROD_VERSION)), sys.version)
@ -436,7 +409,6 @@ def main(args):
cmd = args[i] cmd = args[i]
if cmd == "rod": cmd_rod(join(args[i+1:])) if cmd == "rod": cmd_rod(join(args[i+1:]))
elif cmd == "nim": cmd_nim() elif cmd == "nim": cmd_nim()
elif cmd == "doc": cmd_doc()
elif cmd == "clean": cmd_clean() elif cmd == "clean": cmd_clean()
elif cmd == "boot": cmd_boot(join(args[i+1:])) elif cmd == "boot": cmd_boot(join(args[i+1:]))
elif cmd == "rodsrc": cmd_rodsrc() elif cmd == "rodsrc": cmd_rodsrc()
@ -444,11 +416,14 @@ def main(args):
elif cmd == "profile": cmd_profile() elif cmd == "profile": cmd_profile()
elif cmd == "zip": cmd_zip() elif cmd == "zip": cmd_zip()
elif cmd == "inno": cmd_inno() elif cmd == "inno": cmd_inno()
elif cmd == "csource": cmd_csource()
else: Error("illegal command: " + cmd) else: Error("illegal command: " + cmd)
def cmd_zip(): def cmd_csource():
Exec("nimrod cc -r tools/niminst --var:version=%s csource rod/nimrod" % Exec("nimrod cc -r tools/niminst --var:version=%s csource rod/nimrod" %
NIMROD_VERSION) NIMROD_VERSION)
def cmd_zip():
Exec("nimrod cc -r tools/niminst --var:version=%s zip rod/nimrod" % Exec("nimrod cc -r tools/niminst --var:version=%s zip rod/nimrod" %
NIMROD_VERSION) NIMROD_VERSION)
@ -586,50 +561,10 @@ def cmd_profile():
# ------------------ web ------------------------------------------------------ # ------------------ web ------------------------------------------------------
def buildDoc(destPath):
# call nim for the documentation:
for d in DOC:
Exec("nimrod rst2html --putenv:nimrodversion=%s -o:%s/%s.html "
"--index=%s/theindex doc/%s" %
(NIMROD_VERSION, destPath, d, destPath, d))
for d in SRCDOC:
Exec("nimrod doc --putenv:nimrodversion=%s -o:%s/%s.html "
"--index=%s/theindex lib/%s" %
(NIMROD_VERSION, destPath, FilenameNoExt(d), destPath, d))
Exec("nimrod rst2html -o:%s/theindex.html %s/theindex" % (destPath, destPath))
def buildAddDoc(destPath):
# build additional documentation (without the index):
def build(d):
c = Changed("web__"+d, ["lib/"+d+".nim"], EXPLAIN)
if c.check() or force:
Exec("nimrod doc --putenv:nimrodversion=%s -o:%s/%s.html "
" lib/%s" % (NIMROD_VERSION, destPath, FilenameNoExt(d), d))
c.success()
for a in ADD_SRCDOC:
if '*' in a:
for d in Glob("lib/" + a): build(d)
else:
build(a)
def cmd_web(): def cmd_web():
Exec("nimrod cc -r tools/nimweb.nim web/nimrod --putenv:nimrodversion=%s" Exec("nimrod cc -r tools/nimweb.nim web/nimrod --putenv:nimrodversion=%s"
% NIMROD_VERSION) % NIMROD_VERSION)
# ------------------ doc ------------------------------------------------------
def cmd_doc():
c = Changed("doc", ["koch.py"] +
Glob("doc/*.txt") + Glob("lib/*.txt") + Glob("lib/*.nim")+
Glob("config/*.cfg"),
EXPLAIN)
if c.check() or force:
cmd_nim() # we need Nimrod for processing the documentation
buildDoc("doc")
if Exists("doc/overview.html"):
c.success()
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
def getVersion(): def getVersion():

View file

@ -102,51 +102,16 @@ proc absInt(a: int): int {.compilerProc, inline.} =
raiseOverflow() raiseOverflow()
const const
asmVersion = defined(I386) and (defined(vcc) or defined(wcc) or defined(dmc)) asmVersion = defined(I386) and (defined(vcc) or defined(wcc) or
defined(dmc) or defined(gcc) or defined(llvm_gcc))
# my Version of Borland C++Builder does not have # my Version of Borland C++Builder does not have
# tasm32, which is needed for assembler blocks # tasm32, which is needed for assembler blocks
# this is why Borland is not included in the 'when' # this is why Borland is not included in the 'when'
useInline = not asmVersion
when asmVersion and defined(gcc): when asmVersion and not defined(gcc) and not defined(llvm_gcc):
proc addInt(a, b: int): int {.compilerProc, pure, inline.}
proc subInt(a, b: int): int {.compilerProc, pure, inline.}
proc mulInt(a, b: int): int {.compilerProc, pure, inline.}
proc divInt(a, b: int): int {.compilerProc, pure, inline.}
proc modInt(a, b: int): int {.compilerProc, pure, inline.}
proc negInt(a: int): int {.compilerProc, pure, inline.}
elif asmVersion:
proc addInt(a, b: int): int {.compilerProc, pure.}
proc subInt(a, b: int): int {.compilerProc, pure.}
proc mulInt(a, b: int): int {.compilerProc, pure.}
proc divInt(a, b: int): int {.compilerProc, pure.}
proc modInt(a, b: int): int {.compilerProc, pure.}
proc negInt(a: int): int {.compilerProc, pure.}
elif useInline:
proc addInt(a, b: int): int {.compilerProc, inline.}
proc subInt(a, b: int): int {.compilerProc, inline.}
proc mulInt(a, b: int): int {.compilerProc.}
# mulInt is to large for inlining?
proc divInt(a, b: int): int {.compilerProc, inline.}
proc modInt(a, b: int): int {.compilerProc, inline.}
proc negInt(a: int): int {.compilerProc, inline.}
else:
proc addInt(a, b: int): int {.compilerProc.}
proc subInt(a, b: int): int {.compilerProc.}
proc mulInt(a, b: int): int {.compilerProc.}
proc divInt(a, b: int): int {.compilerProc.}
proc modInt(a, b: int): int {.compilerProc.}
proc negInt(a: int): int {.compilerProc.}
# implementation:
when asmVersion and not defined(gcc):
# assembler optimized versions for compilers that # assembler optimized versions for compilers that
# have an intel syntax assembler: # have an intel syntax assembler:
proc addInt(a, b: int): int = proc addInt(a, b: int): int {.compilerProc, pure.} =
# a in eax, and b in edx # a in eax, and b in edx
asm """ asm """
mov eax, `a` mov eax, `a`
@ -156,7 +121,7 @@ when asmVersion and not defined(gcc):
theEnd: theEnd:
""" """
proc subInt(a, b: int): int = proc subInt(a, b: int): int {.compilerProc, pure.} =
asm """ asm """
mov eax, `a` mov eax, `a`
sub eax, `b` sub eax, `b`
@ -165,7 +130,7 @@ when asmVersion and not defined(gcc):
theEnd: theEnd:
""" """
proc negInt(a: int): int = proc negInt(a: int): int {.compilerProc, pure.} =
asm """ asm """
mov eax, `a` mov eax, `a`
neg eax neg eax
@ -174,7 +139,7 @@ when asmVersion and not defined(gcc):
theEnd: theEnd:
""" """
proc divInt(a, b: int): int = proc divInt(a, b: int): int {.compilerProc, pure.} =
asm """ asm """
mov eax, `a` mov eax, `a`
mov ecx, `b` mov ecx, `b`
@ -185,7 +150,7 @@ when asmVersion and not defined(gcc):
theEnd: theEnd:
""" """
proc modInt(a, b: int): int = proc modInt(a, b: int): int {.compilerProc, pure.} =
asm """ asm """
mov eax, `a` mov eax, `a`
mov ecx, `b` mov ecx, `b`
@ -197,7 +162,7 @@ when asmVersion and not defined(gcc):
mov eax, edx mov eax, edx
""" """
proc mulInt(a, b: int): int = proc mulInt(a, b: int): int {.compilerProc, pure.} =
asm """ asm """
mov eax, `a` mov eax, `a`
mov ecx, `b` mov ecx, `b`
@ -208,99 +173,105 @@ when asmVersion and not defined(gcc):
theEnd: theEnd:
""" """
elif asmVersion and defined(gcc): elif false: # asmVersion and (defined(gcc) or defined(llvm_gcc)):
proc addInt(a, b: int): int = proc addInt(a, b: int): int {.compilerProc, inline.} =
asm """ "addl %1,%%eax\n" # don't use a pure proc here!
asm """
"addl %%ecx, %%eax\n"
"jno 1\n"
"call _raiseOverflow\n"
"1: \n"
:"=a"(`result`)
:"a"(`a`), "c"(`b`)
"""
proc subInt(a, b: int): int {.compilerProc, inline.} =
asm """ "subl %%ecx,%%eax\n"
"jno 1\n"
"call _raiseOverflow\n"
"1: \n"
:"=a"(`result`)
:"a"(`a`), "c"(`b`)
"""
proc mulInt(a, b: int): int {.compilerProc, inline.} =
asm """ "xorl %%edx, %%edx\n"
"imull %%ecx\n"
"jno 1\n" "jno 1\n"
"call _raiseOverflow\n" "call _raiseOverflow\n"
"1: \n" "1: \n"
:"=a"(`a`) :"=a"(`result`)
:"a"(`a`), "r"(`b`) :"a"(`a`), "c"(`b`)
:"%edx"
""" """
proc subInt(a, b: int): int = proc negInt(a: int): int {.compilerProc, inline.} =
asm """ "subl %1,%%eax\n" asm """ "negl %%eax\n"
"jno 1\n" "jno 1\n"
"call _raiseOverflow\n" "call _raiseOverflow\n"
"1: \n" "1: \n"
:"=a"(`a`) :"=a"(`result`)
:"a"(`a`), "r"(`b`) :"a"(`a`)
""" """
proc negInt(a: int): int = proc divInt(a, b: int): int {.compilerProc, inline.} =
asm """ "negl %%eax\n"
"jno 1\n"
"call _raiseOverflow\n"
"1: \n"
:"=a"(`a`)
:"a"(`a`)
"""
proc divInt(a, b: int): int =
asm """ "xorl %%edx, %%edx\n" asm """ "xorl %%edx, %%edx\n"
"idivl %%ecx\n" "idivl %%ecx\n"
"jno 1\n" "jno 1\n"
"call _raiseOverflow\n" "call _raiseOverflow\n"
"1: \n" "1: \n"
:"=a"(`a`) :"=a"(`result`)
:"a"(`a`), "c"(`b`) :"a"(`a`), "c"(`b`)
:"%edx" :"%edx"
""" """
proc modInt(a, b: int): int = proc modInt(a, b: int): int {.compilerProc, inline.} =
asm """ "xorl %%edx, %%edx\n" asm """ "xorl %%edx, %%edx\n"
"idivl %%ecx\n" "idivl %%ecx\n"
"jno 1\n" "jno 1\n"
"call _raiseOverflow\n" "call _raiseOverflow\n"
"1: \n" "1: \n"
"movl %%edx, %%eax" "movl %%edx, %%eax"
:"=a"(`a`) :"=a"(`result`)
:"a"(`a`), "c"(`b`) :"a"(`a`), "c"(`b`)
:"%edx" :"%edx"
""" """
proc mulInt(a, b: int): int = # Platform independant versions of the above (slower!)
asm """ "xorl %%edx, %%edx\n" when not defined(addInt):
"imull %%ecx\n" proc addInt(a, b: int): int {.compilerProc, inline.} =
"jno 1\n"
"call _raiseOverflow\n"
"1: \n"
:"=a"(`a`)
:"a"(`a`), "c"(`b`)
:"%edx"
"""
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: if (result xor a) >= 0 or (result xor b) >= 0:
return result return result
raiseOverflow() raiseOverflow()
proc subInt(a, b: int): int = when not defined(subInt):
proc subInt(a, b: int): int {.compilerProc, inline.} =
result = a -% b result = a -% b
if (result xor a) >= 0 or (result xor not b) >= 0: if (result xor a) >= 0 or (result xor not b) >= 0:
return result return result
raiseOverflow() raiseOverflow()
proc negInt(a: int): int = when not defined(negInt):
proc negInt(a: int): int {.compilerProc, inline.} =
if a != low(int): return -a if a != low(int): return -a
raiseOverflow() raiseOverflow()
proc divInt(a, b: int): int = when not defined(divInt):
proc divInt(a, b: int): int {.compilerProc, inline.} =
if b == 0: if b == 0:
raiseDivByZero() raiseDivByZero()
if a == low(int) and b == -1: if a == low(int) and b == -1:
raiseOverflow() raiseOverflow()
return a div b return a div b
proc modInt(a, b: int): int = when not defined(modInt):
proc modInt(a, b: int): int {.compilerProc, inline.} =
if b == 0: if b == 0:
raiseDivByZero() raiseDivByZero()
return a mod b return a mod b
when not defined(mulInt):
# #
# This code has been inspired by Python's source code. # This code has been inspired by Python's source code.
# The native int product x*y is either exactly right or *way* off, being # The native int product x*y is either exactly right or *way* off, being
@ -321,7 +292,7 @@ else:
# the only one that can lose catastrophic amounts of information, it's the # the only one that can lose catastrophic amounts of information, it's the
# native int product that must have overflowed. # native int product that must have overflowed.
# #
proc mulInt(a, b: int): int = proc mulInt(a, b: int): int {.compilerProc.} =
var var
resAsFloat, floatProd: float resAsFloat, floatProd: float

View file

@ -281,7 +281,7 @@ proc getServerSoftware*(): string =
proc setTestData*(keysvalues: openarray[string]) = proc setTestData*(keysvalues: openarray[string]) =
## fills the appropriate environment variables to test your CGI application. ## fills the appropriate environment variables to test your CGI application.
## This can only simulate the 'GET' 'REQUEST_METHOD'. `keysvalues` should ## This can only simulate the 'GET' request method. `keysvalues` should
## provide embedded (name, value)-pairs. Example: ## provide embedded (name, value)-pairs. Example:
## ##
## .. code-block:: Nimrod ## .. code-block:: Nimrod
@ -300,6 +300,7 @@ proc setTestData*(keysvalues: openarray[string]) =
proc writeContentType*() = proc writeContentType*() =
## call this before starting to send your HTML data to `stdout`. This ## call this before starting to send your HTML data to `stdout`. This
## is just a shorthand for: ## is just a shorthand for:
##
## .. code-block:: Nimrod ## .. code-block:: Nimrod
## write(stdout, "Content-type: text/html\n\n") ## write(stdout, "Content-type: text/html\n\n")
write(stdout, "Content-type: text/html\n\n") write(stdout, "Content-type: text/html\n\n")

View file

@ -1,3 +1,5 @@
{.deadCodeElim: on.}
import import
glib2 glib2

View file

@ -1,3 +1,5 @@
{.deadCodeElim: on.}
import import
glib2, gdk2pixbuf, pango glib2, gdk2pixbuf, pango

View file

@ -1,3 +1,5 @@
{.deadCodeElim: on.}
import import
glib2 glib2

View file

@ -1,3 +1,5 @@
{.deadCodeElim: on.}
import import
Glib2, Gdk2 Glib2, Gdk2

View file

@ -1,3 +1,5 @@
{.deadCodeElim: on.}
when defined(windows): when defined(windows):
const const
gliblib = "libglib-2.0-0.dll" gliblib = "libglib-2.0-0.dll"

View file

@ -1,3 +1,5 @@
{.deadCodeElim: on.}
import import
glib2, atk, pango, gdk2pixbuf, gdk2 glib2, atk, pango, gdk2pixbuf, gdk2

View file

@ -1,3 +1,5 @@
{.deadCodeElim: on.}
import import
Glib2, Gdk2, Gtk2, GdkGLExt Glib2, Gdk2, Gtk2, GdkGLExt

View file

@ -1,3 +1,5 @@
{.deadCodeElim: on.}
import import
gtk2, glib2, atk, pango, gdk2pixbuf, gdk2 gtk2, glib2, atk, pango, gdk2pixbuf, gdk2

View file

@ -1,3 +1,5 @@
{.deadCodeElim: on.}
import import
glib2, gtk2 glib2, gtk2

View file

@ -1,3 +1,5 @@
{.deadCodeElim: on.}
import import
glib2 glib2

View file

@ -1,3 +1,5 @@
{.deadCodeElim: on.}
import import
glib2, pango glib2, pango

View file

@ -270,7 +270,8 @@
# #
# #
# {.deadCodeElim: on.}
when defined(windows): when defined(windows):
const SDLLibName = "SDL.dll" const SDLLibName = "SDL.dll"
elif defined(macosx): elif defined(macosx):

View file

@ -2,93 +2,93 @@
#****************************************************************************** #******************************************************************************
# #
# $Id: sdl_mixer.pas,v 1.18 2007/05/29 21:31:44 savage Exp $ # $Id: sdl_mixer.pas,v 1.18 2007/05/29 21:31:44 savage Exp $
#
# #
# #
# Borland Delphi SDL_Mixer - Simple DirectMedia Layer Mixer Library #
# Conversion of the Simple DirectMedia Layer Headers # Borland Delphi SDL_Mixer - Simple DirectMedia Layer Mixer Library
# # Conversion of the Simple DirectMedia Layer Headers
# Portions created by Sam Lantinga <slouken@devolution.com> are #
# Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga # Portions created by Sam Lantinga <slouken@devolution.com> are
# 5635-34 Springhouse Dr. # Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
# Pleasanton, CA 94588 (USA) # 5635-34 Springhouse Dr.
# # Pleasanton, CA 94588 (USA)
# All Rights Reserved. #
# # All Rights Reserved.
# The original files are : SDL_mixer.h #
# music_cmd.h # The original files are : SDL_mixer.h
# wavestream.h # music_cmd.h
# timidity.h # wavestream.h
# playmidi.h # timidity.h
# music_ogg.h # playmidi.h
# mikmod.h # music_ogg.h
# # mikmod.h
# The initial developer of this Pascal code was : #
# Dominqiue Louis <Dominique@SavageSoftware.com.au> # The initial developer of this Pascal code was :
# # Dominqiue Louis <Dominique@SavageSoftware.com.au>
# Portions created by Dominqiue Louis are #
# Copyright (C) 2000 - 2001 Dominqiue Louis. # Portions created by Dominqiue Louis are
# # Copyright (C) 2000 - 2001 Dominqiue Louis.
# #
# Contributor(s) #
# -------------- # Contributor(s)
# Matthias Thoma <ma.thoma@gmx.de> # --------------
# # Matthias Thoma <ma.thoma@gmx.de>
# Obtained through: #
# Joint Endeavour of Delphi Innovators ( Project JEDI ) # Obtained through:
# # Joint Endeavour of Delphi Innovators ( Project JEDI )
# You may retrieve the latest version of this file at the Project #
# JEDI home page, located at http://delphi-jedi.org # You may retrieve the latest version of this file at the Project
# # JEDI home page, located at http://delphi-jedi.org
# The contents of this file are used with permission, subject to #
# the Mozilla Public License Version 1.1 (the "License"); you may # The contents of this file are used with permission, subject to
# not use this file except in compliance with the License. You may # the Mozilla Public License Version 1.1 (the "License"); you may
# obtain a copy of the License at # not use this file except in compliance with the License. You may
# http://www.mozilla.org/MPL/MPL-1.1.html # obtain a copy of the License at
# # http://www.mozilla.org/MPL/MPL-1.1.html
# Software distributed under the License is distributed on an #
# "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or # Software distributed under the License is distributed on an
# implied. See the License for the specific language governing # "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# rights and limitations under the License. # implied. See the License for the specific language governing
# # rights and limitations under the License.
# Description #
# ----------- # Description
# # -----------
# #
# #
# #
# #
# #
# #
# Requires #
# -------- # Requires
# SDL.pas & SMPEG.pas somewhere within your search path. # --------
# # SDL.pas & SMPEG.pas somewhere within your search path.
# Programming Notes #
# ----------------- # Programming Notes
# See the Aliens Demo to see how this library is used # -----------------
# # See the Aliens Demo to see how this library is used
# Revision History #
# ---------------- # Revision History
# April 02 2001 - DL : Initial Translation # ----------------
# # April 02 2001 - DL : Initial Translation
# February 02 2002 - DL : Update to version 1.2.1 #
# # February 02 2002 - DL : Update to version 1.2.1
# April 03 2003 - DL : Added jedi-sdl.inc include file to support more #
# Pascal compilers. Initial support is now included # April 03 2003 - DL : Added jedi-sdl.inc include file to support more
# for GnuPascal, VirtualPascal, TMT and obviously # Pascal compilers. Initial support is now included
# continue support for Delphi Kylix and FreePascal. # for GnuPascal, VirtualPascal, TMT and obviously
# # continue support for Delphi Kylix and FreePascal.
#
# April 24 2003 - DL : under instruction from Alexey Barkovoy, I have added # April 24 2003 - DL : under instruction from Alexey Barkovoy, I have added
# better TMT Pascal support and under instruction # better TMT Pascal support and under instruction
# from Prof. Abimbola Olowofoyeku (The African Chief), # from Prof. Abimbola Olowofoyeku (The African Chief),
# I have added better Gnu Pascal support # I have added better Gnu Pascal support
# #
# April 30 2003 - DL : under instruction from David Mears AKA # April 30 2003 - DL : under instruction from David Mears AKA
# Jason Siletto, I have added FPC Linux support. # Jason Siletto, I have added FPC Linux support.
# This was compiled with fpc 1.1, so remember to set # This was compiled with fpc 1.1, so remember to set
# include file path. ie. -Fi/usr/share/fpcsrc/rtl/* # include file path. ie. -Fi/usr/share/fpcsrc/rtl/*
# #
# #
# $Log: sdl_mixer.pas,v $ # $Log: sdl_mixer.pas,v $
# Revision 1.18 2007/05/29 21:31:44 savage # Revision 1.18 2007/05/29 21:31:44 savage
@ -166,19 +166,19 @@ const
MIX_MAJOR_VERSION* = SDL_MIXER_MAJOR_VERSION MIX_MAJOR_VERSION* = SDL_MIXER_MAJOR_VERSION
MIX_MINOR_VERSION* = SDL_MIXER_MINOR_VERSION MIX_MINOR_VERSION* = SDL_MIXER_MINOR_VERSION
MIX_PATCHLEVEL* = SDL_MIXER_PATCHLEVEL # SDL_Mixer.h constants MIX_PATCHLEVEL* = SDL_MIXER_PATCHLEVEL # SDL_Mixer.h constants
# The default mixer has 8 simultaneous mixing channels # The default mixer has 8 simultaneous mixing channels
MIX_CHANNELS* = 8 # Good default values for a PC soundcard MIX_CHANNELS* = 8 # Good default values for a PC soundcard
MIX_DEFAULT_FREQUENCY* = 22050 MIX_DEFAULT_FREQUENCY* = 22050
when defined(IA32): when defined(IA32):
const const
MIX_DEFAULT_FORMAT* = AUDIO_S16LSB MIX_DEFAULT_FORMAT* = AUDIO_S16LSB
else: else:
const const
MIX_DEFAULT_FORMAT* = AUDIO_S16MSB MIX_DEFAULT_FORMAT* = AUDIO_S16MSB
const const
MIX_DEFAULT_CHANNELS* = 2 MIX_DEFAULT_CHANNELS* = 2
MIX_MAX_VOLUME* = 128 # Volume of a chunk MIX_MAX_VOLUME* = 128 # Volume of a chunk
PATH_MAX* = 255 # mikmod.h constants PATH_MAX* = 255 # mikmod.h constants
#* #*
# * Library version # * Library version
@ -204,7 +204,7 @@ type #music_cmd.h types
cvt*: TSDL_AudioCVT cvt*: TSDL_AudioCVT
PMidiEvent* = ptr TMidiEvent PMidiEvent* = ptr TMidiEvent
TMidiEvent*{.final.} = object TMidiEvent*{.final.} = object
time*: int32 time*: int32
channel*: uint8 channel*: uint8
type_*: uint8 type_*: uint8
@ -228,43 +228,43 @@ type #music_cmd.h types
len_available*: int len_available*: int
snd_available*: PUint8 snd_available*: PUint8
TErrorEnum* = enum TErrorEnum* = enum
MMERR_OPENING_FILE, MMERR_OUT_OF_MEMORY, MMERR_DYNAMIC_LINKING, MMERR_OPENING_FILE, MMERR_OUT_OF_MEMORY, MMERR_DYNAMIC_LINKING,
MMERR_SAMPLE_TOO_BIG, MMERR_OUT_OF_HANDLES, MMERR_UNKNOWN_WAVE_TYPE, MMERR_SAMPLE_TOO_BIG, MMERR_OUT_OF_HANDLES, MMERR_UNKNOWN_WAVE_TYPE,
MMERR_LOADING_PATTERN, MMERR_LOADING_TRACK, MMERR_LOADING_HEADER, MMERR_LOADING_PATTERN, MMERR_LOADING_TRACK, MMERR_LOADING_HEADER,
MMERR_LOADING_SAMPLEINFO, MMERR_NOT_A_MODULE, MMERR_NOT_A_STREAM, MMERR_LOADING_SAMPLEINFO, MMERR_NOT_A_MODULE, MMERR_NOT_A_STREAM,
MMERR_MED_SYNTHSAMPLES, MMERR_ITPACK_INVALID_DATA, MMERR_DETECTING_DEVICE, MMERR_MED_SYNTHSAMPLES, MMERR_ITPACK_INVALID_DATA, MMERR_DETECTING_DEVICE,
MMERR_INVALID_DEVICE, MMERR_INITIALIZING_MIXER, MMERR_OPENING_AUDIO, MMERR_INVALID_DEVICE, MMERR_INITIALIZING_MIXER, MMERR_OPENING_AUDIO,
MMERR_8BIT_ONLY, MMERR_16BIT_ONLY, MMERR_STEREO_ONLY, MMERR_ULAW, MMERR_8BIT_ONLY, MMERR_16BIT_ONLY, MMERR_STEREO_ONLY, MMERR_ULAW,
MMERR_NON_BLOCK, MMERR_AF_AUDIO_PORT, MMERR_AIX_CONFIG_INIT, MMERR_NON_BLOCK, MMERR_AF_AUDIO_PORT, MMERR_AIX_CONFIG_INIT,
MMERR_AIX_CONFIG_CONTROL, MMERR_AIX_CONFIG_START, MMERR_GUS_SETTINGS, MMERR_AIX_CONFIG_CONTROL, MMERR_AIX_CONFIG_START, MMERR_GUS_SETTINGS,
MMERR_GUS_RESET, MMERR_GUS_TIMER, MMERR_HP_SETSAMPLESIZE, MMERR_HP_SETSPEED, MMERR_GUS_RESET, MMERR_GUS_TIMER, MMERR_HP_SETSAMPLESIZE, MMERR_HP_SETSPEED,
MMERR_HP_CHANNELS, MMERR_HP_AUDIO_OUTPUT, MMERR_HP_AUDIO_DESC, MMERR_HP_CHANNELS, MMERR_HP_AUDIO_OUTPUT, MMERR_HP_AUDIO_DESC,
MMERR_HP_BUFFERSIZE, MMERR_OSS_SETFRAGMENT, MMERR_OSS_SETSAMPLESIZE, MMERR_HP_BUFFERSIZE, MMERR_OSS_SETFRAGMENT, MMERR_OSS_SETSAMPLESIZE,
MMERR_OSS_SETSTEREO, MMERR_OSS_SETSPEED, MMERR_SGI_SPEED, MMERR_SGI_16BIT, MMERR_OSS_SETSTEREO, MMERR_OSS_SETSPEED, MMERR_SGI_SPEED, MMERR_SGI_16BIT,
MMERR_SGI_8BIT, MMERR_SGI_STEREO, MMERR_SGI_MONO, MMERR_SUN_INIT, MMERR_SGI_8BIT, MMERR_SGI_STEREO, MMERR_SGI_MONO, MMERR_SUN_INIT,
MMERR_OS2_MIXSETUP, MMERR_OS2_SEMAPHORE, MMERR_OS2_TIMER, MMERR_OS2_THREAD, MMERR_OS2_MIXSETUP, MMERR_OS2_SEMAPHORE, MMERR_OS2_TIMER, MMERR_OS2_THREAD,
MMERR_DS_PRIORITY, MMERR_DS_BUFFER, MMERR_DS_FORMAT, MMERR_DS_NOTIFY, MMERR_DS_PRIORITY, MMERR_DS_BUFFER, MMERR_DS_FORMAT, MMERR_DS_NOTIFY,
MMERR_DS_EVENT, MMERR_DS_THREAD, MMERR_DS_UPDATE, MMERR_WINMM_HANDLE, MMERR_DS_EVENT, MMERR_DS_THREAD, MMERR_DS_UPDATE, MMERR_WINMM_HANDLE,
MMERR_WINMM_ALLOCATED, MMERR_WINMM_DEVICEID, MMERR_WINMM_FORMAT, MMERR_WINMM_ALLOCATED, MMERR_WINMM_DEVICEID, MMERR_WINMM_FORMAT,
MMERR_WINMM_UNKNOWN, MMERR_MAC_SPEED, MMERR_MAC_START, MMERR_MAX MMERR_WINMM_UNKNOWN, MMERR_MAC_SPEED, MMERR_MAC_START, MMERR_MAX
PMODULE* = ptr TMODULE PMODULE* = ptr TMODULE
TMODULE*{.final.} = object TMODULE*{.final.} = object
PUNIMOD* = ptr TUNIMOD PUNIMOD* = ptr TUNIMOD
TUNIMOD* = TMODULE #SDL_mixer.h types TUNIMOD* = TMODULE #SDL_mixer.h types
# The internal format for an audio chunk # The internal format for an audio chunk
PMix_Chunk* = ptr TMix_Chunk PMix_Chunk* = ptr TMix_Chunk
TMix_Chunk*{.final.} = object TMix_Chunk*{.final.} = object
allocated*: int allocated*: int
abuf*: PUint8 abuf*: PUint8
alen*: Uint32 alen*: Uint32
volume*: Uint8 # Per-sample volume, 0-128 volume*: Uint8 # Per-sample volume, 0-128
Mix_Chunk* = TMix_Chunk # The different fading types supported Mix_Chunk* = TMix_Chunk # The different fading types supported
TMix_Fading* = enum TMix_Fading* = enum
MIX_NO_FADING, MIX_FADING_OUT, MIX_FADING_IN MIX_NO_FADING, MIX_FADING_OUT, MIX_FADING_IN
Mix_Fading* = TMix_Fading Mix_Fading* = TMix_Fading
TMix_MusicType* = enum TMix_MusicType* = enum
MUS_NONE, MUS_CMD, MUS_WAV, MUS_MOD, MUS_MID, MUS_OGG, MUS_MP3 MUS_NONE, MUS_CMD, MUS_WAV, MUS_MOD, MUS_MID, MUS_OGG, MUS_MP3
Mix_MusicType* = TMix_MusicType # Mix_MusicType* = TMix_MusicType #
# TMusicUnion = record # TMusicUnion = record
@ -279,89 +279,84 @@ type #music_cmd.h types
# {$ENDIF} # {$ENDIF}
# end; # end;
PMix_Music* = ptr TMix_Music PMix_Music* = ptr TMix_Music
TMix_Music*{.final.} = object # The internal format for a music chunk interpreted via mikmod TMix_Music*{.final.} = object # The internal format for a music chunk interpreted via mikmod
type_*: TMix_MusicType # other fields are not aviable type_*: TMix_MusicType # other fields are not aviable
# data : TMusicUnion; # data : TMusicUnion;
# fading : TMix_Fading; # fading : TMix_Fading;
# fade_volume : integer; # fade_volume : integer;
# fade_step : integer; # fade_step : integer;
# fade_steps : integer; # fade_steps : integer;
# error : integer; # error : integer;
TMixFunction* = proc (udata: Pointer, stream: PUint8, length: int): Pointer{. TMixFunction* = proc (udata: Pointer, stream: PUint8, length: int): Pointer{.
cdecl.} # This macro can be used to fill a version structure with the compile-time cdecl.} # This macro can be used to fill a version structure with the compile-time
# version of the SDL_mixer library. # version of the SDL_mixer library.
proc SDL_MIXER_VERSION*(X: var TSDL_Version) proc SDL_MIXER_VERSION*(X: var TSDL_Version)
# This function gets the version of the dynamically linked SDL_mixer library. # This function gets the version of the dynamically linked SDL_mixer library.
# It should NOT be used to fill a version structure, instead you should use the # It should NOT be used to fill a version structure, instead you should use the
# SDL_MIXER_VERSION() macro. # SDL_MIXER_VERSION() macro.
proc Mix_Linked_Version*(): PSDL_version{.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_Linked_Version*(): PSDL_version{.cdecl, importc, dynlib: SDL_MixerLibName.}
# Open the mixer with a certain audio format # Open the mixer with a certain audio format
proc Mix_OpenAudio*(frequency: int, format: Uint16, channels: int, proc Mix_OpenAudio*(frequency: int, format: Uint16, channels: int,
chunksize: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.} chunksize: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.}
# Dynamically change the number of channels managed by the mixer. # Dynamically change the number of channels managed by the mixer.
# If decreasing the number of channels, the upper channels are # If decreasing the number of channels, the upper channels are
# stopped. # stopped.
# This function returns the new number of allocated channels. # This function returns the new number of allocated channels.
# #
proc Mix_AllocateChannels*(numchannels: int): int{.cdecl, proc Mix_AllocateChannels*(numchannels: int): int{.cdecl,
importc, dynlib: SDL_MixerLibName.} importc, dynlib: SDL_MixerLibName.}
# Find out what the actual audio device parameters are. # Find out what the actual audio device parameters are.
# This function returns 1 if the audio has been opened, 0 otherwise. # This function returns 1 if the audio has been opened, 0 otherwise.
# #
proc Mix_QuerySpec*(frequency: var int, format: var Uint16, channels: var int): int{. proc Mix_QuerySpec*(frequency: var int, format: var Uint16, channels: var int): int{.
cdecl, importc, dynlib: SDL_MixerLibName.} cdecl, importc, dynlib: SDL_MixerLibName.}
# Load a wave file or a music (.mod .s3m .it .xm) file # Load a wave file or a music (.mod .s3m .it .xm) file
proc Mix_LoadWAV_RW*(src: PSDL_RWops, freesrc: int): PMix_Chunk{.cdecl, proc Mix_LoadWAV_RW*(src: PSDL_RWops, freesrc: int): PMix_Chunk{.cdecl,
importc, dynlib: SDL_MixerLibName.} importc, dynlib: SDL_MixerLibName.}
proc Mix_LoadWAV*(filename: cstring): PMix_Chunk proc Mix_LoadWAV*(filename: cstring): PMix_Chunk
proc Mix_LoadMUS*(filename: cstring): PMix_Music{.cdecl, proc Mix_LoadMUS*(filename: cstring): PMix_Music{.cdecl,
importc, dynlib: SDL_MixerLibName.} importc, dynlib: SDL_MixerLibName.}
##if 0 { This hasn't been hooked into music.c yet } # Load a wave file of the mixer format from a memory buffer
#{ Load a music file from an SDL_RWop object (MikMod-specific currently) proc Mix_QuickLoad_WAV*(mem: PUint8): PMix_Chunk{.cdecl,
# Matt Campbell (matt@campbellhome.dhs.org) April 2000 }
#function Mix_LoadMUS_RW(SDL_RWops *rw) : PMix_Music; cdecl;
##endif
# Load a wave file of the mixer format from a memory buffer
proc Mix_QuickLoad_WAV*(mem: PUint8): PMix_Chunk{.cdecl,
importc, dynlib: SDL_MixerLibName.} importc, dynlib: SDL_MixerLibName.}
# Free an audio chunk previously loaded # Free an audio chunk previously loaded
proc Mix_FreeChunk*(chunk: PMix_Chunk){.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_FreeChunk*(chunk: PMix_Chunk){.cdecl, importc, dynlib: SDL_MixerLibName.}
proc Mix_FreeMusic*(music: PMix_Music){.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_FreeMusic*(music: PMix_Music){.cdecl, importc, dynlib: SDL_MixerLibName.}
# Find out the music format of a mixer music, or the currently playing # Find out the music format of a mixer music, or the currently playing
# music, if 'music' is NULL. # music, if 'music' is NULL.
proc Mix_GetMusicType*(music: PMix_Music): TMix_MusicType{.cdecl, proc Mix_GetMusicType*(music: PMix_Music): TMix_MusicType{.cdecl,
importc, dynlib: SDL_MixerLibName.} importc, dynlib: SDL_MixerLibName.}
# Set a function that is called after all mixing is performed. # Set a function that is called after all mixing is performed.
# This can be used to provide real-time visual display of the audio stream # This can be used to provide real-time visual display of the audio stream
# or add a custom mixer filter for the stream data. # or add a custom mixer filter for the stream data.
# #
proc Mix_SetPostMix*(mix_func: TMixFunction, arg: Pointer){.cdecl, proc Mix_SetPostMix*(mix_func: TMixFunction, arg: Pointer){.cdecl,
importc, dynlib: SDL_MixerLibName.} importc, dynlib: SDL_MixerLibName.}
# Add your own music player or additional mixer function. # Add your own music player or additional mixer function.
# If 'mix_func' is NULL, the default music player is re-enabled. # If 'mix_func' is NULL, the default music player is re-enabled.
# #
proc Mix_HookMusic*(mix_func: TMixFunction, arg: Pointer){.cdecl, proc Mix_HookMusic*(mix_func: TMixFunction, arg: Pointer){.cdecl,
importc, dynlib: SDL_MixerLibName.} importc, dynlib: SDL_MixerLibName.}
# Add your own callback when the music has finished playing. # Add your own callback when the music has finished playing.
# #
proc Mix_HookMusicFinished*(music_finished: Pointer){.cdecl, proc Mix_HookMusicFinished*(music_finished: Pointer){.cdecl,
importc, dynlib: SDL_MixerLibName.} importc, dynlib: SDL_MixerLibName.}
# Get a pointer to the user data for the current music hook # Get a pointer to the user data for the current music hook
proc Mix_GetMusicHookData*(): Pointer{.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_GetMusicHookData*(): Pointer{.cdecl, importc, dynlib: SDL_MixerLibName.}
#* Add your own callback when a channel has finished playing. NULL #* Add your own callback when a channel has finished playing. NULL
# * to disable callback.* # * to disable callback.*
type type
TChannel_finished* = proc (channel: int){.cdecl.} TChannel_finished* = proc (channel: int){.cdecl.}
proc Mix_ChannelFinished*(channel_finished: TChannel_finished){.cdecl, proc Mix_ChannelFinished*(channel_finished: TChannel_finished){.cdecl,
importc, dynlib: SDL_MixerLibName.} importc, dynlib: SDL_MixerLibName.}
const const
MIX_CHANNEL_POST* = - 2 MIX_CHANNEL_POST* = - 2
# This is the format of a special effect callback: # This is the format of a special effect callback:
# myeffect(int chan, void *stream, int len, void *udata); # myeffect(int chan, void *stream, int len, void *udata);
# #
# (chan) is the channel number that your effect is affecting. (stream) is # (chan) is the channel number that your effect is affecting. (stream) is
# the buffer of data to work upon. (len) is the size of (stream), and # the buffer of data to work upon. (len) is the size of (stream), and
# (udata) is a user-defined bit of data, which you pass as the last arg of # (udata) is a user-defined bit of data, which you pass as the last arg of
@ -372,10 +367,10 @@ const
# down the mixing pipeline, through any other effect functions, then finally # down the mixing pipeline, through any other effect functions, then finally
# to be mixed with the rest of the channels and music for the final output # to be mixed with the rest of the channels and music for the final output
# stream. # stream.
# #
type type
TMix_EffectFunc* = proc (chan: int, stream: Pointer, length: int, TMix_EffectFunc* = proc (chan: int, stream: Pointer, length: int,
udata: Pointer): Pointer{.cdecl.} udata: Pointer): Pointer{.cdecl.}
# * This is a callback that signifies that a channel has finished all its # * This is a callback that signifies that a channel has finished all its
# * loops and has completed playback. This gets called if the buffer # * loops and has completed playback. This gets called if the buffer
@ -428,7 +423,7 @@ type
# * Error messages can be retrieved from Mix_GetError(). # * Error messages can be retrieved from Mix_GetError().
# * # *
proc Mix_RegisterEffect*(chan: int, f: TMix_EffectFunc, d: TMix_EffectDone, proc Mix_RegisterEffect*(chan: int, f: TMix_EffectFunc, d: TMix_EffectDone,
arg: Pointer): int{.cdecl, importc, dynlib: SDL_MixerLibName.} arg: Pointer): int{.cdecl, importc, dynlib: SDL_MixerLibName.}
#* You may not need to call this explicitly, unless you need to stop an #* You may not need to call this explicitly, unless you need to stop an
# * effect from processing in the middle of a chunk's playback. # * effect from processing in the middle of a chunk's playback.
@ -438,7 +433,7 @@ proc Mix_RegisterEffect*(chan: int, f: TMix_EffectFunc, d: TMix_EffectDone,
# * returns zero if error (no such channel or effect), nonzero if removed. # * returns zero if error (no such channel or effect), nonzero if removed.
# * Error messages can be retrieved from Mix_GetError(). # * Error messages can be retrieved from Mix_GetError().
# * # *
proc Mix_UnregisterEffect*(channel: int, f: TMix_EffectFunc): int{.cdecl, proc Mix_UnregisterEffect*(channel: int, f: TMix_EffectFunc): int{.cdecl,
importc, dynlib: SDL_MixerLibName.} importc, dynlib: SDL_MixerLibName.}
#* You may not need to call this explicitly, unless you need to stop all #* You may not need to call this explicitly, unless you need to stop all
# * effects from processing in the middle of a chunk's playback. Note that # * effects from processing in the middle of a chunk's playback. Note that
@ -451,17 +446,17 @@ proc Mix_UnregisterEffect*(channel: int, f: TMix_EffectFunc): int{.cdecl,
# * returns zero if error( no such channel ), nonzero if all effects removed. # * returns zero if error( no such channel ), nonzero if all effects removed.
# * Error messages can be retrieved from Mix_GetError( ). # * Error messages can be retrieved from Mix_GetError( ).
# * # *
proc Mix_UnregisterAllEffects*(channel: int): int{.cdecl, proc Mix_UnregisterAllEffects*(channel: int): int{.cdecl,
importc, dynlib: SDL_MixerLibName.} importc, dynlib: SDL_MixerLibName.}
const const
MIX_EFFECTSMAXSPEED* = "MIX_EFFECTSMAXSPEED" MIX_EFFECTSMAXSPEED* = "MIX_EFFECTSMAXSPEED"
# * These are the internally - defined mixing effects.They use the same API that # * These are the internally - defined mixing effects.They use the same API that
# * effects defined in the application use, but are provided here as a # * effects defined in the application use, but are provided here as a
# * convenience.Some effects can reduce their quality or use more memory in # * convenience.Some effects can reduce their quality or use more memory in
# * the name of speed; to enable this, make sure the environment variable # * the name of speed; to enable this, make sure the environment variable
# * MIX_EFFECTSMAXSPEED( see above ) is defined before you call # * MIX_EFFECTSMAXSPEED( see above ) is defined before you call
# * Mix_OpenAudio( ). # * Mix_OpenAudio( ).
# * # *
#* set the panning of a channel.The left and right channels are specified #* set the panning of a channel.The left and right channels are specified
# * as integers between 0 and 255, quietest to loudest, respectively. # * as integers between 0 and 255, quietest to loudest, respectively.
# * # *
@ -486,9 +481,9 @@ const
# * nonzero if panning effect enabled.Note that an audio device in mono # * nonzero if panning effect enabled.Note that an audio device in mono
# * mode is a no - op, but this call will return successful in that case . # * mode is a no - op, but this call will return successful in that case .
# * Error messages can be retrieved from Mix_GetError( ). # * Error messages can be retrieved from Mix_GetError( ).
# * # *
proc Mix_SetPanning*(channel: int, left: Uint8, right: Uint8): int{.cdecl, proc Mix_SetPanning*(channel: int, left: Uint8, right: Uint8): int{.cdecl,
importc, dynlib: SDL_MixerLibName.} importc, dynlib: SDL_MixerLibName.}
# * set the position ofa channel.( angle ) is an integer from 0 to 360, that # * set the position ofa channel.( angle ) is an integer from 0 to 360, that
# * specifies the location of the sound in relation to the listener.( angle ) # * specifies the location of the sound in relation to the listener.( angle )
@ -526,8 +521,8 @@ proc Mix_SetPanning*(channel: int, left: Uint8, right: Uint8): int{.cdecl,
# * returns zero if error( no such channel or Mix_RegisterEffect( )fails ), # * returns zero if error( no such channel or Mix_RegisterEffect( )fails ),
# * nonzero if position effect is enabled. # * nonzero if position effect is enabled.
# * Error messages can be retrieved from Mix_GetError( ). # * Error messages can be retrieved from Mix_GetError( ).
# * # *
proc Mix_SetPosition*(channel: int, angle: Sint16, distance: Uint8): int{.cdecl, proc Mix_SetPosition*(channel: int, angle: Sint16, distance: Uint8): int{.cdecl,
importc, dynlib: SDL_MixerLibName.} importc, dynlib: SDL_MixerLibName.}
#* set the "distance" of a channel.( distance ) is an integer from 0 to 255 #* set the "distance" of a channel.( distance ) is an integer from 0 to 255
# * that specifies the location of the sound in relation to the listener. # * that specifies the location of the sound in relation to the listener.
@ -555,8 +550,8 @@ proc Mix_SetPosition*(channel: int, angle: Sint16, distance: Uint8): int{.cdecl,
# * returns zero if error( no such channel or Mix_RegisterEffect( )fails ), # * returns zero if error( no such channel or Mix_RegisterEffect( )fails ),
# * nonzero if position effect is enabled. # * nonzero if position effect is enabled.
# * Error messages can be retrieved from Mix_GetError( ). # * Error messages can be retrieved from Mix_GetError( ).
# * # *
proc Mix_SetDistance*(channel: int, distance: Uint8): int{.cdecl, proc Mix_SetDistance*(channel: int, distance: Uint8): int{.cdecl,
importc, dynlib: SDL_MixerLibName.} importc, dynlib: SDL_MixerLibName.}
# * # *
# * !!! FIXME : Haven't implemented, since the effect goes past the # * !!! FIXME : Haven't implemented, since the effect goes past the
@ -600,39 +595,39 @@ proc Mix_SetDistance*(channel: int, distance: Uint8): int{.cdecl,
# * nonzero if reversing effect is enabled.Note that an audio device in mono # * nonzero if reversing effect is enabled.Note that an audio device in mono
# * mode is a no - op, but this call will return successful in that case . # * mode is a no - op, but this call will return successful in that case .
# * Error messages can be retrieved from Mix_GetError( ). # * Error messages can be retrieved from Mix_GetError( ).
# * # *
proc Mix_SetReverseStereo*(channel: int, flip: int): int{.cdecl, proc Mix_SetReverseStereo*(channel: int, flip: int): int{.cdecl,
importc, dynlib: SDL_MixerLibName.} importc, dynlib: SDL_MixerLibName.}
# end of effects API. - -ryan. * # end of effects API. - -ryan. *
# Reserve the first channels (0 -> n-1) for the application, i.e. don't allocate # Reserve the first channels (0 -> n-1) for the application, i.e. don't allocate
# them dynamically to the next sample if requested with a -1 value below. # them dynamically to the next sample if requested with a -1 value below.
# Returns the number of reserved channels. # Returns the number of reserved channels.
# #
proc Mix_ReserveChannels*(num: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_ReserveChannels*(num: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.}
# Channel grouping functions # Channel grouping functions
# Attach a tag to a channel. A tag can be assigned to several mixer # Attach a tag to a channel. A tag can be assigned to several mixer
# channels, to form groups of channels. # channels, to form groups of channels.
# If 'tag' is -1, the tag is removed (actually -1 is the tag used to # If 'tag' is -1, the tag is removed (actually -1 is the tag used to
# represent the group of all the channels). # represent the group of all the channels).
# Returns true if everything was OK. # Returns true if everything was OK.
# #
proc Mix_GroupChannel*(which: int, tag: int): int{.cdecl, proc Mix_GroupChannel*(which: int, tag: int): int{.cdecl,
importc, dynlib: SDL_MixerLibName.} importc, dynlib: SDL_MixerLibName.}
# Assign several consecutive channels to a group # Assign several consecutive channels to a group
proc Mix_GroupChannels*(`from`: int, `to`: int, tag: int): int{.cdecl, proc Mix_GroupChannels*(`from`: int, `to`: int, tag: int): int{.cdecl,
importc, dynlib: SDL_MixerLibName.} importc, dynlib: SDL_MixerLibName.}
# Finds the first available channel in a group of channels # Finds the first available channel in a group of channels
proc Mix_GroupAvailable*(tag: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_GroupAvailable*(tag: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.}
# Returns the number of channels in a group. This is also a subtle # Returns the number of channels in a group. This is also a subtle
# way to get the total number of channels when 'tag' is -1 # way to get the total number of channels when 'tag' is -1
# #
proc Mix_GroupCount*(tag: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_GroupCount*(tag: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.}
# Finds the "oldest" sample playing in a group of channels # Finds the "oldest" sample playing in a group of channels
proc Mix_GroupOldest*(tag: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_GroupOldest*(tag: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.}
# Finds the "most recent" (i.e. last) sample playing in a group of channels # Finds the "most recent" (i.e. last) sample playing in a group of channels
proc Mix_GroupNewer*(tag: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_GroupNewer*(tag: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.}
# The same as above, but the sound is played at most 'ticks' milliseconds # The same as above, but the sound is played at most 'ticks' milliseconds
proc Mix_PlayChannelTimed*(channel: int, chunk: PMix_Chunk, loops: int, proc Mix_PlayChannelTimed*(channel: int, chunk: PMix_Chunk, loops: int,
ticks: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.} ticks: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.}
# Play an audio chunk on a specific channel. # Play an audio chunk on a specific channel.
# If the specified channel is -1, play on the first free channel. # If the specified channel is -1, play on the first free channel.
@ -641,13 +636,13 @@ proc Mix_PlayChannelTimed*(channel: int, chunk: PMix_Chunk, loops: int,
# Returns which channel was used to play the sound. # Returns which channel was used to play the sound.
# #
proc Mix_PlayChannel*(channel: int, chunk: PMix_Chunk, loops: int): int proc Mix_PlayChannel*(channel: int, chunk: PMix_Chunk, loops: int): int
proc Mix_PlayMusic*(music: PMix_Music, loops: int): int{.cdecl, proc Mix_PlayMusic*(music: PMix_Music, loops: int): int{.cdecl,
importc, dynlib: SDL_MixerLibName.} importc, dynlib: SDL_MixerLibName.}
# Fade in music or a channel over "ms" milliseconds, same semantics as the "Play" functions # Fade in music or a channel over "ms" milliseconds, same semantics as the "Play" functions
proc Mix_FadeInMusic*(music: PMix_Music, loops: int, ms: int): int{.cdecl, proc Mix_FadeInMusic*(music: PMix_Music, loops: int, ms: int): int{.cdecl,
importc, dynlib: SDL_MixerLibName.} importc, dynlib: SDL_MixerLibName.}
proc Mix_FadeInChannelTimed*(channel: int, chunk: PMix_Chunk, loops: int, proc Mix_FadeInChannelTimed*(channel: int, chunk: PMix_Chunk, loops: int,
ms: int, ticks: int): int{.cdecl, ms: int, ticks: int): int{.cdecl,
importc, dynlib: SDL_MixerLibName.} importc, dynlib: SDL_MixerLibName.}
proc Mix_FadeInChannel*(channel: int, chunk: PMix_Chunk, loops: int, ms: int): int proc Mix_FadeInChannel*(channel: int, chunk: PMix_Chunk, loops: int, ms: int): int
# Set the volume in the range of 0-128 of a specific channel or chunk. # Set the volume in the range of 0-128 of a specific channel or chunk.
@ -655,12 +650,12 @@ proc Mix_FadeInChannel*(channel: int, chunk: PMix_Chunk, loops: int, ms: int): i
# Returns the original volume. # Returns the original volume.
# If the specified volume is -1, just return the current volume. # If the specified volume is -1, just return the current volume.
# #
proc Mix_Volume*(channel: int, volume: int): int{.cdecl, proc Mix_Volume*(channel: int, volume: int): int{.cdecl,
importc, dynlib: SDL_MixerLibName.} importc, dynlib: SDL_MixerLibName.}
proc Mix_VolumeChunk*(chunk: PMix_Chunk, volume: int): int{.cdecl, proc Mix_VolumeChunk*(chunk: PMix_Chunk, volume: int): int{.cdecl,
importc, dynlib: SDL_MixerLibName.} importc, dynlib: SDL_MixerLibName.}
proc Mix_VolumeMusic*(volume: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_VolumeMusic*(volume: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.}
# Halt playing of a particular channel # Halt playing of a particular channel
proc Mix_HaltChannel*(channel: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_HaltChannel*(channel: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.}
proc Mix_HaltGroup*(tag: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_HaltGroup*(tag: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.}
proc Mix_HaltMusic*(): int{.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_HaltMusic*(): int{.cdecl, importc, dynlib: SDL_MixerLibName.}
@ -668,25 +663,25 @@ proc Mix_HaltMusic*(): int{.cdecl, importc, dynlib: SDL_MixerLibName.}
# The sample will stop playing after the 'ticks' milliseconds have elapsed, # The sample will stop playing after the 'ticks' milliseconds have elapsed,
# or remove the expiration if 'ticks' is -1 # or remove the expiration if 'ticks' is -1
# #
proc Mix_ExpireChannel*(channel: int, ticks: int): int{.cdecl, proc Mix_ExpireChannel*(channel: int, ticks: int): int{.cdecl,
importc, dynlib: SDL_MixerLibName.} importc, dynlib: SDL_MixerLibName.}
# Halt a channel, fading it out progressively till it's silent # Halt a channel, fading it out progressively till it's silent
# The ms parameter indicates the number of milliseconds the fading # The ms parameter indicates the number of milliseconds the fading
# will take. # will take.
# #
proc Mix_FadeOutChannel*(which: int, ms: int): int{.cdecl, proc Mix_FadeOutChannel*(which: int, ms: int): int{.cdecl,
importc, dynlib: SDL_MixerLibName.} importc, dynlib: SDL_MixerLibName.}
proc Mix_FadeOutGroup*(tag: int, ms: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_FadeOutGroup*(tag: int, ms: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.}
proc Mix_FadeOutMusic*(ms: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_FadeOutMusic*(ms: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.}
# Query the fading status of a channel # Query the fading status of a channel
proc Mix_FadingMusic*(): TMix_Fading{.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_FadingMusic*(): TMix_Fading{.cdecl, importc, dynlib: SDL_MixerLibName.}
proc Mix_FadingChannel*(which: int): TMix_Fading{.cdecl, proc Mix_FadingChannel*(which: int): TMix_Fading{.cdecl,
importc, dynlib: SDL_MixerLibName.} importc, dynlib: SDL_MixerLibName.}
# Pause/Resume a particular channel # Pause/Resume a particular channel
proc Mix_Pause*(channel: int){.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_Pause*(channel: int){.cdecl, importc, dynlib: SDL_MixerLibName.}
proc Mix_Resume*(channel: int){.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_Resume*(channel: int){.cdecl, importc, dynlib: SDL_MixerLibName.}
proc Mix_Paused*(channel: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_Paused*(channel: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.}
# Pause/Resume the music stream # Pause/Resume the music stream
proc Mix_PauseMusic*(){.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_PauseMusic*(){.cdecl, importc, dynlib: SDL_MixerLibName.}
proc Mix_ResumeMusic*(){.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_ResumeMusic*(){.cdecl, importc, dynlib: SDL_MixerLibName.}
proc Mix_RewindMusic*(){.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_RewindMusic*(){.cdecl, importc, dynlib: SDL_MixerLibName.}
@ -697,16 +692,16 @@ proc Mix_PausedMusic*(): int{.cdecl, importc, dynlib: SDL_MixerLibName.}
# order number) and for OGG music (set position in seconds), at the # order number) and for OGG music (set position in seconds), at the
# moment. # moment.
# #
proc Mix_SetMusicPosition*(position: float64): int{.cdecl, proc Mix_SetMusicPosition*(position: float64): int{.cdecl,
importc, dynlib: SDL_MixerLibName.} importc, dynlib: SDL_MixerLibName.}
# Check the status of a specific channel. # Check the status of a specific channel.
# If the specified channel is -1, check all channels. # If the specified channel is -1, check all channels.
# #
proc Mix_Playing*(channel: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_Playing*(channel: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.}
proc Mix_PlayingMusic*(): int{.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_PlayingMusic*(): int{.cdecl, importc, dynlib: SDL_MixerLibName.}
# Stop music and set external music playback command # Stop music and set external music playback command
proc Mix_SetMusicCMD*(command: cstring): int{.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_SetMusicCMD*(command: cstring): int{.cdecl, importc, dynlib: SDL_MixerLibName.}
# Synchro value is set by MikMod from modules while playing # Synchro value is set by MikMod from modules while playing
proc Mix_SetSynchroValue*(value: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_SetSynchroValue*(value: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.}
proc Mix_GetSynchroValue*(): int{.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_GetSynchroValue*(): int{.cdecl, importc, dynlib: SDL_MixerLibName.}
# #
@ -714,29 +709,29 @@ proc Mix_GetSynchroValue*(): int{.cdecl, importc, dynlib: SDL_MixerLibName.}
# Returns nil if it's an invalid channel, or there's no chunk associated. # Returns nil if it's an invalid channel, or there's no chunk associated.
# #
proc Mix_GetChunk*(channel: int): PMix_Chunk{.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_GetChunk*(channel: int): PMix_Chunk{.cdecl, importc, dynlib: SDL_MixerLibName.}
# Close the mixer, halting all playing audio # Close the mixer, halting all playing audio
proc Mix_CloseAudio*(){.cdecl, importc, dynlib: SDL_MixerLibName.} proc Mix_CloseAudio*(){.cdecl, importc, dynlib: SDL_MixerLibName.}
# We'll use SDL for reporting errors # We'll use SDL for reporting errors
proc Mix_SetError*(fmt: cstring) proc Mix_SetError*(fmt: cstring)
proc Mix_GetError*(): cstring proc Mix_GetError*(): cstring
# implementation # implementation
proc SDL_MIXER_VERSION(X: var TSDL_version) = proc SDL_MIXER_VERSION(X: var TSDL_version) =
X.major = SDL_MIXER_MAJOR_VERSION X.major = SDL_MIXER_MAJOR_VERSION
X.minor = SDL_MIXER_MINOR_VERSION X.minor = SDL_MIXER_MINOR_VERSION
X.patch = SDL_MIXER_PATCHLEVEL X.patch = SDL_MIXER_PATCHLEVEL
proc Mix_LoadWAV(filename: cstring): PMix_Chunk = proc Mix_LoadWAV(filename: cstring): PMix_Chunk =
result = Mix_LoadWAV_RW(SDL_RWFromFile(filename, "rb"), 1) result = Mix_LoadWAV_RW(SDL_RWFromFile(filename, "rb"), 1)
proc Mix_PlayChannel(channel: int, chunk: PMix_Chunk, loops: int): int = proc Mix_PlayChannel(channel: int, chunk: PMix_Chunk, loops: int): int =
result = Mix_PlayChannelTimed(channel, chunk, loops, - 1) result = Mix_PlayChannelTimed(channel, chunk, loops, - 1)
proc Mix_FadeInChannel(channel: int, chunk: PMix_Chunk, loops: int, ms: int): int = proc Mix_FadeInChannel(channel: int, chunk: PMix_Chunk, loops: int, ms: int): int =
result = Mix_FadeInChannelTimed(channel, chunk, loops, ms, - 1) result = Mix_FadeInChannelTimed(channel, chunk, loops, ms, - 1)
proc Mix_SetError(fmt: cstring) = proc Mix_SetError(fmt: cstring) =
SDL_SetError(fmt) SDL_SetError(fmt)
proc Mix_GetError(): cstring = proc Mix_GetError(): cstring =
result = SDL_GetError() result = SDL_GetError()

View file

@ -126,5 +126,5 @@ elif defined(mac):
nss = NSLookupSymbolInModule(NSModule(lib), name) nss = NSLookupSymbolInModule(NSModule(lib), name)
result = TProcAddr(NSAddressOfSymbol(nss)) result = TProcAddr(NSAddressOfSymbol(nss))
else: # workaround a newly introduced bug :-( else:
{.error: "no implementation for dyncalls".} {.error: "no implementation for dyncalls".}

View file

@ -326,6 +326,9 @@ proc echo*(x: cstring) = ewriteln(x)
proc echo[Ty](x: Ty) = proc echo[Ty](x: Ty) =
echo(x) echo(x)
proc echo[Ty](x: openArray[Ty]) =
for a in items(x): echo(a)
# Arithmetic: # Arithmetic:
proc addInt(a, b: int): int {.pure, compilerproc.} = proc addInt(a, b: int): int {.pure, compilerproc.} =
asm """ asm """

View file

@ -61,9 +61,6 @@ type
filename: CString filename: CString
len: int # length of slots (when not debugging always zero) len: int # length of slots (when not debugging always zero)
TTempFrame = tuple[ # used for recursion elimination in WriteStackTrace
procname: CString, line: int]
var var
buf: string # cannot be allocated on the stack! buf: string # cannot be allocated on the stack!
assertBuf: string # we need a different buffer for assertBuf: string # we need a different buffer for
@ -72,33 +69,45 @@ var
framePtr {.exportc.}: PFrame framePtr {.exportc.}: PFrame
tempFrames: array [0..255, TTempFrame] # cannot be allocated tempFrames: array [0..127, PFrame] # cannot be allocated on the stack!
# on the stack!
proc auxWriteStackTrace(f: PFrame, s: var string) = proc auxWriteStackTrace(f: PFrame, s: var string) =
const
firstCalls = 32
var var
it = f it = f
i = 0 i = 0
total = 0 total = 0
while it != nil and i <= high(tempFrames): while it != nil and i <= high(tempFrames)-(firstCalls-1):
tempFrames[i] = (it.procname, it.line) # the (-1) is for a nil entry that marks where the '...' should occur
tempFrames[i] = it
inc(i) inc(i)
inc(total) inc(total)
it = it.prev it = it.prev
var b = it
while it != nil: while it != nil:
inc(total) inc(total)
it = it.prev it = it.prev
# if the buffer overflowed print '...': for j in 1..total-i-(firstCalls-1):
if b != nil: b = b.prev
if total != i: if total != i:
add(s, "(") tempFrames[i] = nil
add(s, $(total-i)) inc(i)
add(s, " calls omitted) ...\n") while b != nil and i <= high(tempFrames):
tempFrames[i] = b
inc(i)
b = b.prev
for j in countdown(i-1, 0): for j in countdown(i-1, 0):
add(s, $tempFrames[j].procname) if tempFrames[j] == nil:
if tempFrames[j].line > 0: add(s, "(")
add(s, ", line: ") add(s, $(total-i-1))
add(s, $tempFrames[j].line) add(s, " calls omitted) ...\n")
add(s, "\n") else:
add(s, $tempFrames[j].procname)
if tempFrames[j].line > 0:
add(s, ", line: ")
add(s, $tempFrames[j].line)
add(s, "\n")
proc rawWriteStackTrace(s: var string) = proc rawWriteStackTrace(s: var string) =
if framePtr == nil: if framePtr == nil:
@ -156,8 +165,7 @@ proc internalAssert(file: cstring, line: int, cond: bool) {.compilerproc.} =
raise gAssertionFailed # newException(EAssertionFailed, assertBuf) raise gAssertionFailed # newException(EAssertionFailed, assertBuf)
proc WriteStackTrace() = proc WriteStackTrace() =
var var s = ""
s: string = ""
rawWriteStackTrace(s) rawWriteStackTrace(s)
writeToStdErr(s) writeToStdErr(s)
@ -208,13 +216,13 @@ assertBuf = newString(2048)
setLen(buf, 0) setLen(buf, 0)
setLen(assertBuf, 0) setLen(assertBuf, 0)
proc raiseRangeError(val: biggestInt) {.compilerproc, noreturn.} = proc raiseRangeError(val: biggestInt) {.compilerproc, noreturn, noinline.} =
raise newException(EOutOfRange, "value " & $val & " out of range") raise newException(EOutOfRange, "value " & $val & " out of range")
proc raiseIndexError() {.compilerproc, noreturn.} = proc raiseIndexError() {.compilerproc, noreturn, noinline.} =
raise newException(EInvalidIndex, "index out of bounds") raise newException(EInvalidIndex, "index out of bounds")
proc raiseFieldError(f: string) {.compilerproc, noreturn.} = proc raiseFieldError(f: string) {.compilerproc, noreturn, noinline.} =
raise newException(EInvalidField, f & " is not accessible") raise newException(EInvalidField, f & " is not accessible")
proc chckIndx(i, a, b: int): int = proc chckIndx(i, a, b: int): int =

View file

@ -13,11 +13,10 @@
# * incremental # * incremental
# * non-recursive # * non-recursive
# * generational # * generational
# * excellent performance
# Future Improvements: # Future Improvements:
# * Both dlmalloc and TLSF lack zero-overhead object allocation. Thus, for # * Both dlmalloc and TLSF lack zero-overhead object allocation. Thus, for
# small objects we will should use our own allocator. # small objects we should use our own allocator.
# * Support for multi-threading. However, locks for the reference counting # * Support for multi-threading. However, locks for the reference counting
# might turn out to be too slow. # might turn out to be too slow.
@ -332,7 +331,7 @@ proc CellSetPut(t: var TCellSet, key: TAddress): PPageDesc =
# ---------- slightly higher level procs -------------------------------------- # ---------- slightly higher level procs --------------------------------------
proc in_Operator(s: TCellSet, cell: PCell): bool = proc contains(s: TCellSet, cell: PCell): bool =
var u = cast[TAddress](cell) var u = cast[TAddress](cell)
var t = CellSetGet(s, u shr PageShift) var t = CellSetGet(s, u shr PageShift)
if t != nil: if t != nil:
@ -468,23 +467,6 @@ proc prepareDealloc(cell: PCell) =
proc setStackBottom(theStackBottom: pointer) {.compilerproc.} = proc setStackBottom(theStackBottom: pointer) {.compilerproc.} =
stackBottom = theStackBottom stackBottom = theStackBottom
proc initGC() =
when traceGC:
for i in low(TCellState)..high(TCellState): CellSetInit(states[i])
gch.stackScans = 0
gch.cycleCollections = 0
gch.maxThreshold = 0
gch.maxStackSize = 0
gch.maxStackPages = 0
gch.cycleTableSize = 0
# init the rt
init(gch.zct)
init(gch.tempStack)
CellSetInit(gch.cycleRoots)
CellSetInit(gch.stackCells)
gch.mask = 0
new(gOutOfMem) # reserve space for the EOutOfMemory exception here!
proc PossibleRoot(gch: var TGcHeap, c: PCell) {.inline.} = proc PossibleRoot(gch: var TGcHeap, c: PCell) {.inline.} =
if canbeCycleRoot(c): incl(gch.cycleRoots, c) if canbeCycleRoot(c): incl(gch.cycleRoots, c)
@ -535,6 +517,23 @@ proc unsureAsgnRef(dest: ppointer, src: pointer) =
if dest^ != nil: decRef(usrToCell(dest^)) if dest^ != nil: decRef(usrToCell(dest^))
dest^ = src dest^ = src
proc initGC() =
when traceGC:
for i in low(TCellState)..high(TCellState): CellSetInit(states[i])
gch.stackScans = 0
gch.cycleCollections = 0
gch.maxThreshold = 0
gch.maxStackSize = 0
gch.maxStackPages = 0
gch.cycleTableSize = 0
# init the rt
init(gch.zct)
init(gch.tempStack)
CellSetInit(gch.cycleRoots)
CellSetInit(gch.stackCells)
gch.mask = 0
new(gOutOfMem) # reserve space for the EOutOfMemory exception here!
proc getDiscriminant(aa: Pointer, n: ptr TNimNode): int = proc getDiscriminant(aa: Pointer, n: ptr TNimNode): int =
assert(n.kind == nkCase) assert(n.kind == nkCase)
var d: int var d: int

View file

@ -151,8 +151,7 @@ proc open(L: var TBaseLexer, input: PStream, bufLen: int = 8192) =
skip_UTF_8_BOM(L) skip_UTF_8_BOM(L)
proc getColNumber(L: TBaseLexer, pos: int): int = proc getColNumber(L: TBaseLexer, pos: int): int =
result = pos - L.lineStart result = abs(pos - L.lineStart)
assert(result >= 0)
proc getCurrentLine(L: TBaseLexer, marker: bool = true): string = proc getCurrentLine(L: TBaseLexer, marker: bool = true): string =
var i: int var i: int

View file

@ -30,59 +30,59 @@
# if key[-4:] == "Flag": continue # if key[-4:] == "Flag": continue
# cog.out(toEnum(key, val)) # cog.out(toEnum(key, val))
#]]] #]]]
type type
TNimrodTypeKind* = enum TNimrodNodeKind* = enum
ntyNone, ntyBool, ntyChar, ntyEmpty, nnkNone, nnkEmpty, nnkIdent, nnkSym,
ntyArrayConstr, ntyNil, ntyGeneric, ntyGenericInst, nnkType, nnkCharLit, nnkIntLit, nnkInt8Lit,
ntyGenericParam, ntyEnum, ntyAnyEnum, ntyArray, nnkInt16Lit, nnkInt32Lit, nnkInt64Lit, nnkFloatLit,
ntyObject, ntyTuple, ntySet, ntyRange, nnkFloat32Lit, nnkFloat64Lit, nnkStrLit, nnkRStrLit,
ntyPtr, ntyRef, ntyVar, ntySequence, nnkTripleStrLit, nnkMetaNode, nnkNilLit, nnkDotCall,
ntyProc, ntyPointer, ntyOpenArray, ntyString, nnkCommand, nnkCall, nnkGenericCall, nnkExplicitTypeListCall,
ntyCString, ntyForward, ntyInt, ntyInt8, nnkExprEqExpr, nnkExprColonExpr, nnkIdentDefs, nnkVarTuple,
ntyInt16, ntyInt32, ntyInt64, ntyFloat, nnkInfix, nnkPrefix, nnkPostfix, nnkPar,
ntyFloat32, ntyFloat64, ntyFloat128 nnkCurly, nnkBracket, nnkBracketExpr, nnkPragmaExpr,
TNimTypeKinds* = set[TNimrodTypeKind] nnkRange, nnkDotExpr, nnkCheckedFieldExpr, nnkDerefExpr,
TNimrodSymKind* = enum nnkIfExpr, nnkElifExpr, nnkElseExpr, nnkLambda,
nskUnknownSym, nskConditional, nskDynLib, nskParam, nnkAccQuoted, nnkHeaderQuoted, nnkTableConstr, nnkQualified,
nskTypeParam, nskTemp, nskType, nskConst, nnkHiddenStdConv, nnkHiddenSubConv, nnkHiddenCallConv, nnkConv,
nskVar, nskProc, nskIterator, nskConverter, nnkCast, nnkAddr, nnkHiddenAddr, nnkHiddenDeref,
nskMacro, nskTemplate, nskField, nskEnumField, nnkObjDownConv, nnkObjUpConv, nnkChckRangeF, nnkChckRange64,
nskForVar, nskModule, nskLabel, nskStub nnkChckRange, nnkStringToCString, nnkCStringToString, nnkPassAsOpenArray,
TNimSymKinds* = set[TNimrodSymKind] nnkAsgn, nnkFastAsgn, nnkDefaultTypeParam, nnkGenericParams,
TNimrodNodeKind* = enum nnkFormalParams, nnkOfInherit, nnkModule, nnkProcDef,
nnkNone, nnkEmpty, nnkIdent, nnkSym, nnkConverterDef, nnkMacroDef, nnkTemplateDef, nnkIteratorDef,
nnkType, nnkCharLit, nnkIntLit, nnkInt8Lit, nnkOfBranch, nnkElifBranch, nnkExceptBranch, nnkElse,
nnkInt16Lit, nnkInt32Lit, nnkInt64Lit, nnkFloatLit, nnkMacroStmt, nnkAsmStmt, nnkPragma, nnkIfStmt,
nnkFloat32Lit, nnkFloat64Lit, nnkStrLit, nnkRStrLit, nnkWhenStmt, nnkForStmt, nnkWhileStmt, nnkCaseStmt,
nnkTripleStrLit, nnkMetaNode, nnkNilLit, nnkDotCall, nnkVarSection, nnkConstSection, nnkConstDef, nnkTypeSection,
nnkCommand, nnkCall, nnkGenericCall, nnkExplicitTypeListCall, nnkTypeDef, nnkYieldStmt, nnkTryStmt, nnkFinally,
nnkExprEqExpr, nnkExprColonExpr, nnkIdentDefs, nnkInfix, nnkRaiseStmt, nnkReturnStmt, nnkBreakStmt, nnkContinueStmt,
nnkPrefix, nnkPostfix, nnkPar, nnkCurly, nnkBlockStmt, nnkDiscardStmt, nnkStmtList, nnkImportStmt,
nnkBracket, nnkBracketExpr, nnkPragmaExpr, nnkRange, nnkFromStmt, nnkImportAs, nnkIncludeStmt, nnkAccessStmt,
nnkDotExpr, nnkCheckedFieldExpr, nnkDerefExpr, nnkIfExpr, nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr, nnkStmtListType,
nnkElifExpr, nnkElseExpr, nnkLambda, nnkAccQuoted, nnkBlockType, nnkVm, nnkTypeOfExpr, nnkObjectTy,
nnkHeaderQuoted, nnkTableConstr, nnkQualified, nnkHiddenStdConv, nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen,
nnkHiddenSubConv, nnkHiddenCallConv, nnkConv, nnkCast, nnkRefTy, nnkPtrTy, nnkVarTy, nnkProcTy,
nnkAddr, nnkHiddenAddr, nnkHiddenDeref, nnkObjDownConv, nnkEnumTy, nnkEnumFieldDef, nnkReturnToken
nnkObjUpConv, nnkChckRangeF, nnkChckRange64, nnkChckRange, TNimNodeKinds* = set[TNimrodNodeKind]
nnkStringToCString, nnkCStringToString, nnkPassAsOpenArray, nnkAsgn, TNimrodTypeKind* = enum
nnkDefaultTypeParam, nnkGenericParams, nnkFormalParams, nnkOfInherit, ntyNone, ntyBool, ntyChar, ntyEmpty,
nnkModule, nnkProcDef, nnkConverterDef, nnkMacroDef, ntyArrayConstr, ntyNil, ntyGeneric, ntyGenericInst,
nnkTemplateDef, nnkIteratorDef, nnkOfBranch, nnkElifBranch, ntyGenericParam, ntyEnum, ntyAnyEnum, ntyArray,
nnkExceptBranch, nnkElse, nnkMacroStmt, nnkAsmStmt, ntyObject, ntyTuple, ntySet, ntyRange,
nnkPragma, nnkIfStmt, nnkWhenStmt, nnkForStmt, ntyPtr, ntyRef, ntyVar, ntySequence,
nnkWhileStmt, nnkCaseStmt, nnkVarSection, nnkConstSection, ntyProc, ntyPointer, ntyOpenArray, ntyString,
nnkConstDef, nnkTypeSection, nnkTypeDef, nnkYieldStmt, ntyCString, ntyForward, ntyInt, ntyInt8,
nnkTryStmt, nnkFinally, nnkRaiseStmt, nnkReturnStmt, ntyInt16, ntyInt32, ntyInt64, ntyFloat,
nnkBreakStmt, nnkContinueStmt, nnkBlockStmt, nnkDiscardStmt, ntyFloat32, ntyFloat64, ntyFloat128
nnkStmtList, nnkImportStmt, nnkFromStmt, nnkImportAs, TNimTypeKinds* = set[TNimrodTypeKind]
nnkIncludeStmt, nnkAccessStmt, nnkCommentStmt, nnkStmtListExpr, TNimrodSymKind* = enum
nnkBlockExpr, nnkStmtListType, nnkBlockType, nnkVm, nskUnknownSym, nskConditional, nskDynLib, nskParam,
nnkTypeOfExpr, nnkObjectTy, nnkTupleTy, nnkRecList, nskTypeParam, nskTemp, nskType, nskConst,
nnkRecCase, nnkRecWhen, nnkRefTy, nnkPtrTy, nskVar, nskProc, nskIterator, nskConverter,
nnkVarTy, nnkProcTy, nnkEnumTy, nnkEnumFieldDef, nskMacro, nskTemplate, nskField, nskEnumField,
nnkReturnToken nskForVar, nskModule, nskLabel, nskStub
TNimNodeKinds* = set[TNimrodNodeKind] TNimSymKinds* = set[TNimrodSymKind]
#[[[end]]] #[[[end]]]
type type

View file

@ -421,18 +421,4 @@ struct NimException {
}; };
#endif #endif
#if 0
typedef struct TStringDesc {
NI len;
NI space;
NIM_CHAR data[1]; /* SEQ_DECL_SIZE]; */
} TStringDesc;
typedef struct {
NI len, space;
} TGenericSeq;
typedef TGenericSeq* PGenericSeq;
#endif
#endif #endif

View file

@ -11,6 +11,7 @@
## retrieving environment variables, reading command line arguments, ## retrieving environment variables, reading command line arguments,
## working with directories, running shell commands, etc. ## working with directories, running shell commands, etc.
## This module is -- like any other basic library -- platform independant. ## This module is -- like any other basic library -- platform independant.
{.deadCodeElim: on.}
{.push debugger: off.} {.push debugger: off.}
@ -863,9 +864,9 @@ var
when defined(windows): when defined(windows):
# because we support Windows GUI applications, things get really # because we support Windows GUI applications, things get really
# messy here... # messy here...
proc GetEnvironmentStringsA*(): cstring {. proc GetEnvironmentStringsA(): cstring {.
stdcall, dynlib: "kernel32", importc.} stdcall, dynlib: "kernel32", importc.}
proc FreeEnvironmentStringsA*(para1: cstring): int32 {. proc FreeEnvironmentStringsA(para1: cstring): int32 {.
stdcall, dynlib: "kernel32", importc.} stdcall, dynlib: "kernel32", importc.}
proc strEnd(cstr: CString, c = 0): CString {.importc: "strchr", nodecl.} proc strEnd(cstr: CString, c = 0): CString {.importc: "strchr", nodecl.}
@ -1091,8 +1092,8 @@ proc expandFilename(filename: string): string =
proc parseCmdLine*(c: string): seq[string] = proc parseCmdLine*(c: string): seq[string] =
## Splits a command line into several components; components are separated by ## Splits a command line into several components; components are separated by
## whitespace or are quoted with the ``"`` or ``'`` characters. This proc is ## whitespace unless the whitespace occurs within ``"`` or ``'`` quotes.
## only occassionally useful, better use the `parseopt` module. ## This proc is only occassionally useful, better use the `parseopt` module.
result = @[] result = @[]
var i = 0 var i = 0
while c[i] != '\0': while c[i] != '\0':

View file

@ -54,7 +54,7 @@ type
TTokKind = enum TTokKind = enum
tkInvalid, tkEof, tkInvalid, tkEof,
tkSymbol, tkEquals, tkColon, tkBracketLe, tkBracketRi, tkDashDash tkSymbol, tkEquals, tkColon, tkBracketLe, tkBracketRi, tkDashDash
TToken{.final.} = object # a token TToken {.final.} = object # a token
kind: TTokKind # the type of the token kind: TTokKind # the type of the token
literal: string # the parsed (string) literal literal: string # the parsed (string) literal
@ -139,7 +139,7 @@ proc getEscapedChar(c: var TCfgParser, tok: var TToken) =
inc(c.bufpos) # skip '\' inc(c.bufpos) # skip '\'
case c.buf[c.bufpos] case c.buf[c.bufpos]
of 'n', 'N': of 'n', 'N':
tok.literal = tok.literal & nl add(tok.literal, nl)
Inc(c.bufpos) Inc(c.bufpos)
of 'r', 'R', 'c', 'C': of 'r', 'R', 'c', 'C':
add(tok.literal, '\c') add(tok.literal, '\c')

View file

@ -53,7 +53,7 @@ proc init(cmdline: string = ""): TOptParser =
else: else:
result.cmd = "" result.cmd = ""
for i in countup(1, ParamCount()): for i in countup(1, ParamCount()):
result.cmd = result.cmd & quoteIfSpaceExists(paramStr(i)) & ' ' result.cmd = result.cmd & quoteIfContainsWhite(paramStr(i)) & ' '
result.kind = cmdEnd result.kind = cmdEnd
result.key = "" result.key = ""
result.val = "" result.val = ""

View file

@ -22,12 +22,12 @@ proc reprPointer(x: pointer): string {.compilerproc.} =
proc reprStrAux(result: var string, s: string) = proc reprStrAux(result: var string, s: string) =
if cast[pointer](s) == nil: if cast[pointer](s) == nil:
add result "nil" add result, "nil"
return return
add result, reprPointer(cast[pointer](s)) & "\"" add result, reprPointer(cast[pointer](s)) & "\""
for c in items(s): for c in items(s):
case c case c
of '"': add result "\\\"" of '"': add result, "\\\""
of '\\': add result, "\\\\" # BUGFIX: forgotten of '\\': add result, "\\\\" # BUGFIX: forgotten
of '\10': add result, "\\10\"\n\"" # " \n " # better readability of '\10': add result, "\\10\"\n\"" # " \n " # better readability
of '\128' .. '\255', '\0'..'\9', '\11'..'\31': of '\128' .. '\255', '\0'..'\9', '\11'..'\31':

View file

@ -12,6 +12,8 @@
## All the routines here are avaiable for the EMCAScript target ## All the routines here are avaiable for the EMCAScript target
## too! ## too!
{.deadCodeElim: on.}
{.push debugger:off .} # the user does not want to trace a part {.push debugger:off .} # the user does not want to trace a part
# of the standard library! # of the standard library!
@ -41,19 +43,19 @@ proc strip*(s: string): string {.noSideEffect.}
proc toLower*(s: string): string {.noSideEffect.} proc toLower*(s: string): string {.noSideEffect.}
## Converts `s` into lower case. This works only for the letters A-Z. ## Converts `s` into lower case. This works only for the letters A-Z.
## See `charsets.nativeToLower` for a version that is locale-dependant. ## See `unicode.toLower` for a version that works for any Unicode character.
proc toLower*(c: Char): Char {.noSideEffect.} proc toLower*(c: Char): Char {.noSideEffect.}
## Converts `c` into lower case. This works only for the letters A-Z. ## Converts `c` into lower case. This works only for the letters A-Z.
## See `charsets.nativeToLower()` for a version that is locale-dependant. ## See `unicode.toLower` for a version that works for any Unicode character.
proc toUpper*(s: string): string {.noSideEffect.} proc toUpper*(s: string): string {.noSideEffect.}
## Converts `s` into upper case. This works only for the letters a-z. ## Converts `s` into upper case. This works only for the letters a-z.
## See `charsets.nativeToUpper()` for a version that is locale-dependant. ## See `unicode.toUpper` for a version that works for any Unicode character.
proc toUpper*(c: Char): Char {.noSideEffect.} proc toUpper*(c: Char): Char {.noSideEffect.}
## Converts `c` into upper case. This works only for the letters a-z. ## Converts `c` into upper case. This works only for the letters a-z.
## See `charsets.nativeToUpper()` for a version that is locale-dependant. ## See `unicode.toUpper` for a version that works for any Unicode character.
proc capitalize*(s: string): string {.noSideEffect.} proc capitalize*(s: string): string {.noSideEffect.}
## Converts the first character of `s` into upper case. ## Converts the first character of `s` into upper case.
@ -71,6 +73,10 @@ proc findSubStr*(sub: char, s: string, start: int = 0): int {.noSideEffect.}
## Searches for `sub` in `s` starting at position `start`. Searching is ## Searches for `sub` in `s` starting at position `start`. Searching is
## case-sensitive. If `sub` is not in `s`, -1 is returned. ## case-sensitive. If `sub` is not in `s`, -1 is returned.
proc findChars*(chars: set[char], s: string, start: int = 0): int {.noSideEffect.}
## Searches for `chars` in `s` starting at position `start`. If `s` contains
## none of the characters in `chars`, -1 is returned.
proc replaceStr*(s, sub, by: string): string {.noSideEffect.} proc replaceStr*(s, sub, by: string): string {.noSideEffect.}
## Replaces `sub` in `s` by the string `by`. ## Replaces `sub` in `s` by the string `by`.
@ -173,11 +179,14 @@ proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect.}
## | < 0 iff a < b ## | < 0 iff a < b
## | > 0 iff a > b ## | > 0 iff a > b
proc in_Operator*(s: string, c: char): bool {.noSideEffect.} proc contains*(s: string, c: char): bool {.noSideEffect.}
## Same as `findSubStr(c, s) >= 0`. ## Same as ``findSubStr(c, s) >= 0``.
proc in_Operator*(s, sub: string): bool {.noSideEffect.} proc contains*(s, sub: string): bool {.noSideEffect.}
## Same as `findSubStr(sub, s) >= 0`. ## Same as ``findSubStr(sub, s) >= 0``.
proc contains*(s: string, chars: set[char]): bool {.noSideEffect.}
## Same as ``findChars(s, chars) >= 0``.
proc toHex*(x: BiggestInt, len: int): string {.noSideEffect.} proc toHex*(x: BiggestInt, len: int): string {.noSideEffect.}
## Converts `x` to its hexadecimal representation. The resulting string ## Converts `x` to its hexadecimal representation. The resulting string
@ -259,10 +268,10 @@ proc allCharsInSet*(s: string, theSet: TCharSet): bool =
if not (c in theSet): return false if not (c in theSet): return false
return true return true
proc quoteIfSpaceExists*(s: string): string = proc quoteIfContainsWhite*(s: string): string =
## returns ``'"' & s & '"'`` if `s` contains a space and does not ## returns ``'"' & s & '"'`` if `s` contains a space and does not
## start with a quote, else returns `s` ## start with a quote, else returns `s`
if findSubStr(' ', s) >= 0 and s[0] != '"': if findChars({' ', '\t'}, s) >= 0 and s[0] != '"':
result = '"' & s & '"' result = '"' & s & '"'
else: else:
result = s result = s
@ -488,11 +497,19 @@ proc findSubStr(sub: char, s: string, start: int = 0): int =
for i in start..len(s)-1: for i in start..len(s)-1:
if sub == s[i]: return i if sub == s[i]: return i
return -1 return -1
proc findChars(chars: set[char], s: string, start: int = 0): int =
for i in start..s.len-1:
if s[i] in chars: return i
return -1
proc contains(s: string, chars: set[char]): bool =
return findChars(chars, s) >= 0
proc in_Operator(s: string, c: char): bool = proc contains(s: string, c: char): bool =
return findSubStr(c, s) >= 0 return findSubStr(c, s) >= 0
proc in_Operator(s, sub: string): bool = proc contains(s, sub: string): bool =
return findSubStr(sub, s) >= 0 return findSubStr(sub, s) >= 0
proc replaceStr(s, sub, by: string): string = proc replaceStr(s, sub, by: string): string =

View file

@ -91,10 +91,13 @@ proc writeln[Ty](f: TFile, x: Ty) =
write(f, "\n") write(f, "\n")
proc writeln[Ty](f: TFile, x: openArray[Ty]) = proc writeln[Ty](f: TFile, x: openArray[Ty]) =
write(f, x) for i in items(x): write(f, i)
write(f, "\n") write(f, "\n")
proc echo[Ty](x: Ty) = writeln(stdout, x) proc echo[Ty](x: Ty) = writeln(stdout, x)
proc echo[Ty](x: openArray[Ty]) =
for i in items(x): write(stdout, i)
write(stdout, "\n")
# interface to the C procs: # interface to the C procs:
proc fopen(filename, mode: CString): pointer {.importc: "fopen", noDecl.} proc fopen(filename, mode: CString): pointer {.importc: "fopen", noDecl.}

View file

@ -15,13 +15,6 @@
# we don't use refcounts because that's a behaviour # we don't use refcounts because that's a behaviour
# the programmer may not want # the programmer may not want
type
# len and space without counting the terminating zero:
NimStringDesc {.compilerproc, final.} = object of TGenericSeq
data: array[0..100_000_000, char] # for the '\0' character
NimString = ptr NimStringDesc
# implementation: # implementation:
proc resize(old: int): int {.inline.} = proc resize(old: int): int {.inline.} =

View file

@ -58,6 +58,17 @@ proc defined*[T] (x: T): bool {.magic: "Defined", noSideEffect.}
proc `not` *(x: bool): bool {.magic: "Not", noSideEffect.} proc `not` *(x: bool): bool {.magic: "Not", noSideEffect.}
## Boolean not; returns true iff ``x == false``. ## Boolean not; returns true iff ``x == false``.
proc `and`*(x, y: bool): bool {.magic: "And", noSideEffect.}
## Boolean ``and``; returns true iff ``x == y == true``.
## Evaluation is short-circuited: This means that if ``x`` is false,
## ``y`` will not even be evaluated.
proc `or`*(x, y: bool): bool {.magic: "Or", noSideEffect.}
## Boolean ``or``; returns true iff ``not (not x and not y)``.
## Evaluation is short-circuited: This means that if ``x`` is true,
## ``y`` will not even be evaluated.
proc `xor`*(x, y: bool): bool {.magic: "Xor", noSideEffect.}
## Boolean `exclusive or`; returns true iff ``x != y``.
proc new*[T](a: var ref T) {.magic: "New".} proc new*[T](a: var ref T) {.magic: "New".}
## creates a new object of type ``T`` and returns a safe (traced) ## creates a new object of type ``T`` and returns a safe (traced)
## reference to it in ``a``. ## reference to it in ``a``.
@ -94,6 +105,19 @@ type
seq*{.magic: "Seq".}[T] ## Generic type to construct sequences. seq*{.magic: "Seq".}[T] ## Generic type to construct sequences.
set*{.magic: "Set".}[T] ## Generic type to construct bit sets. set*{.magic: "Set".}[T] ## Generic type to construct bit sets.
when not defined(EcmaScript) and not defined(NimrodVM):
type
TGenericSeq {.compilerproc, pure.} = object
len, space: int
PGenericSeq {.exportc.} = ptr TGenericSeq
# len and space without counting the terminating zero:
NimStringDesc {.compilerproc, final.} = object of TGenericSeq
data: array[0..100_000_000, char]
NimString = ptr NimStringDesc
include hti
type
Byte* = Int8 ## this is an alias for ``int8``, that is a signed Byte* = Int8 ## this is an alias for ``int8``, that is a signed
## int 8 bits wide. ## int 8 bits wide.
@ -403,8 +427,8 @@ proc abs*(x: int8): int8 {.magic: "AbsI", noSideEffect.}
proc abs*(x: int16): int16 {.magic: "AbsI", noSideEffect.} proc abs*(x: int16): int16 {.magic: "AbsI", noSideEffect.}
proc abs*(x: int32): int32 {.magic: "AbsI", noSideEffect.} proc abs*(x: int32): int32 {.magic: "AbsI", noSideEffect.}
proc abs*(x: int64): int64 {.magic: "AbsI64", noSideEffect.} proc abs*(x: int64): int64 {.magic: "AbsI64", noSideEffect.}
## returns the absolute value of `x`. If `x` is ``low(x)`` (that is ## returns the absolute value of `x`. If `x` is ``low(x)`` (that
## -MININT for its type), an overflow exception is thrown (if overflow ## is -MININT for its type), an overflow exception is thrown (if overflow
## checking is turned on). ## checking is turned on).
proc min*(x, y: int): int {.magic: "MinI", noSideEffect.} proc min*(x, y: int): int {.magic: "MinI", noSideEffect.}
@ -500,18 +524,6 @@ proc abs*(x: float): float {.magic: "AbsF64", noSideEffect.}
proc min*(x, y: float): float {.magic: "MinF64", noSideEffect.} proc min*(x, y: float): float {.magic: "MinF64", noSideEffect.}
proc max*(x, y: float): float {.magic: "MaxF64", noSideEffect.} proc max*(x, y: float): float {.magic: "MaxF64", noSideEffect.}
# boolean operators:
proc `and`*(x, y: bool): bool {.magic: "And", noSideEffect.}
## Boolean ``and``; returns true iff ``x == y == true``.
## Evaluation is short-circuited: This means that if ``x`` is false,
## ``y`` will not even be evaluated.
proc `or`*(x, y: bool): bool {.magic: "Or", noSideEffect.}
## Boolean ``or``; returns true iff ``not (not x and not y)``.
## Evaluation is short-circuited: This means that if ``x`` is true,
## ``y`` will not even be evaluated.
proc `xor`*(x, y: bool): bool {.magic: "Xor", noSideEffect.}
## Boolean `exclusive or`; returns true iff ``x != y``.
# set operators # set operators
proc `*` *[T](x, y: set[T]): set[T] {.magic: "MulSet", noSideEffect.} proc `*` *[T](x, y: set[T]): set[T] {.magic: "MulSet", noSideEffect.}
## This operator computes the intersection of two sets. ## This operator computes the intersection of two sets.
@ -563,11 +575,12 @@ template `>` * (x, y: expr): expr =
## "is greater" operator. This is the same as ``y < x``. ## "is greater" operator. This is the same as ``y < x``.
y < x y < x
proc in_Operator*[T](x: set[T], y: T): bool {.magic: "InSet", noSideEffect.} proc contains*[T](x: set[T], y: T): bool {.magic: "InSet", noSideEffect.}
## One should overload this proc if one wants to overload the ``in`` operator. ## One should overload this proc if one wants to overload the ``in`` operator.
## The parameters are in reverse order! This is because the unification ## The parameters are in reverse order! ``a in b`` is a template for
## algorithm that Nimrod uses for overload resolution works from left to ## ``contains(b, a)``.
## right. ## This is because the unification algorithm that Nimrod uses for overload
## resolution works from left to right.
## But for the ``in`` operator that would be the wrong direction for this ## But for the ``in`` operator that would be the wrong direction for this
## piece of code: ## piece of code:
## ##
@ -578,11 +591,11 @@ proc in_Operator*[T](x: set[T], y: T): bool {.magic: "InSet", noSideEffect.}
## If ``in`` had been declared as ``[T](elem: T, s: set[T])`` then ``T`` would ## 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 to 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 ## ``set[char]``! The solution is to bind ``T`` to ``range['a'..'z']``. This
## is achieved by reversing the parameters for ``in_operator``; ``in`` then ## is achieved by reversing the parameters for ``contains``; ``in`` then
## passes its arguments in reverse order. ## passes its arguments in reverse order.
template `in` * (x, y: expr): expr = in_Operator(y, x) template `in` * (x, y: expr): expr = contains(y, x)
template `not_in` * (x, y: expr): expr = not in_Operator(y, x) template `not_in` * (x, y: expr): expr = not contains(y, x)
proc `is` *[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.} proc `is` *[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.}
template `is_not` *(x, y: expr): expr = not (x is y) template `is_not` *(x, y: expr): expr = not (x is y)
@ -616,15 +629,17 @@ proc `&` * (x: char, y: string): string {.
magic: "ConStrStr", noSideEffect, merge.} magic: "ConStrStr", noSideEffect, merge.}
## is the `concatenation operator`. It concatenates `x` and `y`. ## is the `concatenation operator`. It concatenates `x` and `y`.
proc add * (x: var string, y: char) {.magic: "AppendStrCh".} proc add*(x: var string, y: char) {.magic: "AppendStrCh".}
proc add * (x: var string, y: string) {.magic: "AppendStrStr".} proc add*(x: var string, y: string) {.magic: "AppendStrStr".}
when not defined(ECMAScript): when not defined(ECMAScript):
{.push overflow_checks:off}
proc add* (x: var string, y: cstring) = proc add* (x: var string, y: cstring) =
var i = 0 var i = 0
while y[i] != '\0': while y[i] != '\0':
add(x, y[i]) add(x, y[i])
inc(i) inc(i)
{.pop.}
else: else:
proc add* (x: var string, y: cstring) {.pure.} = proc add* (x: var string, y: cstring) {.pure.} =
asm """ asm """
@ -646,7 +661,7 @@ proc add *[T](x: var seq[T], y: seq[T]) {.magic: "AppendSeqSeq".}
proc repr*[T](x: T): string {.magic: "Repr", noSideEffect.} proc repr*[T](x: T): string {.magic: "Repr", noSideEffect.}
## takes any Nimrod variable and returns its string representation. It ## takes any Nimrod variable and returns its string representation. It
## works even for complex data graphs with cycles. This is an invaluable ## works even for complex data graphs with cycles. This is a great
## debugging tool. ## debugging tool.
type type
@ -729,7 +744,16 @@ const
cpuEndian* {.magic: "CpuEndian"}: TEndian = littleEndian cpuEndian* {.magic: "CpuEndian"}: TEndian = littleEndian
## is the endianness of the target CPU. This is a valuable piece of ## is the endianness of the target CPU. This is a valuable piece of
## information for low-level code only. This works thanks to compiler magic. ## information for low-level code only. This works thanks to compiler magic.
hostOS* {.magic: "HostOS"}: string = ""
## a string that describes the host operating system. Possible values:
## "windows", "macosx", "linux", "netbsd", "freebsd", "openbsd", "solaris",
## "aix"
hostCPU* {.magic: "HostCPU"}: string = ""
## a string that describes the host CPU. Possible values:
## "i386", "alpha", "powerpc", "sparc", "amd64", "mips", "arm"
proc toFloat*(i: int): float {. proc toFloat*(i: int): float {.
magic: "ToFloat", noSideEffect, importc: "toFloat".} magic: "ToFloat", noSideEffect, importc: "toFloat".}
## converts an integer `i` into a ``float``. If the conversion ## converts an integer `i` into a ``float``. If the conversion
@ -896,6 +920,12 @@ proc `$` *(x: string): string {.magic: "StrToStr", noSideEffect.}
## as it is. This operator is useful for generic code, so ## as it is. This operator is useful for generic code, so
## that ``$expr`` also works if ``expr`` is already a string. ## that ``$expr`` also works if ``expr`` is already a string.
proc `$` *(x: TAnyEnum): string {.magic: "EnumToStr", noSideEffect.}
## The stingify operator for an enumeration argument. This works for
## any enumeration type thanks to compiler magic. If a
## a ``$`` operator for a concrete enumeration is provided, this is
## used instead. (In other words: *Overwriting* is possible.)
# undocumented: # undocumented:
proc getRefcount*[T](x: ref T): int {.importc: "getRefcount".} proc getRefcount*[T](x: ref T): int {.importc: "getRefcount".}
## retrieves the reference count of an heap-allocated object. The ## retrieves the reference count of an heap-allocated object. The
@ -1136,6 +1166,10 @@ proc echo*[Ty](x: Ty) {.inline.}
## equivalent to ``writeln(stdout, x); flush(stdout)``. BUT: This is ## equivalent to ``writeln(stdout, x); flush(stdout)``. BUT: This is
## available for the ECMAScript target too! ## available for the ECMAScript target too!
proc echo*[Ty](x: openarray[Ty]) {.inline.}
## equivalent to ``writeln(stdout, x); flush(stdout)``. BUT: This is
## available for the ECMAScript target too!
template newException(exceptn, message: expr): expr = template newException(exceptn, message: expr): expr =
block: # open a new scope block: # open a new scope
@ -1169,8 +1203,6 @@ when not defined(EcmaScript) and not defined(NimrodVM):
when not defined(EcmaScript) and not defined(NimrodVM): when not defined(EcmaScript) and not defined(NimrodVM):
include hti
proc initGC() proc initGC()
var var
@ -1370,13 +1402,6 @@ when not defined(EcmaScript) and not defined(NimrodVM):
include arithm include arithm
{.pop.} # stack trace {.pop.} # stack trace
# sequence type declarations here because the GC needs them too:
type
TGenericSeq {.compilerproc, pure.} = object
len, space: int
PGenericSeq {.exportc.} = ptr TGenericSeq
const const
GenericSeqSize = (2 * sizeof(int)) GenericSeqSize = (2 * sizeof(int))
@ -1417,13 +1442,12 @@ elif defined(NimrodVM):
proc getFreeMem(): int = return -1 proc getFreeMem(): int = return -1
proc getTotalMem(): int = return -1 proc getTotalMem(): int = return -1
proc echo[Ty](x: Ty) = nil proc echo[Ty](x: Ty) = nil
proc echo[Ty](x: openarray[Ty]) = nil
proc cmp(x, y: string): int = proc cmp(x, y: string): int =
if x == y: return 0 if x == y: return 0
if x < y: return -1 if x < y: return -1
return 1 return 1
include macros
{.pop.} # checks {.pop.} # checks
{.pop.} # hints {.pop.} # hints

View file

@ -276,8 +276,8 @@ else:
proc getDateStr(): string = proc getDateStr(): string =
var ti = getLocalTime(getTime()) var ti = getLocalTime(getTime())
result = $ti.year & "-" & intToStr(ord(ti.month)+1, 2) & result = $ti.year & '-' & intToStr(ord(ti.month)+1, 2) &
"-" & intToStr(ti.monthDay, 2) '-' & intToStr(ti.monthDay, 2)
proc getClockStr(): string = proc getClockStr(): string =
var ti = getLocalTime(getTime()) var ti = getLocalTime(getTime())

File diff suppressed because it is too large Load diff

View file

@ -10,6 +10,8 @@
## Define ``winUnicode`` before importing this module for the ## Define ``winUnicode`` before importing this module for the
## unicode version. ## unicode version.
{.deadCodeElim: on.}
type type
ATOM* = int16 ATOM* = int16
TAtom* = ATOM TAtom* = ATOM

View file

@ -7,7 +7,7 @@ all:
.PHONY : install .PHONY : install
install: install:
sh install.sh /usr/bin sh build.sh
.PHONY : clean .PHONY : clean
clean: clean:

View file

@ -65,148 +65,148 @@ for key, val in enums.items():
cog.out(a) cog.out(a)
cog.out(b) cog.out(b)
]]]*) ]]]*)
type type
TTypeFlag = ( TNodeKind = (
tfVarargs, tfFinal, tfAcyclic, tfEnumHasWholes); nkNone, nkEmpty, nkIdent, nkSym,
TTypeFlags = set of TTypeFlag; nkType, nkCharLit, nkIntLit, nkInt8Lit,
const nkInt16Lit, nkInt32Lit, nkInt64Lit, nkFloatLit,
TypeFlagToStr: array [TTypeFlag] of string = ( nkFloat32Lit, nkFloat64Lit, nkStrLit, nkRStrLit,
'tfVarargs', 'tfFinal', 'tfAcyclic', 'tfEnumHasWholes'); nkTripleStrLit, nkMetaNode, nkNilLit, nkDotCall,
type nkCommand, nkCall, nkGenericCall, nkExplicitTypeListCall,
TTypeKind = ( nkExprEqExpr, nkExprColonExpr, nkIdentDefs, nkVarTuple,
tyNone, tyBool, tyChar, tyEmpty, nkInfix, nkPrefix, nkPostfix, nkPar,
tyArrayConstr, tyNil, tyGeneric, tyGenericInst, nkCurly, nkBracket, nkBracketExpr, nkPragmaExpr,
tyGenericParam, tyEnum, tyAnyEnum, tyArray, nkRange, nkDotExpr, nkCheckedFieldExpr, nkDerefExpr,
tyObject, tyTuple, tySet, tyRange, nkIfExpr, nkElifExpr, nkElseExpr, nkLambda,
tyPtr, tyRef, tyVar, tySequence, nkAccQuoted, nkHeaderQuoted, nkTableConstr, nkQualified,
tyProc, tyPointer, tyOpenArray, tyString, nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv, nkConv,
tyCString, tyForward, tyInt, tyInt8, nkCast, nkAddr, nkHiddenAddr, nkHiddenDeref,
tyInt16, tyInt32, tyInt64, tyFloat, nkObjDownConv, nkObjUpConv, nkChckRangeF, nkChckRange64,
tyFloat32, tyFloat64, tyFloat128); nkChckRange, nkStringToCString, nkCStringToString, nkPassAsOpenArray,
TTypeKinds = set of TTypeKind; nkAsgn, nkFastAsgn, nkDefaultTypeParam, nkGenericParams,
const nkFormalParams, nkOfInherit, nkModule, nkProcDef,
TypeKindToStr: array [TTypeKind] of string = ( nkConverterDef, nkMacroDef, nkTemplateDef, nkIteratorDef,
'tyNone', 'tyBool', 'tyChar', 'tyEmpty', nkOfBranch, nkElifBranch, nkExceptBranch, nkElse,
'tyArrayConstr', 'tyNil', 'tyGeneric', 'tyGenericInst', nkMacroStmt, nkAsmStmt, nkPragma, nkIfStmt,
'tyGenericParam', 'tyEnum', 'tyAnyEnum', 'tyArray', nkWhenStmt, nkForStmt, nkWhileStmt, nkCaseStmt,
'tyObject', 'tyTuple', 'tySet', 'tyRange', nkVarSection, nkConstSection, nkConstDef, nkTypeSection,
'tyPtr', 'tyRef', 'tyVar', 'tySequence', nkTypeDef, nkYieldStmt, nkTryStmt, nkFinally,
'tyProc', 'tyPointer', 'tyOpenArray', 'tyString', nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt,
'tyCString', 'tyForward', 'tyInt', 'tyInt8', nkBlockStmt, nkDiscardStmt, nkStmtList, nkImportStmt,
'tyInt16', 'tyInt32', 'tyInt64', 'tyFloat', nkFromStmt, nkImportAs, nkIncludeStmt, nkAccessStmt,
'tyFloat32', 'tyFloat64', 'tyFloat128'); nkCommentStmt, nkStmtListExpr, nkBlockExpr, nkStmtListType,
type nkBlockType, nkVm, nkTypeOfExpr, nkObjectTy,
TSymFlag = ( nkTupleTy, nkRecList, nkRecCase, nkRecWhen,
sfUsed, sfStar, sfMinus, sfInInterface, nkRefTy, nkPtrTy, nkVarTy, nkProcTy,
sfFromGeneric, sfGlobal, sfForward, sfImportc, nkEnumTy, nkEnumFieldDef, nkReturnToken);
sfExportc, sfVolatile, sfRegister, sfPure, TNodeKinds = set of TNodeKind;
sfResult, sfNoSideEffect, sfMainModule, sfSystemModule, const
sfNoReturn, sfAddrTaken, sfCompilerProc, sfCppMethod, NodeKindToStr: array [TNodeKind] of string = (
sfDiscriminant, sfDeprecated, sfInClosure, sfTypeCheck, 'nkNone', 'nkEmpty', 'nkIdent', 'nkSym',
sfCompileTime, sfThreadVar, sfMerge); 'nkType', 'nkCharLit', 'nkIntLit', 'nkInt8Lit',
TSymFlags = set of TSymFlag; 'nkInt16Lit', 'nkInt32Lit', 'nkInt64Lit', 'nkFloatLit',
const 'nkFloat32Lit', 'nkFloat64Lit', 'nkStrLit', 'nkRStrLit',
SymFlagToStr: array [TSymFlag] of string = ( 'nkTripleStrLit', 'nkMetaNode', 'nkNilLit', 'nkDotCall',
'sfUsed', 'sfStar', 'sfMinus', 'sfInInterface', 'nkCommand', 'nkCall', 'nkGenericCall', 'nkExplicitTypeListCall',
'sfFromGeneric', 'sfGlobal', 'sfForward', 'sfImportc', 'nkExprEqExpr', 'nkExprColonExpr', 'nkIdentDefs', 'nkVarTuple',
'sfExportc', 'sfVolatile', 'sfRegister', 'sfPure', 'nkInfix', 'nkPrefix', 'nkPostfix', 'nkPar',
'sfResult', 'sfNoSideEffect', 'sfMainModule', 'sfSystemModule', 'nkCurly', 'nkBracket', 'nkBracketExpr', 'nkPragmaExpr',
'sfNoReturn', 'sfAddrTaken', 'sfCompilerProc', 'sfCppMethod', 'nkRange', 'nkDotExpr', 'nkCheckedFieldExpr', 'nkDerefExpr',
'sfDiscriminant', 'sfDeprecated', 'sfInClosure', 'sfTypeCheck', 'nkIfExpr', 'nkElifExpr', 'nkElseExpr', 'nkLambda',
'sfCompileTime', 'sfThreadVar', 'sfMerge'); 'nkAccQuoted', 'nkHeaderQuoted', 'nkTableConstr', 'nkQualified',
type 'nkHiddenStdConv', 'nkHiddenSubConv', 'nkHiddenCallConv', 'nkConv',
TNodeFlag = ( 'nkCast', 'nkAddr', 'nkHiddenAddr', 'nkHiddenDeref',
nfNone, nfBase2, nfBase8, nfBase16, 'nkObjDownConv', 'nkObjUpConv', 'nkChckRangeF', 'nkChckRange64',
nfAllConst, nfTransf, nfSem); 'nkChckRange', 'nkStringToCString', 'nkCStringToString', 'nkPassAsOpenArray',
TNodeFlags = set of TNodeFlag; 'nkAsgn', 'nkFastAsgn', 'nkDefaultTypeParam', 'nkGenericParams',
const 'nkFormalParams', 'nkOfInherit', 'nkModule', 'nkProcDef',
NodeFlagToStr: array [TNodeFlag] of string = ( 'nkConverterDef', 'nkMacroDef', 'nkTemplateDef', 'nkIteratorDef',
'nfNone', 'nfBase2', 'nfBase8', 'nfBase16', 'nkOfBranch', 'nkElifBranch', 'nkExceptBranch', 'nkElse',
'nfAllConst', 'nfTransf', 'nfSem'); 'nkMacroStmt', 'nkAsmStmt', 'nkPragma', 'nkIfStmt',
type 'nkWhenStmt', 'nkForStmt', 'nkWhileStmt', 'nkCaseStmt',
TSymKind = ( 'nkVarSection', 'nkConstSection', 'nkConstDef', 'nkTypeSection',
skUnknownSym, skConditional, skDynLib, skParam, 'nkTypeDef', 'nkYieldStmt', 'nkTryStmt', 'nkFinally',
skTypeParam, skTemp, skType, skConst, 'nkRaiseStmt', 'nkReturnStmt', 'nkBreakStmt', 'nkContinueStmt',
skVar, skProc, skIterator, skConverter, 'nkBlockStmt', 'nkDiscardStmt', 'nkStmtList', 'nkImportStmt',
skMacro, skTemplate, skField, skEnumField, 'nkFromStmt', 'nkImportAs', 'nkIncludeStmt', 'nkAccessStmt',
skForVar, skModule, skLabel, skStub); 'nkCommentStmt', 'nkStmtListExpr', 'nkBlockExpr', 'nkStmtListType',
TSymKinds = set of TSymKind; 'nkBlockType', 'nkVm', 'nkTypeOfExpr', 'nkObjectTy',
const 'nkTupleTy', 'nkRecList', 'nkRecCase', 'nkRecWhen',
SymKindToStr: array [TSymKind] of string = ( 'nkRefTy', 'nkPtrTy', 'nkVarTy', 'nkProcTy',
'skUnknownSym', 'skConditional', 'skDynLib', 'skParam', 'nkEnumTy', 'nkEnumFieldDef', 'nkReturnToken');
'skTypeParam', 'skTemp', 'skType', 'skConst', type
'skVar', 'skProc', 'skIterator', 'skConverter', TSymFlag = (
'skMacro', 'skTemplate', 'skField', 'skEnumField', sfUsed, sfStar, sfMinus, sfInInterface,
'skForVar', 'skModule', 'skLabel', 'skStub'); sfFromGeneric, sfGlobal, sfForward, sfImportc,
type sfExportc, sfVolatile, sfRegister, sfPure,
TNodeKind = ( sfResult, sfNoSideEffect, sfMainModule, sfSystemModule,
nkNone, nkEmpty, nkIdent, nkSym, sfNoReturn, sfAddrTaken, sfCompilerProc, sfCppMethod,
nkType, nkCharLit, nkIntLit, nkInt8Lit, sfDiscriminant, sfDeprecated, sfInClosure, sfTypeCheck,
nkInt16Lit, nkInt32Lit, nkInt64Lit, nkFloatLit, sfCompileTime, sfThreadVar, sfMerge, sfDeadCodeElim);
nkFloat32Lit, nkFloat64Lit, nkStrLit, nkRStrLit, TSymFlags = set of TSymFlag;
nkTripleStrLit, nkMetaNode, nkNilLit, nkDotCall, const
nkCommand, nkCall, nkGenericCall, nkExplicitTypeListCall, SymFlagToStr: array [TSymFlag] of string = (
nkExprEqExpr, nkExprColonExpr, nkIdentDefs, nkInfix, 'sfUsed', 'sfStar', 'sfMinus', 'sfInInterface',
nkPrefix, nkPostfix, nkPar, nkCurly, 'sfFromGeneric', 'sfGlobal', 'sfForward', 'sfImportc',
nkBracket, nkBracketExpr, nkPragmaExpr, nkRange, 'sfExportc', 'sfVolatile', 'sfRegister', 'sfPure',
nkDotExpr, nkCheckedFieldExpr, nkDerefExpr, nkIfExpr, 'sfResult', 'sfNoSideEffect', 'sfMainModule', 'sfSystemModule',
nkElifExpr, nkElseExpr, nkLambda, nkAccQuoted, 'sfNoReturn', 'sfAddrTaken', 'sfCompilerProc', 'sfCppMethod',
nkHeaderQuoted, nkTableConstr, nkQualified, nkHiddenStdConv, 'sfDiscriminant', 'sfDeprecated', 'sfInClosure', 'sfTypeCheck',
nkHiddenSubConv, nkHiddenCallConv, nkConv, nkCast, 'sfCompileTime', 'sfThreadVar', 'sfMerge', 'sfDeadCodeElim');
nkAddr, nkHiddenAddr, nkHiddenDeref, nkObjDownConv, type
nkObjUpConv, nkChckRangeF, nkChckRange64, nkChckRange, TTypeKind = (
nkStringToCString, nkCStringToString, nkPassAsOpenArray, nkAsgn, tyNone, tyBool, tyChar, tyEmpty,
nkDefaultTypeParam, nkGenericParams, nkFormalParams, nkOfInherit, tyArrayConstr, tyNil, tyGeneric, tyGenericInst,
nkModule, nkProcDef, nkConverterDef, nkMacroDef, tyGenericParam, tyEnum, tyAnyEnum, tyArray,
nkTemplateDef, nkIteratorDef, nkOfBranch, nkElifBranch, tyObject, tyTuple, tySet, tyRange,
nkExceptBranch, nkElse, nkMacroStmt, nkAsmStmt, tyPtr, tyRef, tyVar, tySequence,
nkPragma, nkIfStmt, nkWhenStmt, nkForStmt, tyProc, tyPointer, tyOpenArray, tyString,
nkWhileStmt, nkCaseStmt, nkVarSection, nkConstSection, tyCString, tyForward, tyInt, tyInt8,
nkConstDef, nkTypeSection, nkTypeDef, nkYieldStmt, tyInt16, tyInt32, tyInt64, tyFloat,
nkTryStmt, nkFinally, nkRaiseStmt, nkReturnStmt, tyFloat32, tyFloat64, tyFloat128);
nkBreakStmt, nkContinueStmt, nkBlockStmt, nkDiscardStmt, TTypeKinds = set of TTypeKind;
nkStmtList, nkImportStmt, nkFromStmt, nkImportAs, const
nkIncludeStmt, nkAccessStmt, nkCommentStmt, nkStmtListExpr, TypeKindToStr: array [TTypeKind] of string = (
nkBlockExpr, nkStmtListType, nkBlockType, nkVm, 'tyNone', 'tyBool', 'tyChar', 'tyEmpty',
nkTypeOfExpr, nkObjectTy, nkTupleTy, nkRecList, 'tyArrayConstr', 'tyNil', 'tyGeneric', 'tyGenericInst',
nkRecCase, nkRecWhen, nkRefTy, nkPtrTy, 'tyGenericParam', 'tyEnum', 'tyAnyEnum', 'tyArray',
nkVarTy, nkProcTy, nkEnumTy, nkEnumFieldDef, 'tyObject', 'tyTuple', 'tySet', 'tyRange',
nkReturnToken); 'tyPtr', 'tyRef', 'tyVar', 'tySequence',
TNodeKinds = set of TNodeKind; 'tyProc', 'tyPointer', 'tyOpenArray', 'tyString',
const 'tyCString', 'tyForward', 'tyInt', 'tyInt8',
NodeKindToStr: array [TNodeKind] of string = ( 'tyInt16', 'tyInt32', 'tyInt64', 'tyFloat',
'nkNone', 'nkEmpty', 'nkIdent', 'nkSym', 'tyFloat32', 'tyFloat64', 'tyFloat128');
'nkType', 'nkCharLit', 'nkIntLit', 'nkInt8Lit', type
'nkInt16Lit', 'nkInt32Lit', 'nkInt64Lit', 'nkFloatLit', TNodeFlag = (
'nkFloat32Lit', 'nkFloat64Lit', 'nkStrLit', 'nkRStrLit', nfNone, nfBase2, nfBase8, nfBase16,
'nkTripleStrLit', 'nkMetaNode', 'nkNilLit', 'nkDotCall', nfAllConst, nfTransf, nfSem);
'nkCommand', 'nkCall', 'nkGenericCall', 'nkExplicitTypeListCall', TNodeFlags = set of TNodeFlag;
'nkExprEqExpr', 'nkExprColonExpr', 'nkIdentDefs', 'nkInfix', const
'nkPrefix', 'nkPostfix', 'nkPar', 'nkCurly', NodeFlagToStr: array [TNodeFlag] of string = (
'nkBracket', 'nkBracketExpr', 'nkPragmaExpr', 'nkRange', 'nfNone', 'nfBase2', 'nfBase8', 'nfBase16',
'nkDotExpr', 'nkCheckedFieldExpr', 'nkDerefExpr', 'nkIfExpr', 'nfAllConst', 'nfTransf', 'nfSem');
'nkElifExpr', 'nkElseExpr', 'nkLambda', 'nkAccQuoted', type
'nkHeaderQuoted', 'nkTableConstr', 'nkQualified', 'nkHiddenStdConv', TTypeFlag = (
'nkHiddenSubConv', 'nkHiddenCallConv', 'nkConv', 'nkCast', tfVarargs, tfFinal, tfAcyclic, tfEnumHasWholes);
'nkAddr', 'nkHiddenAddr', 'nkHiddenDeref', 'nkObjDownConv', TTypeFlags = set of TTypeFlag;
'nkObjUpConv', 'nkChckRangeF', 'nkChckRange64', 'nkChckRange', const
'nkStringToCString', 'nkCStringToString', 'nkPassAsOpenArray', 'nkAsgn', TypeFlagToStr: array [TTypeFlag] of string = (
'nkDefaultTypeParam', 'nkGenericParams', 'nkFormalParams', 'nkOfInherit', 'tfVarargs', 'tfFinal', 'tfAcyclic', 'tfEnumHasWholes');
'nkModule', 'nkProcDef', 'nkConverterDef', 'nkMacroDef', type
'nkTemplateDef', 'nkIteratorDef', 'nkOfBranch', 'nkElifBranch', TSymKind = (
'nkExceptBranch', 'nkElse', 'nkMacroStmt', 'nkAsmStmt', skUnknownSym, skConditional, skDynLib, skParam,
'nkPragma', 'nkIfStmt', 'nkWhenStmt', 'nkForStmt', skTypeParam, skTemp, skType, skConst,
'nkWhileStmt', 'nkCaseStmt', 'nkVarSection', 'nkConstSection', skVar, skProc, skIterator, skConverter,
'nkConstDef', 'nkTypeSection', 'nkTypeDef', 'nkYieldStmt', skMacro, skTemplate, skField, skEnumField,
'nkTryStmt', 'nkFinally', 'nkRaiseStmt', 'nkReturnStmt', skForVar, skModule, skLabel, skStub);
'nkBreakStmt', 'nkContinueStmt', 'nkBlockStmt', 'nkDiscardStmt', TSymKinds = set of TSymKind;
'nkStmtList', 'nkImportStmt', 'nkFromStmt', 'nkImportAs', const
'nkIncludeStmt', 'nkAccessStmt', 'nkCommentStmt', 'nkStmtListExpr', SymKindToStr: array [TSymKind] of string = (
'nkBlockExpr', 'nkStmtListType', 'nkBlockType', 'nkVm', 'skUnknownSym', 'skConditional', 'skDynLib', 'skParam',
'nkTypeOfExpr', 'nkObjectTy', 'nkTupleTy', 'nkRecList', 'skTypeParam', 'skTemp', 'skType', 'skConst',
'nkRecCase', 'nkRecWhen', 'nkRefTy', 'nkPtrTy', 'skVar', 'skProc', 'skIterator', 'skConverter',
'nkVarTy', 'nkProcTy', 'nkEnumTy', 'nkEnumFieldDef', 'skMacro', 'skTemplate', 'skField', 'skEnumField',
'nkReturnToken'); 'skForVar', 'skModule', 'skLabel', 'skStub');
{[[[end]]]} {[[[end]]]}
type type
@ -219,43 +219,44 @@ type
// if (i+1) % 6 == 0: cog.outl("") // if (i+1) % 6 == 0: cog.outl("")
//cog.outl("m" + magics[-1]) //cog.outl("m" + magics[-1])
//]]] //]]]
mNone, mDefined, mLow, mHigh, mSizeOf, mIs, mNone, mDefined, mLow, mHigh, mSizeOf, mIs,
mSucc, mPred, mInc, mDec, mOrd, mNew, mSucc, mPred, mInc, mDec, mOrd, mNew,
mNewFinalize, mNewSeq, mRegisterFinalizer, mLengthOpenArray, mLengthStr, mLengthArray, mNewFinalize, mNewSeq, mRegisterFinalizer, mLengthOpenArray, mLengthStr, mLengthArray,
mLengthSeq, mIncl, mExcl, mCard, mChr, mGCref, mLengthSeq, mIncl, mExcl, mCard, mChr, mGCref,
mGCunref, mAddI, mSubI, mMulI, mDivI, mModI, mGCunref, mAddI, mSubI, mMulI, mDivI, mModI,
mAddI64, mSubI64, mMulI64, mDivI64, mModI64, mShrI, mAddI64, mSubI64, mMulI64, mDivI64, mModI64, mShrI,
mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, mMinI64, mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, mMinI64,
mMaxI64, mAddF64, mSubF64, mMulF64, mDivF64, mMinF64, mMaxI64, mAddF64, mSubF64, mMulF64, mDivF64, mMinF64,
mMaxF64, mAddU, mSubU, mMulU, mDivU, mModU, mMaxF64, mAddU, mSubU, mMulU, mDivU, mModU,
mAddU64, mSubU64, mMulU64, mDivU64, mModU64, mEqI, mAddU64, mSubU64, mMulU64, mDivU64, mModU64, mEqI,
mLeI, mLtI, mEqI64, mLeI64, mLtI64, mEqF64, mLeI, mLtI, mEqI64, mLeI64, mLtI64, mEqF64,
mLeF64, mLtF64, mLeU, mLtU, mLeU64, mLtU64, mLeF64, mLtF64, mLeU, mLtU, mLeU64, mLtU64,
mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh,
mEqB, mLeB, mLtB, mEqRef, mEqProc, mEqUntracedRef, mEqB, mLeB, mLtB, mEqRef, mEqProc, mEqUntracedRef,
mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI, mUnaryMinusI64, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI, mUnaryMinusI64,
mAbsI, mAbsI64, mNot, mUnaryPlusI, mBitnotI, mUnaryPlusI64, mAbsI, mAbsI64, mNot, mUnaryPlusI, mBitnotI, mUnaryPlusI64,
mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64, mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16,
mToU32, mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mToU32, mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr,
mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr,
mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mEnumToStr, mAnd, mOr, mEqStr, mLeStr, mLtStr,
mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, mSymDiffSet, mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet,
mConStrStr, mConArrArr, mConArrT, mConTArr, mConTT, mSlice, mSymDiffSet, mConStrStr, mConArrArr, mConArrT, mConTArr, mConTT,
mAppendStrCh, mAppendStrStr, mAppendSeqElem, mAppendSeqSeq, mInRange, mInSet, mSlice, mAppendStrCh, mAppendStrStr, mAppendSeqElem, mAppendSeqSeq, mInRange,
mAsgn, mRepr, mExit, mSetLengthStr, mSetLengthSeq, mAssert, mInSet, mAsgn, mRepr, mExit, mSetLengthStr, mSetLengthSeq,
mSwap, mIsNil, mArrToSeq, mArray, mOpenArray, mRange, mAssert, mSwap, mIsNil, mArrToSeq, mArray, mOpenArray,
mSet, mSeq, mInt, mInt8, mInt16, mInt32, mRange, mSet, mSeq, mInt, mInt8, mInt16,
mInt64, mFloat, mFloat32, mFloat64, mBool, mChar, mInt32, mInt64, mFloat, mFloat32, mFloat64, mBool,
mString, mCstring, mPointer, mAnyEnum, mEmptySet, mIntSetBaseType, mChar, mString, mCstring, mPointer, mAnyEnum, mEmptySet,
mNil, mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor, mIntSetBaseType, mNil, mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion,
mNimrodMinor, mNimrodPatch, mCpuEndian, mNaN, mInf, mNegInf, mNimrodMajor, mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU,
mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNaN, mInf, mNegInf, mNLen, mNChild, mNSetChild,
mNKind, mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNAdd, mNAddMultiple, mNDel, mNKind, mNIntVal, mNFloatVal,
mNStrVal, mNSetIntVal, mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal, mNSetFloatVal,
mNSetStrVal, mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNNewNimNode, mNCopyNimNode,
mEqIdent, mNHint, mNWarning, mNError mNCopyNimTree, mStrToIdent, mIdentToStr, mEqIdent, mNHint, mNWarning,
mNError
//[[[end]]] //[[[end]]]
); );
@ -322,7 +323,6 @@ type
locProc, // location is a proc (an address of a procedure) locProc, // location is a proc (an address of a procedure)
locData, // location is a constant locData, // location is a constant
locCall, // location is a call expression locCall, // location is a call expression
locImmediate, // location is an immediate value
locOther // location is something other locOther // location is something other
); );
@ -477,43 +477,44 @@ const // "MagicToStr" array:
// if (i+1) % 6 == 0: cog.outl("") // if (i+1) % 6 == 0: cog.outl("")
//cog.outl("'%s'" % magics[-1]) //cog.outl("'%s'" % magics[-1])
//]]] //]]]
'None', 'Defined', 'Low', 'High', 'SizeOf', 'Is', 'None', 'Defined', 'Low', 'High', 'SizeOf', 'Is',
'Succ', 'Pred', 'Inc', 'Dec', 'Ord', 'New', 'Succ', 'Pred', 'Inc', 'Dec', 'Ord', 'New',
'NewFinalize', 'NewSeq', 'RegisterFinalizer', 'LengthOpenArray', 'LengthStr', 'LengthArray', 'NewFinalize', 'NewSeq', 'RegisterFinalizer', 'LengthOpenArray', 'LengthStr', 'LengthArray',
'LengthSeq', 'Incl', 'Excl', 'Card', 'Chr', 'GCref', 'LengthSeq', 'Incl', 'Excl', 'Card', 'Chr', 'GCref',
'GCunref', 'AddI', 'SubI', 'MulI', 'DivI', 'ModI', 'GCunref', 'AddI', 'SubI', 'MulI', 'DivI', 'ModI',
'AddI64', 'SubI64', 'MulI64', 'DivI64', 'ModI64', 'ShrI', 'AddI64', 'SubI64', 'MulI64', 'DivI64', 'ModI64', 'ShrI',
'ShlI', 'BitandI', 'BitorI', 'BitxorI', 'MinI', 'MaxI', 'ShlI', 'BitandI', 'BitorI', 'BitxorI', 'MinI', 'MaxI',
'ShrI64', 'ShlI64', 'BitandI64', 'BitorI64', 'BitxorI64', 'MinI64', 'ShrI64', 'ShlI64', 'BitandI64', 'BitorI64', 'BitxorI64', 'MinI64',
'MaxI64', 'AddF64', 'SubF64', 'MulF64', 'DivF64', 'MinF64', 'MaxI64', 'AddF64', 'SubF64', 'MulF64', 'DivF64', 'MinF64',
'MaxF64', 'AddU', 'SubU', 'MulU', 'DivU', 'ModU', 'MaxF64', 'AddU', 'SubU', 'MulU', 'DivU', 'ModU',
'AddU64', 'SubU64', 'MulU64', 'DivU64', 'ModU64', 'EqI', 'AddU64', 'SubU64', 'MulU64', 'DivU64', 'ModU64', 'EqI',
'LeI', 'LtI', 'EqI64', 'LeI64', 'LtI64', 'EqF64', 'LeI', 'LtI', 'EqI64', 'LeI64', 'LtI64', 'EqF64',
'LeF64', 'LtF64', 'LeU', 'LtU', 'LeU64', 'LtU64', 'LeF64', 'LtF64', 'LeU', 'LtU', 'LeU64', 'LtU64',
'EqEnum', 'LeEnum', 'LtEnum', 'EqCh', 'LeCh', 'LtCh', 'EqEnum', 'LeEnum', 'LtEnum', 'EqCh', 'LeCh', 'LtCh',
'EqB', 'LeB', 'LtB', 'EqRef', 'EqProc', 'EqUntracedRef', 'EqB', 'LeB', 'LtB', 'EqRef', 'EqProc', 'EqUntracedRef',
'LePtr', 'LtPtr', 'EqCString', 'Xor', 'UnaryMinusI', 'UnaryMinusI64', 'LePtr', 'LtPtr', 'EqCString', 'Xor', 'UnaryMinusI', 'UnaryMinusI64',
'AbsI', 'AbsI64', 'Not', 'UnaryPlusI', 'BitnotI', 'UnaryPlusI64', 'AbsI', 'AbsI64', 'Not', 'UnaryPlusI', 'BitnotI', 'UnaryPlusI64',
'BitnotI64', 'UnaryPlusF64', 'UnaryMinusF64', 'AbsF64', 'Ze8ToI', 'Ze8ToI64', 'BitnotI64', 'UnaryPlusF64', 'UnaryMinusF64', 'AbsF64', 'Ze8ToI', 'Ze8ToI64',
'Ze16ToI', 'Ze16ToI64', 'Ze32ToI64', 'ZeIToI64', 'ToU8', 'ToU16', 'Ze16ToI', 'Ze16ToI64', 'Ze32ToI64', 'ZeIToI64', 'ToU8', 'ToU16',
'ToU32', 'ToFloat', 'ToBiggestFloat', 'ToInt', 'ToBiggestInt', 'CharToStr', 'ToU32', 'ToFloat', 'ToBiggestFloat', 'ToInt', 'ToBiggestInt', 'CharToStr',
'BoolToStr', 'IntToStr', 'Int64ToStr', 'FloatToStr', 'CStrToStr', 'StrToStr', 'BoolToStr', 'IntToStr', 'Int64ToStr', 'FloatToStr', 'CStrToStr', 'StrToStr',
'And', 'Or', 'EqStr', 'LeStr', 'LtStr', 'EqSet', 'EnumToStr', 'And', 'Or', 'EqStr', 'LeStr', 'LtStr',
'LeSet', 'LtSet', 'MulSet', 'PlusSet', 'MinusSet', 'SymDiffSet', 'EqSet', 'LeSet', 'LtSet', 'MulSet', 'PlusSet', 'MinusSet',
'ConStrStr', 'ConArrArr', 'ConArrT', 'ConTArr', 'ConTT', 'Slice', 'SymDiffSet', 'ConStrStr', 'ConArrArr', 'ConArrT', 'ConTArr', 'ConTT',
'AppendStrCh', 'AppendStrStr', 'AppendSeqElem', 'AppendSeqSeq', 'InRange', 'InSet', 'Slice', 'AppendStrCh', 'AppendStrStr', 'AppendSeqElem', 'AppendSeqSeq', 'InRange',
'Asgn', 'Repr', 'Exit', 'SetLengthStr', 'SetLengthSeq', 'Assert', 'InSet', 'Asgn', 'Repr', 'Exit', 'SetLengthStr', 'SetLengthSeq',
'Swap', 'IsNil', 'ArrToSeq', 'Array', 'OpenArray', 'Range', 'Assert', 'Swap', 'IsNil', 'ArrToSeq', 'Array', 'OpenArray',
'Set', 'Seq', 'Int', 'Int8', 'Int16', 'Int32', 'Range', 'Set', 'Seq', 'Int', 'Int8', 'Int16',
'Int64', 'Float', 'Float32', 'Float64', 'Bool', 'Char', 'Int32', 'Int64', 'Float', 'Float32', 'Float64', 'Bool',
'String', 'Cstring', 'Pointer', 'AnyEnum', 'EmptySet', 'IntSetBaseType', 'Char', 'String', 'Cstring', 'Pointer', 'AnyEnum', 'EmptySet',
'Nil', 'IsMainModule', 'CompileDate', 'CompileTime', 'NimrodVersion', 'NimrodMajor', 'IntSetBaseType', 'Nil', 'IsMainModule', 'CompileDate', 'CompileTime', 'NimrodVersion',
'NimrodMinor', 'NimrodPatch', 'CpuEndian', 'NaN', 'Inf', 'NegInf', 'NimrodMajor', 'NimrodMinor', 'NimrodPatch', 'CpuEndian', 'HostOS', 'HostCPU',
'NLen', 'NChild', 'NSetChild', 'NAdd', 'NAddMultiple', 'NDel', 'NaN', 'Inf', 'NegInf', 'NLen', 'NChild', 'NSetChild',
'NKind', 'NIntVal', 'NFloatVal', 'NSymbol', 'NIdent', 'NGetType', 'NAdd', 'NAddMultiple', 'NDel', 'NKind', 'NIntVal', 'NFloatVal',
'NStrVal', 'NSetIntVal', 'NSetFloatVal', 'NSetSymbol', 'NSetIdent', 'NSetType', 'NSymbol', 'NIdent', 'NGetType', 'NStrVal', 'NSetIntVal', 'NSetFloatVal',
'NSetStrVal', 'NNewNimNode', 'NCopyNimNode', 'NCopyNimTree', 'StrToIdent', 'IdentToStr', 'NSetSymbol', 'NSetIdent', 'NSetType', 'NSetStrVal', 'NNewNimNode', 'NCopyNimNode',
'EqIdent', 'NHint', 'NWarning', 'NError' 'NCopyNimTree', 'StrToIdent', 'IdentToStr', 'EqIdent', 'NHint', 'NWarning',
'NError'
//[[[end]]] //[[[end]]]
); );
@ -1342,13 +1343,13 @@ end;
function IntSetContains(const s: TIntSet; key: int): bool; function IntSetContains(const s: TIntSet; key: int): bool;
var var
u: int; u: TBitScalar;
t: PTrunk; t: PTrunk;
begin begin
t := IntSetGet(s, key shr TrunkShift); t := IntSetGet(s, shru(key, TrunkShift));
if t <> nil then begin if t <> nil then begin
u := key and TrunkMask; u := key and TrunkMask;
result := (t.bits[u shr IntShift] and (1 shl (u and IntMask))) <> 0 result := (t.bits[shru(u, IntShift)] and shlu(1, u and IntMask)) <> 0
end end
else else
result := false result := false
@ -1356,27 +1357,27 @@ end;
procedure IntSetIncl(var s: TIntSet; key: int); procedure IntSetIncl(var s: TIntSet; key: int);
var var
u: int; u: TBitScalar;
t: PTrunk; t: PTrunk;
begin begin
t := IntSetPut(s, key shr TrunkShift); t := IntSetPut(s, shru(key, TrunkShift));
u := key and TrunkMask; u := key and TrunkMask;
t.bits[u shr IntShift] := t.bits[u shr IntShift] t.bits[shru(u, IntShift)] := t.bits[shru(u, IntShift)]
or (1 shl (u and IntMask)); or shlu(1, u and IntMask);
end; end;
function IntSetContainsOrIncl(var s: TIntSet; key: int): bool; function IntSetContainsOrIncl(var s: TIntSet; key: int): bool;
var var
u: int; u: TBitScalar;
t: PTrunk; t: PTrunk;
begin begin
t := IntSetGet(s, key shr TrunkShift); t := IntSetGet(s, shru(key, TrunkShift));
if t <> nil then begin if t <> nil then begin
u := key and TrunkMask; u := key and TrunkMask;
result := (t.bits[u shr IntShift] and (1 shl (u and IntMask))) <> 0; result := (t.bits[shru(u, IntShift)] and shlu(1, u and IntMask)) <> 0;
if not result then if not result then
t.bits[u shr IntShift] := t.bits[u shr IntShift] t.bits[shru(u, IntShift)] := t.bits[shru(u, IntShift)]
or (1 shl (u and IntMask)); or shlu(1, u and IntMask);
end end
else begin else begin
IntSetIncl(s, key); IntSetIncl(s, key);

View file

@ -450,29 +450,27 @@ begin
else begin else begin
istr := spaces(indent+2); istr := spaces(indent+2);
result := ropef('{$n$1"kind": $2', result := ropef('{$n$1"kind": $2',
[istr, makeYamlString(nodeKindToStr[n.kind])]); [istr, makeYamlString(nodeKindToStr[n.kind])]);
if maxRecDepth <> 0 then begin if maxRecDepth <> 0 then begin
appf(result, ',$n$1"info": $2', appf(result, ',$n$1"info": $2',
[istr, lineInfoToStr(n.info)]); [istr, lineInfoToStr(n.info)]);
case n.kind of case n.kind of
nkCharLit..nkInt64Lit: nkCharLit..nkInt64Lit:
appf(result, '$n$1"intVal": $2', [istr, toRope(n.intVal)]); appf(result, ',$n$1"intVal": $2', [istr, toRope(n.intVal)]);
nkFloatLit, nkFloat32Lit, nkFloat64Lit: nkFloatLit, nkFloat32Lit, nkFloat64Lit:
appf(result, '$n$1"floatVal": $2', appf(result, ',$n$1"floatVal": $2', [istr, toRopeF(n.floatVal)]);
[istr, toRopeF(n.floatVal)]);
nkStrLit..nkTripleStrLit: nkStrLit..nkTripleStrLit:
appf(result, '$n$1"strVal": $2', appf(result, ',$n$1"strVal": $2', [istr, makeYamlString(n.strVal)]);
[istr, makeYamlString(n.strVal)]);
nkSym: nkSym:
appf(result, ',$n$1"sym": $2', appf(result, ',$n$1"sym": $2',
[istr, symToYamlAux(n.sym, marker, indent+2, maxRecDepth)]); [istr, symToYamlAux(n.sym, marker, indent+2, maxRecDepth)]);
nkIdent: begin nkIdent: begin
if n.ident <> nil then if n.ident <> nil then
appf(result, '$n$1"ident": $2', appf(result, ',$n$1"ident": $2',
[istr, makeYamlString(n.ident.s)]) [istr, makeYamlString(n.ident.s)])
else else
appf(result, '$n$1"ident": null', [istr]) appf(result, ',$n$1"ident": null', [istr])
end end
else begin else begin
if sonsLen(n) > 0 then begin if sonsLen(n) > 0 then begin
@ -552,12 +550,12 @@ begin
if maxRecDepth <> 0 then begin if maxRecDepth <> 0 then begin
case n.kind of case n.kind of
nkCharLit..nkInt64Lit: nkCharLit..nkInt64Lit:
appf(result, '$n$1"intVal": $2', [istr, toRope(n.intVal)]); appf(result, ',$n$1"intVal": $2', [istr, toRope(n.intVal)]);
nkFloatLit, nkFloat32Lit, nkFloat64Lit: nkFloatLit, nkFloat32Lit, nkFloat64Lit:
appf(result, '$n$1"floatVal": $2', appf(result, ',$n$1"floatVal": $2',
[istr, toRopeF(n.floatVal)]); [istr, toRopeF(n.floatVal)]);
nkStrLit..nkTripleStrLit: nkStrLit..nkTripleStrLit:
appf(result, '$n$1"strVal": $2', appf(result, ',$n$1"strVal": $2',
[istr, makeYamlString(n.strVal)]); [istr, makeYamlString(n.strVal)]);
nkSym: nkSym:
appf(result, ',$n$1"sym": $2_$3', appf(result, ',$n$1"sym": $2_$3',
@ -565,10 +563,10 @@ begin
nkIdent: begin nkIdent: begin
if n.ident <> nil then if n.ident <> nil then
appf(result, '$n$1"ident": $2', appf(result, ',$n$1"ident": $2',
[istr, makeYamlString(n.ident.s)]) [istr, makeYamlString(n.ident.s)])
else else
appf(result, '$n$1"ident": null', [istr]) appf(result, ',$n$1"ident": null', [istr])
end end
else begin else begin
if sonsLen(n) > 0 then begin if sonsLen(n) > 0 then begin

View file

@ -126,7 +126,7 @@ var
j: int; j: int;
begin begin
result := 0; result := 0;
if CPU[hostCPU].endian = CPU[targetCPU].endian then begin if CPU[platform.hostCPU].endian = CPU[targetCPU].endian then begin
for j := 0 to size-1 do for j := 0 to size-1 do
if j < length(s) then if j < length(s) then
result := result or shlu(Ze64(s[j]), j * 8) result := result or shlu(Ze64(s[j]), j * 8)
@ -773,6 +773,34 @@ begin
putIntoDest(p, d, field.typ, r); putIntoDest(p, d, field.typ, r);
end; end;
procedure genTupleElem(p: BProc; e: PNode; var d: TLoc);
var
a: TLoc;
field: PSym;
ty: PType;
r: PRope;
i: int;
begin
initLocExpr(p, e.sons[0], a);
if d.k = locNone then d.s := a.s;
{@discard} getTypeDesc(p.module, a.t); // fill the record's fields.loc
ty := getUniqueType(a.t);
r := rdLoc(a);
case e.sons[1].kind of
nkIntLit..nkInt64Lit: i := int(e.sons[1].intVal);
else internalError(e.info, 'genTupleElem');
end;
if ty.n <> nil then begin
field := ty.n.sons[i].sym;
if field = nil then InternalError(e.info, 'genTupleElem');
if field.loc.r = nil then InternalError(e.info, 'genTupleElem');
appf(r, '.$1', [field.loc.r]);
end
else
appf(r, '.Field$1', [toRope(i)]);
putIntoDest(p, d, ty.sons[i], r);
end;
procedure genInExprAux(p: BProc; e: PNode; var a, b, d: TLoc); forward; procedure genInExprAux(p: BProc; e: PNode; var a, b, d: TLoc); forward;
procedure genCheckedRecordField(p: BProc; e: PNode; var d: TLoc); procedure genCheckedRecordField(p: BProc; e: PNode; var d: TLoc);
@ -848,10 +876,11 @@ begin
first := intLiteral(firstOrd(ty)); first := intLiteral(firstOrd(ty));
// emit range check: // emit range check:
if (optBoundsCheck in p.options) then begin if (optBoundsCheck in p.options) then begin
if b.k <> locImmediate then begin // semantic pass has already checked: if not isConstExpr(e.sons[1]) then begin
// semantic pass has already checked for const index expressions
useMagic(p.module, 'raiseIndexError'); useMagic(p.module, 'raiseIndexError');
if firstOrd(ty) = 0 then begin if firstOrd(ty) = 0 then begin
if lastOrd(b.t) > lastOrd(ty) then if (firstOrd(b.t) < firstOrd(ty)) or (lastOrd(b.t) > lastOrd(ty)) then
appf(p.s[cpsStmts], appf(p.s[cpsStmts],
'if ((NU)($1) > (NU)($2)) raiseIndexError();$n', 'if ((NU)($1) > (NU)($2)) raiseIndexError();$n',
[rdCharLoc(b), intLiteral(lastOrd(ty))]) [rdCharLoc(b), intLiteral(lastOrd(ty))])
@ -1289,14 +1318,22 @@ var
a, b, f: TLoc; a, b, f: TLoc;
refType, bt: PType; refType, bt: PType;
ti: PRope; ti: PRope;
oldModule: BModule;
begin begin
useMagic(p.module, 'newObj'); useMagic(p.module, 'newObj');
refType := skipVarGenericRange(e.sons[1].typ); refType := skipVarGenericRange(e.sons[1].typ);
InitLocExpr(p, e.sons[1], a); InitLocExpr(p, e.sons[1], a);
// This is a little hack:
oldModule := p.module;
p.module := gmti;
InitLocExpr(p, e.sons[2], f); InitLocExpr(p, e.sons[2], f);
p.module := oldModule;
initLoc(b, locExpr, a.t, OnHeap); initLoc(b, locExpr, a.t, OnHeap);
ti := genTypeInfo(p.module, refType); ti := genTypeInfo(p.module, refType);
appf(p.module.s[cfsTypeInit3], '$1->finalizer = (void*)$2;$n', [
appf(gmti.s[cfsTypeInit3], '$1->finalizer = (void*)$2;$n', [
ti, rdLoc(f)]); ti, rdLoc(f)]);
b.r := ropef('($1) newObj($2, sizeof($3))', b.r := ropef('($1) newObj($2, sizeof($3))',
[getTypeDesc(p.module, refType), ti, [getTypeDesc(p.module, refType), ti,
@ -1331,7 +1368,7 @@ begin
UseMagic(p.module, 'reprChar'); UseMagic(p.module, 'reprChar');
putIntoDest(p, d, e.typ, ropef('reprChar($1)', [rdLoc(a)])) putIntoDest(p, d, e.typ, ropef('reprChar($1)', [rdLoc(a)]))
end; end;
tyEnum: begin tyEnum, tyAnyEnum: begin
UseMagic(p.module, 'reprEnum'); UseMagic(p.module, 'reprEnum');
putIntoDest(p, d, e.typ, putIntoDest(p, d, e.typ,
ropef('reprEnum($1, $2)', [rdLoc(a), genTypeInfo(p.module, t)])) ropef('reprEnum($1, $2)', [rdLoc(a), genTypeInfo(p.module, t)]))
@ -1853,6 +1890,7 @@ begin
mFloatToStr: genDollar(p, e, d, 'nimFloatToStr', 'nimFloatToStr($1)'); mFloatToStr: genDollar(p, e, d, 'nimFloatToStr', 'nimFloatToStr($1)');
mCStrToStr: genDollar(p, e, d, 'cstrToNimstr', 'cstrToNimstr($1)'); mCStrToStr: genDollar(p, e, d, 'cstrToNimstr', 'cstrToNimstr($1)');
mStrToStr: expr(p, e.sons[1], d); mStrToStr: expr(p, e.sons[1], d);
mEnumToStr: genRepr(p, e, d);
mAssert: begin mAssert: begin
if (optAssert in p.Options) then begin if (optAssert in p.Options) then begin
useMagic(p.module, 'internalAssert'); useMagic(p.module, 'internalAssert');
@ -1996,23 +2034,31 @@ var
it: PNode; it: PNode;
t: PType; t: PType;
begin begin
// the code generator assumes that there are only tuple constructors with
// field names!
if not handleConstExpr(p, n, d) then begin if not handleConstExpr(p, n, d) then begin
t := getUniqueType(n.typ); t := getUniqueType(n.typ);
{@discard} getTypeDesc(p.module, t); // so that any fields are initialized {@discard} getTypeDesc(p.module, t); // so that any fields are initialized
if d.k = locNone then getTemp(p, t, d); if d.k = locNone then getTemp(p, t, d);
if t.n = nil then InternalError(n.info, 'genTupleConstr');
if sonsLen(t.n) <> sonsLen(n) then
InternalError(n.info, 'genTupleConstr');
for i := 0 to sonsLen(n)-1 do begin for i := 0 to sonsLen(n)-1 do begin
it := n.sons[i]; it := n.sons[i];
if it.kind <> nkExprColonExpr then InternalError(n.info, 'genTupleConstr'); if it.kind = nkExprColonExpr then begin
initLoc(rec, locExpr, it.sons[1].typ, d.s); initLoc(rec, locExpr, it.sons[1].typ, d.s);
if (t.n.sons[i].kind <> nkSym) then if (t.n.sons[i].kind <> nkSym) then
InternalError(n.info, 'genTupleConstr'); InternalError(n.info, 'genTupleConstr');
rec.r := ropef('$1.$2', [rdLoc(d), mangleRecFieldName(t.n.sons[i].sym, t)]); rec.r := ropef('$1.$2', [rdLoc(d), mangleRecFieldName(t.n.sons[i].sym, t)]);
expr(p, it.sons[1], rec); expr(p, it.sons[1], rec);
end
else if t.n = nil then begin
initLoc(rec, locExpr, it.typ, d.s);
rec.r := ropef('$1.Field$2', [rdLoc(d), toRope(i)]);
expr(p, it, rec);
end
else begin
initLoc(rec, locExpr, it.typ, d.s);
if (t.n.sons[i].kind <> nkSym) then
InternalError(n.info, 'genTupleConstr: 2');
rec.r := ropef('$1.$2', [rdLoc(d), mangleRecFieldName(t.n.sons[i].sym, t)]);
expr(p, it, rec);
end
end end
end end
end; end;
@ -2123,11 +2169,10 @@ begin
sym := e.sym; sym := e.sym;
case sym.Kind of case sym.Kind of
skProc, skConverter: begin skProc, skConverter: begin
// generate prototype if not already declared in this translation unit genProc(p.module, sym);
genProcPrototype(p.module, sym);
if ((sym.loc.r = nil) or (sym.loc.t = nil)) then if ((sym.loc.r = nil) or (sym.loc.t = nil)) then
InternalError(e.info, 'expr: proc not init ' + sym.name.s); InternalError(e.info, 'expr: proc not init ' + sym.name.s);
putLocIntoDest(p, d, sym.loc) putLocIntoDest(p, d, sym.loc);
end; end;
skConst: skConst:
if isSimpleConst(sym.typ) then if isSimpleConst(sym.typ) then
@ -2160,8 +2205,6 @@ begin
nkStrLit..nkTripleStrLit, nkIntLit..nkInt64Lit, nkStrLit..nkTripleStrLit, nkIntLit..nkInt64Lit,
nkFloatLit..nkFloat64Lit, nkNilLit, nkCharLit: begin nkFloatLit..nkFloat64Lit, nkNilLit, nkCharLit: begin
putIntoDest(p, d, e.typ, genLiteral(p, e)); putIntoDest(p, d, e.typ, genLiteral(p, e));
if d.k in [locNone, locExpr] then
d.k := locImmediate // for removal of index checks
end; end;
nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkPostfix, nkCommand: begin nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkPostfix, nkCommand: begin
if (e.sons[0].kind = nkSym) and if (e.sons[0].kind = nkSym) and
@ -2189,6 +2232,7 @@ begin
tyOpenArray: genOpenArrayElem(p, e, d); tyOpenArray: genOpenArrayElem(p, e, d);
tySequence, tyString: genSeqElem(p, e, d); tySequence, tyString: genSeqElem(p, e, d);
tyCString: genCStringElem(p, e, d); tyCString: genCStringElem(p, e, d);
tyTuple: genTupleElem(p, e, d);
else InternalError(e.info, else InternalError(e.info,
'expr(nkBracketExpr, ' + typeKindToStr[ty.kind] + ')'); 'expr(nkBracketExpr, ' + typeKindToStr[ty.kind] + ')');
end end

View file

@ -801,9 +801,16 @@ begin
assert(key.kind = nkIdent); assert(key.kind = nkIdent);
case whichKeyword(key.ident) of case whichKeyword(key.ident) of
wBreakpoint: genBreakPoint(p, it); wBreakpoint: genBreakPoint(p, it);
wDeadCodeElim: begin
if not (optDeadCodeElim in gGlobalOptions) then begin
// we need to keep track of ``deadCodeElim`` pragma
if (sfDeadCodeElim in p.module.module.flags) then
addPendingModule(p.module)
end
end
else begin end else begin end
end end
end end;
end; end;
procedure genAsgn(p: BProc; e: PNode); procedure genAsgn(p: BProc; e: PNode);
@ -816,6 +823,17 @@ begin
expr(p, e.sons[1], a); expr(p, e.sons[1], a);
end; end;
procedure genFastAsgn(p: BProc; e: PNode);
var
a: TLoc;
begin
genLineDir(p, e); // BUGFIX
InitLocExpr(p, e.sons[0], a);
include(a.flags, lfNoDeepCopy);
assert(a.t <> nil);
expr(p, e.sons[1], a);
end;
procedure genStmts(p: BProc; t: PNode); procedure genStmts(p: BProc; t: PNode);
var var
a: TLoc; a: TLoc;
@ -844,6 +862,7 @@ begin
initLocExpr(p, t, a); initLocExpr(p, t, a);
end; end;
nkAsgn: genAsgn(p, t); nkAsgn: genAsgn(p, t);
nkFastAsgn: genFastAsgn(p, t);
nkDiscardStmt: begin nkDiscardStmt: begin
genLineDir(p, t); genLineDir(p, t);
initLocExpr(p, t.sons[0], a); initLocExpr(p, t.sons[0], a);
@ -865,17 +884,13 @@ begin
nkProcDef, nkConverterDef: begin nkProcDef, nkConverterDef: begin
if (t.sons[genericParamsPos] = nil) then begin if (t.sons[genericParamsPos] = nil) then begin
prc := t.sons[namePos].sym; prc := t.sons[namePos].sym;
if (t.sons[codePos] <> nil) if not (optDeadCodeElim in gGlobalOptions) and
or (lfDynamicLib in prc.loc.flags) then begin // BUGFIX not (sfDeadCodeElim in getModule(prc).flags)
if IntSetContainsOrIncl(p.module.debugDeclared, prc.id) then begin or ([sfExportc, sfCompilerProc] * prc.flags = [sfExportc]) then begin
internalError(t.info, 'genStmts(): ' + toString(prc.id)); if (t.sons[codePos] <> nil) or (lfDynamicLib in prc.loc.flags) then begin
// XXX: remove this check! genProc(p.module, prc)
end; end
//if IntSetContains(p.module.debugDeclared, 2642) then
// InternalError(t.info, 'this sucks ' + toString(prc.id));
genProc(p.module, prc)
end end
//else if sfCompilerProc in prc.flags then genProcPrototype(prc);
end end
end; end;
else else

View file

@ -8,7 +8,7 @@
// //
//var //var
// newDummyVar: int; // just to check the rodgen mechanism // newDummyVar: int; // just to check the symbol file mechanism
// ------------------------- Name Mangling -------------------------------- // ------------------------- Name Mangling --------------------------------
@ -461,6 +461,22 @@ begin
app(result, '};' + tnl); app(result, '};' + tnl);
end; end;
function getTupleDesc(m: BModule; typ: PType; name: PRope;
var check: TIntSet): PRope;
var
desc: PRope;
i: int;
begin
result := ropef('struct $1 {$n', [name]);
desc := nil;
for i := 0 to sonsLen(typ)-1 do
appf(desc, '$1 Field$2;$n',
[getTypeDescAux(m, typ.sons[i], check), toRope(i)]);
if (desc = nil) then app(result, 'char dummy;' + tnl)
else app(result, desc);
app(result, '};' + tnl);
end;
procedure pushType(m: BModule; typ: PType); procedure pushType(m: BModule; typ: PType);
var var
L: int; L: int;
@ -571,13 +587,15 @@ begin
if result = nil then begin if result = nil then begin
result := getTypeName(t); result := getTypeName(t);
if not isImportedType(t) then if not isImportedType(t) then
appf(m.s[cfsForwardTypes], appf(m.s[cfsForwardTypes], getForwardStructFormat(), [result]);
getForwardStructFormat(), [result]);
IdTablePut(m.forwTypeCache, t, result) IdTablePut(m.forwTypeCache, t, result)
end; end;
IdTablePut(m.typeCache, t, result); IdTablePut(m.typeCache, t, result);
// always call for sideeffects: // always call for sideeffects:
recdesc := getRecordDesc(m, t, result, check); if t.n <> nil then
recdesc := getRecordDesc(m, t, result, check)
else
recdesc := getTupleDesc(m, t, result, check);
if not isImportedType(t) then app(m.s[cfsTypes], recdesc); if not isImportedType(t) then app(m.s[cfsTypes], recdesc);
end; end;
tySet: begin tySet: begin
@ -735,9 +753,11 @@ begin
assert(n.sons[0].kind = nkSym); assert(n.sons[0].kind = nkSym);
field := n.sons[0].sym; field := n.sons[0].sym;
tmp := getTempName(); tmp := getTempName();
useMagic(m, 'chckNil');
appf(m.s[cfsTypeInit3], '$1.kind = 3;$n' + appf(m.s[cfsTypeInit3], '$1.kind = 3;$n' +
'$1.offset = offsetof($2, $3);$n' + '$1.offset = offsetof($2, $3);$n' +
'$1.typ = $4;$n' + '$1.typ = $4;$n' +
'chckNil($1.typ);$n' +
'$1.name = $5;$n' + '$1.name = $5;$n' +
'$1.sons = &$6[0];$n' + '$1.sons = &$6[0];$n' +
'$1.len = $7;$n', '$1.len = $7;$n',
@ -746,7 +766,7 @@ begin
makeCString(field.name.s), tmp, makeCString(field.name.s), tmp,
toRope(lengthOrd(field.typ))]); toRope(lengthOrd(field.typ))]);
appf(m.s[cfsTypeInit1], 'static TNimNode* $1[$2];$n', appf(m.s[cfsTypeInit1], 'static TNimNode* $1[$2];$n',
[tmp, toRope(lengthOrd(field.typ)+1)]); [tmp, toRope(lengthOrd(field.typ)+1)]);
for i := 1 to len-1 do begin for i := 1 to len-1 do begin
b := n.sons[i]; // branch b := n.sons[i]; // branch
tmp2 := getNimNode(m); tmp2 := getNimNode(m);
@ -761,18 +781,18 @@ begin
y := int(getOrdValue(b.sons[j].sons[1])); y := int(getOrdValue(b.sons[j].sons[1]));
while x <= y do begin while x <= y do begin
appf(m.s[cfsTypeInit3], '$1[$2] = &$3;$n', appf(m.s[cfsTypeInit3], '$1[$2] = &$3;$n',
[tmp, toRope(x), tmp2]); [tmp, toRope(x), tmp2]);
inc(x); inc(x);
end; end;
end end
else else
appf(m.s[cfsTypeInit3], '$1[$2] = &$3;$n', appf(m.s[cfsTypeInit3], '$1[$2] = &$3;$n',
[tmp, toRope(getOrdValue(b.sons[j])), tmp2]) [tmp, toRope(getOrdValue(b.sons[j])), tmp2])
end end
end; end;
nkElse: begin nkElse: begin
appf(m.s[cfsTypeInit3], '$1[$2] = &$3;$n', appf(m.s[cfsTypeInit3], '$1[$2] = &$3;$n',
[tmp, toRope(lengthOrd(field.typ)), tmp2]); [tmp, toRope(lengthOrd(field.typ)), tmp2]);
end end
else else
internalError(n.info, 'genObjectFields(nkRecCase)'); internalError(n.info, 'genObjectFields(nkRecCase)');
@ -781,9 +801,11 @@ begin
end; end;
nkSym: begin nkSym: begin
field := n.sym; field := n.sym;
useMagic(m, 'chckNil');
appf(m.s[cfsTypeInit3], '$1.kind = 1;$n' + appf(m.s[cfsTypeInit3], '$1.kind = 1;$n' +
'$1.offset = offsetof($2, $3);$n' + '$1.offset = offsetof($2, $3);$n' +
'$1.typ = $4;$n' + '$1.typ = $4;$n' +
'chckNil($1.typ);$n' +
'$1.name = $5;$n', '$1.name = $5;$n',
[expr, getTypeDesc(m, typ), field.loc.r, [expr, getTypeDesc(m, typ), field.loc.r,
genTypeInfo(m, field.typ), genTypeInfo(m, field.typ),
@ -804,6 +826,41 @@ begin
appf(m.s[cfsTypeInit3], '$1->node = &$2;$n', [name, tmp]); appf(m.s[cfsTypeInit3], '$1->node = &$2;$n', [name, tmp]);
end; end;
procedure genTupleInfo(m: BModule; typ: PType; name: PRope);
var
tmp, expr, tmp2: PRope;
i, len: int;
a: PType;
begin
genTypeInfoAuxBase(m, typ, name, toRope('0'+''));
expr := getNimNode(m);
len := sonsLen(typ);
if len > 0 then begin
tmp := getTempName();
appf(m.s[cfsTypeInit1], 'static TNimNode* $1[$2];$n', [tmp, toRope(len)]);
for i := 0 to len-1 do begin
a := typ.sons[i];
tmp2 := getNimNode(m);
appf(m.s[cfsTypeInit3], '$1[$2] = &$3;$n', [tmp, toRope(i), tmp2]);
useMagic(m, 'chckNil');
appf(m.s[cfsTypeInit3], '$1.kind = 1;$n' +
'$1.offset = offsetof($2, Field$3);$n' +
'$1.typ = $4;$n' +
'chckNil($1.typ);$n' +
'$1.name = "Field$3";$n',
[tmp2, getTypeDesc(m, typ), toRope(i),
genTypeInfo(m, a)]);
end;
appf(m.s[cfsTypeInit3],
'$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n', [
expr, toRope(len), tmp]);
end
else
appf(m.s[cfsTypeInit3],
'$1.len = $2; $1.kind = 2;$n', [expr, toRope(len)]);
appf(m.s[cfsTypeInit3], '$1->node = &$2;$n', [name, tmp]);
end;
procedure genEnumInfo(m: BModule; typ: PType; name: PRope); procedure genEnumInfo(m: BModule; typ: PType; name: PRope);
var var
nodePtrs, elemNode, enumNames, enumArray, counter, specialCases: PRope; nodePtrs, elemNode, enumNames, enumArray, counter, specialCases: PRope;
@ -817,7 +874,8 @@ begin
genTypeInfoAux(m, typ, name); genTypeInfoAux(m, typ, name);
nodePtrs := getTempName(); nodePtrs := getTempName();
len := sonsLen(typ.n); len := sonsLen(typ.n);
appf(m.s[cfsTypeInit1], 'static TNimNode* $1[$2];$n', [nodePtrs, toRope(len)]); appf(m.s[cfsTypeInit1], 'static TNimNode* $1[$2];$n',
[nodePtrs, toRope(len)]);
enumNames := nil; enumNames := nil;
specialCases := nil; specialCases := nil;
firstNimNode := m.typeNodes; firstNimNode := m.typeNodes;
@ -879,83 +937,79 @@ function genTypeInfo(m: BModule; typ: PType): PRope;
var var
t: PType; t: PType;
id: int; id: int;
dataGen: bool; dataGenerated: bool;
begin begin
t := getUniqueType(typ); t := getUniqueType(typ);
id := IiTableGet(gToTypeInfoId, t.id); id := IiTableGet(gToTypeInfoId, t.id);
if id = invalidKey then begin if id = invalidKey then begin
dataGen := false; dataGenerated := false;
case t.kind of id := t.id; // getID();
tyEnum, tyBool: begin
id := t.id;
dataGen := true
end;
tyObject: begin
if isPureObject(t) then
id := getID()
else begin
id := t.id;
dataGen := true
end
end
else
id := getID();
end;
IiTablePut(gToTypeInfoId, t.id, id); IiTablePut(gToTypeInfoId, t.id, id);
end end
else else
dataGen := true; dataGenerated := true;
result := ropef('NTI$1', [toRope(id)]); result := ropef('NTI$1', [toRope(id)]);
if not IntSetContainsOrIncl(m.typeInfoMarker, t.id) then begin if not IntSetContainsOrIncl(m.typeInfoMarker, id) then begin
// declare type information structures: // declare type information structures:
useMagic(m, 'TNimType'); useMagic(m, 'TNimType');
useMagic(m, 'TNimNode'); useMagic(m, 'TNimNode');
if dataGen then appf(m.s[cfsVars], 'extern TNimType* $1; /* $2 */$n',
appf(m.s[cfsVars], 'extern TNimType* $1; /* $2 */$n', [result, toRope(typeToString(t))]);
[result, toRope(typeToString(t))]);
end; end;
if dataGen then exit; if dataGenerated then exit;
case t.kind of case t.kind of
tyPointer, tyProc, tyBool, tyChar, tyCString, tyString, tyPointer, tyProc, tyBool, tyChar, tyCString, tyString,
tyInt..tyFloat128, tyVar: tyInt..tyFloat128, tyVar:
genTypeInfoAuxBase(m, t, result, toRope('0'+'')); genTypeInfoAuxBase(gmti, t, result, toRope('0'+''));
tyRef, tyPtr, tySequence, tyRange: genTypeInfoAux(m, t, result); tyRef, tyPtr, tySequence, tyRange: genTypeInfoAux(gmti, t, result);
tyArrayConstr, tyArray: genArrayInfo(m, t, result); tyArrayConstr, tyArray: genArrayInfo(gmti, t, result);
tySet: genSetInfo(m, t, result); tySet: genSetInfo(gmti, t, result);
tyEnum: genEnumInfo(m, t, result); tyEnum: genEnumInfo(gmti, t, result);
tyObject, tyTuple: genObjectInfo(m, t, result); tyObject: genObjectInfo(gmti, t, result);
tyTuple: begin
if t.n <> nil then genObjectInfo(gmti, t, result)
else genTupleInfo(gmti, t, result);
end;
else InternalError('genTypeInfo(' + typekindToStr[t.kind] + ')'); else InternalError('genTypeInfo(' + typekindToStr[t.kind] + ')');
end end
end; end;
procedure genTypeSection(m: BModule; n: PNode);
begin
end;
(*
procedure genTypeSection(m: BModule; n: PNode); procedure genTypeSection(m: BModule; n: PNode);
var var
i: int; i: int;
a: PNode; a: PNode;
t: PType; t: PType;
begin begin
for i := 0 to sonsLen(n)-1 do begin if not (optDeadCodeElim in gGlobalOptions) then begin
a := n.sons[i]; for i := 0 to sonsLen(n)-1 do begin
if a.kind = nkCommentStmt then continue; a := n.sons[i];
if (a.sons[0].kind <> nkSym) then InternalError(a.info, 'genTypeSection'); if a.kind = nkCommentStmt then continue;
t := a.sons[0].sym.typ; if (a.sons[0].kind <> nkSym) then InternalError(a.info, 'genTypeSection');
if (a.sons[2] = nil) t := a.sons[0].sym.typ;
or not (a.sons[2].kind in [nkSym, nkIdent, nkAccQuoted]) then if (a.sons[2] = nil)
if t <> nil then or not (a.sons[2].kind in [nkSym, nkIdent, nkAccQuoted]) then
case t.kind of if t <> nil then
tyEnum, tyBool: begin case t.kind of
useMagic(m, 'TNimType'); tyEnum, tyBool: begin
useMagic(m, 'TNimNode');
genEnumInfo(m, t, ropef('NTI$1', [toRope(t.id)]));
end;
tyObject: begin
if not isPureObject(t) then begin
useMagic(m, 'TNimType'); useMagic(m, 'TNimType');
useMagic(m, 'TNimNode'); useMagic(m, 'TNimNode');
genObjectInfo(m, t, ropef('NTI$1', [toRope(t.id)])); genEnumInfo(m, t, ropef('NTI$1', [toRope(t.id)]));
end;
tyObject: begin
if not isPureObject(t) then begin
useMagic(m, 'TNimType');
useMagic(m, 'TNimNode');
genObjectInfo(m, t, ropef('NTI$1', [toRope(t.id)]));
end
end end
else begin end
end end
else begin end end
end
end end
end; end;
*)

View file

@ -27,16 +27,48 @@ function GetUniqueType(key: PType): PType;
implementation implementation
var var
gTypeTable: TIdTable; gTypeTable: array [TTypeKind] of TIdTable;
procedure initTypeTables();
var
i: TTypeKind;
begin
for i := low(TTypeKind) to high(TTypeKind) do
InitIdTable(gTypeTable[i]);
end;
function GetUniqueType(key: PType): PType; function GetUniqueType(key: PType): PType;
var var
t: PType; t: PType;
h: THash; h: THash;
k: TTypeKind;
begin begin
// this was a hotspot in the compiler! // this is a hotspot in the compiler!
result := key; result := key;
if key = nil then exit; if key = nil then exit;
k := key.kind;
case k of
tyObject, tyEnum: begin
result := PType(IdTableGet(gTypeTable[k], key));
if result = nil then begin
IdTablePut(gTypeTable[k], key, key);
result := key;
end
end;
tyGenericInst: result := GetUniqueType(lastSon(key));
tyProc: begin end;
else begin
// we have to do a slow linear search because types may need
// to be compared by their structure:
if IdTableHasObjectAsKey(gTypeTable[k], key) then exit;
for h := 0 to high(gTypeTable[k].data) do begin
t := PType(gTypeTable[k].data[h].key);
if (t <> nil) and sameType(t, key) then begin result := t; exit end
end;
IdTablePut(gTypeTable[k], key, key);
end;
end;
(*
case key.Kind of case key.Kind of
tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString, tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
tyInt..tyFloat128, tyProc, tyAnyEnum: begin end; tyInt..tyFloat128, tyProc, tyAnyEnum: begin end;
@ -62,7 +94,7 @@ begin
end end
end; end;
tyGenericInst: result := GetUniqueType(lastSon(key)); tyGenericInst: result := GetUniqueType(lastSon(key));
end; end; *)
end; end;
function TableGetType(const tab: TIdTable; key: PType): PObject; function TableGetType(const tab: TIdTable; key: PType): PObject;
@ -122,6 +154,6 @@ begin
app(result, toRope(res)); app(result, toRope(res));
end; end;
initialization begin
InitIdTable(gTypeTable); InitTypeTables();
end. end.

View file

@ -73,7 +73,6 @@ type
cpsStmts // section of local statements for C proc cpsStmts // section of local statements for C proc
); );
TCProcSections = array [TCProcSection] of PRope; TCProcSections = array [TCProcSection] of PRope;
// TCProcSections represents a generated C proc // TCProcSections represents a generated C proc
@ -112,21 +111,64 @@ type
typeCache: TIdTable; // cache the generated types typeCache: TIdTable; // cache the generated types
forwTypeCache: TIdTable; // cache for forward declarations of types forwTypeCache: TIdTable; // cache for forward declarations of types
declaredThings: TIntSet; // things we have declared in this .c file declaredThings: TIntSet; // things we have declared in this .c file
debugDeclared: TIntSet; // for debugging purposes declaredProtos: TIntSet; // prototypes we have declared in this .c file
headerFiles: TLinkedList; // needed headers to include headerFiles: TLinkedList; // needed headers to include
typeInfoMarker: TIntSet; // needed for generating type information typeInfoMarker: TIntSet; // needed for generating type information
initProc: BProc; // code for init procedure initProc: BProc; // code for init procedure
typeStack: TTypeSeq; // used for type generation typeStack: TTypeSeq; // used for type generation
dataCache: TNodeTable; dataCache: TNodeTable;
forwardedProcs: TSymSeq; // keep forwarded procs here
typeNodes, nimTypes: int;// used for type info generation typeNodes, nimTypes: int;// used for type info generation
typeNodesName, nimTypesName: PRope; // used for type info generation typeNodesName, nimTypesName: PRope; // used for type info generation
end; end;
var var
mainModProcs, mainModInit: PRope; // parts of the main module mainModProcs, mainModInit: PRope; // parts of the main module
gMapping: PRope; // the generated mapping file (if requested) gMapping: PRope; // the generated mapping file (if requested)
gProcProfile: Natural; // proc profile counter gProcProfile: Natural; // proc profile counter
gGeneratedSyms: TIntSet; // set of ID's of generated symbols
gPendingModules: array of BModule = {@ignore} nil {@emit @[]};
// list of modules that are not finished with code generation
gForwardedProcsCounter: int = 0;
gmti: BModule; // generated type info: no need to initialize: defaults fit
procedure addForwardedProc(m: BModule; prc: PSym);
var
L: int;
begin
L := length(m.forwardedProcs);
setLength(m.forwardedProcs, L+1);
m.forwardedProcs[L] := prc;
inc(gForwardedProcsCounter);
end;
procedure addPendingModule(m: BModule);
var
L, i: int;
begin
for i := 0 to high(gPendingModules) do
if gPendingModules[i] = m then
InternalError('module already pending: ' + m.module.name.s);
L := length(gPendingModules);
setLength(gPendingModules, L+1);
gPendingModules[L] := m;
end;
function findPendingModule(m: BModule; s: PSym): BModule;
var
ms: PSym;
i: int;
begin
ms := getModule(s);
if ms.id = m.module.id then begin
result := m; exit
end;
for i := 0 to high(gPendingModules) do begin
result := gPendingModules[i];
if result.module.id = ms.id then exit;
end;
InternalError(s.info, 'no pending module found for: ' + s.name.s);
end;
procedure initLoc(var result: TLoc; k: TLocKind; typ: PType; s: TStorageLoc); procedure initLoc(var result: TLoc; k: TLocKind; typ: PType; s: TStorageLoc);
begin begin
@ -209,26 +251,13 @@ end;
// -------------------------- Variable manager ---------------------------- // -------------------------- Variable manager ----------------------------
procedure declareGlobalVar(m: BModule; s: PSym);
begin
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(m.s[cfsVars], ' register');
if sfVolatile in s.flags then
app(m.s[cfsVars], ' volatile');
if sfThreadVar in s.flags then
app(m.s[cfsVars], ' NIM_THREADVAR');
appf(m.s[cfsVars], ' $1;$n', [s.loc.r])
end
end;
procedure assignLocalVar(p: BProc; s: PSym); procedure assignLocalVar(p: BProc; s: PSym);
begin begin
//assert(s.loc.k == locNone) // not yet assigned //assert(s.loc.k == locNone) // not yet assigned
// this need not be fullfilled for inline procs; they are regenerated // this need not be fullfilled for inline procs; they are regenerated
// for each module that uses them! // for each module that uses them!
fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack); if s.loc.k = locNone then
fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack);
app(p.s[cpsLocals], getTypeDesc(p.module, s.loc.t)); app(p.s[cpsLocals], getTypeDesc(p.module, s.loc.t));
if sfRegister in s.flags then if sfRegister in s.flags then
app(p.s[cpsLocals], ' register'); app(p.s[cpsLocals], ' register');
@ -248,11 +277,19 @@ end;
procedure assignGlobalVar(m: BModule; s: PSym); procedure assignGlobalVar(m: BModule; s: PSym);
begin begin
fillLoc(s.loc, locGlobalVar, s.typ, mangleName(s), OnHeap); if s.loc.k = locNone then
fillLoc(s.loc, locGlobalVar, s.typ, mangleName(s), OnHeap);
useHeader(m, s); useHeader(m, s);
if lfNoDecl in s.loc.flags then exit; if lfNoDecl in s.loc.flags then exit;
if sfImportc in s.flags then app(m.s[cfsVars], 'extern '); if sfImportc in s.flags then app(m.s[cfsVars], 'extern ');
declareGlobalVar(m, s); app(m.s[cfsVars], getTypeDesc(m, s.loc.t));
if sfRegister in s.flags then
app(m.s[cfsVars], ' register');
if sfVolatile in s.flags then
app(m.s[cfsVars], ' volatile');
if sfThreadVar in s.flags then
app(m.s[cfsVars], ' NIM_THREADVAR');
appf(m.s[cfsVars], ' $1;$n', [s.loc.r]);
if [optStackTrace, optEndb] * m.module.options = if [optStackTrace, optEndb] * m.module.options =
[optStackTrace, optEndb] then begin [optStackTrace, optEndb] then begin
useMagic(m, 'dbgRegisterGlobal'); useMagic(m, 'dbgRegisterGlobal');
@ -282,6 +319,12 @@ begin
end end
end; end;
procedure fillProcLoc(sym: PSym);
begin
if sym.loc.k = locNone then
fillLoc(sym.loc, locProc, sym.typ, mangleName(sym), OnStack);
end;
// -------------------------- label manager ------------------------------- // -------------------------- label manager -------------------------------
// note that a label is a location too // note that a label is a location too
@ -296,11 +339,11 @@ begin
appf(p.s[cpsStmts], '$1: ;$n', [labl]) appf(p.s[cpsStmts], '$1: ;$n', [labl])
end; end;
procedure genProcPrototype(m: BModule; sym: PSym); forward;
procedure genVarPrototype(m: BModule; sym: PSym); forward; procedure genVarPrototype(m: BModule; sym: PSym); forward;
procedure genConstPrototype(m: BModule; sym: PSym); forward; procedure genConstPrototype(m: BModule; sym: PSym); forward;
procedure genProc(m: BModule; prc: PSym); forward; procedure genProc(m: BModule; prc: PSym); forward;
procedure genStmts(p: BProc; t: PNode); forward; procedure genStmts(p: BProc; t: PNode); forward;
procedure genProcPrototype(m: BModule; sym: PSym); forward;
{$include 'ccgexprs.pas'} {$include 'ccgexprs.pas'}
{$include 'ccgstmts.pas'} {$include 'ccgstmts.pas'}
@ -343,11 +386,11 @@ begin
tmp := ropef('Dl_$1', [toRope(sym.id)]); tmp := ropef('Dl_$1', [toRope(sym.id)]);
sym.loc.r := tmp; // from now on we only need the internal name sym.loc.r := tmp; // from now on we only need the internal name
sym.typ.sym := nil; // generate a new name sym.typ.sym := nil; // generate a new name
appf(m.s[cfsDynLibInit], appf(m.s[cfsDynLibInit], '$1 = ($2) nimGetProcAddr($3, $4);$n',
'$1 = ($2) nimGetProcAddr($3, $4);$n', [tmp, getTypeDesc(m, sym.typ), lib.name, makeCString(ropeToStr(extname))]);
[tmp, getTypeDesc(m, sym.typ), lib.name,
makeCString(ropeToStr(extname))]); app(m.s[cfsVars], getTypeDesc(m, sym.loc.t));
declareGlobalVar(m, sym) appf(m.s[cfsVars], ' $1;$n', [sym.loc.r]);
end; end;
// ----------------------------- sections --------------------------------- // ----------------------------- sections ---------------------------------
@ -356,16 +399,16 @@ procedure UseMagic(m: BModule; const name: string);
var var
sym: PSym; sym: PSym;
begin begin
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); sym := magicsys.getCompilerProc(name);
case sym.kind of if sym <> nil then
skProc, skConverter: genProcPrototype(m, sym); case sym.kind of
skVar: genVarPrototype(m, sym); skProc, skConverter: genProc(m, sym);
skType: {@discard} getTypeDesc(m, sym.typ); skVar: genVarPrototype(m, sym);
else InternalError('useMagic: ' + name) skType: {@discard} getTypeDesc(m, sym.typ);
end else InternalError('useMagic: ' + name)
end
else if not (sfSystemModule in m.module.flags) then
rawMessage(errSystemNeeds, name); // don't be too picky here
end; end;
procedure generateHeaders(m: BModule); procedure generateHeaders(m: BModule);
@ -405,95 +448,131 @@ begin
result := (s.typ.sons[0] <> nil) and not isInvalidReturnType(s.typ.sons[0]) result := (s.typ.sons[0] <> nil) and not isInvalidReturnType(s.typ.sons[0])
end; end;
procedure genProc(m: BModule; prc: PSym); procedure genProcAux(m: BModule; prc: PSym);
var var
p: BProc; p: BProc;
generatedProc, header, returnStmt: PRope; generatedProc, header, returnStmt: PRope;
i, profileId: int; i: int;
res, param: PSym; res, param: PSym;
begin begin
useHeader(m, prc); p := newProc(prc, m);
fillLoc(prc.loc, locProc, prc.typ, mangleName(prc), OnStack); header := genProcHeader(m, prc);
if (lfNoDecl in prc.loc.Flags) then exit; returnStmt := nil;
if lfDynamicLib in prc.loc.flags then assert(prc.ast <> nil);
SymInDynamicLib(m, prc)
else if not (sfImportc in prc.flags) then begin
// we have a real proc here:
p := newProc(prc, m);
header := genProcHeader(m, prc);
if (sfCompilerProc in prc.flags)
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);
if not (sfPure in prc.flags) and (prc.typ.sons[0] <> nil) then begin if not (sfPure in prc.flags) and (prc.typ.sons[0] <> nil) then begin
res := prc.ast.sons[resultPos].sym; // get result symbol res := prc.ast.sons[resultPos].sym; // get result symbol
if not isInvalidReturnType(prc.typ.sons[0]) then begin if not isInvalidReturnType(prc.typ.sons[0]) then begin
// declare the result symbol: // declare the result symbol:
assignLocalVar(p, res); assignLocalVar(p, res);
assert(res.loc.r <> nil); assert(res.loc.r <> nil);
returnStmt := ropef('return $1;$n', [rdLoc(res.loc)]); returnStmt := ropef('return $1;$n', [rdLoc(res.loc)]);
end end
else begin
fillResult(res);
assignParam(p, res);
end;
initVariable(p, res);
genObjectInit(p, res.typ, res.loc, true);
end;
for i := 1 to sonsLen(prc.typ.n)-1 do begin
param := prc.typ.n.sons[i].sym;
assignParam(p, param)
end;
genStmts(p, prc.ast.sons[codePos]); // modifies p.locals, p.init, etc.
if sfPure in prc.flags then
generatedProc := ropef('$1 {$n$2$3$4}$n',
[header, p.s[cpsLocals], p.s[cpsInit], p.s[cpsStmts]])
else begin else begin
generatedProc := con(header, '{' + tnl); fillResult(res);
if optStackTrace in prc.options then begin assignParam(p, res);
getFrameDecl(p);
prepend(p.s[cpsInit], ropef(
'F.procname = $1;$n' +
'F.prev = framePtr;$n' +
'F.filename = $2;$n' +
'F.line = 0;$n' +
'framePtr = (TFrame*)&F;$n',
[makeCString(prc.owner.name.s +{&} '.' +{&} prc.name.s),
makeCString(toFilename(prc.info))]));
end;
if optProfiler in prc.options then begin
if gProcProfile >= 64*1024 then // XXX: hard coded value!
InternalError(prc.info, 'too many procedures for profiling');
useMagic(m, 'profileData');
app(p.s[cpsLocals], 'ticks NIM_profilingStart;'+tnl);
if prc.loc.a < 0 then begin
appf(m.s[cfsDebugInit], 'profileData[$1].procname = $2;$n',
[toRope(gProcProfile),
makeCString(prc.owner.name.s +{&} '.' +{&} prc.name.s)]);
prc.loc.a := gProcProfile;
inc(gProcProfile);
end;
prepend(p.s[cpsInit], toRope('NIM_profilingStart = getticks();' + tnl));
end;
app(generatedProc, con(p.s));
if p.beforeRetNeeded then
app(generatedProc, 'BeforeRet: ;' + tnl);
if optStackTrace in prc.options then
app(generatedProc, 'framePtr = framePtr->prev;' + tnl);
if optProfiler in prc.options then
appf(generatedProc,
'profileData[$1].total += elapsed(getticks(), NIM_profilingStart);$n',
[toRope(prc.loc.a)]);
app(generatedProc, returnStmt);
app(generatedProc, '}' + tnl);
end; end;
app(m.s[cfsProcs], generatedProc); initVariable(p, res);
genObjectInit(p, res.typ, res.loc, true);
end;
for i := 1 to sonsLen(prc.typ.n)-1 do begin
param := prc.typ.n.sons[i].sym;
assignParam(p, param)
end;
genStmts(p, prc.ast.sons[codePos]); // modifies p.locals, p.init, etc.
if sfPure in prc.flags then
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], ropef(
'F.procname = $1;$n' +
'F.prev = framePtr;$n' +
'F.filename = $2;$n' +
'F.line = 0;$n' +
'framePtr = (TFrame*)&F;$n',
[makeCString(prc.owner.name.s +{&} '.' +{&} prc.name.s),
makeCString(toFilename(prc.info))]));
end;
if optProfiler in prc.options then begin
if gProcProfile >= 64*1024 then // XXX: hard coded value!
InternalError(prc.info, 'too many procedures for profiling');
useMagic(m, 'profileData');
app(p.s[cpsLocals], 'ticks NIM_profilingStart;'+tnl);
if prc.loc.a < 0 then begin
appf(m.s[cfsDebugInit], 'profileData[$1].procname = $2;$n',
[toRope(gProcProfile),
makeCString(prc.owner.name.s +{&} '.' +{&} prc.name.s)]);
prc.loc.a := gProcProfile;
inc(gProcProfile);
end;
prepend(p.s[cpsInit], toRope('NIM_profilingStart = getticks();' + tnl));
end;
app(generatedProc, con(p.s));
if p.beforeRetNeeded then
app(generatedProc, 'BeforeRet: ;' + tnl);
if optStackTrace in prc.options then
app(generatedProc, 'framePtr = framePtr->prev;' + tnl);
if optProfiler in prc.options then
appf(generatedProc,
'profileData[$1].total += elapsed(getticks(), NIM_profilingStart);$n',
[toRope(prc.loc.a)]);
app(generatedProc, returnStmt);
app(generatedProc, '}' + tnl);
end;
app(m.s[cfsProcs], generatedProc);
end;
procedure genProcPrototype(m: BModule; sym: PSym);
begin
useHeader(m, sym);
if (lfNoDecl in sym.loc.Flags) then exit;
if lfDynamicLib in sym.loc.Flags then begin
if (sym.owner.id <> m.module.id) and
not intSetContainsOrIncl(m.declaredThings, sym.id) then begin
appf(m.s[cfsVars], 'extern $1 Dl_$2;$n',
[getTypeDesc(m, sym.loc.t), toRope(sym.id)])
end
end end
else begin
if not IntSetContainsOrIncl(m.declaredProtos, sym.id) then
appf(m.s[cfsProcHeaders], '$1;$n', [genProcHeader(m, sym)]);
end
end;
procedure genProcNoForward(m: BModule; prc: PSym);
begin
fillProcLoc(prc);
useHeader(m, prc);
genProcPrototype(m, prc);
if (lfNoDecl in prc.loc.Flags) then exit;
if prc.typ.callConv = ccInline then begin
// We add inline procs to the calling module to enable C based inlining.
// This also means that a check with ``gGeneratedSyms`` is wrong, we need
// a check for ``m.declaredThings``.
if not intSetContainsOrIncl(m.declaredThings, prc.id) then
genProcAux(m, prc);
end
else if lfDynamicLib in prc.loc.flags then begin
if not IntSetContainsOrIncl(gGeneratedSyms, prc.id) then
SymInDynamicLib(findPendingModule(m, prc), prc);
end
else if not (sfImportc in prc.flags) then begin
if not IntSetContainsOrIncl(gGeneratedSyms, prc.id) then
genProcAux(findPendingModule(m, prc), prc);
end
end;
procedure genProc(m: BModule; prc: PSym);
begin
fillProcLoc(prc);
if [sfForward, sfFromGeneric] * prc.flags <> [] then
addForwardedProc(m, prc)
else
genProcNoForward(m, prc)
end; end;
procedure genVarPrototype(m: BModule; sym: PSym); procedure genVarPrototype(m: BModule; sym: PSym);
@ -522,7 +601,8 @@ end;
procedure genConstPrototype(m: BModule; sym: PSym); procedure genConstPrototype(m: BModule; sym: PSym);
begin begin
useHeader(m, sym); useHeader(m, sym);
fillLoc(sym.loc, locData, sym.typ, mangleName(sym), OnUnknown); if sym.loc.k = locNone then
fillLoc(sym.loc, locData, sym.typ, mangleName(sym), OnUnknown);
if (lfNoDecl in sym.loc.Flags) or if (lfNoDecl in sym.loc.Flags) or
intSetContainsOrIncl(m.declaredThings, sym.id) then intSetContainsOrIncl(m.declaredThings, sym.id) then
exit; exit;
@ -535,32 +615,6 @@ begin
end end
end; end;
procedure genProcPrototype(m: BModule; sym: PSym);
begin
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 <> 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(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(m.declaredThings, sym.id) then exit;
appf(m.s[cfsProcHeaders], '$1;$n', [genProcHeader(m, sym)]);
if (sym.typ.callConv = ccInline)
and (sym.owner.id <> m.module.id) then
genProc(m, sym) // generate the code again!
end
end;
function getFileHeader(const cfilenoext: string): PRope; function getFileHeader(const cfilenoext: string): PRope;
begin begin
if optCompileOnly in gGlobalOptions then if optCompileOnly in gGlobalOptions then
@ -593,6 +647,7 @@ procedure genMainProc(m: BModule);
const const
CommonMainBody = CommonMainBody =
' setStackBottom(dummy);$n' + ' setStackBottom(dummy);$n' +
' nim__datInit();$n' +
' systemInit();$n' + ' systemInit();$n' +
'$1' + '$1' +
'$2'; '$2';
@ -652,8 +707,7 @@ var
initname: PRope; initname: PRope;
begin begin
initname := getInitName(m); initname := getInitName(m);
appf(mainModProcs, 'N_NOINLINE(void, $1)(void);$n', appf(mainModProcs, 'N_NOINLINE(void, $1)(void);$n', [initname]);
[initname]);
if not (sfSystemModule in m.flags) then if not (sfSystemModule in m.flags) then
appf(mainModInit, '$1();$n', [initname]); appf(mainModInit, '$1();$n', [initname]);
end; end;
@ -669,14 +723,18 @@ begin
{@discard} lists.IncludeStr(m.headerFiles, '<cycle.h>'); {@discard} lists.IncludeStr(m.headerFiles, '<cycle.h>');
end; end;
initname := getInitName(m.module); initname := getInitName(m.module);
registerModuleToMain(m.module);
prc := ropef('N_NOINLINE(void, $1)(void) {$n', [initname]); prc := ropef('N_NOINLINE(void, $1)(void) {$n', [initname]);
if m.typeNodes > 0 then
if m.typeNodes > 0 then begin
useMagic(m, 'TNimNode');
appf(m.s[cfsTypeInit1], 'static TNimNode $1[$2];$n', appf(m.s[cfsTypeInit1], 'static TNimNode $1[$2];$n',
[m.typeNodesName, toRope(m.typeNodes)]); [m.typeNodesName, toRope(m.typeNodes)]);
if m.nimTypes > 0 then end;
if m.nimTypes > 0 then begin
useMagic(m, 'TNimType');
appf(m.s[cfsTypeInit1], 'static TNimType $1[$2];$n', appf(m.s[cfsTypeInit1], 'static TNimType $1[$2];$n',
[m.nimTypesName, toRope(m.nimTypes)]); [m.nimTypesName, toRope(m.nimTypes)]);
end;
if optStackTrace in m.initProc.options then begin if optStackTrace in m.initProc.options then begin
getFrameDecl(m.initProc); getFrameDecl(m.initProc);
app(prc, m.initProc.s[cpsLocals]); app(prc, m.initProc.s[cpsLocals]);
@ -716,7 +774,7 @@ begin
for i := low(TCFileSection) to cfsProcs do app(result, m.s[i]) for i := low(TCFileSection) to cfsProcs do app(result, m.s[i])
end; end;
function newModule(module: PSym; const filename: string): BModule; function rawNewModule(module: PSym; const filename: string): BModule;
begin begin
new(result); new(result);
{@ignore} {@ignore}
@ -724,7 +782,7 @@ begin
{@emit} {@emit}
InitLinkedList(result.headerFiles); InitLinkedList(result.headerFiles);
intSetInit(result.declaredThings); intSetInit(result.declaredThings);
intSetInit(result.debugDeclared); intSetInit(result.declaredProtos);
result.cfilename := filename; result.cfilename := filename;
result.filename := filename; result.filename := filename;
initIdTable(result.typeCache); initIdTable(result.typeCache);
@ -735,12 +793,36 @@ begin
result.initProc.options := gOptions; result.initProc.options := gOptions;
initNodeTable(result.dataCache); initNodeTable(result.dataCache);
{@emit result.typeStack := @[];} {@emit result.typeStack := @[];}
{@emit result.forwardedProcs := @[];}
result.typeNodesName := getTempName(); result.typeNodesName := getTempName();
result.nimTypesName := getTempName(); result.nimTypesName := getTempName();
end; end;
function newModule(module: PSym; const filename: string): BModule;
begin
result := rawNewModule(module, filename);
if (optDeadCodeElim in gGlobalOptions) then begin
if (sfDeadCodeElim in module.flags) then
InternalError('added pending module twice: ' + filename);
addPendingModule(result)
end;
end;
procedure registerTypeInfoModule();
const
moduleName = 'nim__dat';
var
s: PSym;
begin
s := NewSym(skModule, getIdent(moduleName), nil);
gmti := rawNewModule(s, joinPath(options.projectPath, moduleName)+'.nim');
addPendingModule(gmti);
appf(mainModProcs, 'N_NOINLINE(void, $1)(void);$n', [getInitName(s)]);
end;
function myOpen(module: PSym; const filename: string): PPassContext; function myOpen(module: PSym; const filename: string): PPassContext;
begin begin
if gmti = nil then registerTypeInfoModule();
result := newModule(module, filename); result := newModule(module, filename);
end; end;
@ -749,6 +831,7 @@ function myOpenCached(module: PSym; const filename: string;
var var
cfile, cfilenoext, objFile: string; cfile, cfilenoext, objFile: string;
begin begin
if gmti = nil then registerTypeInfoModule();
//MessageOut('cgen.myOpenCached has been called ' + filename); //MessageOut('cgen.myOpenCached has been called ' + filename);
cfile := changeFileExt(completeCFilePath(filename), cExt); cfile := changeFileExt(completeCFilePath(filename), cExt);
cfilenoext := changeFileExt(cfile, ''); cfilenoext := changeFileExt(cfile, '');
@ -761,6 +844,8 @@ begin
end; *) end; *)
addFileToLink(cfilenoext); addFileToLink(cfilenoext);
registerModuleToMain(module); registerModuleToMain(module);
// XXX: this cannot be right here, initalization has to be appended during
// the ``myClose`` call
result := nil; result := nil;
end; end;
@ -790,11 +875,52 @@ begin
genStmts(m.initProc, n); genStmts(m.initProc, n);
end; end;
function myClose(b: PPassContext; n: PNode): PNode; procedure finishModule(m: BModule);
var
i: int;
prc: PSym;
begin
i := 0;
while i <= high(m.forwardedProcs) do begin
// Note: ``genProc`` may add to ``m.forwardedProcs``, so we cannot use
// a for loop here
prc := m.forwardedProcs[i];
if sfForward in prc.flags then InternalError(prc.info, 'still forwarded');
genProcNoForward(m, prc);
inc(i);
end;
assert(gForwardedProcsCounter >= i);
dec(gForwardedProcsCounter, i);
setLength(m.forwardedProcs, 0);
end;
procedure writeModule(m: BModule);
var var
cfile, cfilenoext: string; cfile, cfilenoext: string;
m: BModule;
code: PRope; code: PRope;
begin
// generate code for the init statements of the module:
genInitCode(m);
finishTypeDescriptions(m);
cfile := completeCFilePath(m.cfilename);
cfilenoext := changeFileExt(cfile, '');
if sfMainModule in m.module.flags then begin
// generate main file:
app(m.s[cfsProcHeaders], mainModProcs);
end;
code := genModule(m, cfilenoext);
if shouldRecompile(code, changeFileExt(cfile, cExt), cfilenoext) then begin
addFileToCompile(cfilenoext);
end;
addFileToLink(cfilenoext);
if sfMainModule in m.module.flags then writeMapping(cfile, gMapping);
end;
function myClose(b: PPassContext; n: PNode): PNode;
var
m: BModule;
i: int;
begin begin
result := n; result := n;
if b = nil then exit; if b = nil then exit;
@ -803,22 +929,24 @@ begin
m.initProc.options := gOptions; m.initProc.options := gOptions;
genStmts(m.initProc, n); genStmts(m.initProc, n);
end; end;
// generate code for the init statements of the module: registerModuleToMain(m.module);
genInitCode(m); if not (optDeadCodeElim in gGlobalOptions) and
finishTypeDescriptions(m); not (sfDeadCodeElim in m.module.flags) then
cfile := completeCFilePath(m.cfilename); finishModule(m);
cfilenoext := changeFileExt(cfile, '');
if sfMainModule in m.module.flags then begin if sfMainModule in m.module.flags then begin
// generate main file:
app(m.s[cfsProcHeaders], mainModProcs);
genMainProc(m); genMainProc(m);
// we need to process the transitive closure because recursive module
// deps are allowed (and the system module is processed in the wrong
// order anyway)
while gForwardedProcsCounter > 0 do
for i := 0 to high(gPendingModules) do
finishModule(gPendingModules[i]);
for i := 0 to high(gPendingModules) do writeModule(gPendingModules[i]);
setLength(gPendingModules, 0);
end; end;
code := genModule(m, cfilenoext); if not (optDeadCodeElim in gGlobalOptions) and
if shouldRecompile(code, changeFileExt(cfile, cExt), cfilenoext) then begin not (sfDeadCodeElim in m.module.flags) then
addFileToCompile(cfilenoext); // is to compile writeModule(m);
end;
addFileToLink(cfilenoext);
if sfMainModule in m.module.flags then writeMapping(cfile, gMapping);
end; end;
function cgenPass(): TPass; function cgenPass(): TPass;
@ -832,4 +960,5 @@ end;
initialization initialization
InitIiTable(gToTypeInfoId); InitIiTable(gToTypeInfoId);
IntSetInit(gGeneratedSyms);
end. end.

View file

@ -39,14 +39,14 @@ const
{$ifdef fpc} {$ifdef fpc}
compileDate = {$I %date%}; compileDate = {$I %date%};
{$else} {$else}
compileDate = '2008-0-0'; compileDate = '2009-0-0';
{$endif} {$endif}
{@emit} {@emit}
const const
HelpMessage = 'Nimrod Compiler Version $1 (' +{&} HelpMessage = 'Nimrod Compiler Version $1 (' +{&}
compileDate +{&} ') [$2: $3]' +{&} nl +{&} compileDate +{&} ') [$2: $3]' +{&} nl +{&}
'Copyright (c) 2004-2008 by Andreas Rumpf' +{&} nl; 'Copyright (c) 2004-2009 by Andreas Rumpf' +{&} nl;
const const
Usage = '' Usage = ''
@ -82,6 +82,7 @@ const
+{&} ' --bound_checks:on|off code generation for bound 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 +{&} ' --overflow_checks:on|off code generation for over-/underflow checks ON|OFF' +{&} nl
+{&} ' -a, --assertions:on|off code generation for assertions ON|OFF' +{&} nl +{&} ' -a, --assertions:on|off code generation for assertions ON|OFF' +{&} nl
+{&} ' --dead_code_elim:on|off whole program dead code elimination ON|OFF' +{&} nl
+{&} ' --opt:none|speed|size optimize not at all or for speed|size' +{&} nl +{&} ' --opt:none|speed|size optimize not at all or for speed|size' +{&} nl
+{&} ' --app:console|gui|lib generate a console|GUI application or a shared lib' +{&} nl +{&} ' --app:console|gui|lib generate a console|GUI application or a shared lib' +{&} nl
+{&} ' -r, --run run the compiled program with given arguments' +{&} nl +{&} ' -r, --run run the compiled program with given arguments' +{&} nl
@ -96,7 +97,7 @@ const
// cog.outl(f(line)) // cog.outl(f(line))
//]]] //]]]
+{&} 'Advanced commands::' +{&} nl +{&} 'Advanced commands::' +{&} nl
+{&} ' pas convert a Pascal file to Nimrod standard syntax' +{&} nl +{&} ' pas convert a Pascal file to Nimrod syntax' +{&} nl
+{&} ' pretty pretty print the inputfile' +{&} nl +{&} ' pretty pretty print the inputfile' +{&} nl
+{&} ' gen_depend generate a DOT file containing the' +{&} nl +{&} ' gen_depend generate a DOT file containing the' +{&} nl
+{&} ' module dependency graph' +{&} nl +{&} ' module dependency graph' +{&} nl
@ -135,8 +136,8 @@ const
function getCommandLineDesc: string; function getCommandLineDesc: string;
begin begin
result := format(HelpMessage, [VersionAsString, platform.os[hostOS].name, result := format(HelpMessage, [VersionAsString,
cpu[hostCPU].name]) +{&} Usage platform.os[platform.hostOS].name, cpu[platform.hostCPU].name]) +{&} Usage
end; end;
var var
@ -157,8 +158,10 @@ procedure writeAdvancedUsage(pass: TCmdLinePass);
begin begin
if (pass = passCmd1) and not advHelpWritten then begin if (pass = passCmd1) and not advHelpWritten then begin
// BUGFIX 19 // BUGFIX 19
MessageOut(format(HelpMessage, [VersionAsString, platform.os[hostOS].name, MessageOut(format(HelpMessage, [VersionAsString,
cpu[hostCPU].name]) +{&} AdvancedUsage); platform.os[platform.hostOS].name,
cpu[platform.hostCPU].name]) +{&}
AdvancedUsage);
advHelpWritten := true; advHelpWritten := true;
helpWritten := true; helpWritten := true;
halt(0); halt(0);
@ -170,8 +173,9 @@ begin
if (pass = passCmd1) and not versionWritten then begin if (pass = passCmd1) and not versionWritten then begin
versionWritten := true; versionWritten := true;
helpWritten := true; helpWritten := true;
messageOut(format(HelpMessage, [VersionAsString, platform.os[hostOS].name, messageOut(format(HelpMessage, [VersionAsString,
cpu[hostCPU].name])) platform.os[platform.hostOS].name,
cpu[platform.hostCPU].name]))
end end
end; end;
@ -388,6 +392,7 @@ begin
wOverflowChecks: ProcessOnOffSwitch({@set}[optOverflowCheck], arg, pass, info); wOverflowChecks: ProcessOnOffSwitch({@set}[optOverflowCheck], arg, pass, info);
wLineDir: ProcessOnOffSwitch({@set}[optLineDir], arg, pass, info); wLineDir: ProcessOnOffSwitch({@set}[optLineDir], arg, pass, info);
wAssertions, wA: ProcessOnOffSwitch({@set}[optAssert], arg, pass, info); wAssertions, wA: ProcessOnOffSwitch({@set}[optAssert], arg, pass, info);
wDeadCodeElim: ProcessOnOffSwitchG({@set}[optDeadCodeElim], arg, pass, info);
wOpt: begin wOpt: begin
case whichKeyword(arg) of case whichKeyword(arg) of
wSpeed: begin wSpeed: begin
@ -453,7 +458,7 @@ begin
theOS := platform.NameToOS(arg); theOS := platform.NameToOS(arg);
if theOS = osNone then if theOS = osNone then
liMessage(info, errUnknownOS, arg); liMessage(info, errUnknownOS, arg);
if theOS <> hostOS then begin if theOS <> platform.hostOS then begin
setTarget(theOS, targetCPU); setTarget(theOS, targetCPU);
include(gGlobalOptions, optCompileOnly); include(gGlobalOptions, optCompileOnly);
condsyms.InitDefines() condsyms.InitDefines()
@ -465,7 +470,7 @@ begin
cpu := platform.NameToCPU(arg); cpu := platform.NameToCPU(arg);
if cpu = cpuNone then if cpu = cpuNone then
liMessage(info, errUnknownCPU, arg); liMessage(info, errUnknownCPU, arg);
if cpu <> hostCPU then begin if cpu <> platform.hostCPU then begin
setTarget(targetOS, cpu); setTarget(targetOS, cpu);
include(gGlobalOptions, optCompileOnly); include(gGlobalOptions, optCompileOnly);
condsyms.InitDefines() condsyms.InitDefines()

View file

@ -218,8 +218,6 @@ begin
end; end;
function nextSplitPoint(const s: string; start: int): int; function nextSplitPoint(const s: string; start: int): int;
var
i: int;
begin begin
result := start; result := start;
while result < length(s)+strStart do begin while result < length(s)+strStart do begin
@ -227,7 +225,7 @@ begin
'_': exit; '_': exit;
'a'..'z': begin 'a'..'z': begin
if result+1 < length(s)+strStart then if result+1 < length(s)+strStart then
if s[result+1] in ['A'..'Z'] then exit; if s[result+1] in ['A'..'Z'] then exit;
end; end;
else begin end; else begin end;
end; end;
@ -393,7 +391,8 @@ begin
fillChar(r, sizeof(r), 0); fillChar(r, sizeof(r), 0);
{@emit} {@emit}
comm := genRecComment(d, n); // call this here for the side-effect! comm := genRecComment(d, n); // call this here for the side-effect!
initTokRender(r, n, {@set}[renderNoPragmas, renderNoBody]); initTokRender(r, n, {@set}[renderNoPragmas, renderNoBody, renderNoComments,
renderDocComments]);
while true do begin while true do begin
getNextTok(r, kind, literal); getNextTok(r, kind, literal);
case kind of case kind of
@ -579,7 +578,7 @@ begin
end; end;
rnHyperlink: begin rnHyperlink: begin
result := ropef('`$1 <$2>`_', [renderRstToRst(d, n.sons[0]), result := ropef('`$1 <$2>`_', [renderRstToRst(d, n.sons[0]),
renderRstToRst(d, n.sons[1])]); renderRstToRst(d, n.sons[1])]);
end; end;
rnGeneralRole: begin rnGeneralRole: begin
result := renderRstToRst(d, n.sons[0]); result := renderRstToRst(d, n.sons[0]);
@ -661,21 +660,26 @@ begin
result := ropef('<ul class="simple">$1</ul>', [result]); result := ropef('<ul class="simple">$1</ul>', [result]);
end; end;
function fieldAux(const s: string): PRope;
begin
result := toRope(strip(s))
end;
function renderImage(d: PDoc; n: PRstNode): PRope; function renderImage(d: PDoc; n: PRstNode): PRope;
var var
s: string; s: string;
begin begin
result := ropef('<img src="$1"', [toRope(getArgument(n))]); result := ropef('<img src="$1"', [toRope(getArgument(n))]);
s := getFieldValue(n, 'height'); s := getFieldValue(n, 'height');
if s <> '' then appf(result, ' height="$1"', [toRope(s)]); if s <> '' then appf(result, ' height="$1"', [fieldAux(s)]);
s := getFieldValue(n, 'width'); s := getFieldValue(n, 'width');
if s <> '' then appf(result, ' width="$1"', [toRope(s)]); if s <> '' then appf(result, ' width="$1"', [fieldAux(s)]);
s := getFieldValue(n, 'scale'); s := getFieldValue(n, 'scale');
if s <> '' then appf(result, ' scale="$1"', [toRope(s)]); if s <> '' then appf(result, ' scale="$1"', [fieldAux(s)]);
s := getFieldValue(n, 'alt'); s := getFieldValue(n, 'alt');
if s <> '' then appf(result, ' alt="$1"', [toRope(s)]); if s <> '' then appf(result, ' alt="$1"', [fieldAux(s)]);
s := getFieldValue(n, 'align'); s := getFieldValue(n, 'align');
if s <> '' then appf(result, ' align="$1"', [toRope(s)]); if s <> '' then appf(result, ' align="$1"', [fieldAux(s)]);
app(result, ' />'); app(result, ' />');
if rsonsLen(n) >= 3 then app(result, renderRstToHtml(d, n.sons[2])) if rsonsLen(n) >= 3 then app(result, renderRstToHtml(d, n.sons[2]))
end; end;
@ -863,15 +867,18 @@ begin
nkConverterDef: genItem(d, n, n.sons[namePos], skConverter); nkConverterDef: genItem(d, n, n.sons[namePos], skConverter);
nkVarSection: begin nkVarSection: begin
for i := 0 to sonsLen(n)-1 do for i := 0 to sonsLen(n)-1 do
genItem(d, n.sons[i], n.sons[i].sons[0], skVar); if n.sons[i].kind <> nkCommentStmt then
genItem(d, n.sons[i], n.sons[i].sons[0], skVar);
end; end;
nkConstSection: begin nkConstSection: begin
for i := 0 to sonsLen(n)-1 do for i := 0 to sonsLen(n)-1 do
genItem(d, n.sons[i], n.sons[i].sons[0], skConst); if n.sons[i].kind <> nkCommentStmt then
genItem(d, n.sons[i], n.sons[i].sons[0], skConst);
end; end;
nkTypeSection: begin nkTypeSection: begin
for i := 0 to sonsLen(n)-1 do for i := 0 to sonsLen(n)-1 do
genItem(d, n.sons[i], n.sons[i].sons[0], skType); if n.sons[i].kind <> nkCommentStmt then
genItem(d, n.sons[i], n.sons[i].sons[0], skType);
end; end;
nkStmtList: begin nkStmtList: begin
for i := 0 to sonsLen(n)-1 do generateDoc(d, n.sons[i]); for i := 0 to sonsLen(n)-1 do generateDoc(d, n.sons[i]);

View file

@ -896,7 +896,8 @@ begin
or (skipGeneric(y.typ).kind in [tyRef, tyPtr, tyVar]) or (skipGeneric(y.typ).kind in [tyRef, tyPtr, tyVar])
end; end;
procedure genAsgnAux(var p: TProc; x, y: PNode; var r: TCompRes); procedure genAsgnAux(var p: TProc; x, y: PNode; var r: TCompRes;
noCopyNeeded: bool);
var var
a, b: TCompRes; a, b: TCompRes;
begin begin
@ -906,7 +907,7 @@ begin
etyObject: begin etyObject: begin
if a.com <> nil then appf(r.com, '$1;$n', [a.com]); if a.com <> nil then appf(r.com, '$1;$n', [a.com]);
if b.com <> nil then appf(r.com, '$1;$n', [b.com]); if b.com <> nil then appf(r.com, '$1;$n', [b.com]);
if needsNoCopy(y) then if needsNoCopy(y) or noCopyNeeded then
appf(r.com, '$1 = $2;$n', [a.res, b.res]) appf(r.com, '$1 = $2;$n', [a.res, b.res])
else begin else begin
useMagic(p, 'NimCopy'); useMagic(p, 'NimCopy');
@ -930,7 +931,13 @@ end;
procedure genAsgn(var p: TProc; n: PNode; var r: TCompRes); procedure genAsgn(var p: TProc; n: PNode; var r: TCompRes);
begin begin
genLineDir(p, n, r); genLineDir(p, n, r);
genAsgnAux(p, n.sons[0], n.sons[1], r); genAsgnAux(p, n.sons[0], n.sons[1], r, false);
end;
procedure genFastAsgn(var p: TProc; n: PNode; var r: TCompRes);
begin
genLineDir(p, n, r);
genAsgnAux(p, n.sons[0], n.sons[1], r, true);
end; end;
procedure genSwap(var p: TProc; n: PNode; var r: TCompRes); procedure genSwap(var p: TProc; n: PNode; var r: TCompRes);
@ -1692,6 +1699,7 @@ begin
nkReturnStmt: genReturnStmt(p, n, r); nkReturnStmt: genReturnStmt(p, n, r);
nkBreakStmt: genBreakStmt(p, n, r); nkBreakStmt: genBreakStmt(p, n, r);
nkAsgn: genAsgn(p, n, r); nkAsgn: genAsgn(p, n, r);
nkFastAsgn: genFastAsgn(p, n, r);
nkDiscardStmt: begin nkDiscardStmt: begin
genLineDir(p, n, r); genLineDir(p, n, r);
gen(p, n.sons[0], r); gen(p, n.sons[0], r);

View file

@ -28,7 +28,7 @@ type
TStackFrame = record TStackFrame = record
mapping: TIdNodeTable; // mapping from symbols to nodes mapping: TIdNodeTable; // mapping from symbols to nodes
prc: PSym; // current prc; proc that is evaluated prc: PSym; // current prc; proc that is evaluated
call: PNode; // current for stmt call: PNode;
next: PStackFrame; // for stacking next: PStackFrame; // for stacking
params: TNodeSeq; // parameters passed to the proc params: TNodeSeq; // parameters passed to the proc
end; end;
@ -127,7 +127,7 @@ begin
inc(i) inc(i)
end; end;
if (i < len) and (sonsLen(n.sons[i]) < 2) then // eval else-part if (i < len) and (sonsLen(n.sons[i]) < 2) then // eval else-part
result := evalAux(c, n.sons[0]) result := evalAux(c, n.sons[i].sons[0])
else else
result := emptyNode result := emptyNode
end; end;
@ -1227,7 +1227,7 @@ begin
nkDerefExpr, nkHiddenDeref: result := evalDeref(c, n); nkDerefExpr, nkHiddenDeref: result := evalDeref(c, n);
nkAddr, nkHiddenAddr: result := evalAddr(c, n); nkAddr, nkHiddenAddr: result := evalAddr(c, n);
nkHiddenStdConv, nkHiddenSubConv, nkConv: result := evalConv(c, n); nkHiddenStdConv, nkHiddenSubConv, nkConv: result := evalConv(c, n);
nkAsgn: result := evalAsgn(c, n); nkAsgn, nkFastAsgn: result := evalAsgn(c, n);
nkWhenStmt, nkIfStmt, nkIfExpr: result := evalIf(c, n); nkWhenStmt, nkIfStmt, nkIfExpr: result := evalIf(c, n);
nkWhileStmt: result := evalWhile(c, n); nkWhileStmt: result := evalWhile(c, n);
nkCaseStmt: result := evalCase(c, n); nkCaseStmt: result := evalCase(c, n);
@ -1259,7 +1259,7 @@ begin
nkTemplateDef, nkConstSection, nkIteratorDef, nkConverterDef, nkTemplateDef, nkConstSection, nkIteratorDef, nkConverterDef,
nkIncludeStmt, nkImportStmt, nkFromStmt: begin end; nkIncludeStmt, nkImportStmt, nkFromStmt: begin end;
nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr, nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr,
nkQualified, nkLambda, nkContinueStmt: nkQualified, nkLambda, nkContinueStmt, nkIdent:
stackTrace(c, n, errCannotInterpretNodeX, nodeKindToStr[n.kind]); stackTrace(c, n, errCannotInterpretNodeX, nodeKindToStr[n.kind]);
else InternalError(n.info, 'evalAux: ' + nodekindToStr[n.kind]); else InternalError(n.info, 'evalAux: ' + nodekindToStr[n.kind]);
end; end;

View file

@ -343,17 +343,11 @@ begin
result := ccNone result := ccNone
end; end;
procedure addStr(var dest: string; const src: string);
begin
dest := dest +{&} src;
end;
procedure addOpt(var dest: string; const src: string); procedure addOpt(var dest: string; const src: string);
begin begin
if (length(dest) = 0) or (dest[length(dest)-1+strStart] <> ' ') then if (length(dest) = 0) or (dest[length(dest)-1+strStart] <> ' ') then
addStr(dest, ' '+''); add(dest, ' '+'');
addStr(dest, src); add(dest, src);
end; end;
procedure addCompileOption(const option: string); procedure addCompileOption(const option: string);
@ -473,40 +467,52 @@ begin
key := cc[c].name + '.exe'; key := cc[c].name + '.exe';
if existsConfigVar(key) then if existsConfigVar(key) then
exe := getConfigVar(key); exe := getConfigVar(key);
if targetOS = osWindows then exe := appendFileExt(exe, 'exe');
if (optGenDynLib in gGlobalOptions) if (optGenDynLib in gGlobalOptions)
and (ospNeedsPIC in platform.OS[targetOS].props) then and (ospNeedsPIC in platform.OS[targetOS].props) then
addStr(options, ' ' + cc[c].pic); add(options, ' ' + cc[c].pic);
if targetOS = hostOS then begin if targetOS = platform.hostOS then begin
// compute include paths: // compute include paths:
includeCmd := cc[c].includeCmd; // this is more complex than needed, but includeCmd := cc[c].includeCmd; // this is more complex than needed, but
// a workaround of a FPC bug... // a workaround of a FPC bug...
addStr(includeCmd, libpath); add(includeCmd, quoteIfContainsWhite(libpath));
compilePattern := quoteIfSpaceExists(JoinPath(ccompilerpath, exe)); compilePattern := JoinPath(ccompilerpath, exe);
end end
else begin else begin
includeCmd := ''; includeCmd := '';
compilePattern := cc[c].compilerExe compilePattern := cc[c].compilerExe
end; end;
if targetOS = hostOS then if targetOS = platform.hostOS then
cfile := cfilename cfile := cfilename
else else
cfile := extractFileName(cfilename); cfile := extractFileName(cfilename);
if not isExternal or (targetOS <> hostOS) then if not isExternal or (targetOS <> platform.hostOS) then
objfile := toObjFile(cfile) objfile := toObjFile(cfile)
else else
objfile := completeCFilePath(toObjFile(cfile)); objfile := completeCFilePath(toObjFile(cfile));
cfile := quoteIfContainsWhite(AppendFileExt(cfile, cExt));
result := format(compilePattern +{&} ' ' +{&} cc[c].compileTmpl, objfile := quoteIfContainsWhite(objfile);
['file', AppendFileExt(cfile, cExt),
result := quoteIfContainsWhite(format(compilePattern,
['file', cfile,
'objfile', objfile, 'objfile', objfile,
'options', options, 'options', options,
'include', includeCmd, 'include', includeCmd,
'nimrod', getPrefixDir(), 'nimrod', getPrefixDir(),
'lib', libpath 'lib', libpath
]); ]));
add(result, ' ');
add(result, format(cc[c].compileTmpl,
['file', cfile,
'objfile', objfile,
'options', options,
'include', includeCmd,
'nimrod', quoteIfContainsWhite(getPrefixDir()),
'lib', quoteIfContainsWhite(libpath)
]));
end; end;
procedure CompileCFile(const list: TLinkedList; procedure CompileCFile(const list: TLinkedList;
@ -551,11 +557,12 @@ begin
// call the linker: // call the linker:
linkerExe := getConfigVar(cc[c].name + '.linkerexe'); linkerExe := getConfigVar(cc[c].name + '.linkerexe');
if length(linkerExe) = 0 then linkerExe := cc[c].linkerExe; if length(linkerExe) = 0 then linkerExe := cc[c].linkerExe;
if targetOS = osWindows then linkerExe := appendFileExt(linkerExe, 'exe');
if (hostOS <> targetOS) then if (platform.hostOS <> targetOS) then
linkCmd := linkerExe linkCmd := quoteIfContainsWhite(linkerExe)
else else
linkCmd := quoteIfSpaceExists(JoinPath(ccompilerpath, linkerExe)); linkCmd := quoteIfContainsWhite(JoinPath(ccompilerpath, linkerExe));
if optGenDynLib in gGlobalOptions then if optGenDynLib in gGlobalOptions then
buildDll := cc[c].buildDll buildDll := cc[c].buildDll
@ -570,27 +577,29 @@ begin
exefile := platform.os[targetOS].dllPrefix exefile := platform.os[targetOS].dllPrefix
else else
exefile := ''; exefile := '';
if targetOS = hostOS then if targetOS = platform.hostOS then
addStr(exefile, projectFile) add(exefile, projectFile)
else else
addStr(exefile, extractFileName(projectFile)); add(exefile, extractFileName(projectFile));
if optGenDynLib in gGlobalOptions then if optGenDynLib in gGlobalOptions then
addStr(exefile, platform.os[targetOS].dllExt) add(exefile, platform.os[targetOS].dllExt)
else else
addStr(exefile, platform.os[targetOS].exeExt); add(exefile, platform.os[targetOS].exeExt);
exefile := quoteIfContainsWhite(exefile);
it := PStrEntry(toLink.head); it := PStrEntry(toLink.head);
objfiles := ''; objfiles := '';
while it <> nil do begin while it <> nil do begin
addStr(objfiles, ' '+''); add(objfiles, ' '+'');
if targetOS = hostOS then if targetOS = platform.hostOS then
addStr(objfiles, toObjfile(it.data)) add(objfiles, quoteIfContainsWhite(toObjfile(it.data)))
else else
addStr(objfiles, toObjfile(extractFileName(it.data))); add(objfiles, quoteIfContainsWhite(
toObjfile(extractFileName(it.data))));
it := PStrEntry(it.next); it := PStrEntry(it.next);
end; end;
linkCmd := format(linkCmd +{&} ' ' +{&} cc[c].linkTmpl, [ linkCmd := quoteIfContainsWhite(format(linkCmd, [
'builddll', builddll, 'builddll', builddll,
'buildgui', buildgui, 'buildgui', buildgui,
'options', linkOptions, 'options', linkOptions,
@ -598,7 +607,18 @@ begin
'exefile', exefile, 'exefile', exefile,
'nimrod', getPrefixDir(), 'nimrod', getPrefixDir(),
'lib', libpath 'lib', libpath
]); ]));
add(linkCmd, ' ');
add(linkCmd, format(cc[c].linkTmpl, [
'builddll', builddll,
'buildgui', buildgui,
'options', linkOptions,
'objfiles', objfiles,
'exefile', exefile,
'nimrod', quoteIfContainsWhite(getPrefixDir()),
'lib', quoteIfContainsWhite(libpath)
]));
if not (optCompileOnly in gGlobalOptions) then if not (optCompileOnly in gGlobalOptions) then
execExternalProgram(linkCmd); execExternalProgram(linkCmd);
end // end if not noLinking end // end if not noLinking

View file

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

View file

@ -64,7 +64,7 @@ function getCurrentLine(const L: TBaseLexer; marker: boolean = true): string;
function getColNumber(const L: TBaseLexer; pos: int): int; function getColNumber(const L: TBaseLexer; pos: int): int;
function HandleCR(var L: TBaseLexer; pos: int): int; function HandleCR(var L: TBaseLexer; pos: int): int;
// Call this if you scanned over CR in the buffer; it returns the the // Call this if you scanned over CR in the buffer; it returns the
// position to continue the scanning from. `pos` must be the position // position to continue the scanning from. `pos` must be the position
// of the CR. // of the CR.
@ -211,8 +211,7 @@ end;
function getColNumber(const L: TBaseLexer; pos: int): int; function getColNumber(const L: TBaseLexer; pos: int): int;
begin begin
result := pos - L.lineStart; result := abs(pos - L.lineStart);
assert(result >= 0);
end; end;
function getCurrentLine(const L: TBaseLexer; marker: boolean = true): string; function getCurrentLine(const L: TBaseLexer; marker: boolean = true): string;

View file

@ -96,9 +96,10 @@ begin
result := StrTableGet(compilerprocs, ident); result := StrTableGet(compilerprocs, ident);
if result = nil then begin if result = nil then begin
result := StrTableGet(rodCompilerProcs, ident); result := StrTableGet(rodCompilerProcs, ident);
if result = nil then rawMessage(errSystemNeeds, name); if result <> nil then begin
strTableAdd(compilerprocs, result); strTableAdd(compilerprocs, result);
if result.kind = skStub then loadStub(result); if result.kind = skStub then loadStub(result);
end;
// A bit hacky that this code is needed here, but it is the easiest // A bit hacky that this code is needed here, but it is the easiest
// solution in order to avoid special cases for sfCompilerProc in the // solution in order to avoid special cases for sfCompilerProc in the
// rodgen module. Another solution would be to always recompile the system // rodgen module. Another solution would be to always recompile the system

View file

@ -173,7 +173,7 @@ type
errSelectorMustBeOrdinal, errSelectorMustBeOrdinal,
errOrdXMustNotBeNegative, errOrdXMustNotBeNegative,
errLenXinvalid, errLenXinvalid,
errWrongNumberOfLoopVariables, errWrongNumberOfVariables,
errExprCannotBeRaised, errExprCannotBeRaised,
errBreakOnlyInLoop, errBreakOnlyInLoop,
errTypeXhasUnknownSize, errTypeXhasUnknownSize,
@ -431,7 +431,7 @@ const
'selector must be of an ordinal type', 'selector must be of an ordinal type',
'ord($1) must not be negative', 'ord($1) must not be negative',
'len($1) must be less than 32768', 'len($1) must be less than 32768',
'wrong number of loop variables', 'wrong number of variables',
'only objects can be raised', 'only objects can be raised',
'''break'' only allowed in loop construct', '''break'' only allowed in loop construct',
'type ''$1'' has unknown size', 'type ''$1'' has unknown size',

View file

@ -93,7 +93,8 @@ begin
} }
end; end;
if optRun in gGlobalOptions then if optRun in gGlobalOptions then
execExternalProgram(changeFileExt(filename, '') +{&} ' ' +{&} arguments) execExternalProgram(quoteIfContainsWhite(changeFileExt(filename, '')) +{&}
' ' +{&} arguments)
end end
end; end;

View file

@ -35,9 +35,11 @@ const
{$ifdef mswindows} {$ifdef mswindows}
dirsep = '\'; // seperator within paths dirsep = '\'; // seperator within paths
altsep = '/'; altsep = '/';
exeExt = 'exe';
{$else} {$else}
dirsep = '/'; dirsep = '/';
altsep = #0; // work around fpc bug altsep = #0; // work around fpc bug
exeExt = '';
{$endif} {$endif}
pathSep = ';'; // seperator between paths pathSep = ';'; // seperator between paths
sep = dirsep; // alternative name sep = dirsep; // alternative name

View file

@ -149,8 +149,12 @@ function subU(a, b: biggestInt): biggestInt;
function mulU(a, b: biggestInt): biggestInt; function mulU(a, b: biggestInt): biggestInt;
function divU(a, b: biggestInt): biggestInt; function divU(a, b: biggestInt): biggestInt;
function modU(a, b: biggestInt): biggestInt; function modU(a, b: biggestInt): biggestInt;
function shlU(a, b: biggestInt): biggestInt; function shlU(a, b: biggestInt): biggestInt; overload;
function shrU(a, b: biggestInt): biggestInt; function shrU(a, b: biggestInt): biggestInt; overload;
function shlU(a, b: Int32): Int32;overload;
function shrU(a, b: int32): int32;overload;
function ltU(a, b: biggestInt): bool; function ltU(a, b: biggestInt): bool;
function leU(a, b: biggestInt): bool; function leU(a, b: biggestInt): bool;
@ -281,6 +285,16 @@ begin
result := biggestInt(biggestUInt(a) shr biggestUInt(b)); result := biggestInt(biggestUInt(a) shr biggestUInt(b));
end; end;
function shlU(a, b: Int32): Int32;
begin
result := Int32(UInt32(a) shl UInt32(b));
end;
function shrU(a, b: int32): int32;
begin
result := Int32(UInt32(a) shr UInt32(b));
end;
function ltU(a, b: biggestInt): bool; function ltU(a, b: biggestInt): bool;
begin begin
result := biggestUInt(a) < biggestUInt(b); result := biggestUInt(a) < biggestUInt(b);

View file

@ -31,10 +31,10 @@ const
//cog.outl('VersionMinor = %s;' % ver[1]) //cog.outl('VersionMinor = %s;' % ver[1])
//cog.outl('VersionPatch = %s;' % ver[2]) //cog.outl('VersionPatch = %s;' % ver[2])
//]]] //]]]
VersionAsString = '0.7.2'; VersionAsString = '0.7.4';
VersionMajor = 0; VersionMajor = 0;
VersionMinor = 7; VersionMinor = 7;
VersionPatch = 2; VersionPatch = 4;
//[[[[end]]]] //[[[[end]]]]
implementation implementation

View file

@ -1,34 +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 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

@ -201,6 +201,12 @@ begin
if startsWith(dir, prefix) then begin if startsWith(dir, prefix) then begin
result := ncopy(dir, length(prefix) + strStart); exit result := ncopy(dir, length(prefix) + strStart); exit
end; end;
prefix := projectPath +{&} dirSep;
//writeln(output, prefix);
//writeln(output, dir);
if startsWith(dir, prefix) then begin
result := ncopy(dir, length(prefix) + strStart); exit
end;
result := dir result := dir
end; end;
@ -209,7 +215,7 @@ var
head, tail: string; head, tail: string;
begin begin
splitPath(path, head, tail); splitPath(path, head, tail);
result := joinPath([projectPath, genSubDir, shortenDir(head), result := joinPath([projectPath, genSubDir, shortenDir(head +{&} dirSep),
changeFileExt(tail, ext)]) changeFileExt(tail, ext)])
end; end;
@ -219,9 +225,11 @@ var
head, tail, subdir: string; head, tail, subdir: string;
begin begin
splitPath(f, head, tail); splitPath(f, head, tail);
subdir := joinPath([projectPath, genSubDir, shortenDir(head)]); subdir := joinPath([projectPath, genSubDir, shortenDir(head +{&} dirSep)]);
if createSubDir then if createSubDir then begin
//Writeln(output, subdir);
createDir(subdir); createDir(subdir);
end;
result := joinPath(subdir, tail) result := joinPath(subdir, tail)
end; end;

View file

@ -51,7 +51,7 @@ begin
else begin else begin
result.cmd := ''; result.cmd := '';
for i := 1 to ParamCount() do for i := 1 to ParamCount() do
result.cmd := result.cmd +{&} quoteIfSpaceExists(paramStr(i)) +{&} ' '; result.cmd := result.cmd +{&} quoteIfContainsWhite(paramStr(i)) +{&} ' ';
{@ignore} {@ignore}
result.cmd := result.cmd + #0; result.cmd := result.cmd + #0;
{@emit} {@emit}

View file

@ -14,7 +14,7 @@ unit passaux;
interface interface
uses uses
nsystem, strutils, ast, passes, msgs, options; nsystem, strutils, ast, astalgo, passes, msgs, options;
function verbosePass: TPass; function verbosePass: TPass;
function cleanupPass: TPass; function cleanupPass: TPass;
@ -50,6 +50,8 @@ var
s: PSym; s: PSym;
begin begin
result := n; result := n;
// we cannot clean up if dead code elimination is activated
if (optDeadCodeElim in gGlobalOptions) then exit;
case n.kind of case n.kind of
nkStmtList: begin nkStmtList: begin
for i := 0 to sonsLen(n)-1 do {@discard} cleanup(c, n.sons[i]); for i := 0 to sonsLen(n)-1 do {@discard} cleanup(c, n.sons[i]);
@ -57,7 +59,8 @@ begin
nkProcDef: begin nkProcDef: begin
if (n.sons[namePos].kind = nkSym) then begin if (n.sons[namePos].kind = nkSym) then begin
s := n.sons[namePos].sym; s := n.sons[namePos].sym;
if not astNeeded(s) then s.ast.sons[codePos] := nil; // free the memory if not (sfDeadCodeElim in getModule(s).flags) and
not astNeeded(s) then s.ast.sons[codePos] := nil; // free the memory
end end
end end
else begin end; else begin end;

View file

@ -23,7 +23,7 @@ uses
type type
TSystemOS = ( TSystemOS = (
// Also add OS for in initialization section and alias conditionals to // Also add OS in initialization section and alias conditionals to
// condsyms (end of module). // condsyms (end of module).
osNone, osNone,
osDos, osDos,
@ -264,8 +264,8 @@ const
curDir: '.'+''; curDir: '.'+'';
exeExt: ''; exeExt: '';
extSep: '.'+''; extSep: '.'+'';
props: {@set}[ospNeedsPIC, ospPosix]; props: {@set}[ospNeedsPIC, ospPosix];
), ),
( (
name: 'PalmOS'; name: 'PalmOS';
parDir: '..'; parDir: '..';

View file

@ -9,7 +9,7 @@
unit pnimsyn; unit pnimsyn;
// This module implements the parser of the standard Nimrod representation. // This module implements the parser of the standard Nimrod representation.
// The parser is strictly reflects the grammar ("doc/grammar.txt"); however // The parser strictly reflects the grammar ("doc/grammar.txt"); however
// it uses several helper routines to keep the parser small. A special // it uses several helper routines to keep the parser small. A special
// efficient algorithm is used for the precedence levels. The parser here can // efficient algorithm is used for the precedence levels. The parser here can
// be seen as a refinement of the grammar, as it specifies how the AST is build // be seen as a refinement of the grammar, as it specifies how the AST is build
@ -98,15 +98,21 @@ end;
// ---------------- parser helpers -------------------------------------------- // ---------------- parser helpers --------------------------------------------
procedure parMessage(const p: TParser; const msg: TMsgKind;
const arg: string = '');
begin
lexMessage(p.lex^, msg, arg);
end;
procedure skipComment(var p: TParser; node: PNode); procedure skipComment(var p: TParser; node: PNode);
begin begin
if p.tok.tokType = tkComment then begin if p.tok.tokType = tkComment then begin
if node <> nil then begin if node <> nil then begin
if node.comment = snil then node.comment := ''; if node.comment = snil then node.comment := '';
node.comment := node.comment +{&} p.tok.literal; add(node.comment, p.tok.literal);
end end
else else
assert(false); parMessage(p, errInternal, 'skipComment');
getTok(p); getTok(p);
end end
end; end;
@ -116,6 +122,11 @@ begin
if p.tok.tokType = tkInd then getTok(p) if p.tok.tokType = tkInd then getTok(p)
end; end;
procedure optSad(var p: TParser);
begin
if p.tok.tokType = tkSad then getTok(p)
end;
procedure optInd(var p: TParser; n: PNode); procedure optInd(var p: TParser; n: PNode);
begin begin
skipComment(p, n); skipComment(p, n);
@ -146,12 +157,6 @@ begin
else lexMessage(p.lex^, errTokenExpected, TokTypeToStr[tokType]) else lexMessage(p.lex^, errTokenExpected, TokTypeToStr[tokType])
end; end;
procedure parMessage(const p: TParser; const msg: TMsgKind;
const arg: string = '');
begin
lexMessage(p.lex^, msg, arg);
end;
function parLineInfo(const p: TParser): TLineInfo; function parLineInfo(const p: TParser): TLineInfo;
begin begin
result := getLineInfo(p.lex^) result := getLineInfo(p.lex^)
@ -385,7 +390,7 @@ begin
result := newNodeP(nkExprEqExpr, p); result := newNodeP(nkExprEqExpr, p);
addSon(result, a); addSon(result, a);
getTok(p); getTok(p);
optInd(p, result); //optInd(p, result);
case p.tok.tokType of case p.tok.tokType of
tkVar, tkRef, tkPtr, tkProc: tkVar, tkRef, tkPtr, tkProc:
addSon(result, parseTypeDescK(p)); addSon(result, parseTypeDescK(p));
@ -413,21 +418,16 @@ begin
addSon(result, first); addSon(result, first);
getTok(p); getTok(p);
optInd(p, result); optInd(p, result);
while true do begin while (p.tok.tokType <> tkBracketRi) and (p.tok.tokType <> tkEof)
if p.tok.tokType = tkBracketRi then begin and (p.tok.tokType <> tkSad) do begin
getTok(p); break
end;
if p.tok.tokType = tkEof then begin
parMessage(p, errTokenExpected, TokTypeToStr[tkBracketRi]); break
end;
a := namedTypeOrExpr(p); a := namedTypeOrExpr(p);
optInd(p, a);
if p.tok.tokType = tkComma then begin
getTok(p);
optInd(p, a)
end;
addSon(result, a); addSon(result, a);
if p.tok.tokType <> tkComma then break;
getTok(p);
optInd(p, a)
end; end;
optSad(p);
eat(p, tkBracketRi);
end; end;
function exprColonEqExpr(var p: TParser; kind: TNodeKind; function exprColonEqExpr(var p: TParser; kind: TNodeKind;
@ -439,7 +439,7 @@ begin
if p.tok.tokType = tok then begin if p.tok.tokType = tok then begin
result := newNodeP(kind, p); result := newNodeP(kind, p);
getTok(p); getTok(p);
optInd(p, result); //optInd(p, result);
addSon(result, a); addSon(result, a);
addSon(result, parseExpr(p)); addSon(result, parseExpr(p));
end end
@ -454,21 +454,14 @@ var
begin begin
getTok(p); getTok(p);
optInd(p, result); optInd(p, result);
while true do begin while (p.tok.tokType <> endTok) and (p.tok.tokType <> tkEof) do begin
if p.tok.tokType = endTok then begin
getTok(p); break
end;
if p.tok.tokType = tkEof then begin
parMessage(p, errTokenExpected, TokTypeToStr[endtok]); break
end;
a := exprColonEqExpr(p, elemKind, sepTok); a := exprColonEqExpr(p, elemKind, sepTok);
optInd(p, a);
if p.tok.tokType = tkComma then begin
getTok(p);
optInd(p, a)
end;
addSon(result, a); addSon(result, a);
if p.tok.tokType <> tkComma then break;
getTok(p);
optInd(p, a)
end; end;
eat(p, endTok);
end; end;
function qualifiedIdent(var p: TParser): PNode; function qualifiedIdent(var p: TParser): PNode;
@ -476,7 +469,7 @@ var
a: PNode; a: PNode;
begin begin
result := parseSymbol(p); result := parseSymbol(p);
optInd(p, result); //optInd(p, result);
if p.tok.tokType = tkDot then begin if p.tok.tokType = tkDot then begin
getTok(p); getTok(p);
optInd(p, result); optInd(p, result);
@ -494,28 +487,41 @@ var
begin begin
getTok(p); getTok(p);
optInd(p, result); optInd(p, result);
while true do begin while (p.tok.tokType <> endTok) and (p.tok.tokType <> tkEof) do begin
if p.tok.tokType = endTok then begin
getTok(p); break
end;
if p.tok.tokType = tkEof then begin
parMessage(p, errTokenExpected, TokTypeToStr[endtok]); break
end;
a := qualifiedIdent(p); a := qualifiedIdent(p);
optInd(p, a);
if p.tok.tokType = tkComma then begin
getTok(p);
optInd(p, a)
end;
addSon(result, a); addSon(result, a);
//optInd(p, a);
if p.tok.tokType <> tkComma then break;
getTok(p);
optInd(p, a)
end; end;
eat(p, endTok);
end;
procedure exprColonEqExprListAux(var p: TParser; elemKind: TNodeKind;
endTok, sepTok: TTokType; result: PNode);
var
a: PNode;
begin
getTok(p);
optInd(p, result);
while (p.tok.tokType <> endTok) and (p.tok.tokType <> tkEof)
and (p.tok.tokType <> tkSad) do begin
a := exprColonEqExpr(p, elemKind, sepTok);
addSon(result, a);
if p.tok.tokType <> tkComma then break;
getTok(p);
optInd(p, a)
end;
optSad(p);
eat(p, endTok);
end; end;
function exprColonEqExprList(var p: TParser; kind, elemKind: TNodeKind; function exprColonEqExprList(var p: TParser; kind, elemKind: TNodeKind;
endTok, sepTok: TTokType): PNode; endTok, sepTok: TTokType): PNode;
begin begin
result := newNodeP(kind, p); result := newNodeP(kind, p);
exprListAux(p, elemKind, endTok, sepTok, result); exprColonEqExprListAux(p, elemKind, endTok, sepTok, result);
end; end;
function parseCast(var p: TParser): PNode; function parseCast(var p: TParser): PNode;
@ -525,12 +531,12 @@ begin
eat(p, tkBracketLe); eat(p, tkBracketLe);
optInd(p, result); optInd(p, result);
addSon(result, parseTypeDesc(p)); addSon(result, parseTypeDesc(p));
optInd(p, result); optSad(p);
eat(p, tkBracketRi); eat(p, tkBracketRi);
eat(p, tkParLe); eat(p, tkParLe);
optInd(p, result); optInd(p, result);
addSon(result, parseExpr(p)); addSon(result, parseExpr(p));
optInd(p, result); optSad(p);
eat(p, tkParRi); eat(p, tkParRi);
end; end;
@ -541,7 +547,7 @@ begin
eat(p, tkParLe); eat(p, tkParLe);
optInd(p, result); optInd(p, result);
addSon(result, parseExpr(p)); addSon(result, parseExpr(p));
optInd(p, result); optSad(p);
eat(p, tkParRi); eat(p, tkParRi);
end; end;
@ -667,7 +673,7 @@ begin
a := result; a := result;
result := newNodeP(nkCall, p); result := newNodeP(nkCall, p);
addSon(result, a); addSon(result, a);
exprListAux(p, nkExprEqExpr, tkParRi, tkEquals, result); exprColonEqExprListAux(p, nkExprEqExpr, tkParRi, tkEquals, result);
end; end;
tkDot: begin tkDot: begin
a := result; a := result;
@ -709,8 +715,9 @@ begin
opNode := newIdentNodeP(op.ident, p); opNode := newIdentNodeP(op.ident, p);
// skip operator: // skip operator:
getTok(p); getTok(p);
skipComment(p, opNode); //skipComment(p, opNode);
skipInd(p); //skipInd(p);
optInd(p, opNode);
// read sub-expression with higher priority // read sub-expression with higher priority
nextop := lowestExprAux(p, v2, opPred); nextop := lowestExprAux(p, v2, opPred);
@ -739,12 +746,12 @@ begin
while true do begin while true do begin
getTok(p); // skip `if`, `elif` getTok(p); // skip `if`, `elif`
branch := newNodeP(nkElifExpr, p); branch := newNodeP(nkElifExpr, p);
optInd(p, branch); //optInd(p, branch);
addSon(branch, parseExpr(p)); addSon(branch, parseExpr(p));
eat(p, tkColon); eat(p, tkColon);
optInd(p, branch); //optInd(p, branch);
addSon(branch, parseExpr(p)); addSon(branch, parseExpr(p));
optInd(p, branch); //optInd(p, branch);
addSon(result, branch); addSon(result, branch);
if p.tok.tokType <> tkElif then break if p.tok.tokType <> tkElif then break
end; end;
@ -770,31 +777,33 @@ var
begin begin
result := newNodeP(nkPragma, p); result := newNodeP(nkPragma, p);
getTok(p); getTok(p);
while true do begin optInd(p, result);
skipComment(p, result); while (p.tok.tokType <> tkCurlyDotRi) and (p.tok.tokType <> tkCurlyRi)
skipInd(p); and (p.tok.tokType <> tkEof) and (p.tok.tokType <> tkSad) do begin
case p.tok.TokType of a := exprColonEqExpr(p, nkExprColonExpr, tkColon);
tkCurlyDotRi, tkCurlyRi: begin addSon(result, a);
getTok(p); // skip } or .} if p.tok.tokType = tkComma then begin
break getTok(p);
end; optInd(p, a)
tkEof: begin
parMessage(p, errTokenExpected, '.}');
break
end
else begin
a := exprColonEqExpr(p, nkExprColonExpr, tkColon);
addSon(result, a);
if p.tok.tokType = tkComma then begin
getTok(p);
skipComment(p, a)
end
end
end end
end end;
optSad(p);
if (p.tok.tokType = tkCurlyDotRi) or (p.tok.tokType = tkCurlyRi) then
getTok(p)
else
parMessage(p, errTokenExpected, '.}');
end; end;
// ---------------------- statement parser ------------------------------------ // ---------------------- statement parser ------------------------------------
function isExprStart(const p: TParser): bool;
begin
case p.tok.tokType of
tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkLambda,
tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit: result := true;
else result := false;
end;
end;
function parseExprStmt(var p: TParser): PNode; function parseExprStmt(var p: TParser): PNode;
var var
a, b, e: PNode; a, b, e: PNode;
@ -813,16 +822,16 @@ begin
result.info := a.info; result.info := a.info;
addSon(result, a); addSon(result, a);
while true do begin while true do begin
case p.tok.tokType of (*case p.tok.tokType of
tkColon, tkInd, tkSad, tkDed, tkEof, tkComment: break; tkColon, tkInd, tkSad, tkDed, tkEof, tkComment: break;
else begin end else begin end
end; end;*)
if not isExprStart(p) then break;
e := parseExpr(p); e := parseExpr(p);
if p.tok.tokType = tkComma then begin
getTok(p);
skipComment(p, e)
end;
addSon(result, e); addSon(result, e);
if p.tok.tokType <> tkComma then break;
getTok(p);
optInd(p, a);
end; end;
if sonsLen(result) <= 1 then result := a if sonsLen(result) <= 1 then result := a
else a := result; else a := result;
@ -897,7 +906,7 @@ begin
break break
end; end;
end; end;
optInd(p, a); //optInd(p, a);
if p.tok.tokType = tkAs then begin if p.tok.tokType = tkAs then begin
getTok(p); getTok(p);
optInd(p, a); optInd(p, a);
@ -906,11 +915,10 @@ begin
addSon(a, b); addSon(a, b);
addSon(a, parseSymbol(p)); addSon(a, parseSymbol(p));
end; end;
if p.tok.tokType = tkComma then begin
getTok(p);
optInd(p, a)
end;
addSon(result, a); addSon(result, a);
if p.tok.tokType <> tkComma then break;
getTok(p);
optInd(p, a)
end; end;
end; end;
@ -942,12 +950,11 @@ begin
break break
end; end;
end; end;
optInd(p, a);
if p.tok.tokType = tkComma then begin
getTok(p);
optInd(p, a)
end;
addSon(result, a); addSon(result, a);
//optInd(p, a);
if p.tok.tokType <> tkComma then break;
getTok(p);
optInd(p, a)
end; end;
end; end;
@ -977,7 +984,7 @@ begin
end end
end; end;
addSon(result, a); addSon(result, a);
optInd(p, a); //optInd(p, a);
eat(p, tkImport); eat(p, tkImport);
optInd(p, result); optInd(p, result);
while true do begin while true do begin
@ -989,12 +996,11 @@ begin
break break
end; end;
end; end;
optInd(p, a); //optInd(p, a);
if p.tok.tokType = tkComma then begin
getTok(p);
optInd(p, a)
end;
addSon(result, a); addSon(result, a);
if p.tok.tokType <> tkComma then break;
getTok(p);
optInd(p, a)
end; end;
end; end;
@ -1074,6 +1080,7 @@ begin
result := newNodeP(nkCaseStmt, p); result := newNodeP(nkCaseStmt, p);
getTok(p); getTok(p);
addSon(result, parseExpr(p)); addSon(result, parseExpr(p));
if p.tok.tokType = tkColon then getTok(p);
skipComment(p, result); skipComment(p, result);
inElif := false; inElif := false;
while true do begin while true do begin
@ -1145,22 +1152,15 @@ begin
result := newNodeP(nkForStmt, p); result := newNodeP(nkForStmt, p);
getTok(p); getTok(p);
optInd(p, result); optInd(p, result);
while true do begin a := parseSymbol(p);
if p.tok.tokType = tkIn then begin addSon(result, a);
getTok(p); break while p.tok.tokType = tkComma do begin
end; getTok(p);
if p.tok.tokType = tkEof then begin
parMessage(p, errTokenExpected, TokTypeToStr[tkIn]); break
end;
a := parseSymbol(p);
if a = nil then break;
optInd(p, a); optInd(p, a);
if p.tok.tokType = tkComma then begin a := parseSymbol(p);
getTok(p); optInd(p, a) addSon(result, a);
end;
addSon(result, a);
end; end;
eat(p, tkIn);
addSon(result, exprColonEqExpr(p, nkRange, tkDotDot)); addSon(result, exprColonEqExpr(p, nkRange, tkDotDot));
eat(p, tkColon); eat(p, tkColon);
skipComment(p, result); skipComment(p, result);
@ -1246,12 +1246,11 @@ begin
if a = nil then exit; if a = nil then exit;
end end
end; end;
optInd(p, a);
if p.tok.tokType = tkComma then begin
getTok(p);
optInd(p, a)
end;
addSon(result, a); addSon(result, a);
//optInd(p, a);
if p.tok.tokType <> tkComma then break;
getTok(p);
optInd(p, a)
end; end;
if p.tok.tokType = tkColon then begin if p.tok.tokType = tkColon then begin
getTok(p); optInd(p, result); getTok(p); optInd(p, result);
@ -1282,15 +1281,17 @@ begin
while true do begin while true do begin
case p.tok.tokType of case p.tok.tokType of
tkSymbol, tkAccent: a := parseIdentColonEquals(p, false); tkSymbol, tkAccent: a := parseIdentColonEquals(p, false);
tkParRi: begin getTok(p); break end; tkParRi: break;
else begin parMessage(p, errTokenExpected, ')'+''); break; end; else begin parMessage(p, errTokenExpected, ')'+''); break; end;
end; end;
optInd(p, a); //optInd(p, a);
if p.tok.tokType = tkComma then begin
getTok(p); optInd(p, a)
end;
addSon(result, a); addSon(result, a);
if p.tok.tokType <> tkComma then break;
getTok(p);
optInd(p, a)
end; end;
optSad(p);
eat(p, tkParRi);
end; end;
if p.tok.tokType = tkColon then begin if p.tok.tokType = tkColon then begin
getTok(p); getTok(p);
@ -1336,18 +1337,15 @@ begin
getTok(p); getTok(p);
eat(p, tkBracketLe); eat(p, tkBracketLe);
optInd(p, result); optInd(p, result);
while true do begin while (p.tok.tokType = tkSymbol) or (p.tok.tokType = tkAccent) do begin
case p.tok.tokType of a := parseIdentColonEquals(p, false);
tkSymbol, tkAccent: a := parseIdentColonEquals(p, false); addSon(result, a);
tkBracketRi: begin getTok(p); break end; if p.tok.tokType <> tkComma then break;
else begin parMessage(p, errTokenExpected, ']'+''); break; end; getTok(p);
end; optInd(p, a)
optInd(p, a);
if p.tok.tokType = tkComma then begin
getTok(p); optInd(p, a)
end;
addSon(result, a);
end; end;
optSad(p);
eat(p, tkBracketRi);
end; end;
else begin else begin
InternalError(parLineInfo(p), 'pnimsyn.parseTypeDescK'); InternalError(parLineInfo(p), 'pnimsyn.parseTypeDescK');
@ -1389,18 +1387,15 @@ begin
result := newNodeP(nkGenericParams, p); result := newNodeP(nkGenericParams, p);
getTok(p); getTok(p);
optInd(p, result); optInd(p, result);
while true do begin while (p.tok.tokType = tkSymbol) or (p.tok.tokType = tkAccent) do begin
case p.tok.tokType of a := parseGenericParam(p);
tkSymbol, tkAccent: a := parseGenericParam(p);
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); addSon(result, a);
if p.tok.tokType <> tkComma then break;
getTok(p);
optInd(p, a)
end; end;
optSad(p);
eat(p, tkBracketRi);
end; end;
function parseRoutine(var p: TParser; kind: TNodeKind): PNode; function parseRoutine(var p: TParser; kind: TNodeKind): PNode;
@ -1484,7 +1479,8 @@ begin
break break
end end
end end
end end;
popInd(p.lex^);
end; end;
tkSymbol, tkAccent: addSon(result, defparser(p)); tkSymbol, tkAccent: addSon(result, defparser(p));
else parMessage(p, errIdentifierExpected, tokToStr(p.tok)); else parMessage(p, errIdentifierExpected, tokToStr(p.tok));
@ -1628,7 +1624,8 @@ begin
break break
end end
end end
end end;
popInd(p.lex^);
end; end;
tkWhen: result := parseRecordWhen(p); tkWhen: result := parseRecordWhen(p);
tkCase: result := parseRecordCase(p); tkCase: result := parseRecordCase(p);
@ -1688,9 +1685,34 @@ begin
indAndComment(p, result); // special extension! indAndComment(p, result); // special extension!
end; end;
function parseVarTuple(var p: TParser): PNode;
var
a: PNode;
begin
result := newNodeP(nkVarTuple, p);
getTok(p); // skip '('
optInd(p, result);
while (p.tok.tokType = tkSymbol) or (p.tok.tokType = tkAccent) do begin
a := identWithPragma(p);
addSon(result, a);
if p.tok.tokType <> tkComma then break;
getTok(p);
optInd(p, a)
end;
addSon(result, nil); // no type desc
optSad(p);
eat(p, tkParRi);
eat(p, tkEquals);
optInd(p, result);
addSon(result, parseExpr(p));
end;
function parseVariable(var p: TParser): PNode; function parseVariable(var p: TParser): PNode;
begin begin
result := parseIdentColonEquals(p, true); if p.tok.tokType = tkParLe then
result := parseVarTuple(p)
else
result := parseIdentColonEquals(p, true);
indAndComment(p, result); // special extension! indAndComment(p, result); // special extension!
end; end;
@ -1708,10 +1730,15 @@ begin
tkFrom: result := parseFromStmt(p); tkFrom: result := parseFromStmt(p);
tkInclude: result := parseIncludeStmt(p); tkInclude: result := parseIncludeStmt(p);
tkComment: result := newCommentStmt(p); tkComment: result := newCommentStmt(p);
//tkSad, tkInd, tkDed: assert(false); else begin
else result := parseExprStmt(p) if isExprStart(p) then
result := parseExprStmt(p)
else
result := nil;
end
end; end;
skipComment(p, result); if result <> nil then
skipComment(p, result);
end; end;
function complexOrSimpleStmt(var p: TParser): PNode; function complexOrSimpleStmt(var p: TParser): PNode;
@ -1738,6 +1765,8 @@ begin
end; end;
function parseStmt(var p: TParser): PNode; function parseStmt(var p: TParser): PNode;
var
a: PNode;
begin begin
if p.tok.tokType = tkInd then begin if p.tok.tokType = tkInd then begin
result := newNodeP(nkStmtList, p); result := newNodeP(nkStmtList, p);
@ -1748,9 +1777,14 @@ begin
tkSad: getTok(p); tkSad: getTok(p);
tkEof: break; tkEof: break;
tkDed: begin getTok(p); break end; tkDed: begin getTok(p); break end;
else addSon(result, complexOrSimpleStmt(p)); else begin
end; a := complexOrSimpleStmt(p);
end if a = nil then break;
addSon(result, a);
end
end
end;
popInd(p.lex^);
end end
else begin else begin
// the case statement is only needed for better error messages: // the case statement is only needed for better error messages:
@ -1762,7 +1796,7 @@ begin
end end
else begin else begin
result := simpleStmt(p); result := simpleStmt(p);
skipComment(p, result); if result = nil then parMessage(p, errExprExpected, tokToStr(p.tok));
if p.tok.tokType = tkSad then getTok(p); if p.tok.tokType = tkSad then getTok(p);
end end
end end
@ -1770,6 +1804,8 @@ begin
end; end;
function parseModule(var p: TParser): PNode; function parseModule(var p: TParser): PNode;
var
a: PNode;
begin begin
result := newNodeP(nkStmtList, p); result := newNodeP(nkStmtList, p);
while true do begin while true do begin
@ -1777,7 +1813,11 @@ begin
tkSad: getTok(p); tkSad: getTok(p);
tkDed, tkInd: parMessage(p, errInvalidIndentation); tkDed, tkInd: parMessage(p, errInvalidIndentation);
tkEof: break; tkEof: break;
else addSon(result, complexOrSimpleStmt(p)); else begin
a := complexOrSimpleStmt(p);
if a = nil then parMessage(p, errExprExpected, tokToStr(p.tok));
addSon(result, a);
end
end end
end end
end; end;
@ -1795,6 +1835,7 @@ begin
tkEof: break; tkEof: break;
else begin else begin
result := complexOrSimpleStmt(p); result := complexOrSimpleStmt(p);
if result = nil then parMessage(p, errExprExpected, tokToStr(p.tok));
break break
end end
end end

View file

@ -135,8 +135,8 @@ var
v: string; v: string;
m: TMagic; m: TMagic;
begin begin
if not (sfSystemModule in c.module.flags) then //if not (sfSystemModule in c.module.flags) then
liMessage(n.info, errMagicOnlyInSystem); // liMessage(n.info, errMagicOnlyInSystem);
if n.kind <> nkExprColonExpr then if n.kind <> nkExprColonExpr then
liMessage(n.info, errStringLiteralExpected); liMessage(n.info, errStringLiteralExpected);
if n.sons[1].kind = nkIdent then v := n.sons[1].ident.s if n.sons[1].kind = nkIdent then v := n.sons[1].ident.s
@ -172,6 +172,19 @@ begin
liMessage(n.info, errOnOrOffExpected) liMessage(n.info, errOnOrOffExpected)
end; end;
procedure pragmaDeadCodeElim(c: PContext; n: PNode);
begin
if (n.kind = nkExprColonExpr) and (n.sons[1].kind = nkIdent) then begin
case whichKeyword(n.sons[1].ident) of
wOn: include(c.module.flags, sfDeadCodeElim);
wOff: exclude(c.module.flags, sfDeadCodeElim);
else liMessage(n.info, errOnOrOffExpected)
end
end
else
liMessage(n.info, errOnOrOffExpected)
end;
procedure processCallConv(c: PContext; n: PNode); procedure processCallConv(c: PContext; n: PNode);
var var
sw: TSpecialWord; sw: TSpecialWord;
@ -466,6 +479,7 @@ begin
wVolatile: begin noVal(it); Include(sym.flags, sfVolatile); end; wVolatile: begin noVal(it); Include(sym.flags, sfVolatile); end;
wRegister: begin noVal(it); include(sym.flags, sfRegister); end; wRegister: begin noVal(it); include(sym.flags, sfRegister); end;
wThreadVar: begin noVal(it); include(sym.flags, sfThreadVar); end; wThreadVar: begin noVal(it); include(sym.flags, sfThreadVar); end;
wDeadCodeElim: pragmaDeadCodeElim(c, it);
wMagic: processMagic(c, it, sym); wMagic: processMagic(c, it, sym);
wCompileTime: begin wCompileTime: begin
noVal(it); noVal(it);
@ -612,7 +626,7 @@ begin
wHint, wWarning, wError, wFatal, wDefine, wUndef, wHint, wWarning, wError, wFatal, wDefine, wUndef,
wCompile, wLink, wLinkSys, wPure, wCompile, wLink, wLinkSys, wPure,
wPush, wPop, wFixupSystem, wBreakpoint, wCheckpoint, wPush, wPop, wFixupSystem, wBreakpoint, wCheckpoint,
wPassL, wPassC]); wPassL, wPassC, wDeadCodeElim]);
end; end;
procedure pragmaLambda(c: PContext; s: PSym; n: PNode); procedure pragmaLambda(c: PContext; s: PSym; n: PNode);

View file

@ -21,7 +21,7 @@ uses
type type
TRenderFlag = (renderNone, renderNoBody, renderNoComments, TRenderFlag = (renderNone, renderNoBody, renderNoComments,
renderNoPragmas, renderIds); renderDocComments, renderNoPragmas, renderIds);
TRenderFlags = set of TRenderFlag; TRenderFlags = set of TRenderFlag;
TRenderTok = record TRenderTok = record
@ -354,12 +354,20 @@ end;
const const
Space = ' '+''; Space = ' '+'';
function shouldRenderComment(var g: TSrcGen; n: PNode): bool;
begin
result := false;
if n.comment <> snil then
result := not (renderNoComments in g.flags) or
(renderDocComments in g.flags) and startsWith(n.comment, '##');
end;
procedure gcom(var g: TSrcGen; n: PNode); procedure gcom(var g: TSrcGen; n: PNode);
var var
ml: int; ml: int;
begin begin
assert(n <> nil); assert(n <> nil);
if (n.comment <> snil) and not (renderNoComments in g.flags) then begin if shouldRenderComment(g, n) then begin
if (g.pendingNL < 0) and (length(g.buf) > 0) if (g.pendingNL < 0) and (length(g.buf) > 0)
and (g.buf[length(g.buf)] <> ' ') then and (g.buf[length(g.buf)] <> ' ') then
put(g, tkSpaces, Space); put(g, tkSpaces, Space);
@ -488,7 +496,7 @@ begin
nkAddr: result := lsub(n.sons[0])+length('addr()'); nkAddr: result := lsub(n.sons[0])+length('addr()');
nkHiddenAddr, nkHiddenDeref: result := lsub(n.sons[0]); nkHiddenAddr, nkHiddenDeref: result := lsub(n.sons[0]);
nkCommand: result := lsub(n.sons[0])+lcomma(n, 1)+1; nkCommand: result := lsub(n.sons[0])+lcomma(n, 1)+1;
nkExprEqExpr, nkDefaultTypeParam, nkAsgn: result := lsons(n)+3; nkExprEqExpr, nkDefaultTypeParam, nkAsgn, nkFastAsgn: result := lsons(n)+3;
nkPar, nkCurly, nkBracket: result := lcomma(n)+2; nkPar, nkCurly, nkBracket: result := lcomma(n)+2;
nkTupleTy: result := lcomma(n)+length('tuple[]'); nkTupleTy: result := lcomma(n)+length('tuple[]');
nkQualified, nkDotExpr: result := lsons(n)+1; nkQualified, nkDotExpr: result := lsons(n)+1;
@ -502,11 +510,12 @@ begin
if n.sons[L-1] <> nil then if n.sons[L-1] <> nil then
result := result + lsub(n.sons[L-1]) + 3; result := result + lsub(n.sons[L-1]) + 3;
end; end;
nkVarTuple: result := lcomma(n, 0, -3) + length('() = ') + lsub(lastSon(n));
nkChckRangeF: result := length('chckRangeF') + 2 + lcomma(n); nkChckRangeF: result := length('chckRangeF') + 2 + lcomma(n);
nkChckRange64: result := length('chckRange64') + 2 + lcomma(n); nkChckRange64: result := length('chckRange64') + 2 + lcomma(n);
nkChckRange: result := length('chckRange') + 2 + lcomma(n); nkChckRange: result := length('chckRange') + 2 + lcomma(n);
nkObjDownConv, nkObjUpConv, nkObjDownConv, nkObjUpConv,
nkStringToCString, nkCStringToString, nkPassAsOpenArray: begin nkStringToCString, nkCStringToString, nkPassAsOpenArray: begin
result := 2; result := 2;
if sonsLen(n) >= 1 then if sonsLen(n) >= 1 then
@ -981,7 +990,7 @@ begin
put(g, tkSpaces, space); put(g, tkSpaces, space);
gcomma(g, n, 1); gcomma(g, n, 1);
end; end;
nkExprEqExpr, nkDefaultTypeParam, nkAsgn: begin nkExprEqExpr, nkDefaultTypeParam, nkAsgn, nkFastAsgn: begin
gsub(g, n.sons[0]); gsub(g, n.sons[0]);
put(g, tkSpaces, Space); put(g, tkSpaces, Space);
putWithSpace(g, tkEquals, '='+''); putWithSpace(g, tkEquals, '='+'');
@ -997,7 +1006,7 @@ begin
put(g, tkSymbol, 'chckRange64'); put(g, tkSymbol, 'chckRange64');
put(g, tkParLe, '('+''); put(g, tkParLe, '('+'');
gcomma(g, n); gcomma(g, n);
put(g, tkParRi, ')'+''); put(g, tkParRi, ')'+'');
end; end;
nkChckRange: begin nkChckRange: begin
put(g, tkSymbol, 'chckRange'); put(g, tkSymbol, 'chckRange');
@ -1005,13 +1014,13 @@ begin
gcomma(g, n); gcomma(g, n);
put(g, tkParRi, ')'+''); put(g, tkParRi, ')'+'');
end; end;
nkObjDownConv, nkObjUpConv, nkObjDownConv, nkObjUpConv,
nkStringToCString, nkCStringToString, nkPassAsOpenArray: begin nkStringToCString, nkCStringToString, nkPassAsOpenArray: begin
if sonsLen(n) >= 1 then if sonsLen(n) >= 1 then
gsub(g, n.sons[0]); gsub(g, n.sons[0]);
put(g, tkParLe, '('+''); put(g, tkParLe, '('+'');
gcomma(g, n, 1); gcomma(g, n, 1);
put(g, tkParRi, ')'+''); put(g, tkParRi, ')'+'');
end; end;
nkPar: begin nkPar: begin
put(g, tkParLe, '('+''); put(g, tkParLe, '('+'');
@ -1056,6 +1065,14 @@ begin
gsub(g, n.sons[L-1], c) gsub(g, n.sons[L-1], c)
end; end;
end; end;
nkVarTuple: begin
put(g, tkParLe, '('+'');
gcomma(g, n, 0, -3);
put(g, tkParRi, ')'+'');
put(g, tkSpaces, Space);
putWithSpace(g, tkEquals, '='+'');
gsub(g, lastSon(n), c);
end;
nkExprColonExpr: begin nkExprColonExpr: begin
gsub(g, n.sons[0]); gsub(g, n.sons[0]);
putWithSpace(g, tkColon, ':'+''); putWithSpace(g, tkColon, ':'+'');
@ -1362,11 +1379,11 @@ begin
nkTupleTy: begin nkTupleTy: begin
put(g, tkTuple, 'tuple'); put(g, tkTuple, 'tuple');
put(g, tkBracketLe, '['+''); put(g, tkBracketLe, '['+'');
assert(n.sons[0].kind = nkIdentDefs);
gcomma(g, n); gcomma(g, n);
put(g, tkBracketRi, ']'+''); put(g, tkBracketRi, ']'+'');
end; end;
else begin else begin
//nkNone, nkMetaNode, nkTableConstr, nkExplicitTypeListCall: begin
InternalError(n.info, 'rnimsyn.gsub(' +{&} nodeKindToStr[n.kind] +{&} ')') InternalError(n.info, 'rnimsyn.gsub(' +{&} nodeKindToStr[n.kind] +{&} ')')
end end
end end

View file

@ -503,7 +503,7 @@ end;
function process(c: PPassContext; n: PNode): PNode; function process(c: PPassContext; n: PNode): PNode;
var var
i, j: int; i: int;
w: PRodWriter; w: PRodWriter;
a: PNode; a: PNode;
s: PSym; s: PSym;

View file

@ -14,7 +14,7 @@ unit ropes;
efficiently; especially concatenation is done in O(1) instead of O(N). efficiently; especially concatenation is done in O(1) instead of O(N).
Ropes make use a lazy evaluation: They are essentially concatenation Ropes make use a lazy evaluation: They are essentially concatenation
trees that are only flattened when converting to a native Nimrod trees that are only flattened when converting to a native Nimrod
string or when written to disk. The empty string is represented with a string or when written to disk. The empty string is represented by a
nil pointer. nil pointer.
A little picture makes everything clear: A little picture makes everything clear:
@ -541,7 +541,6 @@ begin
if (r.data <> snil) then begin if (r.data <> snil) then begin
if r.len > bufSize then if r.len > bufSize then
// A token bigger than 1 KB? - This cannot happen in reality. // A token bigger than 1 KB? - This cannot happen in reality.
// Well, at least I hope so. 1 KB did happen!
internalError('ropes: token too long'); internalError('ropes: token too long');
readBytes := readBuffer(bin, buf, r.len); readBytes := readBuffer(bin, buf, r.len);
result := (readBytes = r.len) // BUGFIX result := (readBytes = r.len) // BUGFIX

View file

@ -494,7 +494,13 @@ begin
if n.kind = rnLeaf then begin if n.kind = rnLeaf then begin
for i := strStart to length(n.text)+strStart-1 do begin for i := strStart to length(n.text)+strStart-1 do begin
case n.text[i] of case n.text[i] of
'a'..'z', '0'..'9': begin '0'..'9': begin
if b then begin addChar(r, '-'); b := false; end;
// BUGFIX: HTML id's cannot start with a digit
if length(r) = 0 then addChar(r, 'Z');
addChar(r, n.text[i])
end;
'a'..'z': begin
if b then begin addChar(r, '-'); b := false; end; if b then begin addChar(r, '-'); b := false; end;
addChar(r, n.text[i]) addChar(r, n.text[i])
end; end;
@ -1235,7 +1241,7 @@ begin
result := nil; result := nil;
if (p.tok[p.idx].kind = tkIndent) if (p.tok[p.idx].kind = tkIndent)
and (p.tok[p.idx+1].symbol = ':'+'') then begin and (p.tok[p.idx+1].symbol = ':'+'') then begin
col := p.tok[p.idx].col; col := p.tok[p.idx].ival; // BUGFIX!
result := newRstNode(rnFieldList); result := newRstNode(rnFieldList);
inc(p.idx); inc(p.idx);
while true do begin while true do begin
@ -1252,10 +1258,10 @@ var
i: int; i: int;
f: PRstNode; f: PRstNode;
begin begin
assert(n.kind = rnDirective);
result := ''; result := '';
if n.sons[1] = nil then exit; if n.sons[1] = nil then exit;
assert(n.sons[1].kind = rnFieldList); if (n.sons[1].kind <> rnFieldList) then
InternalError('getFieldValue (2): ' + rstnodeKindToStr[n.sons[1].kind]);
for i := 0 to rsonsLen(n.sons[1])-1 do begin for i := 0 to rsonsLen(n.sons[1])-1 do begin
f := n.sons[1].sons[i]; f := n.sons[1].sons[i];
if cmpIgnoreStyle(addNodes(f.sons[0]), fieldname) = 0 then begin if cmpIgnoreStyle(addNodes(f.sons[0]), fieldname) = 0 then begin

View file

@ -21,9 +21,8 @@ interface
{$include 'config.inc'} {$include 'config.inc'}
uses uses
charsets, nsystem, sysutils, charsets, nsystem, sysutils, hashes, options, msgs, strutils, platform,
hashes, options, msgs, strutils, platform, idents, idents, lexbase, llstream, wordrecg;
lexbase, llstream, wordrecg;
const const
MaxLineLength = 80; // lines longer than this lead to a warning MaxLineLength = 80; // lines longer than this lead to a warning
@ -31,7 +30,7 @@ const
numChars: TCharSet = ['0'..'9','a'..'z','A'..'Z']; numChars: TCharSet = ['0'..'9','a'..'z','A'..'Z'];
SymChars: TCharSet = ['a'..'z', 'A'..'Z', '0'..'9', #128..#255]; SymChars: TCharSet = ['a'..'z', 'A'..'Z', '0'..'9', #128..#255];
SymStartChars: TCharSet = ['a'..'z', 'A'..'Z', #128..#255]; SymStartChars: TCharSet = ['a'..'z', 'A'..'Z', #128..#255];
OpChars: TCharSet = ['+', '-', '*', '/', '<', '>', '!', '?', '^', '.', OpChars: TCharSet = ['+', '-', '*', '/', '\', '<', '>', '!', '?', '^', '.',
'|', '=', '%', '&', '$', '@', '~', #128..#255]; '|', '=', '%', '&', '$', '@', '~', #128..#255];
type type
@ -162,6 +161,8 @@ var
gLinesCompiled: int; // all lines that have been compiled gLinesCompiled: int; // all lines that have been compiled
procedure pushInd(var L: TLexer; indent: int); procedure pushInd(var L: TLexer; indent: int);
procedure popInd(var L: TLexer);
function isKeyword(kind: TTokType): boolean; function isKeyword(kind: TTokType): boolean;
procedure openLexer(out lex: TLexer; const filename: string; procedure openLexer(out lex: TLexer; const filename: string;
@ -206,6 +207,14 @@ begin
//writeln('push indent ', indent); //writeln('push indent ', indent);
end; end;
procedure popInd(var L: TLexer);
var
len: int;
begin
len := length(L.indentStack);
setLength(L.indentStack, len-1);
end;
function findIdent(const L: TLexer; indent: int): boolean; function findIdent(const L: TLexer; indent: int): boolean;
var var
i: int; i: int;
@ -809,13 +818,11 @@ begin
end; end;
dec(L.dedent); dec(L.dedent);
tok.tokType := tkDed; tok.tokType := tkDed;
if i >= 0 then if i < 0 then begin
setLength(L.indentStack, i+1) // pop indentations
else begin
tok.tokType := tkSad; // for the parser it is better as SAD tok.tokType := tkSad; // for the parser it is better as SAD
lexMessage(L, errInvalidIndentation); lexMessage(L, errInvalidIndentation);
end end
end; end
end; end;
procedure scanComment(var L: TLexer; var tok: TToken); procedure scanComment(var L: TLexer; var tok: TToken);

View file

@ -76,6 +76,22 @@ function semStmt(c: PContext; n: PNode): PNode; forward;
function semConstExpr(c: PContext; n: PNode): PNode; function semConstExpr(c: PContext; n: PNode): PNode;
var var
e: PNode; e: PNode;
begin
e := semExprWithType(c, n);
if e = nil then begin
liMessage(n.info, errConstExprExpected);
result := nil; exit
end;
result := getConstExpr(c.module, e);
if result = nil then
liMessage(n.info, errConstExprExpected);
end;
function semAndEvalConstExpr(c: PContext; n: PNode): PNode;
var
e: PNode;
p: PEvalContext;
s: PStackFrame;
begin begin
e := semExprWithType(c, n); e := semExprWithType(c, n);
if e = nil then begin if e = nil then begin
@ -85,7 +101,14 @@ begin
result := getConstExpr(c.module, e); result := getConstExpr(c.module, e);
if result = nil then begin if result = nil then begin
//writeln(output, renderTree(n)); //writeln(output, renderTree(n));
liMessage(n.info, errConstExprExpected); p := newEvalContext(c.module, '');
s := newStackFrame();
s.call := e;
pushStackFrame(p, s);
result := eval(p, e);
popStackFrame(p);
if (result = nil) or (result.kind = nkEmpty) then
liMessage(n.info, errConstExprExpected);
end end
end; end;

View file

@ -43,6 +43,7 @@ type
PContext = ^TContext; PContext = ^TContext;
TContext = object(TPassContext) // a context represents a module TContext = object(TPassContext) // a context represents a module
module: PSym; // the module sym belonging to the context module: PSym; // the module sym belonging to the context
filename: string; // the module's filename
tab: TSymTab; // each module has its own symbol table tab: TSymTab; // each module has its own symbol table
AmbigiousSymbols: TIntSet; // contains ids of all ambigious symbols (cannot AmbigiousSymbols: TIntSet; // contains ids of all ambigious symbols (cannot
// store this info in the syms themselves!) // store this info in the syms themselves!)
@ -160,6 +161,7 @@ begin
result.module := module; result.module := module;
result.generics := newNode(nkStmtList); result.generics := newNode(nkStmtList);
{@emit result.converters := @[];} {@emit result.converters := @[];}
result.filename := nimfile;
end; end;
procedure addConverter(c: PContext; conv: PSym); procedure addConverter(c: PContext; conv: PSym);

View file

@ -36,9 +36,9 @@ var
diff: int; diff: int;
begin begin
diff := inheritanceDiff(castDest, src); diff := inheritanceDiff(castDest, src);
if diff = 0 then //if diff = 0 then
liMessage(info, hintConvToBaseNotNeeded) // liMessage(info, hintConvToBaseNotNeeded)
else if diff = high(int) then if diff = high(int) then
liMessage(info, errGenerated, liMessage(info, errGenerated,
format(MsgKindToString(errIllegalConvFromXtoY), format(MsgKindToString(errIllegalConvFromXtoY),
[typeToString(src), typeToString(castDest)])); [typeToString(src), typeToString(castDest)]));
@ -466,11 +466,11 @@ begin
if m.state <> csMatch then begin if m.state <> csMatch then begin
msg := msgKindToString(errTypeMismatch); msg := msgKindToString(errTypeMismatch);
for i := 1 to sonsLen(n)-1 do begin for i := 1 to sonsLen(n)-1 do begin
msg := msg +{&} typeToString(n.sons[i].typ); add(msg, typeToString(n.sons[i].typ));
if i <> sonsLen(n)-1 then msg := msg + ', '; if i <> sonsLen(n)-1 then add(msg, ', ');
end; end;
msg := msg +{&} ')' +{&} nl +{&} msgKindToString(errButExpected) +{&} add(msg, ')' +{&} nl +{&} msgKindToString(errButExpected) +{&}
nl +{&} typeToString(n.sons[0].typ); nl +{&} typeToString(n.sons[0].typ));
liMessage(n.Info, errGenerated, msg); liMessage(n.Info, errGenerated, msg);
result := nil result := nil
end end
@ -1117,7 +1117,7 @@ begin
if s <> nil then if s <> nil then
result := semSym(c, n, s, flags) result := semSym(c, n, s, flags)
else else
// test! // this is a test comment; please don't touch it
result := semFieldAccess(c, n, flags); result := semFieldAccess(c, n, flags);
end; end;

View file

@ -94,6 +94,25 @@ begin
end end
end; end;
function enumValToString(a: PNode): string;
var
n: PNode;
field: PSym;
x: biggestInt;
i: int;
begin
x := getInt(a);
n := a.typ.n;
for i := 0 to sonsLen(n)-1 do begin
if n.sons[i].kind <> nkSym then InternalError(a.info, 'enumValToString');
field := n.sons[i].sym;
if field.position = x then begin
result := field.name.s; exit
end;
end;
InternalError(a.info, 'no symbol for ordinal value: ' + toString(x));
end;
function evalOp(m: TMagic; n, a, b: PNode): PNode; function evalOp(m: TMagic; n, a, b: PNode): PNode;
// if this is an unary operation, b is nil // if this is an unary operation, b is nil
begin begin
@ -246,11 +265,18 @@ begin
// available for interpretation. I don't know how to fix this. // available for interpretation. I don't know how to fix this.
//result := newStrNodeT(renderTree(a, {@set}[renderNoComments]), n); //result := newStrNodeT(renderTree(a, {@set}[renderNoComments]), n);
end; end;
mIntToStr, mInt64ToStr, mBoolToStr, mCharToStr: mIntToStr, mInt64ToStr:
result := newStrNodeT(toString(getOrdValue(a)), n); result := newStrNodeT(toString(getOrdValue(a)), n);
mBoolToStr: begin
if getOrdValue(a) = 0 then
result := newStrNodeT('false', n)
else
result := newStrNodeT('true', n)
end;
mFloatToStr: result := newStrNodeT(toStringF(getFloat(a)), n); mFloatToStr: result := newStrNodeT(toStringF(getFloat(a)), n);
mCStrToStr: result := newStrNodeT(getStrOrChar(a), n); mCStrToStr, mCharToStr: result := newStrNodeT(getStrOrChar(a), n);
mStrToStr: result := a; mStrToStr: result := a;
mEnumToStr: result := newStrNodeT(enumValToString(a), n);
mArrToSeq: begin mArrToSeq: begin
result := copyTree(a); result := copyTree(a);
result.typ := n.typ; result.typ := n.typ;
@ -370,6 +396,10 @@ begin
mNimrodMinor: result := newIntNodeT(VersionMinor, n); mNimrodMinor: result := newIntNodeT(VersionMinor, n);
mNimrodPatch: result := newIntNodeT(VersionPatch, n); mNimrodPatch: result := newIntNodeT(VersionPatch, n);
mCpuEndian: result := newIntNodeT(ord(CPU[targetCPU].endian), n); mCpuEndian: result := newIntNodeT(ord(CPU[targetCPU].endian), n);
mHostOS:
result := newStrNodeT(toLower(platform.OS[targetOS].name), n);
mHostCPU:
result := newStrNodeT(toLower(platform.CPU[targetCPU].name),n);
mNaN: result := newFloatNodeT(NaN, n); mNaN: result := newFloatNodeT(NaN, n);
mInf: result := newFloatNodeT(Inf, n); mInf: result := newFloatNodeT(Inf, n);
mNegInf: result := newFloatNodeT(NegInf, n); mNegInf: result := newFloatNodeT(NegInf, n);

View file

@ -324,7 +324,7 @@ begin
a := newNodeI(nkAsgn, n.sons[0].info); a := newNodeI(nkAsgn, n.sons[0].info);
n.sons[0] := fitNode(c, restype, n.sons[0]); n.sons[0] := fitNode(c, restype, n.sons[0]);
// optimize away ``return result``, because it would be transferred // optimize away ``return result``, because it would be transformed
// to ``result = result; return``: // to ``result = result; return``:
if (n.sons[0].kind = nkSym) and (sfResult in n.sons[0].sym.flags) then if (n.sons[0].kind = nkSym) and (sfResult in n.sons[0].sym.flags) then
begin begin
@ -378,14 +378,14 @@ function semVar(c: PContext; n: PNode): PNode;
var var
i, j, len: int; i, j, len: int;
a, b, def: PNode; a, b, def: PNode;
typ: PType; typ, tup: PType;
v: PSym; v: PSym;
begin begin
result := copyNode(n); result := copyNode(n);
for i := 0 to sonsLen(n)-1 do begin for i := 0 to sonsLen(n)-1 do begin
a := n.sons[i]; a := n.sons[i];
if a.kind = nkCommentStmt then continue; if a.kind = nkCommentStmt then continue;
if (a.kind <> nkIdentDefs) then IllFormedAst(a); if (a.kind <> nkIdentDefs) and (a.kind <> nkVarTuple) then IllFormedAst(a);
checkMinSonsLen(a, 3); checkMinSonsLen(a, 3);
len := sonsLen(a); len := sonsLen(a);
if a.sons[len-2] <> nil then if a.sons[len-2] <> nil then
@ -401,14 +401,21 @@ begin
end end
else else
def := nil; def := nil;
tup := skipGeneric(typ);
if a.kind = nkVarTuple then begin
if tup.kind <> tyTuple then liMessage(a.info, errXExpected, 'tuple');
if len-2 <> sonsLen(tup) then
liMessage(a.info, errWrongNumberOfVariables);
end;
for j := 0 to len-3 do begin for j := 0 to len-3 do begin
if (c.p.owner = nil) then begin if c.p.owner = nil then begin
v := semIdentWithPragma(c, skVar, a.sons[j], {@set}[sfStar, sfMinus]); v := semIdentWithPragma(c, skVar, a.sons[j], {@set}[sfStar, sfMinus]);
include(v.flags, sfGlobal); include(v.flags, sfGlobal);
end end
else else
v := semIdentWithPragma(c, skVar, a.sons[j], {@set}[]); v := semIdentWithPragma(c, skVar, a.sons[j], {@set}[]);
v.typ := typ; if a.kind <> nkVarTuple then v.typ := typ
else v.typ := tup.sons[j];
if v.flags * [sfStar, sfMinus] <> {@set}[] then if v.flags * [sfStar, sfMinus] <> {@set}[] then
include(v.flags, sfInInterface); include(v.flags, sfInInterface);
addInterfaceDecl(c, v); addInterfaceDecl(c, v);
@ -443,7 +450,7 @@ begin
if a.sons[1] <> nil then typ := semTypeNode(c, a.sons[1], nil) if a.sons[1] <> nil then typ := semTypeNode(c, a.sons[1], nil)
else typ := nil; else typ := nil;
def := semConstExpr(c, a.sons[2]); def := semAndEvalConstExpr(c, a.sons[2]);
// check type compability between def.typ and typ: // check type compability between def.typ and typ:
if (typ <> nil) then begin if (typ <> nil) then begin
def := fitRemoveHiddenConv(c, typ, def); def := fitRemoveHiddenConv(c, typ, def);
@ -495,7 +502,7 @@ begin
iter := skipGeneric(n.sons[len-2].typ); iter := skipGeneric(n.sons[len-2].typ);
openScope(c.tab); openScope(c.tab);
if iter.kind <> tyTuple then begin if iter.kind <> tyTuple then begin
if len <> 3 then liMessage(n.info, errWrongNumberOfLoopVariables); if len <> 3 then liMessage(n.info, errWrongNumberOfVariables);
v := newSymS(skForVar, n.sons[0], c); v := newSymS(skForVar, n.sons[0], c);
v.typ := iter; v.typ := iter;
n.sons[0] := newSymNode(v); n.sons[0] := newSymNode(v);
@ -503,7 +510,7 @@ begin
end end
else begin else begin
if len-2 <> sonsLen(iter) then if len-2 <> sonsLen(iter) then
liMessage(n.info, errWrongNumberOfLoopVariables); liMessage(n.info, errWrongNumberOfVariables);
for i := 0 to len-3 do begin for i := 0 to len-3 do begin
v := newSymS(skForVar, n.sons[i], c); v := newSymS(skForVar, n.sons[i], c);
v.typ := iter.sons[i]; v.typ := iter.sons[i];
@ -840,6 +847,7 @@ begin
closeScope(c.tab); // close scope for parameters closeScope(c.tab); // close scope for parameters
popOwner(); popOwner();
c.p := oldP; // restore c.p := oldP; // restore
result.typ := s.typ;
end; end;
function semProcAux(c: PContext; n: PNode; kind: TSymKind): PNode; function semProcAux(c: PContext; n: PNode; kind: TSymKind): PNode;

View file

@ -256,8 +256,8 @@ begin
if templ = nil then begin result := nil; exit end; if templ = nil then begin result := nil; exit end;
case templ.kind of case templ.kind of
nkSym: begin nkSym: begin
if (templ.sym.kind = skTypeParam) if (templ.sym.kind = skTypeParam) then
and (templ.sym.owner.id = sym.id) then //and (templ.sym.owner.id = sym.id) then
result := copyTree(actual.sons[templ.sym.position+1]) result := copyTree(actual.sons[templ.sym.position+1])
else else
result := copyNode(templ) result := copyNode(templ)
@ -285,15 +285,18 @@ begin
result.containerID := s.typ.containerID; // ... but the same containerID result.containerID := s.typ.containerID; // ... but the same containerID
result.sym := s; result.sym := s;
if (s.typ.containerID = 0) then if (s.typ.containerID = 0) then
InternalError(n.info, 'semGeneric'); InternalError(n.info, 'semtypes.semGeneric');
for i := 1 to sonsLen(n)-1 do begin for i := 1 to sonsLen(n)-1 do begin
elem := semTypeNode(c, n.sons[i], nil); elem := semTypeNode(c, n.sons[i], nil);
if elem.kind = tyGenericParam then result.kind := tyGeneric; if elem.kind = tyGenericParam then
result.kind := tyGeneric; // prevend type from instantiation
addSon(result, elem); addSon(result, elem);
end; end;
if s.ast <> nil then begin if s.ast <> nil then begin
inst := instGenericAux(c, s.ast.sons[2], n, s); if (result.kind = tyGenericInst) then begin
if result.kind = tyGenericInst then begin inst := instGenericAux(c, s.ast.sons[2], n, s);
internalError(n.info, 'Generic containers not implemented');
// XXX: implementation does not work this way
// does checking of instantiated type for us: // does checking of instantiated type for us:
elem := semTypeNode(c, inst, nil); elem := semTypeNode(c, inst, nil);
elem.id := result.containerID; elem.id := result.containerID;
@ -303,7 +306,9 @@ begin
addSon(result, nil); addSon(result, nil);
end end
else else
liMessage(n.info, errCannotInstantiateX, s.name.s); liMessage(n.info, errCannotInstantiateX, s.name.s);
(*if computeSize(result) < 0 then
liMessage(s.info, errIllegalRecursionInTypeX, s.name.s);*)
end; end;
function semIdentVis(c: PContext; kind: TSymKind; n: PNode; function semIdentVis(c: PContext; kind: TSymKind; n: PNode;

View file

@ -80,20 +80,23 @@ var
begin begin
result := msgKindToString(errTypeMismatch); result := msgKindToString(errTypeMismatch);
for i := 1 to sonsLen(n)-1 do begin for i := 1 to sonsLen(n)-1 do begin
result := result +{&} typeToString(n.sons[i].typ); debug(n.sons[i].typ);
if i <> sonsLen(n)-1 then result := result + ', '; add(result, typeToString(n.sons[i].typ));
if i <> sonsLen(n)-1 then add(result, ', ');
end; end;
addChar(result, ')'); addChar(result, ')');
candidates := ''; candidates := '';
sym := initOverloadIter(o, c, n.sons[0]); sym := initOverloadIter(o, c, n.sons[0]);
while sym <> nil do begin while sym <> nil do begin
if sym.kind in [skProc, skIterator, skConverter] then if sym.kind in [skProc, skIterator, skConverter] then begin
candidates := candidates +{&} getProcHeader(sym) +{&} nl; add(candidates, getProcHeader(sym));
add(candidates, nl)
end;
sym := nextOverloadIter(o, c, n.sons[0]); sym := nextOverloadIter(o, c, n.sons[0]);
end; end;
if candidates <> '' then if candidates <> '' then
result := result +{&} nl +{&} msgKindToString(errButExpected) +{&} nl add(result, nl +{&} msgKindToString(errButExpected) +{&} nl
+{&} candidates; +{&} candidates);
end; end;
function typeRel(var mapping: TIdTable; f, a: PType): TTypeRelation; overload; function typeRel(var mapping: TIdTable; f, a: PType): TTypeRelation; overload;
@ -431,7 +434,7 @@ begin // is a subtype of f?
tyAnyEnum: begin tyAnyEnum: begin
case a.kind of case a.kind of
tyRange: result := typeRel(mapping, f, base(a)); tyRange: result := typeRel(mapping, f, base(a));
tyEnum: result := isEqual; tyEnum: result := isSubtype;
else begin end else begin end
end end
end; end;

View file

@ -8,8 +8,7 @@
// //
unit strtabs; unit strtabs;
// A configuration file parser; the Nimrod version of this file // String tables.
// will become part of the standard library.
interface interface

View file

@ -75,13 +75,14 @@ const
function strip(const s: string; const chars: TCharSet = WhiteSpace): string; function strip(const s: string; const chars: TCharSet = WhiteSpace): string;
function allCharsInSet(const s: string; const theSet: TCharSet): bool; function allCharsInSet(const s: string; const theSet: TCharSet): bool;
function quoteIfSpaceExists(const s: string): string; function quoteIfContainsWhite(const s: string): string;
implementation implementation
function quoteIfSpaceExists(const s: string): string; function quoteIfContainsWhite(const s: string): string;
begin begin
if (findSubStr(' ', s) >= strStart) and (s[strStart] <> '"') then if ((findSubStr(' ', s) >= strStart)
or (findSubStr(#9, s) >= strStart)) and (s[strStart] <> '"') then
result := '"' +{&} s +{&} '"' result := '"' +{&} s +{&} '"'
else else
result := s result := s

47
nim/tigen.pas Normal file
View file

@ -0,0 +1,47 @@
//
//
// The Nimrod Compiler
// (c) Copyright 2008 Andreas Rumpf
//
// See the file "copying.txt", included in this
// distribution, for details about the copyright.
//
unit tigen;
// Type information generator. It transforms types into the AST of walker
// procs. This is used by the code generators.
interface
{$include 'config.inc'}
uses
nsystem, ast, astalgo, strutils, hashes, trees, treetab, platform, magicsys,
options, msgs, crc, idents, lists, types, rnimsyn;
function gcWalker(t: PType): PNode;
function initWalker(t: PType): PNode;
function asgnWalker(t: PType): PNode;
function reprWalker(t: PType): PNode;
implementation
function gcWalker(t: PType): PNode;
begin
end;
function initWalker(t: PType): PNode;
begin
end;
function asgnWalker(t: PType): PNode;
begin
end;
function reprWalker(t: PType): PNode;
begin
end;
end.

View file

@ -22,7 +22,7 @@ interface
uses uses
sysutils, nsystem, charsets, strutils, sysutils, nsystem, charsets, strutils,
lists, options, ast, astalgo, trees, treetab, lists, options, ast, astalgo, trees, treetab,
msgs, nos, idents, rnimsyn, types, passes, semfold; msgs, nos, idents, rnimsyn, types, passes, semfold, magicsys;
const const
genPrefix = ':tmp'; // prefix for generated names genPrefix = ':tmp'; // prefix for generated names
@ -139,7 +139,7 @@ More efficient, but not implementable:
function newAsgnStmt(c: PTransf; le, ri: PNode): PNode; function newAsgnStmt(c: PTransf; le, ri: PNode): PNode;
begin begin
result := newNodeI(nkAsgn, ri.info); result := newNodeI(nkFastAsgn, ri.info);
addSon(result, le); addSon(result, le);
addSon(result, ri); addSon(result, ri);
end; end;
@ -224,6 +224,28 @@ begin
end end
end; end;
function newTupleAccess(tup: PNode; i: int): PNode;
var
lit: PNode;
begin
result := newNodeIT(nkBracketExpr, tup.info, tup.typ.sons[i]);
addSon(result, copyTree(tup));
lit := newNodeIT(nkIntLit, tup.info, getSysType(tyInt));
lit.intVal := i;
addSon(result, lit);
end;
procedure unpackTuple(c: PTransf; n, father: PNode);
var
i: int;
begin
// XXX: BUG: what if `n` is an expression with side-effects?
for i := 0 to sonsLen(n)-1 do begin
addSon(father, newAsgnStmt(c, c.transCon.forStmt.sons[i],
transform(c, newTupleAccess(n, i))));
end
end;
function transformYield(c: PTransf; n: PNode): PNode; function transformYield(c: PTransf; n: PNode): PNode;
var var
e: PNode; e: PNode;
@ -239,10 +261,8 @@ begin
transform(c, copyTree(e.sons[i])))); transform(c, copyTree(e.sons[i]))));
end end
end end
else begin else
// XXX: tuple unpacking: unpackTuple(c, e, result);
internalError(n.info, 'tuple unpacking is not implemented');
end
end end
else begin else begin
e := transform(c, copyTree(e)); e := transform(c, copyTree(e));
@ -523,7 +543,7 @@ end;
(* (*
# example: # example:
proc map(f: proc (x: int): int {.closure}, a: seq[int]): seq[int] = proc map(f: proc (x: int): int {.closure}, a: seq[int]): seq[int] =
result = [] result = @[]
for elem in a: for elem in a:
add result, f(a) add result, f(a)
@ -534,12 +554,12 @@ end;
proc map(f: proc(x: int): int, closure: pointer, proc map(f: proc(x: int): int, closure: pointer,
a: seq[int]): seq[int] = a: seq[int]): seq[int] =
result = [] result = @[]
for elem in a: for elem in a:
add result, f(a, closure) add result, f(a, closure)
type type
PMyClosure = ref record PMyClosure = ref object
y: var int y: var int
proc myLambda(x: int, closure: pointer) = proc myLambda(x: int, closure: pointer) =

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