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.
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
doc.section = """
@ -136,6 +136,10 @@ pre, span.tok {
background-color:#F9F9F9;
border:1px dotted #2F6FAB;
color:black;
}
span.red {
color: #A80000;
}
/*

View file

@ -1,100 +1,95 @@
# Configuration file for the Nimrod Compiler.
# (c) 2008 Andreas Rumpf
# Feel free to edit the default values as you need.
# You may set environment variables with
# @putenv "key" "val"
# Environment variables cannot be used in the options, however!
cc = @if windows: llvm_gcc @else: gcc @end
lib="$nimrod/lib"
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
#hint[XDeclaredButNotUsed]=off
@if unix:
@if not bsd: passl= "-ldl" @end
@end
@if icc:
passl = "-cxxlib"
passc = "-cxxlib"
@end
# Configuration for the LLVM GCC compiler:
@if windows:
llvm_gcc.path = r"$nimrod\dist\llvm-gcc4.2\bin"
@elif macosx:
llvm_gcc.path =
r"/Users/andreasrumpf/download/C/llvm-gcc4.2-2.3-x86-darwin8/bin"
@end
llvm_gcc.options.debug = "-g"
llvm_gcc.options.always = "-w"
llvm_gcc.options.speed = "-O2"
llvm_gcc.options.size = "-Os"
# Configuration for the Visual C/C++ compiler:
@if vcc:
passl: r"/F33554432" # set the stack size to 8 MB
@end
vcc.options.debug = "/RTC1 /ZI"
vcc.options.always = "/nologo"
vcc.options.speed = "/Ox /arch:SSE2"
vcc.options.size = "/O1"
# Configuration for the GNU C/C++ compiler:
@if windows:
gcc.path = r"C:\eigenes\compiler\mingw\bin"
@end
#gcc.exe = "gcc-4.1"
#gcc.linkerExe = "gcc-4.1"
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"
# Configuration for the Digital Mars C/C++ compiler:
@if windows:
dmc.path = r"C:\eigenes\compiler\d\dm\bin"
@end
# Configuration for the Tiny C Compiler:
@if windows:
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"
# Configuration file for the Nimrod Compiler.
# (c) 2008 Andreas Rumpf
# Feel free to edit the default values as you need.
# You may set environment variables with
# @putenv "key" "val"
# Environment variables cannot be used in the options, however!
cc = @if windows: llvm_gcc @else: gcc @end
lib="$nimrod/lib"
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
dead_code_elim:on
@end
# additional options always passed to the compiler:
--verbosity: "1"
hint[LineTooLong]=off
#hint[XDeclaredButNotUsed]=off
@if unix:
@if not bsd: passl= "-ldl" @end
@end
@if icc:
passl = "-cxxlib"
passc = "-cxxlib"
@end
# Configuration for the LLVM GCC compiler:
llvm_gcc.options.debug = "-g"
llvm_gcc.options.always = "-w"
llvm_gcc.options.speed = "-O2"
llvm_gcc.options.size = "-Os"
# Configuration for the Visual C/C++ compiler:
@if vcc:
passl: r"/F33554432" # set the stack size to 8 MB
@end
vcc.options.debug = "/RTC1 /ZI"
vcc.options.always = "/nologo"
vcc.options.speed = "/Ox /arch:SSE2"
vcc.options.size = "/O1"
# Configuration for the GNU C/C++ compiler:
@if windows:
gcc.path = r"C:\eigenes\compiler\mingw\bin"
@end
#gcc.exe = "gcc-4.1"
#gcc.linkerExe = "gcc-4.1"
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"
# Configuration for the Digital Mars C/C++ compiler:
@if windows:
dmc.path = r"C:\eigenes\compiler\d\dm\bin"
@end
# Configuration for the Tiny C Compiler:
@if windows:
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
Copyright (C) 2004-2008 Andreas Rumpf
=======================================================
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2
of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
=======================================================
The Nimrod Compiler
Copyright (C) 2004-2009 Andreas Rumpf
=======================================================
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2
of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

View file

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

View file

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

View file

@ -24,6 +24,7 @@ Options:
--bound_checks:on|off code generation for bound 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
--dead_code_elim:on|off whole program dead code elimination ON|OFF
--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
-r, --run run the compiled program with given arguments

View file

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

View file

@ -142,7 +142,7 @@
'selector must be of an ordinal type'},
{'errOrdXMustNotBeNegative': 'ord($1) must not be negative'},
{'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'},
{'errBreakOnlyInLoop': "'break' only allowed in loop construct"},
{'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:
- | `First steps after installation <steps.html>`_
| Read this after installation for a quick introduction.
- | `Nimrod tutorial (part I) <tut1.html>`_
| 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>`_
| 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>`_
| 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>`_
| This document describes how to use the Embedded debugger. The embedded
debugger currently has no GUI. Please help!
| This document describes how to use the Embedded Debugger.
- | `Nimrod library documentation <lib.html>`_
| This document describes Nimrod's standard library.
- | `Nimrod internal documentation <intern.html>`_
| 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>`_
| The generated index. Often the quickest way to find the piece of

View file

@ -1,41 +1,54 @@
Short description of Nimrod's modules
-------------------------------------
============== ==========================================================
Module Description
============== ==========================================================
lexbase buffer handling of the lexical analyser
scanner lexical analyser
ast type definitions of the abstract syntax tree (AST) and
node constructors
astalgo algorithms for containers of AST nodes; converting the
AST to YAML; the symbol table
passes implement the passes managemer for passes over the AST
trees few algorithms for nodes; this module is less important
types module for traversing type graphs; also contain several
helpers for dealing with types
sigmatch contains the matching algorithm that is used for proc
calls
semexprs contains the semantic checking phase for expressions
semstmts contains the semantic checking phase for statements
semtypes contains the semantic checking phase for types
idents implements a general mapping from identifiers to an internal
representation (``PIdent``) that is used, so that a simple
id-comparison suffices to say whether two Nimrod identifiers
are equivalent
ropes implements long strings using represented as trees for
lazy evaluation; used mainly by the code generators
ccgobj contains type definitions neeeded for C code generation
and some helpers
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
============== ==========================================================
Short description of Nimrod's modules
-------------------------------------
============== ==========================================================
Module Description
============== ==========================================================
nimrod main module: parses the command line and calls
```main.MainCommand``
main implements the top-level command dispatching
lexbase buffer handling of the lexical analyser
scanner lexical analyser
pnimsyn Nimrod's parser
rnimsyn Nimrod code renderer (AST back to its textual form)
paslex lexer for Pascal
pasparse parser for Pascal; Pascal's advanced OO features are not
supported
options contains global and local compiler options
ast type definitions of the abstract syntax tree (AST) and
node constructors
astalgo algorithms for containers of AST nodes; converting the
AST to YAML; the symbol table
passes implement the passes managemer for passes over the AST
trees few algorithms for nodes; this module is less important
types module for traversing type graphs; also contain several
helpers for dealing with types
sigmatch contains the matching algorithm that is used for proc
calls
semexprs contains the semantic checking phase for expressions
semstmts contains the semantic checking phase for statements
semtypes contains the semantic checking phase for types
semfold contains code to deal with constant folding
evals contains an AST interpreter for compile time evaluation
pragmas semantic checking of pragmas
idents implements a general mapping from identifiers to an internal
representation (``PIdent``) that is used, so that a simple
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)*
comma ::= ',' [COMMENT] [IND]
operator ::= OP0 | OR | XOR | AND | OP3 | OP4 | OP5 | IS | ISNOT | IN | NOTIN
| OP6 | DIV | MOD | SHL | SHR | OP7 | NOT
operator ::= OP0 | OR | XOR | AND | OP3 | OP4 | OP5 | OP6 | OP7
| '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]
lowestExpr ::= orExpr ( OP0 optInd orExpr )*
orExpr ::= andExpr ( OR | XOR optInd andExpr )*
andExpr ::= cmpExpr ( AND optInd cmpExpr )*
cmpExpr ::= ampExpr ( OP3 | IS | ISNOT | IN | NOTIN optInd ampExpr )*
ampExpr ::= plusExpr ( OP4 optInd plusExpr )*
plusExpr ::= mulExpr ( OP5 optInd mulExpr )*
mulExpr ::= dollarExpr ( OP6 | DIV | MOD | SHL | SHR optInd dollarExpr )*
dollarExpr ::= primary ( OP7 optInd primary )*
lowestExpr ::= orExpr (OP0 optInd orExpr)*
orExpr ::= andExpr (OR | 'xor' optInd andExpr)*
andExpr ::= cmpExpr ('and' optInd cmpExpr)*
cmpExpr ::= ampExpr (OP3 | 'is' | 'isnot' | 'in' | 'notin' optInd ampExpr)*
ampExpr ::= plusExpr (OP4 optInd plusExpr)*
plusExpr ::= mulExpr (OP5 optInd mulExpr)*
mulExpr ::= dollarExpr (OP6 | 'div' | 'mod' | 'shl' | 'shr' optInd dollarExpr)*
dollarExpr ::= primary (OP7 optInd primary)*
namedTypeOrExpr ::=
DOTDOT [expr]
| expr [EQUALS (expr [DOTDOT expr] | typeDescK | DOTDOT [expr] )
| DOTDOT [expr]]
'..' [expr]
| expr ['=' (expr ['..' expr] | typeDescK | '..' [expr]) | '..' [expr]]
| typeDescK
castExpr ::= CAST BRACKET_LE optInd typeDesc BRACKERT_RI
PAR_LE optInd expr PAR_RI
addrExpr ::= ADDR PAR_LE optInd expr PAR_RI
symbol ::= ACC (KEYWORD | IDENT | operator | PAR_LE PAR_RI
| BRACKET_LE BRACKET_RI | EQUALS | literal )+ ACC
castExpr ::= 'cast' '[' optInd typeDesc [SAD] ']' '(' optInd expr [SAD] ')'
addrExpr ::= 'addr' '(' optInd expr ')'
symbol ::= '`' (KEYWORD | IDENT | operator | '(' ')'
| '[' ']' | '=' | literal)+ '`'
| IDENT
primary ::= ( prefixOperator optInd )* ( symbol | constructor |
| castExpr | addrExpr ) (
DOT optInd symbol
#| CURLY_LE namedTypeDescList CURLY_RI
| PAR_LE optInd namedExprList PAR_RI
| BRACKET_LE optInd
[ namedTypeOrExpr (comma namedTypeOrExpr)* [comma] ]
BRACKET_RI
| CIRCUM
| pragma )*
primary ::= (prefixOperator optInd)* (symbol | constructor |
| castExpr | addrExpr) (
'.' optInd symbol
| '(' optInd namedExprList [SAD] ')'
| '[' optInd
[namedTypeOrExpr (comma namedTypeOrExpr)* [comma]]
[SAD] ']'
| '^'
| pragma)*
literal ::= INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
| FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
@ -48,48 +46,42 @@ literal ::= INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
| NIL
constructor ::= literal
| BRACKET_LE optInd colonExprList BRACKET_RI # []-Constructor
| CURLY_LE optInd sliceExprList CURLY_RI # {}-Constructor
| PAR_LE optInd colonExprList PAR_RI # ()-Constructor
| '[' optInd colonExprList [SAD] ']'
| '{' optInd sliceExprList [SAD] '}'
| '(' optInd colonExprList [SAD] ')'
exprList ::= [ expr (comma expr)* [comma] ]
colonExpr ::= expr [':' expr]
colonExprList ::= [colonExpr (comma colonExpr)* [comma]]
colonExpr ::= expr [COLON expr]
colonExprList ::= [ colonExpr (comma colonExpr)* [comma] ]
namedExpr ::= expr ['=' expr]
namedExprList ::= [namedExpr (comma namedExpr)* [comma]]
namedExpr ::= expr [EQUALS expr] # actually this is symbol EQUALS expr|expr
namedExprList ::= [ namedExpr (comma namedExpr)* [comma] ]
sliceExpr ::= expr ['..' expr]
sliceExprList ::= [sliceExpr (comma sliceExpr)* [comma]]
sliceExpr ::= expr [ DOTDOT expr ]
sliceExprList ::= [ sliceExpr (comma sliceExpr)* [comma] ]
anonymousProc ::= LAMBDA paramList [pragma] EQUALS stmt
anonymousProc ::= 'lambda' paramList [pragma] '=' stmt
expr ::= lowestExpr
| anonymousProc
| IF expr COLON expr
(ELIF expr COLON expr)*
ELSE COLON expr
| 'if' expr ':' expr ('elif' expr ':' expr)* 'else' ':' expr
namedTypeDesc ::= typeDescK | expr [EQUALS (typeDescK | expr)]
namedTypeDescList ::= [ namedTypeDesc (comma namedTypeDesc)* [comma] ]
namedTypeDesc ::= typeDescK | expr ['=' (typeDescK | expr)]
namedTypeDescList ::= [namedTypeDesc (comma namedTypeDesc)* [comma]]
qualifiedIdent ::= symbol [ DOT symbol ]
qualifiedIdent ::= symbol ['.' symbol]
typeDescK ::= VAR typeDesc
| REF typeDesc
| PTR typeDesc
| TYPE expr
| TUPLE tupleDesc
| PROC paramList [pragma]
typeDescK ::= 'var' typeDesc
| 'ref' typeDesc
| 'ptr' typeDesc
| 'type' expr
| 'tuple' tupleDesc
| 'proc' paramList [pragma]
typeDesc ::= typeDescK | primary
optSemicolon ::= [SEMICOLON]
macroStmt ::= COLON [stmt] (OF [sliceExprList] COLON stmt
| ELIF expr COLON stmt
| EXCEPT exceptList COLON stmt )*
[ELSE COLON stmt]
macroStmt ::= ':' [stmt] ('of' [sliceExprList] ':' stmt
|'elif' expr ':' stmt
|'except' exceptList ':' stmt )*
['else' ':' stmt]
simpleStmt ::= returnStmt
| yieldStmt
@ -107,88 +99,91 @@ complexStmt ::= ifStmt | whileStmt | caseStmt | tryStmt | forStmt
| procDecl | iteratorDecl | macroDecl | templateDecl
| constSection | typeSection | whenStmt | varSection
indPush ::= IND # push
indPush ::= IND # and push indentation onto the stack
indPop ::= # pop indentation from the stack
stmt ::= simpleStmt [SAD]
| indPush (complexStmt | simpleStmt)
([SAD] (complexStmt | simpleStmt) )*
DED
([SAD] (complexStmt | simpleStmt))*
DED indPop
exprStmt ::= lowestExpr [EQUALS expr | [expr (comma expr)* [comma]] [macroStmt]]
returnStmt ::= RETURN [expr]
yieldStmt ::= YIELD expr
discardStmt ::= DISCARD expr
raiseStmt ::= RAISE [expr]
breakStmt ::= BREAK [symbol]
continueStmt ::= CONTINUE
ifStmt ::= IF expr COLON stmt (ELIF expr COLON stmt)* [ELSE COLON stmt]
whenStmt ::= WHEN expr COLON stmt (ELIF expr COLON stmt)* [ELSE COLON stmt]
caseStmt ::= CASE expr (OF sliceExprList COLON stmt)*
(ELIF expr COLON stmt)*
[ELSE COLON stmt]
whileStmt ::= WHILE expr COLON stmt
forStmt ::= FOR symbol (comma symbol)* [comma] IN expr [DOTDOT expr] COLON stmt
exceptList ::= [qualifiedIdent (comma qualifiedIdent)* [comma]]
exprStmt ::= lowestExpr ['=' expr | [expr (comma expr)*] [macroStmt]]
returnStmt ::= 'return' [expr]
yieldStmt ::= 'yield' expr
discardStmt ::= 'discard' expr
raiseStmt ::= 'raise' [expr]
breakStmt ::= 'break' [symbol]
continueStmt ::= 'continue'
ifStmt ::= 'if' expr ':' stmt ('elif' expr ':' stmt)* ['else' ':' stmt]
whenStmt ::= 'when' expr ':' stmt ('elif' expr ':' stmt)* ['else' ':' stmt]
caseStmt ::= 'case' expr [':'] ('of' sliceExprList ':' stmt)*
('elif' expr ':' stmt)*
['else' ':' stmt]
whileStmt ::= 'while' expr ':' stmt
forStmt ::= 'for' symbol (comma symbol)* 'in' expr ['..' expr] ':' stmt
exceptList ::= [qualifiedIdent (comma qualifiedIdent)*]
tryStmt ::= TRY COLON stmt
(EXCEPT exceptList COLON stmt)*
[FINALLY COLON stmt]
asmStmt ::= ASM [pragma] (STR_LIT | RSTR_LIT | TRIPLESTR_LIT)
blockStmt ::= BLOCK [symbol] COLON stmt
tryStmt ::= 'try' ':' stmt
('except' exceptList ':' stmt)*
['finally' ':' stmt]
asmStmt ::= 'asm' [pragma] (STR_LIT | RSTR_LIT | TRIPLESTR_LIT)
blockStmt ::= 'block' [symbol] ':' stmt
filename ::= symbol | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
importStmt ::= IMPORT filename (comma filename)* [comma]
includeStmt ::= INCLUDE filename (comma filename)* [comma]
fromStmt ::= FROM filename IMPORT symbol (comma symbol)* [comma]
importStmt ::= 'import' filename (comma filename)*
includeStmt ::= 'include' filename (comma filename)*
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
paramList ::= [PAR_LE [param (comma param)* [comma]] PAR_RI] [COLON typeDesc]
param ::= symbol (comma symbol)* ':' 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]
paramList [pragma]
[EQUALS stmt]
macroDecl ::= MACRO symbol ["*"] [genericParams] paramList [pragma]
[EQUALS stmt]
iteratorDecl ::= ITERATOR symbol ["*"] [genericParams] paramList [pragma]
[EQUALS stmt]
templateDecl ::= TEMPLATE symbol ["*"] [genericParams] paramList [pragma]
[EQUALS stmt]
procDecl ::= 'proc' symbol ['*'] [genericParams] paramList [pragma]
['=' stmt]
macroDecl ::= 'macro' symbol ['*'] [genericParams] paramList [pragma]
['=' stmt]
iteratorDecl ::= 'iterator' symbol ['*'] [genericParams] paramList [pragma]
['=' stmt]
templateDecl ::= 'template' symbol ['*'] [genericParams] paramList [pragma]
['=' stmt]
colonAndEquals ::= [COLON typeDesc] EQUALS expr
colonAndEquals ::= [':' typeDesc] '=' expr
constDecl ::= symbol ["*"] [pragma] colonAndEquals [COMMENT | IND COMMENT]
constDecl ::= symbol ['*'] [pragma] colonAndEquals [COMMENT | IND COMMENT]
| COMMENT
constSection ::= CONST indPush constDecl (SAD constDecl)* DED
constSection ::= 'const' indPush constDecl (SAD constDecl)* DED indPop
typeDef ::= typeDesc | objectDef | enumDef
objectField ::= symbol ["*"] [pragma]
objectField ::= symbol ['*'] [pragma]
objectIdentPart ::=
objectField (comma objectField)* [comma] COLON typeDesc [COMMENT|IND COMMENT]
objectField (comma objectField)* ':' typeDesc [COMMENT|IND COMMENT]
objectWhen ::= WHEN expr COLON [COMMENT] objectPart
(ELIF expr COLON [COMMENT] objectPart)*
[ELSE COLON [COMMENT] objectPart]
objectCase ::= CASE expr COLON typeDesc [COMMENT]
(OF sliceExprList COLON [COMMENT] objectPart)*
[ELSE COLON [COMMENT] objectPart]
objectWhen ::= 'when' expr ':' [COMMENT] objectPart
('elif' expr ':' [COMMENT] objectPart)*
['else' ':' [COMMENT] objectPart]
objectCase ::= 'case' expr ':' typeDesc [COMMENT]
('of' sliceExprList ':' [COMMENT] objectPart)*
['else' ':' [COMMENT] objectPart]
objectPart ::= objectWhen | objectCase | objectIdentPart | NIL
| indPush objectPart (SAD objectPart)* DED
tupleDesc ::= BRACKET_LE optInd [param (comma param)* [comma]] BRACKET_RI
objectPart ::= objectWhen | objectCase | objectIdentPart | 'nil'
| indPush objectPart (SAD objectPart)* DED indPop
tupleDesc ::= '[' optInd [param (comma param)*] [SAD] ']'
objectDef ::= OBJECT [pragma] [OF typeDesc] objectPart
enumField ::= symbol [EQUALS expr]
enumDef ::= ENUM [OF typeDesc] (enumField [comma | COMMENT | IND COMMENT])+
objectDef ::= 'object' [pragma] ['of' typeDesc] objectPart
enumField ::= symbol ['=' expr]
enumDef ::= 'enum' ['of' typeDesc] (enumField [comma] [COMMENT | IND 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
varField ::= symbol ["*"] [pragma]
varPart ::= symbol (comma symbol)* [comma] colonOrEquals [COMMENT | IND COMMENT]
varSection ::= VAR (varPart
| indPush (COMMENT|varPart) (SAD (COMMENT|varPart))* DED)
colonOrEquals ::= ':' typeDesc ['=' expr] | '=' expr
varField ::= symbol ['*'] [pragma]
varPart ::= symbol (comma symbol)* colonOrEquals [COMMENT | IND COMMENT]
varSection ::= 'var' (varPart
| indPush (COMMENT|varPart)
(SAD (COMMENT|varPart))* DED indPop)

View file

@ -34,7 +34,6 @@ Path Purpose
on it!
``web`` website of Nimrod; generated by ``koch.py``
from the ``*.txt`` and ``*.tmpl`` files
``koch`` the Koch Build System (written for Nimrod)
``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
that it can be translated to Nimrod code automatically. This conversion is
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:
- Free Pascal (I used version 2.2) [optional]
- Python (should work with version 1.5 or higher)
- Python (should work with version 1.5 or higher) (optional)
- supported C compiler
- C compiler -- one of:
Compiling the compiler is a simple matter of running::
* win32-lcc (currently broken)
* 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
koch.py boot
| Compiling the compiler is a simple matter of running:
| ``koch.py boot``
| Or you can compile by hand, this is not difficult.
For a release version use::
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
been automated is accessible with it. It is a replacement for make and shell
scripting with the advantage that it is more portable.
If you don't have Python, there is a ``boot`` Nimrod program which does roughly
the same::
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
that it can be translated to Nimrod code automatically. As a general rule,
Pascal code that does not translate to Nimrod automatically is forbidden.
``{@discard} <expr>``
Tells the compiler that a ``discard`` statement is needed for Nimrod
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
@ -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
collector needs some assembler tweaking to work. The standard
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.
@ -132,11 +163,11 @@ The Garbage Collector
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).
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
code generation.
@ -170,7 +201,7 @@ modifying a ``TCellSet`` during traversation leads to undefined behaviour.
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.
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.
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
whole module only after it has been checked for semantics.
parsing. Otherwise generics would not work.
.. 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
---------------
@ -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
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])``.
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
=======================
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
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
the CCG. Therefore the module ``magicsys`` contains a table
(``compilerprocs``) with all symbols that are marked as ``compilerproc``.
the CCG. Therefore the module ``magicsys`` contains a table (``compilerprocs``)
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
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.
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*
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
`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)
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.
Configuration settings can be overwritten in a project specific
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
----------------------------
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.
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
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
===================
@ -86,8 +78,8 @@ available.
Importc Pragma
~~~~~~~~~~~~~~
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
identifier. If the argument is missing, the C name is the Nimrod
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 *exactly as spelled*:
.. code-block::
@ -97,8 +89,8 @@ identifier *exactly as spelled*:
Exportc Pragma
~~~~~~~~~~~~~~
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
identifier. If the argument is missing, the C name is the Nimrod
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 *exactly as spelled*:
.. code-block:: Nimrod
@ -109,7 +101,7 @@ Dynlib Pragma
~~~~~~~~~~~~~
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
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
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
var
EOF {.importc: "EOF", no_decl.}: cint # pretend EOF was a variable, as
# Nimrod does not know its value
EACCES {.importc, no_decl.}: cint # pretend EACCES was a variable, as
# Nimrod does not know its value
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
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
~~~~~~~~~~~~~~~
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
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.
Acyclic Pragma
~~~~~~~~~~~~~~
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::
type
@ -231,15 +215,31 @@ collector to not consider objects of this type as part of a cycle::
TNode {.acyclic, final.} = object
left, right: PNode
data: string
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
this type may form a cyclic graph. The ``acyclic`` pragma passes the
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
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
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
--------------------------
@ -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
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
assembler *might*.
everything that can be done in C can be done in Nimrod.
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
usable. The missing features can easily be circumvented. An indication of this
fact is that Nimrod's
*whole* documentation itself (including this document) is
fact is that Nimrod's *whole* documentation itself (including this document) is
processed by Nimrod's |rst| parser. (Which is an order of magnitude faster than
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 on Linux/UNIX
--------------------------
Note:
A C compiler is required - knowledge of C is not!
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
distributions do not ship with a GCC compiler preinstalled - then you have to
install 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
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``
does work.
Then run the following command::
sh build.sh
Unlike other software, Nimrod does not distribute its files over the whole file
hierarchy. This has the advantage that you can deinstall it by just deleting
its folder. The disadvantage is that you have to add it to your ``PATH``
manually. An alternative is to create a symbolic link in ``/usr/bin``::
[sudo] ln -s $your_install_dir/bin/nimrod /usr/bin/nimrod
Installation on the Macintosh
-----------------------------
Only MacOS X is supported.
Since MacOS X is UNIX based too, it works like the installation on Linux. You
need to install Apple's developer's tools for the GNU Compiler Collection
though.
Installation on Windows
-----------------------
Install Nimrod by downloading and running
the ``nimrod_$version.exe`` file. As default, the ``LLVM-GCC``
compiler is used that is bundled with this installer. You can change
the configuration file to use another C compiler.
Currently, the following C compilers are supported under Windows:
- | Microsoft's Visual C++
| http://msdn.microsoft.com/visualc
| (You need the SDK too - but not the full one: Essential are only
the win32api header files and import libraries.)
- | Gnu C Compiler (the mingw version; the cygwin version has not been tested!)
| http://www.mingw.org/download.shtml
- | LLVM with GNU C/C++ frontend
| http://llvm.org/releases/download.html#2.2
- | Digital Mars C++
| http://www.digitalmars.com/download/freecompiler.html
For better compile times I recommend Digital Mars C++ -- it is easy to install
and a small package.
Installation
============
Installation on Linux/UNIX
--------------------------
Note:
A C compiler is required - knowledge of C is not!
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
distributions do not ship with a GCC compiler preinstalled - then you have to
install 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
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``
does work.
Then run the following command::
sh build.sh
Unlike other software, Nimrod does not distribute its files over the whole file
hierarchy. This has the advantage that you can deinstall it by just deleting
its folder. The disadvantage is that you have to add it to your ``PATH``
manually. An alternative is to create a symbolic link in ``/usr/bin``::
[sudo] ln -s $your_install_dir/bin/nimrod /usr/bin/nimrod
Installation on the Macintosh
-----------------------------
Only MacOS X is supported.
Since MacOS X is UNIX based too, it works like the installation on Linux. You
need to install Apple's developer's tools for the GNU Compiler Collection
though.
Installation on Windows
-----------------------
Install Nimrod by downloading and running
the ``nimrod_$version.exe`` file. As default, the ``LLVM-GCC``
compiler is used that is bundled with this installer. You can change
the configuration file to use another C compiler.
Currently, the following C compilers are supported under Windows:
- | Microsoft's Visual C++
| http://msdn.microsoft.com/visualc
| (You need the SDK too - but not the full one: Essential are only
the win32api header files and import libraries.)
- | Gnu C Compiler (the mingw version; the cygwin version has not been tested!)
| http://www.mingw.org/download.shtml
- | LLVM with GNU C/C++ frontend
| http://llvm.org/releases/download.html#2.2
- | Digital Mars C++
| http://www.digitalmars.com/download/freecompiler.html
For better compile times I recommend Digital Mars C++ -- it is easy to install
and a small package.

81
koch.py
View file

@ -18,7 +18,7 @@ False = 0 == 1
# --------------------- constants ----------------------------------------
NIMROD_VERSION = '0.7.2'
NIMROD_VERSION = '0.7.4'
# This string contains Nimrod's version. It is the only place
# where the version needs to be updated. The rest is done by
# the build process automatically. It is replaced **everywhere**
@ -35,8 +35,6 @@ force = False
GENERATE_DIFF = False
# 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
@ -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 Warn(msg): print "[Koch] *** WARNING: " + msg
def Echo(msg): print "[Koch] " + msg
@ -140,7 +113,7 @@ BaseDir = _baseDir
def Path(a):
# Gets a UNIX like path and converts it to a path on this platform.
# With UNIX like, I mean: slashes, not backslashes, only relative
# paths ('../etc' can be used)
# paths ('../etc') can be used
result = a
if os.sep != "/": result = replace(result, "/", os.sep)
if os.pardir != "..": result = replace(result, "..", os.pardir)
@ -401,12 +374,12 @@ Options:
Possible Commands:
nim builds the Pascal version of Nimrod
rod [options] builds the Nimrod version of Nimrod (with options)
doc builds the documentation in HTML
clean cleans Nimrod project; removes generated files
boot [options] bootstraps with given command line options
rodsrc generates Nimrod version from Pascal version
web generates the website
profile profile the Nimrod compiler
csource build the C sources for installation
zip build the installation ZIP package
inno build the Inno Setup installer
""" % (NIMROD_VERSION + ' ' * (44-len(NIMROD_VERSION)), sys.version)
@ -436,7 +409,6 @@ def main(args):
cmd = args[i]
if cmd == "rod": cmd_rod(join(args[i+1:]))
elif cmd == "nim": cmd_nim()
elif cmd == "doc": cmd_doc()
elif cmd == "clean": cmd_clean()
elif cmd == "boot": cmd_boot(join(args[i+1:]))
elif cmd == "rodsrc": cmd_rodsrc()
@ -444,11 +416,14 @@ def main(args):
elif cmd == "profile": cmd_profile()
elif cmd == "zip": cmd_zip()
elif cmd == "inno": cmd_inno()
elif cmd == "csource": cmd_csource()
else: Error("illegal command: " + cmd)
def cmd_zip():
def cmd_csource():
Exec("nimrod cc -r tools/niminst --var:version=%s csource rod/nimrod" %
NIMROD_VERSION)
def cmd_zip():
Exec("nimrod cc -r tools/niminst --var:version=%s zip rod/nimrod" %
NIMROD_VERSION)
@ -586,50 +561,10 @@ def cmd_profile():
# ------------------ 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():
Exec("nimrod cc -r tools/nimweb.nim web/nimrod --putenv:nimrodversion=%s"
% 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():

View file

@ -102,51 +102,16 @@ proc absInt(a: int): int {.compilerProc, inline.} =
raiseOverflow()
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
# tasm32, which is needed for assembler blocks
# this is why Borland is not included in the 'when'
useInline = not asmVersion
when asmVersion and defined(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):
when asmVersion and not defined(gcc) and not defined(llvm_gcc):
# assembler optimized versions for compilers that
# 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
asm """
mov eax, `a`
@ -156,7 +121,7 @@ when asmVersion and not defined(gcc):
theEnd:
"""
proc subInt(a, b: int): int =
proc subInt(a, b: int): int {.compilerProc, pure.} =
asm """
mov eax, `a`
sub eax, `b`
@ -165,7 +130,7 @@ when asmVersion and not defined(gcc):
theEnd:
"""
proc negInt(a: int): int =
proc negInt(a: int): int {.compilerProc, pure.} =
asm """
mov eax, `a`
neg eax
@ -174,7 +139,7 @@ when asmVersion and not defined(gcc):
theEnd:
"""
proc divInt(a, b: int): int =
proc divInt(a, b: int): int {.compilerProc, pure.} =
asm """
mov eax, `a`
mov ecx, `b`
@ -185,7 +150,7 @@ when asmVersion and not defined(gcc):
theEnd:
"""
proc modInt(a, b: int): int =
proc modInt(a, b: int): int {.compilerProc, pure.} =
asm """
mov eax, `a`
mov ecx, `b`
@ -197,7 +162,7 @@ when asmVersion and not defined(gcc):
mov eax, edx
"""
proc mulInt(a, b: int): int =
proc mulInt(a, b: int): int {.compilerProc, pure.} =
asm """
mov eax, `a`
mov ecx, `b`
@ -208,99 +173,105 @@ when asmVersion and not defined(gcc):
theEnd:
"""
elif asmVersion and defined(gcc):
proc addInt(a, b: int): int =
asm """ "addl %1,%%eax\n"
elif false: # asmVersion and (defined(gcc) or defined(llvm_gcc)):
proc addInt(a, b: int): int {.compilerProc, inline.} =
# 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"
"call _raiseOverflow\n"
"1: \n"
:"=a"(`a`)
:"a"(`a`), "r"(`b`)
:"=a"(`result`)
:"a"(`a`), "c"(`b`)
:"%edx"
"""
proc subInt(a, b: int): int =
asm """ "subl %1,%%eax\n"
"jno 1\n"
"call _raiseOverflow\n"
"1: \n"
:"=a"(`a`)
:"a"(`a`), "r"(`b`)
proc negInt(a: int): int {.compilerProc, inline.} =
asm """ "negl %%eax\n"
"jno 1\n"
"call _raiseOverflow\n"
"1: \n"
:"=a"(`result`)
:"a"(`a`)
"""
proc negInt(a: int): int =
asm """ "negl %%eax\n"
"jno 1\n"
"call _raiseOverflow\n"
"1: \n"
:"=a"(`a`)
:"a"(`a`)
"""
proc divInt(a, b: int): int =
proc divInt(a, b: int): int {.compilerProc, inline.} =
asm """ "xorl %%edx, %%edx\n"
"idivl %%ecx\n"
"jno 1\n"
"call _raiseOverflow\n"
"1: \n"
:"=a"(`a`)
:"a"(`a`), "c"(`b`)
:"%edx"
:"=a"(`result`)
:"a"(`a`), "c"(`b`)
:"%edx"
"""
proc modInt(a, b: int): int =
proc modInt(a, b: int): int {.compilerProc, inline.} =
asm """ "xorl %%edx, %%edx\n"
"idivl %%ecx\n"
"jno 1\n"
"call _raiseOverflow\n"
"1: \n"
"movl %%edx, %%eax"
:"=a"(`a`)
:"a"(`a`), "c"(`b`)
:"%edx"
:"=a"(`result`)
:"a"(`a`), "c"(`b`)
:"%edx"
"""
proc mulInt(a, b: int): int =
asm """ "xorl %%edx, %%edx\n"
"imull %%ecx\n"
"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 =
# Platform independant versions of the above (slower!)
when not defined(addInt):
proc addInt(a, b: int): int {.compilerProc, inline.} =
result = a +% b
if (result xor a) >= 0 or (result xor b) >= 0:
return result
raiseOverflow()
proc subInt(a, b: int): int =
when not defined(subInt):
proc subInt(a, b: int): int {.compilerProc, inline.} =
result = a -% b
if (result xor a) >= 0 or (result xor not b) >= 0:
return result
raiseOverflow()
proc negInt(a: int): int =
when not defined(negInt):
proc negInt(a: int): int {.compilerProc, inline.} =
if a != low(int): return -a
raiseOverflow()
proc divInt(a, b: int): int =
when not defined(divInt):
proc divInt(a, b: int): int {.compilerProc, inline.} =
if b == 0:
raiseDivByZero()
if a == low(int) and b == -1:
raiseOverflow()
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:
raiseDivByZero()
return a mod b
when not defined(mulInt):
#
# This code has been inspired by Python's source code.
# 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
# native int product that must have overflowed.
#
proc mulInt(a, b: int): int =
proc mulInt(a, b: int): int {.compilerProc.} =
var
resAsFloat, floatProd: float

View file

@ -281,7 +281,7 @@ proc getServerSoftware*(): string =
proc setTestData*(keysvalues: openarray[string]) =
## 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:
##
## .. code-block:: Nimrod
@ -300,6 +300,7 @@ proc setTestData*(keysvalues: openarray[string]) =
proc writeContentType*() =
## call this before starting to send your HTML data to `stdout`. This
## is just a shorthand for:
##
## .. code-block:: Nimrod
## 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
glib2

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -2,93 +2,93 @@
#******************************************************************************
#
# $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
#
# Portions created by Sam Lantinga <slouken@devolution.com> are
# Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
# 5635-34 Springhouse Dr.
# Pleasanton, CA 94588 (USA)
#
# All Rights Reserved.
#
# The original files are : SDL_mixer.h
# music_cmd.h
# wavestream.h
# timidity.h
# playmidi.h
# music_ogg.h
# mikmod.h
#
# 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.
#
#
# Contributor(s)
# --------------
# Matthias Thoma <ma.thoma@gmx.de>
#
# 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
#
# The contents of this file are used with permission, subject to
# the Mozilla Public License Version 1.1 (the "License"); you may
# not use this file except in compliance with the License. You may
# 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
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# Description
# -----------
#
#
#
#
#
#
#
# Requires
# --------
# SDL.pas & SMPEG.pas somewhere within your search path.
#
# Programming Notes
# -----------------
# See the Aliens Demo to see how this library is used
#
# Revision History
# ----------------
# April 02 2001 - DL : Initial Translation
#
# 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
# for GnuPascal, VirtualPascal, TMT and obviously
# continue support for Delphi Kylix and FreePascal.
#
#
#
# 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
# 5635-34 Springhouse Dr.
# Pleasanton, CA 94588 (USA)
#
# All Rights Reserved.
#
# The original files are : SDL_mixer.h
# music_cmd.h
# wavestream.h
# timidity.h
# playmidi.h
# music_ogg.h
# mikmod.h
#
# 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.
#
#
# Contributor(s)
# --------------
# Matthias Thoma <ma.thoma@gmx.de>
#
# 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
#
# The contents of this file are used with permission, subject to
# the Mozilla Public License Version 1.1 (the "License"); you may
# not use this file except in compliance with the License. You may
# 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
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# Description
# -----------
#
#
#
#
#
#
#
# Requires
# --------
# SDL.pas & SMPEG.pas somewhere within your search path.
#
# Programming Notes
# -----------------
# See the Aliens Demo to see how this library is used
#
# Revision History
# ----------------
# April 02 2001 - DL : Initial Translation
#
# 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
# 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
# better TMT Pascal support and under instruction
# better TMT Pascal support and under instruction
# from Prof. Abimbola Olowofoyeku (The African Chief),
# I have added better Gnu Pascal support
#
# April 30 2003 - DL : under instruction from David Mears AKA
# Jason Siletto, I have added FPC Linux support.
# This was compiled with fpc 1.1, so remember to set
# include file path. ie. -Fi/usr/share/fpcsrc/rtl/*
#
# I have added better Gnu Pascal support
#
# April 30 2003 - DL : under instruction from David Mears AKA
# Jason Siletto, I have added FPC Linux support.
# This was compiled with fpc 1.1, so remember to set
# include file path. ie. -Fi/usr/share/fpcsrc/rtl/*
#
#
# $Log: sdl_mixer.pas,v $
# Revision 1.18 2007/05/29 21:31:44 savage
@ -166,19 +166,19 @@ const
MIX_MAJOR_VERSION* = SDL_MIXER_MAJOR_VERSION
MIX_MINOR_VERSION* = SDL_MIXER_MINOR_VERSION
MIX_PATCHLEVEL* = SDL_MIXER_PATCHLEVEL # SDL_Mixer.h constants
# The default mixer has 8 simultaneous mixing channels
MIX_CHANNELS* = 8 # Good default values for a PC soundcard
# The default mixer has 8 simultaneous mixing channels
MIX_CHANNELS* = 8 # Good default values for a PC soundcard
MIX_DEFAULT_FREQUENCY* = 22050
when defined(IA32):
const
when defined(IA32):
const
MIX_DEFAULT_FORMAT* = AUDIO_S16LSB
else:
const
else:
const
MIX_DEFAULT_FORMAT* = AUDIO_S16MSB
const
const
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
#*
# * Library version
@ -204,7 +204,7 @@ type #music_cmd.h types
cvt*: TSDL_AudioCVT
PMidiEvent* = ptr TMidiEvent
TMidiEvent*{.final.} = object
TMidiEvent*{.final.} = object
time*: int32
channel*: uint8
type_*: uint8
@ -228,43 +228,43 @@ type #music_cmd.h types
len_available*: int
snd_available*: PUint8
TErrorEnum* = enum
MMERR_OPENING_FILE, MMERR_OUT_OF_MEMORY, MMERR_DYNAMIC_LINKING,
MMERR_SAMPLE_TOO_BIG, MMERR_OUT_OF_HANDLES, MMERR_UNKNOWN_WAVE_TYPE,
MMERR_LOADING_PATTERN, MMERR_LOADING_TRACK, MMERR_LOADING_HEADER,
MMERR_LOADING_SAMPLEINFO, MMERR_NOT_A_MODULE, MMERR_NOT_A_STREAM,
MMERR_MED_SYNTHSAMPLES, MMERR_ITPACK_INVALID_DATA, MMERR_DETECTING_DEVICE,
MMERR_INVALID_DEVICE, MMERR_INITIALIZING_MIXER, MMERR_OPENING_AUDIO,
MMERR_8BIT_ONLY, MMERR_16BIT_ONLY, MMERR_STEREO_ONLY, MMERR_ULAW,
MMERR_NON_BLOCK, MMERR_AF_AUDIO_PORT, MMERR_AIX_CONFIG_INIT,
MMERR_AIX_CONFIG_CONTROL, MMERR_AIX_CONFIG_START, MMERR_GUS_SETTINGS,
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_BUFFERSIZE, MMERR_OSS_SETFRAGMENT, MMERR_OSS_SETSAMPLESIZE,
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_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_EVENT, MMERR_DS_THREAD, MMERR_DS_UPDATE, MMERR_WINMM_HANDLE,
MMERR_WINMM_ALLOCATED, MMERR_WINMM_DEVICEID, MMERR_WINMM_FORMAT,
TErrorEnum* = enum
MMERR_OPENING_FILE, MMERR_OUT_OF_MEMORY, MMERR_DYNAMIC_LINKING,
MMERR_SAMPLE_TOO_BIG, MMERR_OUT_OF_HANDLES, MMERR_UNKNOWN_WAVE_TYPE,
MMERR_LOADING_PATTERN, MMERR_LOADING_TRACK, MMERR_LOADING_HEADER,
MMERR_LOADING_SAMPLEINFO, MMERR_NOT_A_MODULE, MMERR_NOT_A_STREAM,
MMERR_MED_SYNTHSAMPLES, MMERR_ITPACK_INVALID_DATA, MMERR_DETECTING_DEVICE,
MMERR_INVALID_DEVICE, MMERR_INITIALIZING_MIXER, MMERR_OPENING_AUDIO,
MMERR_8BIT_ONLY, MMERR_16BIT_ONLY, MMERR_STEREO_ONLY, MMERR_ULAW,
MMERR_NON_BLOCK, MMERR_AF_AUDIO_PORT, MMERR_AIX_CONFIG_INIT,
MMERR_AIX_CONFIG_CONTROL, MMERR_AIX_CONFIG_START, MMERR_GUS_SETTINGS,
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_BUFFERSIZE, MMERR_OSS_SETFRAGMENT, MMERR_OSS_SETSAMPLESIZE,
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_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_EVENT, MMERR_DS_THREAD, MMERR_DS_UPDATE, MMERR_WINMM_HANDLE,
MMERR_WINMM_ALLOCATED, MMERR_WINMM_DEVICEID, MMERR_WINMM_FORMAT,
MMERR_WINMM_UNKNOWN, MMERR_MAC_SPEED, MMERR_MAC_START, MMERR_MAX
PMODULE* = ptr TMODULE
TMODULE*{.final.} = object
TMODULE*{.final.} = object
PUNIMOD* = ptr TUNIMOD
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
TMix_Chunk*{.final.} = object
TMix_Chunk*{.final.} = object
allocated*: int
abuf*: PUint8
alen*: Uint32
volume*: Uint8 # Per-sample volume, 0-128
Mix_Chunk* = TMix_Chunk # The different fading types supported
TMix_Fading* = enum
volume*: Uint8 # Per-sample volume, 0-128
Mix_Chunk* = TMix_Chunk # The different fading types supported
TMix_Fading* = enum
MIX_NO_FADING, MIX_FADING_OUT, MIX_FADING_IN
Mix_Fading* = TMix_Fading
TMix_MusicType* = enum
TMix_MusicType* = enum
MUS_NONE, MUS_CMD, MUS_WAV, MUS_MOD, MUS_MID, MUS_OGG, MUS_MP3
Mix_MusicType* = TMix_MusicType #
# TMusicUnion = record
@ -279,89 +279,84 @@ type #music_cmd.h types
# {$ENDIF}
# end;
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
# data : TMusicUnion;
# fading : TMix_Fading;
# fade_volume : integer;
# fade_step : integer;
# fade_steps : integer;
# error : integer;
# error : integer;
TMixFunction* = proc (udata: Pointer, stream: PUint8, length: int): Pointer{.
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)
# 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
# SDL_MIXER_VERSION() macro.
# SDL_MIXER_VERSION() macro.
proc Mix_Linked_Version*(): PSDL_version{.cdecl, importc, dynlib: SDL_MixerLibName.}
# Open the mixer with a certain audio format
proc Mix_OpenAudio*(frequency: int, format: Uint16, channels: int,
# Open the mixer with a certain audio format
proc Mix_OpenAudio*(frequency: int, format: Uint16, channels: int,
chunksize: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.}
# Dynamically change the number of channels managed by the mixer.
# If decreasing the number of channels, the upper channels are
# stopped.
# 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.}
# Find out what the actual audio device parameters are.
# 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{.
cdecl, importc, dynlib: SDL_MixerLibName.}
# Load a wave file or a music (.mod .s3m .it .xm) file
proc Mix_LoadWAV_RW*(src: PSDL_RWops, freesrc: int): PMix_Chunk{.cdecl,
# Load a wave file or a music (.mod .s3m .it .xm) file
proc Mix_LoadWAV_RW*(src: PSDL_RWops, freesrc: int): PMix_Chunk{.cdecl,
importc, dynlib: SDL_MixerLibName.}
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.}
##if 0 { This hasn't been hooked into music.c yet }
#{ Load a music file from an SDL_RWop object (MikMod-specific currently)
# 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,
# 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.}
# 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_FreeMusic*(music: PMix_Music){.cdecl, importc, dynlib: SDL_MixerLibName.}
# Find out the music format of a mixer music, or the currently playing
# 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.}
# 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
# 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.}
# Add your own music player or additional mixer function.
# 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.}
# 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.}
# 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.}
#* Add your own callback when a channel has finished playing. NULL
# * to disable callback.*
type
type
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.}
const
const
MIX_CHANNEL_POST* = - 2
# This is the format of a special effect callback:
# myeffect(int chan, void *stream, int len, void *udata);
#
#
# (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
# (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
# to be mixed with the rest of the channels and music for the final output
# stream.
#
#
type
TMix_EffectFunc* = proc (chan: int, stream: Pointer, length: int,
type
TMix_EffectFunc* = proc (chan: int, stream: Pointer, length: int,
udata: Pointer): Pointer{.cdecl.}
# * This is a callback that signifies that a channel has finished all its
# * loops and has completed playback. This gets called if the buffer
@ -428,7 +423,7 @@ type
# * 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.}
#* 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.
@ -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.
# * 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.}
#* 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
@ -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.
# * 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.}
const
MIX_EFFECTSMAXSPEED* = "MIX_EFFECTSMAXSPEED"
const
MIX_EFFECTSMAXSPEED* = "MIX_EFFECTSMAXSPEED"
# * 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
# * convenience.Some effects can reduce their quality or use more memory in
# * the name of speed; to enable this, make sure the environment variable
# * MIX_EFFECTSMAXSPEED( see above ) is defined before you call
# * Mix_OpenAudio( ).
# *
# *
#* set the panning of a channel.The left and right channels are specified
# * 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
# * mode is a no - op, but this call will return successful in that case .
# * 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.}
# * 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 )
@ -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 ),
# * nonzero if position effect is enabled.
# * 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.}
#* 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.
@ -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 ),
# * nonzero if position effect is enabled.
# * 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.}
# *
# * !!! 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
# * mode is a no - op, but this call will return successful in that case .
# * 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.}
# end of effects API. - -ryan. *
# 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.
# Returns the number of reserved channels.
#
#
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
# channels, to form groups of channels.
# If 'tag' is -1, the tag is removed (actually -1 is the tag used to
# represent the group of all the channels).
# 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.}
# Assign several consecutive channels to a group
proc Mix_GroupChannels*(`from`: int, `to`: int, tag: int): int{.cdecl,
# Assign several consecutive channels to a group
proc Mix_GroupChannels*(`from`: int, `to`: int, tag: int): int{.cdecl,
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.}
# 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
#
#
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.}
# 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.}
# The same as above, but the sound is played at most 'ticks' milliseconds
proc Mix_PlayChannelTimed*(channel: int, chunk: PMix_Chunk, loops: int,
# The same as above, but the sound is played at most 'ticks' milliseconds
proc Mix_PlayChannelTimed*(channel: int, chunk: PMix_Chunk, loops: int,
ticks: int): int{.cdecl, importc, dynlib: SDL_MixerLibName.}
# Play an audio chunk on a specific 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.
#
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.}
# 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,
# 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,
importc, dynlib: SDL_MixerLibName.}
proc Mix_FadeInChannelTimed*(channel: int, chunk: PMix_Chunk, loops: int,
ms: int, ticks: int): int{.cdecl,
proc Mix_FadeInChannelTimed*(channel: int, chunk: PMix_Chunk, loops: int,
ms: int, ticks: int): int{.cdecl,
importc, dynlib: SDL_MixerLibName.}
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.
@ -655,12 +650,12 @@ proc Mix_FadeInChannel*(channel: int, chunk: PMix_Chunk, loops: int, ms: int): i
# Returns the original 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.}
proc Mix_VolumeChunk*(chunk: PMix_Chunk, volume: int): int{.cdecl,
proc Mix_VolumeChunk*(chunk: PMix_Chunk, 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_HaltGroup*(tag: int): 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,
# 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.}
# Halt a channel, fading it out progressively till it's silent
# The ms parameter indicates the number of milliseconds the fading
# will take.
#
proc Mix_FadeOutChannel*(which: int, ms: int): int{.cdecl,
#
proc Mix_FadeOutChannel*(which: 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.}
# 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_FadingChannel*(which: int): TMix_Fading{.cdecl,
proc Mix_FadingChannel*(which: int): TMix_Fading{.cdecl,
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_Resume*(channel: 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_ResumeMusic*(){.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
# moment.
#
proc Mix_SetMusicPosition*(position: float64): int{.cdecl,
proc Mix_SetMusicPosition*(position: float64): int{.cdecl,
importc, dynlib: SDL_MixerLibName.}
# Check the status of a specific channel.
# If the specified channel is -1, check all channels.
#
proc Mix_Playing*(channel: int): 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.}
# 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_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.
#
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.}
# We'll use SDL for reporting errors
# We'll use SDL for reporting errors
proc Mix_SetError*(fmt: cstring)
proc Mix_GetError*(): cstring
# implementation
proc SDL_MIXER_VERSION(X: var TSDL_version) =
proc SDL_MIXER_VERSION(X: var TSDL_version) =
X.major = SDL_MIXER_MAJOR_VERSION
X.minor = SDL_MIXER_MINOR_VERSION
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)
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)
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)
proc Mix_SetError(fmt: cstring) =
proc Mix_SetError(fmt: cstring) =
SDL_SetError(fmt)
proc Mix_GetError(): cstring =
proc Mix_GetError(): cstring =
result = SDL_GetError()

View file

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

View file

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

View file

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

View file

@ -13,11 +13,10 @@
# * incremental
# * non-recursive
# * generational
# * excellent performance
# Future Improvements:
# * 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
# might turn out to be too slow.
@ -332,7 +331,7 @@ proc CellSetPut(t: var TCellSet, key: TAddress): PPageDesc =
# ---------- 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 t = CellSetGet(s, u shr PageShift)
if t != nil:
@ -468,23 +467,6 @@ proc prepareDealloc(cell: PCell) =
proc setStackBottom(theStackBottom: pointer) {.compilerproc.} =
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.} =
if canbeCycleRoot(c): incl(gch.cycleRoots, c)
@ -535,6 +517,23 @@ proc unsureAsgnRef(dest: ppointer, src: pointer) =
if dest^ != nil: decRef(usrToCell(dest^))
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 =
assert(n.kind == nkCase)
var d: int

View file

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

View file

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

View file

@ -421,18 +421,4 @@ struct NimException {
};
#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

View file

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

View file

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

View file

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

View file

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

View file

@ -12,6 +12,8 @@
## All the routines here are avaiable for the EMCAScript target
## too!
{.deadCodeElim: on.}
{.push debugger:off .} # the user does not want to trace a part
# of the standard library!
@ -41,19 +43,19 @@ proc strip*(s: string): string {.noSideEffect.}
proc toLower*(s: string): string {.noSideEffect.}
## 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.}
## 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.}
## 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.}
## 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.}
## 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
## 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.}
## 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
proc in_Operator*(s: string, c: char): bool {.noSideEffect.}
## Same as `findSubStr(c, s) >= 0`.
proc contains*(s: string, c: char): bool {.noSideEffect.}
## Same as ``findSubStr(c, s) >= 0``.
proc in_Operator*(s, sub: string): bool {.noSideEffect.}
## Same as `findSubStr(sub, s) >= 0`.
proc contains*(s, sub: string): bool {.noSideEffect.}
## 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.}
## 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
return true
proc quoteIfSpaceExists*(s: string): string =
proc quoteIfContainsWhite*(s: string): string =
## returns ``'"' & s & '"'`` if `s` contains a space and does not
## start with a quote, else returns `s`
if findSubStr(' ', s) >= 0 and s[0] != '"':
if findChars({' ', '\t'}, s) >= 0 and s[0] != '"':
result = '"' & s & '"'
else:
result = s
@ -488,11 +497,19 @@ proc findSubStr(sub: char, s: string, start: int = 0): int =
for i in start..len(s)-1:
if sub == s[i]: return i
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
proc in_Operator(s, sub: string): bool =
proc contains(s, sub: string): bool =
return findSubStr(sub, s) >= 0
proc replaceStr(s, sub, by: string): string =

View file

@ -91,10 +91,13 @@ proc writeln[Ty](f: TFile, x: Ty) =
write(f, "\n")
proc writeln[Ty](f: TFile, x: openArray[Ty]) =
write(f, x)
for i in items(x): write(f, i)
write(f, "\n")
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:
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
# 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:
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.}
## 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".}
## creates a new object of type ``T`` and returns a safe (traced)
## reference to it in ``a``.
@ -94,6 +105,19 @@ type
seq*{.magic: "Seq".}[T] ## Generic type to construct sequences.
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
## 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: int32): int32 {.magic: "AbsI", noSideEffect.}
proc abs*(x: int64): int64 {.magic: "AbsI64", noSideEffect.}
## returns the absolute value of `x`. If `x` is ``low(x)`` (that is
## -MININT for its type), an overflow exception is thrown (if overflow
## returns the absolute value of `x`. If `x` is ``low(x)`` (that
## is -MININT for its type), an overflow exception is thrown (if overflow
## checking is turned on).
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 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
proc `*` *[T](x, y: set[T]): set[T] {.magic: "MulSet", noSideEffect.}
## 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``.
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.
## The parameters are in reverse order! This is because the unification
## algorithm that Nimrod uses for overload resolution works from left to
## right.
## The parameters are in reverse order! ``a in b`` is a template for
## ``contains(b, a)``.
## 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
## 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
## have been bound to ``char``. But ``s`` is not compatible to type
## ``set[char]``! The solution is to bind ``T`` to ``range['a'..'z']``. This
## is achieved by reversing the parameters for ``in_operator``; ``in`` then
## is achieved by reversing the parameters for ``contains``; ``in`` then
## passes its arguments in reverse order.
template `in` * (x, y: expr): expr = in_Operator(y, x)
template `not_in` * (x, y: expr): expr = not in_Operator(y, x)
template `in` * (x, y: expr): expr = contains(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.}
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.}
## is the `concatenation operator`. It concatenates `x` and `y`.
proc add * (x: var string, y: char) {.magic: "AppendStrCh".}
proc add * (x: var string, y: string) {.magic: "AppendStrStr".}
proc add*(x: var string, y: char) {.magic: "AppendStrCh".}
proc add*(x: var string, y: string) {.magic: "AppendStrStr".}
when not defined(ECMAScript):
{.push overflow_checks:off}
proc add* (x: var string, y: cstring) =
var i = 0
while y[i] != '\0':
add(x, y[i])
inc(i)
{.pop.}
else:
proc add* (x: var string, y: cstring) {.pure.} =
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.}
## 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.
type
@ -729,7 +744,16 @@ const
cpuEndian* {.magic: "CpuEndian"}: TEndian = littleEndian
## 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.
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 {.
magic: "ToFloat", noSideEffect, importc: "toFloat".}
## 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
## 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:
proc getRefcount*[T](x: ref T): int {.importc: "getRefcount".}
## 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
## 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 =
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):
include hti
proc initGC()
var
@ -1370,13 +1402,6 @@ when not defined(EcmaScript) and not defined(NimrodVM):
include arithm
{.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
GenericSeqSize = (2 * sizeof(int))
@ -1417,13 +1442,12 @@ elif defined(NimrodVM):
proc getFreeMem(): int = return -1
proc getTotalMem(): int = return -1
proc echo[Ty](x: Ty) = nil
proc echo[Ty](x: openarray[Ty]) = nil
proc cmp(x, y: string): int =
if x == y: return 0
if x < y: return -1
return 1
include macros
{.pop.} # checks
{.pop.} # hints

View file

@ -276,8 +276,8 @@ else:
proc getDateStr(): string =
var ti = getLocalTime(getTime())
result = $ti.year & "-" & intToStr(ord(ti.month)+1, 2) &
"-" & intToStr(ti.monthDay, 2)
result = $ti.year & '-' & intToStr(ord(ti.month)+1, 2) &
'-' & intToStr(ti.monthDay, 2)
proc getClockStr(): string =
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
## unicode version.
{.deadCodeElim: on.}
type
ATOM* = int16
TAtom* = ATOM

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -27,16 +27,48 @@ function GetUniqueType(key: PType): PType;
implementation
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;
var
t: PType;
h: THash;
k: TTypeKind;
begin
// this was a hotspot in the compiler!
// this is a hotspot in the compiler!
result := key;
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
tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
tyInt..tyFloat128, tyProc, tyAnyEnum: begin end;
@ -62,7 +94,7 @@ begin
end
end;
tyGenericInst: result := GetUniqueType(lastSon(key));
end;
end; *)
end;
function TableGetType(const tab: TIdTable; key: PType): PObject;
@ -122,6 +154,6 @@ begin
app(result, toRope(res));
end;
initialization
InitIdTable(gTypeTable);
begin
InitTypeTables();
end.

View file

@ -73,7 +73,6 @@ type
cpsStmts // section of local statements for C proc
);
TCProcSections = array [TCProcSection] of PRope;
// TCProcSections represents a generated C proc
@ -112,21 +111,64 @@ type
typeCache: TIdTable; // cache the generated types
forwTypeCache: TIdTable; // cache for forward declarations of types
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
typeInfoMarker: TIntSet; // needed for generating type information
initProc: BProc; // code for init procedure
typeStack: TTypeSeq; // used for type generation
dataCache: TNodeTable;
forwardedProcs: TSymSeq; // keep forwarded procs here
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;
var
mainModProcs, mainModInit: PRope; // parts of the main module
gMapping: PRope; // the generated mapping file (if requested)
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);
begin
@ -209,26 +251,13 @@ end;
// -------------------------- 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);
begin
//assert(s.loc.k == locNone) // not yet assigned
// this need not be fullfilled for inline procs; they are regenerated
// for each module that uses them!
fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), 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));
if sfRegister in s.flags then
app(p.s[cpsLocals], ' register');
@ -248,11 +277,19 @@ end;
procedure assignGlobalVar(m: BModule; s: PSym);
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);
if lfNoDecl in s.loc.flags then exit;
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 =
[optStackTrace, optEndb] then begin
useMagic(m, 'dbgRegisterGlobal');
@ -282,6 +319,12 @@ begin
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 -------------------------------
// note that a label is a location too
@ -296,11 +339,11 @@ begin
appf(p.s[cpsStmts], '$1: ;$n', [labl])
end;
procedure genProcPrototype(m: BModule; sym: PSym); forward;
procedure genVarPrototype(m: BModule; sym: PSym); forward;
procedure genConstPrototype(m: BModule; sym: PSym); forward;
procedure genProc(m: BModule; prc: PSym); forward;
procedure genStmts(p: BProc; t: PNode); forward;
procedure genProcPrototype(m: BModule; sym: PSym); forward;
{$include 'ccgexprs.pas'}
{$include 'ccgstmts.pas'}
@ -343,11 +386,11 @@ begin
tmp := ropef('Dl_$1', [toRope(sym.id)]);
sym.loc.r := tmp; // from now on we only need the internal name
sym.typ.sym := nil; // generate a new name
appf(m.s[cfsDynLibInit],
'$1 = ($2) nimGetProcAddr($3, $4);$n',
[tmp, getTypeDesc(m, sym.typ), lib.name,
makeCString(ropeToStr(extname))]);
declareGlobalVar(m, sym)
appf(m.s[cfsDynLibInit], '$1 = ($2) nimGetProcAddr($3, $4);$n',
[tmp, getTypeDesc(m, sym.typ), lib.name, makeCString(ropeToStr(extname))]);
app(m.s[cfsVars], getTypeDesc(m, sym.loc.t));
appf(m.s[cfsVars], ' $1;$n', [sym.loc.r]);
end;
// ----------------------------- sections ---------------------------------
@ -356,16 +399,16 @@ procedure UseMagic(m: BModule; const name: string);
var
sym: PSym;
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);
case sym.kind of
skProc, skConverter: genProcPrototype(m, sym);
skVar: genVarPrototype(m, sym);
skType: {@discard} getTypeDesc(m, sym.typ);
else InternalError('useMagic: ' + name)
end
if sym <> nil then
case sym.kind of
skProc, skConverter: genProc(m, sym);
skVar: genVarPrototype(m, sym);
skType: {@discard} getTypeDesc(m, sym.typ);
else InternalError('useMagic: ' + name)
end
else if not (sfSystemModule in m.module.flags) then
rawMessage(errSystemNeeds, name); // don't be too picky here
end;
procedure generateHeaders(m: BModule);
@ -405,95 +448,131 @@ begin
result := (s.typ.sons[0] <> nil) and not isInvalidReturnType(s.typ.sons[0])
end;
procedure genProc(m: BModule; prc: PSym);
procedure genProcAux(m: BModule; prc: PSym);
var
p: BProc;
generatedProc, header, returnStmt: PRope;
i, profileId: int;
i: int;
res, param: PSym;
begin
useHeader(m, prc);
fillLoc(prc.loc, locProc, prc.typ, mangleName(prc), OnStack);
if (lfNoDecl in prc.loc.Flags) then exit;
if lfDynamicLib in prc.loc.flags then
SymInDynamicLib(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);
p := newProc(prc, m);
header := genProcHeader(m, prc);
returnStmt := nil;
assert(prc.ast <> nil);
if not (sfPure in prc.flags) and (prc.typ.sons[0] <> nil) then begin
res := prc.ast.sons[resultPos].sym; // get result symbol
if not isInvalidReturnType(prc.typ.sons[0]) then begin
// declare the result symbol:
assignLocalVar(p, res);
assert(res.loc.r <> nil);
returnStmt := ropef('return $1;$n', [rdLoc(res.loc)]);
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]])
if not (sfPure in prc.flags) and (prc.typ.sons[0] <> nil) then begin
res := prc.ast.sons[resultPos].sym; // get result symbol
if not isInvalidReturnType(prc.typ.sons[0]) then begin
// declare the result symbol:
assignLocalVar(p, res);
assert(res.loc.r <> nil);
returnStmt := ropef('return $1;$n', [rdLoc(res.loc)]);
end
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);
fillResult(res);
assignParam(p, res);
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
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;
procedure genVarPrototype(m: BModule; sym: PSym);
@ -522,7 +601,8 @@ end;
procedure genConstPrototype(m: BModule; sym: PSym);
begin
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
intSetContainsOrIncl(m.declaredThings, sym.id) then
exit;
@ -535,32 +615,6 @@ begin
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;
begin
if optCompileOnly in gGlobalOptions then
@ -593,6 +647,7 @@ procedure genMainProc(m: BModule);
const
CommonMainBody =
' setStackBottom(dummy);$n' +
' nim__datInit();$n' +
' systemInit();$n' +
'$1' +
'$2';
@ -652,8 +707,7 @@ var
initname: PRope;
begin
initname := getInitName(m);
appf(mainModProcs, 'N_NOINLINE(void, $1)(void);$n',
[initname]);
appf(mainModProcs, 'N_NOINLINE(void, $1)(void);$n', [initname]);
if not (sfSystemModule in m.flags) then
appf(mainModInit, '$1();$n', [initname]);
end;
@ -669,14 +723,18 @@ begin
{@discard} lists.IncludeStr(m.headerFiles, '<cycle.h>');
end;
initname := getInitName(m.module);
registerModuleToMain(m.module);
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',
[m.typeNodesName, toRope(m.typeNodes)]);
if m.nimTypes > 0 then
[m.typeNodesName, toRope(m.typeNodes)]);
end;
if m.nimTypes > 0 then begin
useMagic(m, 'TNimType');
appf(m.s[cfsTypeInit1], 'static TNimType $1[$2];$n',
[m.nimTypesName, toRope(m.nimTypes)]);
end;
if optStackTrace in m.initProc.options then begin
getFrameDecl(m.initProc);
app(prc, m.initProc.s[cpsLocals]);
@ -716,7 +774,7 @@ begin
for i := low(TCFileSection) to cfsProcs do app(result, m.s[i])
end;
function newModule(module: PSym; const filename: string): BModule;
function rawNewModule(module: PSym; const filename: string): BModule;
begin
new(result);
{@ignore}
@ -724,7 +782,7 @@ begin
{@emit}
InitLinkedList(result.headerFiles);
intSetInit(result.declaredThings);
intSetInit(result.debugDeclared);
intSetInit(result.declaredProtos);
result.cfilename := filename;
result.filename := filename;
initIdTable(result.typeCache);
@ -735,12 +793,36 @@ begin
result.initProc.options := gOptions;
initNodeTable(result.dataCache);
{@emit result.typeStack := @[];}
{@emit result.forwardedProcs := @[];}
result.typeNodesName := getTempName();
result.nimTypesName := getTempName();
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;
begin
if gmti = nil then registerTypeInfoModule();
result := newModule(module, filename);
end;
@ -749,6 +831,7 @@ function myOpenCached(module: PSym; const filename: string;
var
cfile, cfilenoext, objFile: string;
begin
if gmti = nil then registerTypeInfoModule();
//MessageOut('cgen.myOpenCached has been called ' + filename);
cfile := changeFileExt(completeCFilePath(filename), cExt);
cfilenoext := changeFileExt(cfile, '');
@ -761,6 +844,8 @@ begin
end; *)
addFileToLink(cfilenoext);
registerModuleToMain(module);
// XXX: this cannot be right here, initalization has to be appended during
// the ``myClose`` call
result := nil;
end;
@ -790,11 +875,52 @@ begin
genStmts(m.initProc, n);
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
cfile, cfilenoext: string;
m: BModule;
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
result := n;
if b = nil then exit;
@ -803,22 +929,24 @@ begin
m.initProc.options := gOptions;
genStmts(m.initProc, n);
end;
// generate code for the init statements of the module:
genInitCode(m);
finishTypeDescriptions(m);
cfile := completeCFilePath(m.cfilename);
cfilenoext := changeFileExt(cfile, '');
registerModuleToMain(m.module);
if not (optDeadCodeElim in gGlobalOptions) and
not (sfDeadCodeElim in m.module.flags) then
finishModule(m);
if sfMainModule in m.module.flags then begin
// generate main file:
app(m.s[cfsProcHeaders], mainModProcs);
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;
code := genModule(m, cfilenoext);
if shouldRecompile(code, changeFileExt(cfile, cExt), cfilenoext) then begin
addFileToCompile(cfilenoext); // is to compile
end;
addFileToLink(cfilenoext);
if sfMainModule in m.module.flags then writeMapping(cfile, gMapping);
if not (optDeadCodeElim in gGlobalOptions) and
not (sfDeadCodeElim in m.module.flags) then
writeModule(m);
end;
function cgenPass(): TPass;
@ -832,4 +960,5 @@ end;
initialization
InitIiTable(gToTypeInfoId);
IntSetInit(gGeneratedSyms);
end.

View file

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

View file

@ -218,8 +218,6 @@ begin
end;
function nextSplitPoint(const s: string; start: int): int;
var
i: int;
begin
result := start;
while result < length(s)+strStart do begin
@ -227,7 +225,7 @@ begin
'_': exit;
'a'..'z': begin
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;
else begin end;
end;
@ -393,7 +391,8 @@ begin
fillChar(r, sizeof(r), 0);
{@emit}
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
getNextTok(r, kind, literal);
case kind of
@ -579,7 +578,7 @@ begin
end;
rnHyperlink: begin
result := ropef('`$1 <$2>`_', [renderRstToRst(d, n.sons[0]),
renderRstToRst(d, n.sons[1])]);
renderRstToRst(d, n.sons[1])]);
end;
rnGeneralRole: begin
result := renderRstToRst(d, n.sons[0]);
@ -661,21 +660,26 @@ begin
result := ropef('<ul class="simple">$1</ul>', [result]);
end;
function fieldAux(const s: string): PRope;
begin
result := toRope(strip(s))
end;
function renderImage(d: PDoc; n: PRstNode): PRope;
var
s: string;
begin
result := ropef('<img src="$1"', [toRope(getArgument(n))]);
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');
if s <> '' then appf(result, ' width="$1"', [toRope(s)]);
if s <> '' then appf(result, ' width="$1"', [fieldAux(s)]);
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');
if s <> '' then appf(result, ' alt="$1"', [toRope(s)]);
if s <> '' then appf(result, ' alt="$1"', [fieldAux(s)]);
s := getFieldValue(n, 'align');
if s <> '' then appf(result, ' align="$1"', [toRope(s)]);
if s <> '' then appf(result, ' align="$1"', [fieldAux(s)]);
app(result, ' />');
if rsonsLen(n) >= 3 then app(result, renderRstToHtml(d, n.sons[2]))
end;
@ -863,15 +867,18 @@ begin
nkConverterDef: genItem(d, n, n.sons[namePos], skConverter);
nkVarSection: begin
for i := 0 to sonsLen(n)-1 do
genItem(d, n.sons[i], n.sons[i].sons[0], skVar);
if n.sons[i].kind <> nkCommentStmt then
genItem(d, n.sons[i], n.sons[i].sons[0], skVar);
end;
nkConstSection: begin
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;
nkTypeSection: begin
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;
nkStmtList: begin
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])
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
a, b: TCompRes;
begin
@ -906,7 +907,7 @@ begin
etyObject: begin
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 needsNoCopy(y) then
if needsNoCopy(y) or noCopyNeeded then
appf(r.com, '$1 = $2;$n', [a.res, b.res])
else begin
useMagic(p, 'NimCopy');
@ -930,7 +931,13 @@ end;
procedure genAsgn(var p: TProc; n: PNode; var r: TCompRes);
begin
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;
procedure genSwap(var p: TProc; n: PNode; var r: TCompRes);
@ -1692,6 +1699,7 @@ begin
nkReturnStmt: genReturnStmt(p, n, r);
nkBreakStmt: genBreakStmt(p, n, r);
nkAsgn: genAsgn(p, n, r);
nkFastAsgn: genFastAsgn(p, n, r);
nkDiscardStmt: begin
genLineDir(p, n, r);
gen(p, n.sons[0], r);

View file

@ -28,7 +28,7 @@ type
TStackFrame = record
mapping: TIdNodeTable; // mapping from symbols to nodes
prc: PSym; // current prc; proc that is evaluated
call: PNode; // current for stmt
call: PNode;
next: PStackFrame; // for stacking
params: TNodeSeq; // parameters passed to the proc
end;
@ -127,7 +127,7 @@ begin
inc(i)
end;
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
result := emptyNode
end;
@ -1227,7 +1227,7 @@ begin
nkDerefExpr, nkHiddenDeref: result := evalDeref(c, n);
nkAddr, nkHiddenAddr: result := evalAddr(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);
nkWhileStmt: result := evalWhile(c, n);
nkCaseStmt: result := evalCase(c, n);
@ -1259,7 +1259,7 @@ begin
nkTemplateDef, nkConstSection, nkIteratorDef, nkConverterDef,
nkIncludeStmt, nkImportStmt, nkFromStmt: begin end;
nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr,
nkQualified, nkLambda, nkContinueStmt:
nkQualified, nkLambda, nkContinueStmt, nkIdent:
stackTrace(c, n, errCannotInterpretNodeX, nodeKindToStr[n.kind]);
else InternalError(n.info, 'evalAux: ' + nodekindToStr[n.kind]);
end;

View file

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

View file

@ -61,7 +61,7 @@ begin
result := x -{%} 1;
// complicated, to make it a nop if sizeof(int) == 4,
// because shifting more than 31 bits is undefined in C
result := result or (result shr ((sizeof(int)-4)* 32));
result := result or (result shr ((sizeof(int)-4)* 8));
result := result or (result shr 16);
result := result or (result shr 8);
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 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
// of the CR.
@ -211,8 +211,7 @@ end;
function getColNumber(const L: TBaseLexer; pos: int): int;
begin
result := pos - L.lineStart;
assert(result >= 0);
result := abs(pos - L.lineStart);
end;
function getCurrentLine(const L: TBaseLexer; marker: boolean = true): string;

View file

@ -96,9 +96,10 @@ begin
result := StrTableGet(compilerprocs, ident);
if result = nil then begin
result := StrTableGet(rodCompilerProcs, ident);
if result = nil then rawMessage(errSystemNeeds, name);
strTableAdd(compilerprocs, result);
if result.kind = skStub then loadStub(result);
if result <> nil then begin
strTableAdd(compilerprocs, result);
if result.kind = skStub then loadStub(result);
end;
// 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
// rodgen module. Another solution would be to always recompile the system

View file

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

View file

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

View file

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

View file

@ -149,8 +149,12 @@ function subU(a, b: biggestInt): biggestInt;
function mulU(a, b: biggestInt): biggestInt;
function divU(a, b: biggestInt): biggestInt;
function modU(a, b: biggestInt): biggestInt;
function shlU(a, b: biggestInt): biggestInt;
function shrU(a, b: biggestInt): biggestInt;
function shlU(a, b: biggestInt): biggestInt; overload;
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 leU(a, b: biggestInt): bool;
@ -281,6 +285,16 @@ begin
result := biggestInt(biggestUInt(a) shr biggestUInt(b));
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;
begin
result := biggestUInt(a) < biggestUInt(b);

View file

@ -31,10 +31,10 @@ const
//cog.outl('VersionMinor = %s;' % ver[1])
//cog.outl('VersionPatch = %s;' % ver[2])
//]]]
VersionAsString = '0.7.2';
VersionAsString = '0.7.4';
VersionMajor = 0;
VersionMinor = 7;
VersionPatch = 2;
VersionPatch = 4;
//[[[[end]]]]
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
result := ncopy(dir, length(prefix) + strStart); exit
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
end;
@ -209,7 +215,7 @@ var
head, tail: string;
begin
splitPath(path, head, tail);
result := joinPath([projectPath, genSubDir, shortenDir(head),
result := joinPath([projectPath, genSubDir, shortenDir(head +{&} dirSep),
changeFileExt(tail, ext)])
end;
@ -219,9 +225,11 @@ var
head, tail, subdir: string;
begin
splitPath(f, head, tail);
subdir := joinPath([projectPath, genSubDir, shortenDir(head)]);
if createSubDir then
subdir := joinPath([projectPath, genSubDir, shortenDir(head +{&} dirSep)]);
if createSubDir then begin
//Writeln(output, subdir);
createDir(subdir);
end;
result := joinPath(subdir, tail)
end;

View file

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

View file

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

View file

@ -23,7 +23,7 @@ uses
type
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).
osNone,
osDos,
@ -264,8 +264,8 @@ const
curDir: '.'+'';
exeExt: '';
extSep: '.'+'';
props: {@set}[ospNeedsPIC, ospPosix];
),
props: {@set}[ospNeedsPIC, ospPosix];
),
(
name: 'PalmOS';
parDir: '..';

View file

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

View file

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

View file

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

View file

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

View file

@ -14,7 +14,7 @@ unit ropes;
efficiently; especially concatenation is done in O(1) instead of O(N).
Ropes make use a lazy evaluation: They are essentially concatenation
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.
A little picture makes everything clear:
@ -541,7 +541,6 @@ begin
if (r.data <> snil) then begin
if r.len > bufSize then
// 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');
readBytes := readBuffer(bin, buf, r.len);
result := (readBytes = r.len) // BUGFIX

View file

@ -494,7 +494,13 @@ begin
if n.kind = rnLeaf then begin
for i := strStart to length(n.text)+strStart-1 do begin
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;
addChar(r, n.text[i])
end;
@ -1235,7 +1241,7 @@ begin
result := nil;
if (p.tok[p.idx].kind = tkIndent)
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);
inc(p.idx);
while true do begin
@ -1252,10 +1258,10 @@ var
i: int;
f: PRstNode;
begin
assert(n.kind = rnDirective);
result := '';
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
f := n.sons[1].sons[i];
if cmpIgnoreStyle(addNodes(f.sons[0]), fieldname) = 0 then begin

View file

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

View file

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

View file

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

View file

@ -94,6 +94,25 @@ begin
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;
// if this is an unary operation, b is nil
begin
@ -246,11 +265,18 @@ begin
// available for interpretation. I don't know how to fix this.
//result := newStrNodeT(renderTree(a, {@set}[renderNoComments]), n);
end;
mIntToStr, mInt64ToStr, mBoolToStr, mCharToStr:
mIntToStr, mInt64ToStr:
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);
mCStrToStr: result := newStrNodeT(getStrOrChar(a), n);
mCStrToStr, mCharToStr: result := newStrNodeT(getStrOrChar(a), n);
mStrToStr: result := a;
mEnumToStr: result := newStrNodeT(enumValToString(a), n);
mArrToSeq: begin
result := copyTree(a);
result.typ := n.typ;
@ -370,6 +396,10 @@ begin
mNimrodMinor: result := newIntNodeT(VersionMinor, n);
mNimrodPatch: result := newIntNodeT(VersionPatch, 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);
mInf: result := newFloatNodeT(Inf, n);
mNegInf: result := newFloatNodeT(NegInf, n);

View file

@ -324,7 +324,7 @@ begin
a := newNodeI(nkAsgn, n.sons[0].info);
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``:
if (n.sons[0].kind = nkSym) and (sfResult in n.sons[0].sym.flags) then
begin
@ -378,14 +378,14 @@ function semVar(c: PContext; n: PNode): PNode;
var
i, j, len: int;
a, b, def: PNode;
typ: PType;
typ, tup: PType;
v: PSym;
begin
result := copyNode(n);
for i := 0 to sonsLen(n)-1 do begin
a := n.sons[i];
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);
len := sonsLen(a);
if a.sons[len-2] <> nil then
@ -401,14 +401,21 @@ begin
end
else
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
if (c.p.owner = nil) then begin
if c.p.owner = nil then begin
v := semIdentWithPragma(c, skVar, a.sons[j], {@set}[sfStar, sfMinus]);
include(v.flags, sfGlobal);
end
else
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
include(v.flags, sfInInterface);
addInterfaceDecl(c, v);
@ -443,7 +450,7 @@ begin
if a.sons[1] <> nil then typ := semTypeNode(c, a.sons[1], nil)
else typ := nil;
def := semConstExpr(c, a.sons[2]);
def := semAndEvalConstExpr(c, a.sons[2]);
// check type compability between def.typ and typ:
if (typ <> nil) then begin
def := fitRemoveHiddenConv(c, typ, def);
@ -495,7 +502,7 @@ begin
iter := skipGeneric(n.sons[len-2].typ);
openScope(c.tab);
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.typ := iter;
n.sons[0] := newSymNode(v);
@ -503,7 +510,7 @@ begin
end
else begin
if len-2 <> sonsLen(iter) then
liMessage(n.info, errWrongNumberOfLoopVariables);
liMessage(n.info, errWrongNumberOfVariables);
for i := 0 to len-3 do begin
v := newSymS(skForVar, n.sons[i], c);
v.typ := iter.sons[i];
@ -840,6 +847,7 @@ begin
closeScope(c.tab); // close scope for parameters
popOwner();
c.p := oldP; // restore
result.typ := s.typ;
end;
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;
case templ.kind of
nkSym: begin
if (templ.sym.kind = skTypeParam)
and (templ.sym.owner.id = sym.id) then
if (templ.sym.kind = skTypeParam) then
//and (templ.sym.owner.id = sym.id) then
result := copyTree(actual.sons[templ.sym.position+1])
else
result := copyNode(templ)
@ -285,15 +285,18 @@ begin
result.containerID := s.typ.containerID; // ... but the same containerID
result.sym := s;
if (s.typ.containerID = 0) then
InternalError(n.info, 'semGeneric');
InternalError(n.info, 'semtypes.semGeneric');
for i := 1 to sonsLen(n)-1 do begin
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);
end;
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:
elem := semTypeNode(c, inst, nil);
elem.id := result.containerID;
@ -303,7 +306,9 @@ begin
addSon(result, nil);
end
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;
function semIdentVis(c: PContext; kind: TSymKind; n: PNode;

View file

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

View file

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

View file

@ -75,13 +75,14 @@ const
function strip(const s: string; const chars: TCharSet = WhiteSpace): string;
function allCharsInSet(const s: string; const theSet: TCharSet): bool;
function quoteIfSpaceExists(const s: string): string;
function quoteIfContainsWhite(const s: string): string;
implementation
function quoteIfSpaceExists(const s: string): string;
function quoteIfContainsWhite(const s: string): string;
begin
if (findSubStr(' ', s) >= strStart) and (s[strStart] <> '"') then
if ((findSubStr(' ', s) >= strStart)
or (findSubStr(#9, s) >= strStart)) and (s[strStart] <> '"') then
result := '"' +{&} s +{&} '"'
else
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
sysutils, nsystem, charsets, strutils,
lists, options, ast, astalgo, trees, treetab,
msgs, nos, idents, rnimsyn, types, passes, semfold;
msgs, nos, idents, rnimsyn, types, passes, semfold, magicsys;
const
genPrefix = ':tmp'; // prefix for generated names
@ -139,7 +139,7 @@ More efficient, but not implementable:
function newAsgnStmt(c: PTransf; le, ri: PNode): PNode;
begin
result := newNodeI(nkAsgn, ri.info);
result := newNodeI(nkFastAsgn, ri.info);
addSon(result, le);
addSon(result, ri);
end;
@ -224,6 +224,28 @@ begin
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;
var
e: PNode;
@ -239,10 +261,8 @@ begin
transform(c, copyTree(e.sons[i]))));
end
end
else begin
// XXX: tuple unpacking:
internalError(n.info, 'tuple unpacking is not implemented');
end
else
unpackTuple(c, e, result);
end
else begin
e := transform(c, copyTree(e));
@ -523,7 +543,7 @@ end;
(*
# example:
proc map(f: proc (x: int): int {.closure}, a: seq[int]): seq[int] =
result = []
result = @[]
for elem in a:
add result, f(a)
@ -534,12 +554,12 @@ end;
proc map(f: proc(x: int): int, closure: pointer,
a: seq[int]): seq[int] =
result = []
result = @[]
for elem in a:
add result, f(a, closure)
type
PMyClosure = ref record
PMyClosure = ref object
y: var int
proc myLambda(x: int, closure: pointer) =

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