version 0.7.4
This commit is contained in:
parent
1c8ddca7e0
commit
439aa2d04d
114 changed files with 13664 additions and 10110 deletions
|
|
@ -3,7 +3,7 @@
|
||||||
# Feel free to edit the templates as you need.
|
# Feel free to edit the templates as you need.
|
||||||
|
|
||||||
split.item.toc = "20"
|
split.item.toc = "20"
|
||||||
# too long entries in the table of contents get truncated
|
# too long entries in the table of contents wrap around
|
||||||
# after this number of characters
|
# after this number of characters
|
||||||
|
|
||||||
doc.section = """
|
doc.section = """
|
||||||
|
|
@ -138,6 +138,10 @@ pre, span.tok {
|
||||||
color:black;
|
color:black;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
span.red {
|
||||||
|
color: #A80000;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
:Author: David Goodger
|
:Author: David Goodger
|
||||||
:Contact: goodger@python.org
|
:Contact: goodger@python.org
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ path="$lib/extra"
|
||||||
debugger:off
|
debugger:off
|
||||||
line_dir:off
|
line_dir:off
|
||||||
opt:speed
|
opt:speed
|
||||||
|
dead_code_elim:on
|
||||||
@end
|
@end
|
||||||
|
|
||||||
# additional options always passed to the compiler:
|
# additional options always passed to the compiler:
|
||||||
|
|
@ -51,12 +52,6 @@ hint[LineTooLong]=off
|
||||||
@end
|
@end
|
||||||
|
|
||||||
# Configuration for the LLVM GCC compiler:
|
# 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.debug = "-g"
|
||||||
llvm_gcc.options.always = "-w"
|
llvm_gcc.options.always = "-w"
|
||||||
llvm_gcc.options.speed = "-O2"
|
llvm_gcc.options.speed = "-O2"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
=======================================================
|
=======================================================
|
||||||
The Nimrod Compiler
|
The Nimrod Compiler
|
||||||
Copyright (C) 2004-2008 Andreas Rumpf
|
Copyright (C) 2004-2009 Andreas Rumpf
|
||||||
=======================================================
|
=======================================================
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or
|
This program is free software; you can redistribute it and/or
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
Advanced commands::
|
Advanced commands::
|
||||||
pas convert a Pascal file to Nimrod standard syntax
|
pas convert a Pascal file to Nimrod syntax
|
||||||
pretty pretty print the inputfile
|
pretty pretty print the inputfile
|
||||||
gen_depend generate a DOT file containing the
|
gen_depend generate a DOT file containing the
|
||||||
module dependency graph
|
module dependency graph
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@
|
||||||
'sfCompileTime', # proc can be evaluated at compile time
|
'sfCompileTime', # proc can be evaluated at compile time
|
||||||
'sfThreadVar', # variable is a thread variable
|
'sfThreadVar', # variable is a thread variable
|
||||||
'sfMerge', # proc can be merged with itself
|
'sfMerge', # proc can be merged with itself
|
||||||
|
'sfDeadCodeElim', # dead code elimination for the module is turned on
|
||||||
],
|
],
|
||||||
|
|
||||||
'TypeFlag': [
|
'TypeFlag': [
|
||||||
|
|
@ -116,7 +117,7 @@
|
||||||
# end of atoms
|
# end of atoms
|
||||||
'nkDotCall', # used to temporarily flag a nkCall node; this is used
|
'nkDotCall', # used to temporarily flag a nkCall node; this is used
|
||||||
# for transforming ``s.len`` to ``len(s)``
|
# for transforming ``s.len`` to ``len(s)``
|
||||||
'nkCommand', # a call like ``p 2 4`` without parenthesis
|
'nkCommand', # a call like ``p 2, 4`` without parenthesis
|
||||||
'nkCall', # a call like p(x, y) or an operation like +(a, b)
|
'nkCall', # a call like p(x, y) or an operation like +(a, b)
|
||||||
'nkGenericCall', # a call with given type parameters
|
'nkGenericCall', # a call with given type parameters
|
||||||
'nkExplicitTypeListCall', # a call with given explicit typelist
|
'nkExplicitTypeListCall', # a call with given explicit typelist
|
||||||
|
|
@ -125,6 +126,7 @@
|
||||||
'nkIdentDefs', # a definition like `a, b: typeDesc = expr`
|
'nkIdentDefs', # a definition like `a, b: typeDesc = expr`
|
||||||
# either typeDesc or expr may be nil; used in
|
# either typeDesc or expr may be nil; used in
|
||||||
# formal parameters, var statements, etc.
|
# formal parameters, var statements, etc.
|
||||||
|
'nkVarTuple', # a ``var (a, b) = expr`` construct
|
||||||
'nkInfix', # a call like (a + b)
|
'nkInfix', # a call like (a + b)
|
||||||
'nkPrefix', # a call like !a
|
'nkPrefix', # a call like !a
|
||||||
'nkPostfix', # something like a! (also used for visibility)
|
'nkPostfix', # something like a! (also used for visibility)
|
||||||
|
|
@ -166,6 +168,7 @@
|
||||||
# end of expressions
|
# end of expressions
|
||||||
|
|
||||||
'nkAsgn', # a = b
|
'nkAsgn', # a = b
|
||||||
|
'nkFastAsgn', # internal node for a fast ``a = b`` (no string copy)
|
||||||
'nkDefaultTypeParam', # `ident = typeDesc` in generic parameters
|
'nkDefaultTypeParam', # `ident = typeDesc` in generic parameters
|
||||||
'nkGenericParams', # generic parameters
|
'nkGenericParams', # generic parameters
|
||||||
'nkFormalParams', # formal parameters
|
'nkFormalParams', # formal parameters
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ Options:
|
||||||
--bound_checks:on|off code generation for bound checks ON|OFF
|
--bound_checks:on|off code generation for bound checks ON|OFF
|
||||||
--overflow_checks:on|off code generation for over-/underflow checks ON|OFF
|
--overflow_checks:on|off code generation for over-/underflow checks ON|OFF
|
||||||
-a, --assertions:on|off code generation for assertions ON|OFF
|
-a, --assertions:on|off code generation for assertions ON|OFF
|
||||||
|
--dead_code_elim:on|off whole program dead code elimination ON|OFF
|
||||||
--opt:none|speed|size optimize not at all or for speed|size
|
--opt:none|speed|size optimize not at all or for speed|size
|
||||||
--app:console|gui|lib generate a console|GUI application or a shared lib
|
--app:console|gui|lib generate a console|GUI application or a shared lib
|
||||||
-r, --run run the compiled program with given arguments
|
-r, --run run the compiled program with given arguments
|
||||||
|
|
|
||||||
|
|
@ -140,6 +140,7 @@
|
||||||
'FloatToStr',
|
'FloatToStr',
|
||||||
'CStrToStr',
|
'CStrToStr',
|
||||||
'StrToStr',
|
'StrToStr',
|
||||||
|
'EnumToStr',
|
||||||
|
|
||||||
# special ones:
|
# special ones:
|
||||||
'And',
|
'And',
|
||||||
|
|
@ -209,6 +210,8 @@
|
||||||
'NimrodMinor',
|
'NimrodMinor',
|
||||||
'NimrodPatch',
|
'NimrodPatch',
|
||||||
'CpuEndian',
|
'CpuEndian',
|
||||||
|
'HostOS',
|
||||||
|
'HostCPU',
|
||||||
'NaN',
|
'NaN',
|
||||||
'Inf',
|
'Inf',
|
||||||
'NegInf',
|
'NegInf',
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,7 @@
|
||||||
'selector must be of an ordinal type'},
|
'selector must be of an ordinal type'},
|
||||||
{'errOrdXMustNotBeNegative': 'ord($1) must not be negative'},
|
{'errOrdXMustNotBeNegative': 'ord($1) must not be negative'},
|
||||||
{'errLenXinvalid': 'len($1) must be less than 32768'},
|
{'errLenXinvalid': 'len($1) must be less than 32768'},
|
||||||
{'errWrongNumberOfLoopVariables': 'wrong number of loop variables'},
|
{'errWrongNumberOfVariables': 'wrong number of variables'},
|
||||||
{'errExprCannotBeRaised': 'only objects can be raised'},
|
{'errExprCannotBeRaised': 'only objects can be raised'},
|
||||||
{'errBreakOnlyInLoop': "'break' only allowed in loop construct"},
|
{'errBreakOnlyInLoop': "'break' only allowed in loop construct"},
|
||||||
{'errTypeXhasUnknownSize': "type '$1' has unknown size"},
|
{'errTypeXhasUnknownSize': "type '$1' has unknown size"},
|
||||||
|
|
|
||||||
38
deinstall.sh
38
deinstall.sh
|
|
@ -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
|
|
||||||
|
|
||||||
17
doc/docs.txt
17
doc/docs.txt
|
|
@ -3,25 +3,28 @@
|
||||||
|
|
||||||
The documentation consists of several documents:
|
The documentation consists of several documents:
|
||||||
|
|
||||||
- | `First steps after installation <steps.html>`_
|
- | `Nimrod tutorial (part I) <tut1.html>`_
|
||||||
| Read this after installation for a quick introduction.
|
| The Nimrod tutorial part one deals with the basics.
|
||||||
|
|
||||||
|
- | `Nimrod tutorial (part II) <tut2.html>`_
|
||||||
|
| The Nimrod tutorial part two deals with the advanced language constructs.
|
||||||
|
|
||||||
- | `Nimrod manual <manual.html>`_
|
- | `Nimrod manual <manual.html>`_
|
||||||
| Read this to get to know the Nimrod programming system.
|
| The Nimrod manual is a draft that will evolve into a proper specification.
|
||||||
|
|
||||||
- | `User guide for the Nimrod Compiler <nimrodc.html>`_
|
- | `User guide for the Nimrod Compiler <nimrodc.html>`_
|
||||||
| The user guide lists command line arguments, Nimrodc's special features, etc.
|
| The user guide lists command line arguments, special features of the
|
||||||
|
compiler, etc.
|
||||||
|
|
||||||
- | `User guide for the Embedded Nimrod Debugger <endb.html>`_
|
- | `User guide for the Embedded Nimrod Debugger <endb.html>`_
|
||||||
| This document describes how to use the Embedded debugger. The embedded
|
| This document describes how to use the Embedded Debugger.
|
||||||
debugger currently has no GUI. Please help!
|
|
||||||
|
|
||||||
- | `Nimrod library documentation <lib.html>`_
|
- | `Nimrod library documentation <lib.html>`_
|
||||||
| This document describes Nimrod's standard library.
|
| This document describes Nimrod's standard library.
|
||||||
|
|
||||||
- | `Nimrod internal documentation <intern.html>`_
|
- | `Nimrod internal documentation <intern.html>`_
|
||||||
| The internal documentation describes how the compiler is implemented. Read
|
| The internal documentation describes how the compiler is implemented. Read
|
||||||
this if you want to hack the compiler or develop advanced macros.
|
this if you want to hack the compiler.
|
||||||
|
|
||||||
- | `Index <theindex.html>`_
|
- | `Index <theindex.html>`_
|
||||||
| The generated index. Often the quickest way to find the piece of
|
| The generated index. Often the quickest way to find the piece of
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,19 @@ Short description of Nimrod's modules
|
||||||
============== ==========================================================
|
============== ==========================================================
|
||||||
Module Description
|
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
|
lexbase buffer handling of the lexical analyser
|
||||||
scanner 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
|
ast type definitions of the abstract syntax tree (AST) and
|
||||||
node constructors
|
node constructors
|
||||||
astalgo algorithms for containers of AST nodes; converting the
|
astalgo algorithms for containers of AST nodes; converting the
|
||||||
|
|
@ -21,17 +31,20 @@ sigmatch contains the matching algorithm that is used for proc
|
||||||
semexprs contains the semantic checking phase for expressions
|
semexprs contains the semantic checking phase for expressions
|
||||||
semstmts contains the semantic checking phase for statements
|
semstmts contains the semantic checking phase for statements
|
||||||
semtypes contains the semantic checking phase for types
|
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
|
idents implements a general mapping from identifiers to an internal
|
||||||
representation (``PIdent``) that is used, so that a simple
|
representation (``PIdent``) that is used, so that a simple
|
||||||
id-comparison suffices to say whether two Nimrod identifiers
|
id-comparison suffices to say whether two Nimrod identifiers
|
||||||
are equivalent
|
are equivalent
|
||||||
|
ropes implements long strings represented as trees for
|
||||||
ropes implements long strings using represented as trees for
|
|
||||||
lazy evaluation; used mainly by the code generators
|
lazy evaluation; used mainly by the code generators
|
||||||
|
|
||||||
ccgobj contains type definitions neeeded for C code generation
|
transf transformations on the AST that need to be done before
|
||||||
and some helpers
|
code generation
|
||||||
|
cgen main file of the C code generator
|
||||||
ccgutils contains helpers for the C code generator
|
ccgutils contains helpers for the C code generator
|
||||||
ccgtypes the generator for C types
|
ccgtypes the generator for C types
|
||||||
ccgstmts the generator for statements
|
ccgstmts the generator for statements
|
||||||
|
|
|
||||||
239
doc/grammar.txt
239
doc/grammar.txt
|
|
@ -1,45 +1,43 @@
|
||||||
module ::= ([COMMENT] [SAD] stmt)*
|
module ::= ([COMMENT] [SAD] stmt)*
|
||||||
|
|
||||||
comma ::= ',' [COMMENT] [IND]
|
comma ::= ',' [COMMENT] [IND]
|
||||||
operator ::= OP0 | OR | XOR | AND | OP3 | OP4 | OP5 | IS | ISNOT | IN | NOTIN
|
operator ::= OP0 | OR | XOR | AND | OP3 | OP4 | OP5 | OP6 | OP7
|
||||||
| OP6 | DIV | MOD | SHL | SHR | OP7 | NOT
|
| 'is' | 'isnot' | 'in' | 'notin'
|
||||||
|
| 'div' | 'mod' | 'shl' | 'shr' | 'not'
|
||||||
|
|
||||||
prefixOperator ::= OP0 | OP3 | OP4 | OP5 | OP6 | OP7 | NOT
|
prefixOperator ::= OP0 | OP3 | OP4 | OP5 | OP6 | OP7 | 'not'
|
||||||
|
|
||||||
optInd ::= [COMMENT] [IND]
|
optInd ::= [COMMENT] [IND]
|
||||||
|
|
||||||
|
|
||||||
lowestExpr ::= orExpr ( OP0 optInd orExpr )*
|
lowestExpr ::= orExpr (OP0 optInd orExpr)*
|
||||||
orExpr ::= andExpr ( OR | XOR optInd andExpr )*
|
orExpr ::= andExpr (OR | 'xor' optInd andExpr)*
|
||||||
andExpr ::= cmpExpr ( AND optInd cmpExpr )*
|
andExpr ::= cmpExpr ('and' optInd cmpExpr)*
|
||||||
cmpExpr ::= ampExpr ( OP3 | IS | ISNOT | IN | NOTIN optInd ampExpr )*
|
cmpExpr ::= ampExpr (OP3 | 'is' | 'isnot' | 'in' | 'notin' optInd ampExpr)*
|
||||||
ampExpr ::= plusExpr ( OP4 optInd plusExpr )*
|
ampExpr ::= plusExpr (OP4 optInd plusExpr)*
|
||||||
plusExpr ::= mulExpr ( OP5 optInd mulExpr )*
|
plusExpr ::= mulExpr (OP5 optInd mulExpr)*
|
||||||
mulExpr ::= dollarExpr ( OP6 | DIV | MOD | SHL | SHR optInd dollarExpr )*
|
mulExpr ::= dollarExpr (OP6 | 'div' | 'mod' | 'shl' | 'shr' optInd dollarExpr)*
|
||||||
dollarExpr ::= primary ( OP7 optInd primary )*
|
dollarExpr ::= primary (OP7 optInd primary)*
|
||||||
|
|
||||||
namedTypeOrExpr ::=
|
namedTypeOrExpr ::=
|
||||||
DOTDOT [expr]
|
'..' [expr]
|
||||||
| expr [EQUALS (expr [DOTDOT expr] | typeDescK | DOTDOT [expr] )
|
| expr ['=' (expr ['..' expr] | typeDescK | '..' [expr]) | '..' [expr]]
|
||||||
| DOTDOT [expr]]
|
|
||||||
| typeDescK
|
| typeDescK
|
||||||
|
|
||||||
castExpr ::= CAST BRACKET_LE optInd typeDesc BRACKERT_RI
|
castExpr ::= 'cast' '[' optInd typeDesc [SAD] ']' '(' optInd expr [SAD] ')'
|
||||||
PAR_LE optInd expr PAR_RI
|
addrExpr ::= 'addr' '(' optInd expr ')'
|
||||||
addrExpr ::= ADDR PAR_LE optInd expr PAR_RI
|
symbol ::= '`' (KEYWORD | IDENT | operator | '(' ')'
|
||||||
symbol ::= ACC (KEYWORD | IDENT | operator | PAR_LE PAR_RI
|
| '[' ']' | '=' | literal)+ '`'
|
||||||
| BRACKET_LE BRACKET_RI | EQUALS | literal )+ ACC
|
|
||||||
| IDENT
|
| IDENT
|
||||||
primary ::= ( prefixOperator optInd )* ( symbol | constructor |
|
primary ::= (prefixOperator optInd)* (symbol | constructor |
|
||||||
| castExpr | addrExpr ) (
|
| castExpr | addrExpr) (
|
||||||
DOT optInd symbol
|
'.' optInd symbol
|
||||||
#| CURLY_LE namedTypeDescList CURLY_RI
|
| '(' optInd namedExprList [SAD] ')'
|
||||||
| PAR_LE optInd namedExprList PAR_RI
|
| '[' optInd
|
||||||
| BRACKET_LE optInd
|
[namedTypeOrExpr (comma namedTypeOrExpr)* [comma]]
|
||||||
[ namedTypeOrExpr (comma namedTypeOrExpr)* [comma] ]
|
[SAD] ']'
|
||||||
BRACKET_RI
|
| '^'
|
||||||
| CIRCUM
|
| pragma)*
|
||||||
| pragma )*
|
|
||||||
|
|
||||||
literal ::= INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
|
literal ::= INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
|
||||||
| FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
|
| FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
|
||||||
|
|
@ -48,48 +46,42 @@ literal ::= INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
|
||||||
| NIL
|
| NIL
|
||||||
|
|
||||||
constructor ::= literal
|
constructor ::= literal
|
||||||
| BRACKET_LE optInd colonExprList BRACKET_RI # []-Constructor
|
| '[' optInd colonExprList [SAD] ']'
|
||||||
| CURLY_LE optInd sliceExprList CURLY_RI # {}-Constructor
|
| '{' optInd sliceExprList [SAD] '}'
|
||||||
| PAR_LE optInd colonExprList PAR_RI # ()-Constructor
|
| '(' optInd colonExprList [SAD] ')'
|
||||||
|
|
||||||
exprList ::= [ expr (comma expr)* [comma] ]
|
colonExpr ::= expr [':' expr]
|
||||||
|
colonExprList ::= [colonExpr (comma colonExpr)* [comma]]
|
||||||
|
|
||||||
colonExpr ::= expr [COLON expr]
|
namedExpr ::= expr ['=' expr]
|
||||||
colonExprList ::= [ colonExpr (comma colonExpr)* [comma] ]
|
namedExprList ::= [namedExpr (comma namedExpr)* [comma]]
|
||||||
|
|
||||||
namedExpr ::= expr [EQUALS expr] # actually this is symbol EQUALS expr|expr
|
sliceExpr ::= expr ['..' expr]
|
||||||
namedExprList ::= [ namedExpr (comma namedExpr)* [comma] ]
|
sliceExprList ::= [sliceExpr (comma sliceExpr)* [comma]]
|
||||||
|
|
||||||
sliceExpr ::= expr [ DOTDOT expr ]
|
anonymousProc ::= 'lambda' paramList [pragma] '=' stmt
|
||||||
sliceExprList ::= [ sliceExpr (comma sliceExpr)* [comma] ]
|
|
||||||
|
|
||||||
anonymousProc ::= LAMBDA paramList [pragma] EQUALS stmt
|
|
||||||
expr ::= lowestExpr
|
expr ::= lowestExpr
|
||||||
| anonymousProc
|
| anonymousProc
|
||||||
| IF expr COLON expr
|
| 'if' expr ':' expr ('elif' expr ':' expr)* 'else' ':' expr
|
||||||
(ELIF expr COLON expr)*
|
|
||||||
ELSE COLON expr
|
|
||||||
|
|
||||||
namedTypeDesc ::= typeDescK | expr [EQUALS (typeDescK | expr)]
|
namedTypeDesc ::= typeDescK | expr ['=' (typeDescK | expr)]
|
||||||
namedTypeDescList ::= [ namedTypeDesc (comma namedTypeDesc)* [comma] ]
|
namedTypeDescList ::= [namedTypeDesc (comma namedTypeDesc)* [comma]]
|
||||||
|
|
||||||
qualifiedIdent ::= symbol [ DOT symbol ]
|
qualifiedIdent ::= symbol ['.' symbol]
|
||||||
|
|
||||||
typeDescK ::= VAR typeDesc
|
typeDescK ::= 'var' typeDesc
|
||||||
| REF typeDesc
|
| 'ref' typeDesc
|
||||||
| PTR typeDesc
|
| 'ptr' typeDesc
|
||||||
| TYPE expr
|
| 'type' expr
|
||||||
| TUPLE tupleDesc
|
| 'tuple' tupleDesc
|
||||||
| PROC paramList [pragma]
|
| 'proc' paramList [pragma]
|
||||||
|
|
||||||
typeDesc ::= typeDescK | primary
|
typeDesc ::= typeDescK | primary
|
||||||
|
|
||||||
optSemicolon ::= [SEMICOLON]
|
macroStmt ::= ':' [stmt] ('of' [sliceExprList] ':' stmt
|
||||||
|
|'elif' expr ':' stmt
|
||||||
macroStmt ::= COLON [stmt] (OF [sliceExprList] COLON stmt
|
|'except' exceptList ':' stmt )*
|
||||||
| ELIF expr COLON stmt
|
['else' ':' stmt]
|
||||||
| EXCEPT exceptList COLON stmt )*
|
|
||||||
[ELSE COLON stmt]
|
|
||||||
|
|
||||||
simpleStmt ::= returnStmt
|
simpleStmt ::= returnStmt
|
||||||
| yieldStmt
|
| yieldStmt
|
||||||
|
|
@ -107,88 +99,91 @@ complexStmt ::= ifStmt | whileStmt | caseStmt | tryStmt | forStmt
|
||||||
| procDecl | iteratorDecl | macroDecl | templateDecl
|
| procDecl | iteratorDecl | macroDecl | templateDecl
|
||||||
| constSection | typeSection | whenStmt | varSection
|
| constSection | typeSection | whenStmt | varSection
|
||||||
|
|
||||||
indPush ::= IND # push
|
indPush ::= IND # and push indentation onto the stack
|
||||||
|
indPop ::= # pop indentation from the stack
|
||||||
|
|
||||||
stmt ::= simpleStmt [SAD]
|
stmt ::= simpleStmt [SAD]
|
||||||
| indPush (complexStmt | simpleStmt)
|
| indPush (complexStmt | simpleStmt)
|
||||||
([SAD] (complexStmt | simpleStmt) )*
|
([SAD] (complexStmt | simpleStmt))*
|
||||||
DED
|
DED indPop
|
||||||
|
|
||||||
exprStmt ::= lowestExpr [EQUALS expr | [expr (comma expr)* [comma]] [macroStmt]]
|
exprStmt ::= lowestExpr ['=' expr | [expr (comma expr)*] [macroStmt]]
|
||||||
returnStmt ::= RETURN [expr]
|
returnStmt ::= 'return' [expr]
|
||||||
yieldStmt ::= YIELD expr
|
yieldStmt ::= 'yield' expr
|
||||||
discardStmt ::= DISCARD expr
|
discardStmt ::= 'discard' expr
|
||||||
raiseStmt ::= RAISE [expr]
|
raiseStmt ::= 'raise' [expr]
|
||||||
breakStmt ::= BREAK [symbol]
|
breakStmt ::= 'break' [symbol]
|
||||||
continueStmt ::= CONTINUE
|
continueStmt ::= 'continue'
|
||||||
ifStmt ::= IF expr COLON stmt (ELIF expr COLON stmt)* [ELSE COLON stmt]
|
ifStmt ::= 'if' expr ':' stmt ('elif' expr ':' stmt)* ['else' ':' stmt]
|
||||||
whenStmt ::= WHEN expr COLON stmt (ELIF expr COLON stmt)* [ELSE COLON stmt]
|
whenStmt ::= 'when' expr ':' stmt ('elif' expr ':' stmt)* ['else' ':' stmt]
|
||||||
caseStmt ::= CASE expr (OF sliceExprList COLON stmt)*
|
caseStmt ::= 'case' expr [':'] ('of' sliceExprList ':' stmt)*
|
||||||
(ELIF expr COLON stmt)*
|
('elif' expr ':' stmt)*
|
||||||
[ELSE COLON stmt]
|
['else' ':' stmt]
|
||||||
whileStmt ::= WHILE expr COLON stmt
|
whileStmt ::= 'while' expr ':' stmt
|
||||||
forStmt ::= FOR symbol (comma symbol)* [comma] IN expr [DOTDOT expr] COLON stmt
|
forStmt ::= 'for' symbol (comma symbol)* 'in' expr ['..' expr] ':' stmt
|
||||||
exceptList ::= [qualifiedIdent (comma qualifiedIdent)* [comma]]
|
exceptList ::= [qualifiedIdent (comma qualifiedIdent)*]
|
||||||
|
|
||||||
tryStmt ::= TRY COLON stmt
|
tryStmt ::= 'try' ':' stmt
|
||||||
(EXCEPT exceptList COLON stmt)*
|
('except' exceptList ':' stmt)*
|
||||||
[FINALLY COLON stmt]
|
['finally' ':' stmt]
|
||||||
asmStmt ::= ASM [pragma] (STR_LIT | RSTR_LIT | TRIPLESTR_LIT)
|
asmStmt ::= 'asm' [pragma] (STR_LIT | RSTR_LIT | TRIPLESTR_LIT)
|
||||||
blockStmt ::= BLOCK [symbol] COLON stmt
|
blockStmt ::= 'block' [symbol] ':' stmt
|
||||||
filename ::= symbol | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
|
filename ::= symbol | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
|
||||||
importStmt ::= IMPORT filename (comma filename)* [comma]
|
importStmt ::= 'import' filename (comma filename)*
|
||||||
includeStmt ::= INCLUDE filename (comma filename)* [comma]
|
includeStmt ::= 'include' filename (comma filename)*
|
||||||
fromStmt ::= FROM filename IMPORT symbol (comma symbol)* [comma]
|
fromStmt ::= 'from' filename 'import' symbol (comma symbol)*
|
||||||
|
|
||||||
pragma ::= CURLYDOT_LE colonExprList (CURLYDOT_RI | CURLY_RI)
|
pragma ::= '{.' optInd (colonExpr [comma])* [SAD] ('.}' | '}')
|
||||||
|
|
||||||
param ::= symbol (comma symbol)* [comma] COLON typeDesc
|
param ::= symbol (comma symbol)* ':' typeDesc
|
||||||
paramList ::= [PAR_LE [param (comma param)* [comma]] PAR_RI] [COLON typeDesc]
|
paramList ::= ['(' [param (comma param)*] [SAD] ')'] [':' typeDesc]
|
||||||
|
|
||||||
genericParams ::= BRACKET_LE (symbol [EQUALS typeDesc] )* BRACKET_RI
|
genericParam ::= symbol [':' typeDesc]
|
||||||
|
genericParams ::= '[' genericParam (comma genericParam)* [SAD] ']'
|
||||||
|
|
||||||
procDecl ::= PROC symbol ["*"] [genericParams]
|
procDecl ::= 'proc' symbol ['*'] [genericParams] paramList [pragma]
|
||||||
paramList [pragma]
|
['=' stmt]
|
||||||
[EQUALS stmt]
|
macroDecl ::= 'macro' symbol ['*'] [genericParams] paramList [pragma]
|
||||||
macroDecl ::= MACRO symbol ["*"] [genericParams] paramList [pragma]
|
['=' stmt]
|
||||||
[EQUALS stmt]
|
iteratorDecl ::= 'iterator' symbol ['*'] [genericParams] paramList [pragma]
|
||||||
iteratorDecl ::= ITERATOR symbol ["*"] [genericParams] paramList [pragma]
|
['=' stmt]
|
||||||
[EQUALS stmt]
|
templateDecl ::= 'template' symbol ['*'] [genericParams] paramList [pragma]
|
||||||
templateDecl ::= TEMPLATE symbol ["*"] [genericParams] paramList [pragma]
|
['=' stmt]
|
||||||
[EQUALS stmt]
|
|
||||||
|
|
||||||
colonAndEquals ::= [COLON typeDesc] EQUALS expr
|
colonAndEquals ::= [':' typeDesc] '=' expr
|
||||||
|
|
||||||
constDecl ::= symbol ["*"] [pragma] colonAndEquals [COMMENT | IND COMMENT]
|
constDecl ::= symbol ['*'] [pragma] colonAndEquals [COMMENT | IND COMMENT]
|
||||||
| COMMENT
|
| COMMENT
|
||||||
constSection ::= CONST indPush constDecl (SAD constDecl)* DED
|
constSection ::= 'const' indPush constDecl (SAD constDecl)* DED indPop
|
||||||
typeDef ::= typeDesc | objectDef | enumDef
|
typeDef ::= typeDesc | objectDef | enumDef
|
||||||
|
|
||||||
objectField ::= symbol ["*"] [pragma]
|
objectField ::= symbol ['*'] [pragma]
|
||||||
objectIdentPart ::=
|
objectIdentPart ::=
|
||||||
objectField (comma objectField)* [comma] COLON typeDesc [COMMENT|IND COMMENT]
|
objectField (comma objectField)* ':' typeDesc [COMMENT|IND COMMENT]
|
||||||
|
|
||||||
objectWhen ::= WHEN expr COLON [COMMENT] objectPart
|
objectWhen ::= 'when' expr ':' [COMMENT] objectPart
|
||||||
(ELIF expr COLON [COMMENT] objectPart)*
|
('elif' expr ':' [COMMENT] objectPart)*
|
||||||
[ELSE COLON [COMMENT] objectPart]
|
['else' ':' [COMMENT] objectPart]
|
||||||
objectCase ::= CASE expr COLON typeDesc [COMMENT]
|
objectCase ::= 'case' expr ':' typeDesc [COMMENT]
|
||||||
(OF sliceExprList COLON [COMMENT] objectPart)*
|
('of' sliceExprList ':' [COMMENT] objectPart)*
|
||||||
[ELSE COLON [COMMENT] objectPart]
|
['else' ':' [COMMENT] objectPart]
|
||||||
|
|
||||||
objectPart ::= objectWhen | objectCase | objectIdentPart | NIL
|
objectPart ::= objectWhen | objectCase | objectIdentPart | 'nil'
|
||||||
| indPush objectPart (SAD objectPart)* DED
|
| indPush objectPart (SAD objectPart)* DED indPop
|
||||||
tupleDesc ::= BRACKET_LE optInd [param (comma param)* [comma]] BRACKET_RI
|
tupleDesc ::= '[' optInd [param (comma param)*] [SAD] ']'
|
||||||
|
|
||||||
objectDef ::= OBJECT [pragma] [OF typeDesc] objectPart
|
objectDef ::= 'object' [pragma] ['of' typeDesc] objectPart
|
||||||
enumField ::= symbol [EQUALS expr]
|
enumField ::= symbol ['=' expr]
|
||||||
enumDef ::= ENUM [OF typeDesc] (enumField [comma | COMMENT | IND COMMENT])+
|
enumDef ::= 'enum' ['of' typeDesc] (enumField [comma] [COMMENT | IND COMMENT])+
|
||||||
|
|
||||||
typeDecl ::= COMMENT
|
typeDecl ::= COMMENT
|
||||||
| symbol ["*"] [genericParams] [EQUALS typeDef] [COMMENT | IND COMMENT]
|
| symbol ['*'] [genericParams] ['=' typeDef] [COMMENT | IND COMMENT]
|
||||||
|
|
||||||
typeSection ::= TYPE indPush typeDecl (SAD typeDecl)* DED
|
typeSection ::= 'type' indPush typeDecl (SAD typeDecl)* DED indPop
|
||||||
|
|
||||||
colonOrEquals ::= COLON typeDesc [EQUALS expr] | EQUALS expr
|
colonOrEquals ::= ':' typeDesc ['=' expr] | '=' expr
|
||||||
varField ::= symbol ["*"] [pragma]
|
varField ::= symbol ['*'] [pragma]
|
||||||
varPart ::= symbol (comma symbol)* [comma] colonOrEquals [COMMENT | IND COMMENT]
|
varPart ::= symbol (comma symbol)* colonOrEquals [COMMENT | IND COMMENT]
|
||||||
varSection ::= VAR (varPart
|
varSection ::= 'var' (varPart
|
||||||
| indPush (COMMENT|varPart) (SAD (COMMENT|varPart))* DED)
|
| indPush (COMMENT|varPart)
|
||||||
|
(SAD (COMMENT|varPart))* DED indPop)
|
||||||
|
|
|
||||||
187
doc/intern.txt
187
doc/intern.txt
|
|
@ -34,7 +34,6 @@ Path Purpose
|
||||||
on it!
|
on it!
|
||||||
``web`` website of Nimrod; generated by ``koch.py``
|
``web`` website of Nimrod; generated by ``koch.py``
|
||||||
from the ``*.txt`` and ``*.tmpl`` files
|
from the ``*.txt`` and ``*.tmpl`` files
|
||||||
``koch`` the Koch Build System (written for Nimrod)
|
|
||||||
``obj`` generated ``*.obj`` files go into here
|
``obj`` generated ``*.obj`` files go into here
|
||||||
============ ==============================================
|
============ ==============================================
|
||||||
|
|
||||||
|
|
@ -45,44 +44,76 @@ Bootstrapping the compiler
|
||||||
The compiler is written in a subset of Pascal with special annotations so
|
The compiler is written in a subset of Pascal with special annotations so
|
||||||
that it can be translated to Nimrod code automatically. This conversion is
|
that it can be translated to Nimrod code automatically. This conversion is
|
||||||
done by Nimrod itself via the undocumented ``boot`` command. Thus both Nimrod
|
done by Nimrod itself via the undocumented ``boot`` command. Thus both Nimrod
|
||||||
and Free Pascal can compile the Nimrod compiler.
|
and Free Pascal can compile the Nimrod compiler. However, the Pascal version
|
||||||
|
has no garbage collector and leaks memory like crazy! So the Pascal version
|
||||||
|
should only be used for bootstrapping.
|
||||||
|
|
||||||
Requirements for bootstrapping:
|
Requirements for bootstrapping:
|
||||||
|
|
||||||
- Free Pascal (I used version 2.2) [optional]
|
- Python (should work with version 1.5 or higher) (optional)
|
||||||
- Python (should work with version 1.5 or higher)
|
- supported C compiler
|
||||||
|
|
||||||
- C compiler -- one of:
|
Compiling the compiler is a simple matter of running::
|
||||||
|
|
||||||
* win32-lcc (currently broken)
|
koch.py boot
|
||||||
* Borland C++ (tested with 5.5; currently broken)
|
|
||||||
* Microsoft C++
|
|
||||||
* Digital Mars C++
|
|
||||||
* Watcom C++ (currently broken)
|
|
||||||
* GCC
|
|
||||||
* Intel C++
|
|
||||||
* Pelles C (currently broken)
|
|
||||||
* llvm-gcc
|
|
||||||
|
|
||||||
| Compiling the compiler is a simple matter of running:
|
For a release version use::
|
||||||
| ``koch.py boot``
|
|
||||||
| Or you can compile by hand, this is not difficult.
|
|
||||||
|
|
||||||
If you want to debug the compiler, use the command::
|
koch.py boot -d:release
|
||||||
|
|
||||||
koch.py boot --debugger:on
|
The ``koch.py`` script is Nimrod's maintainance script. It is a replacement for
|
||||||
|
make and shell scripting with the advantage that it is much more portable.
|
||||||
|
|
||||||
The ``koch.py`` script is Nimrod's maintainance script: Everything that has
|
If you don't have Python, there is a ``boot`` Nimrod program which does roughly
|
||||||
been automated is accessible with it. It is a replacement for make and shell
|
the same::
|
||||||
scripting with the advantage that it is more portable.
|
|
||||||
|
nimrod cc boot.nim
|
||||||
|
./boot [-d:release]
|
||||||
|
|
||||||
|
|
||||||
Coding standards
|
Pascal annotations
|
||||||
================
|
==================
|
||||||
|
There are some annotations that the Pascal sources use so that they can
|
||||||
|
be converted to Nimrod automatically:
|
||||||
|
|
||||||
The compiler is written in a subset of Pascal with special annotations so
|
``{@discard} <expr>``
|
||||||
that it can be translated to Nimrod code automatically. As a general rule,
|
Tells the compiler that a ``discard`` statement is needed for Nimrod
|
||||||
Pascal code that does not translate to Nimrod automatically is forbidden.
|
here.
|
||||||
|
|
||||||
|
``{@cast}typ(expr)``
|
||||||
|
Tells the compiler that the Pascal conversion is a ``cast`` in Nimrod.
|
||||||
|
|
||||||
|
``{@emit <code>}``
|
||||||
|
Emits ``<code>``. The code fragment needs to be in Pascal syntax.
|
||||||
|
|
||||||
|
``{@ignore} <codeA> {@emit <codeB>}``
|
||||||
|
Ignores ``<codeA>`` and instead emits ``<codeB>`` which needs to be in
|
||||||
|
Pascal syntax. An empty ``{@emit}`` is possible too (it then only closes
|
||||||
|
the ``<codeA>`` part).
|
||||||
|
|
||||||
|
``record {@tuple}``
|
||||||
|
Is used to tell the compiler that the record type should be transformed
|
||||||
|
to a Nimrod tuple type.
|
||||||
|
|
||||||
|
``^ {@ptr}``
|
||||||
|
Is used to tell the compiler that the pointer type should be transformed
|
||||||
|
to a Nimrod ``ptr`` type. The default is a ``ref`` type.
|
||||||
|
|
||||||
|
``'a' + ''``
|
||||||
|
The idiom ``+''`` is used to tell the compiler that it is a string
|
||||||
|
literal and not a character literal. (Pascal does not distinguish between
|
||||||
|
character literals and string literals of length 1.)
|
||||||
|
|
||||||
|
``+{&}``
|
||||||
|
This tells the compiler that Pascal's ``+`` here is a string concatenation
|
||||||
|
and thus should be converted to ``&``. Note that this is not needed if
|
||||||
|
any of the operands is a string literal because the compiler then can
|
||||||
|
figure this out by itself.
|
||||||
|
|
||||||
|
``{@set}['a', 'b', 'c']``
|
||||||
|
Tells the compiler that Pascal's ``[]`` constructor is a set and not an
|
||||||
|
array. This is only needed if the compiler cannot figure this out for
|
||||||
|
itself.
|
||||||
|
|
||||||
|
|
||||||
Porting to new platforms
|
Porting to new platforms
|
||||||
|
|
@ -99,7 +130,7 @@ check that the OS, System modules work and recompile Nimrod.
|
||||||
The only case where things aren't as easy is when the garbage
|
The only case where things aren't as easy is when the garbage
|
||||||
collector needs some assembler tweaking to work. The standard
|
collector needs some assembler tweaking to work. The standard
|
||||||
version of the GC uses C's ``setjmp`` function to store all registers
|
version of the GC uses C's ``setjmp`` function to store all registers
|
||||||
on the hardware stack. It may be that the new platform needs to
|
on the hardware stack. It may be necessary that the new platform needs to
|
||||||
replace this generic code by some assembler code.
|
replace this generic code by some assembler code.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -132,11 +163,11 @@ The Garbage Collector
|
||||||
Introduction
|
Introduction
|
||||||
------------
|
------------
|
||||||
|
|
||||||
We use the term *cell* here to refer to everything that is traced
|
I use the term *cell* here to refer to everything that is traced
|
||||||
(sequences, refs, strings).
|
(sequences, refs, strings).
|
||||||
This section describes how the new GC works.
|
This section describes how the new GC works.
|
||||||
|
|
||||||
The basic algorithm is *Deferrent reference counting* with cycle detection.
|
The basic algorithm is *Deferrent Reference Counting* with cycle detection.
|
||||||
References in the stack are not counted for better performance and easier C
|
References in the stack are not counted for better performance and easier C
|
||||||
code generation.
|
code generation.
|
||||||
|
|
||||||
|
|
@ -170,7 +201,7 @@ modifying a ``TCellSet`` during traversation leads to undefined behaviour.
|
||||||
iterator elements(s: TCellSet): (elem: PCell)
|
iterator elements(s: TCellSet): (elem: PCell)
|
||||||
|
|
||||||
|
|
||||||
All the operations have to be perform efficiently. Because a Cellset can
|
All the operations have to perform efficiently. Because a Cellset can
|
||||||
become huge a hash table alone is not suitable for this.
|
become huge a hash table alone is not suitable for this.
|
||||||
|
|
||||||
We use a mixture of bitset and hash table for this. The hash table maps *pages*
|
We use a mixture of bitset and hash table for this. The hash table maps *pages*
|
||||||
|
|
@ -246,16 +277,10 @@ This syntax tree is the interface between the parser and the code generator.
|
||||||
It is essential to understand most of the compiler's code.
|
It is essential to understand most of the compiler's code.
|
||||||
|
|
||||||
In order to compile Nimrod correctly, type-checking has to be seperated from
|
In order to compile Nimrod correctly, type-checking has to be seperated from
|
||||||
parsing. Otherwise generics would not work. Code generation is done for a
|
parsing. Otherwise generics would not work.
|
||||||
whole module only after it has been checked for semantics.
|
|
||||||
|
|
||||||
.. include:: filelist.txt
|
.. include:: filelist.txt
|
||||||
|
|
||||||
The first command line argument selects the backend. Thus the backend is
|
|
||||||
responsible for calling the parser and semantic checker. However, when
|
|
||||||
compiling ``import`` or ``include`` statements, the semantic checker needs to
|
|
||||||
call the backend, this is done by embedding a PBackend into a TContext.
|
|
||||||
|
|
||||||
|
|
||||||
The syntax tree
|
The syntax tree
|
||||||
---------------
|
---------------
|
||||||
|
|
@ -265,7 +290,7 @@ may contain cycles. The AST changes its shape after semantic checking. This
|
||||||
is needed to make life easier for the code generators. See the "ast" module
|
is needed to make life easier for the code generators. See the "ast" module
|
||||||
for the type definitions.
|
for the type definitions.
|
||||||
|
|
||||||
We use the notation ``nodeKind(fields, [sons])`` for describing
|
I use the notation ``nodeKind(fields, [sons])`` for describing
|
||||||
nodes. ``nodeKind[sons]`` is a short-cut for ``nodeKind([sons])``.
|
nodes. ``nodeKind[sons]`` is a short-cut for ``nodeKind([sons])``.
|
||||||
XXX: Description of the language's syntax and the corresponding trees.
|
XXX: Description of the language's syntax and the corresponding trees.
|
||||||
|
|
||||||
|
|
@ -273,12 +298,16 @@ XXX: Description of the language's syntax and the corresponding trees.
|
||||||
How the RTL is compiled
|
How the RTL is compiled
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
The system module contains the part of the RTL which needs support by
|
The ``system`` module contains the part of the RTL which needs support by
|
||||||
compiler magic (and the stuff that needs to be in it because the spec
|
compiler magic (and the stuff that needs to be in it because the spec
|
||||||
says so). The C code generator generates the C code for it just like any other
|
says so). The C code generator generates the C code for it just like any other
|
||||||
module. However, calls to some procedures like ``addInt`` are inserted by
|
module. However, calls to some procedures like ``addInt`` are inserted by
|
||||||
the CCG. Therefore the module ``magicsys`` contains a table
|
the CCG. Therefore the module ``magicsys`` contains a table (``compilerprocs``)
|
||||||
(``compilerprocs``) with all symbols that are marked as ``compilerproc``.
|
with all symbols that are marked as ``compilerproc``. ``compilerprocs`` are
|
||||||
|
needed by the code generator. A ``magic`` proc is not the same as a
|
||||||
|
``compilerproc``: A ``magic`` is a proc that needs compiler magic for its
|
||||||
|
semantic checking, a ``compilerproc`` is a proc that is used by the code
|
||||||
|
generator.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -290,77 +319,3 @@ underlying C compiler already does all the hard work for us. The problem is the
|
||||||
common runtime library, especially the memory manager. Note that Borland's
|
common runtime library, especially the memory manager. Note that Borland's
|
||||||
Delphi had exactly the same problem. The workaround is to not link the GC with
|
Delphi had exactly the same problem. The workaround is to not link the GC with
|
||||||
the Dll and provide an extra runtime dll that needs to be initialized.
|
the Dll and provide an extra runtime dll that needs to be initialized.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
How to implement closures
|
|
||||||
=========================
|
|
||||||
|
|
||||||
A closure is a record of a proc pointer and a context ref. The context ref
|
|
||||||
points to a garbage collected record that contains the needed variables.
|
|
||||||
An example:
|
|
||||||
|
|
||||||
.. code-block:: Nimrod
|
|
||||||
|
|
||||||
type
|
|
||||||
TListRec = record
|
|
||||||
data: string
|
|
||||||
next: ref TListRec
|
|
||||||
|
|
||||||
proc forEach(head: ref TListRec, visitor: proc (s: string) {.closure.}) =
|
|
||||||
var it = head
|
|
||||||
while it != nil:
|
|
||||||
visit(it.data)
|
|
||||||
it = it.next
|
|
||||||
|
|
||||||
proc sayHello() =
|
|
||||||
var L = new List(["hallo", "Andreas"])
|
|
||||||
var temp = "jup\xff"
|
|
||||||
forEach(L, lambda(s: string) =
|
|
||||||
io.write(temp)
|
|
||||||
io.write(s)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
This should become the following in C:
|
|
||||||
|
|
||||||
.. code-block:: C
|
|
||||||
typedef struct ... /* List type */
|
|
||||||
|
|
||||||
typedef struct closure {
|
|
||||||
void (*PrcPart)(string, void*);
|
|
||||||
void* ClPart;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct Tcl_data {
|
|
||||||
string temp; // all accessed variables are put in here!
|
|
||||||
}
|
|
||||||
|
|
||||||
void forEach(TListRec* head, const closure visitor) {
|
|
||||||
TListRec* it = head;
|
|
||||||
while (it != NIM_NULL) {
|
|
||||||
visitor.prc(it->data, visitor->cl_data);
|
|
||||||
it = it->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void printStr(string s, void* cl_data) {
|
|
||||||
Tcl_data* x = (Tcl_data*) cl_data;
|
|
||||||
io_write(x->temp);
|
|
||||||
io_write(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sayhello() {
|
|
||||||
Tcl_data* data = new(...);
|
|
||||||
asgnRef(&data->temp, "jup\xff");
|
|
||||||
...
|
|
||||||
|
|
||||||
closure cl;
|
|
||||||
cl.prc = printStr;
|
|
||||||
cl.cl_data = data;
|
|
||||||
foreach(L, cl);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
What about nested closure? - There's not much difference: Just put all used
|
|
||||||
variables in the data record.
|
|
||||||
|
|
|
||||||
515
doc/manual.txt
515
doc/manual.txt
|
|
@ -11,6 +11,10 @@ Nimrod Manual
|
||||||
About this document
|
About this document
|
||||||
===================
|
===================
|
||||||
|
|
||||||
|
**Note**: This document is a draft! Several of Nimrod's features need more
|
||||||
|
precise wording. This manual will evolve into a proper specification some
|
||||||
|
day.
|
||||||
|
|
||||||
This document describes the lexis, the syntax, and the semantics of Nimrod.
|
This document describes the lexis, the syntax, and the semantics of Nimrod.
|
||||||
|
|
||||||
The language constructs are explained using an extended BNF, in
|
The language constructs are explained using an extended BNF, in
|
||||||
|
|
@ -18,10 +22,11 @@ which ``(a)*`` means 0 or more ``a``'s, ``a+`` means 1 or more ``a``'s, and
|
||||||
``(a)?`` means an optional *a*; an alternative spelling for optional parts is
|
``(a)?`` means an optional *a*; an alternative spelling for optional parts is
|
||||||
``[a]``. The ``|`` symbol is used to mark alternatives
|
``[a]``. The ``|`` symbol is used to mark alternatives
|
||||||
and has the lowest precedence. Parentheses may be used to group elements.
|
and has the lowest precedence. Parentheses may be used to group elements.
|
||||||
Non-terminals are in lowercase, terminal symbols (including keywords) are in
|
Non-terminals start with a lowercase letter, abstract terminal symbols are in
|
||||||
UPPERCASE. An example::
|
UPPERCASE. Verbatim terminal symbols (including keywords) are quoted
|
||||||
|
with ``'``. An example::
|
||||||
|
|
||||||
if_stmt ::= IF expr COLON stmts (ELIF expr COLON stmts)* [ELSE stmts]
|
ifStmt ::= 'if' expr ':' stmts ('elif' expr ':' stmts)* ['else' stmts]
|
||||||
|
|
||||||
Other parts of Nimrod - like scoping rules or runtime semantics are only
|
Other parts of Nimrod - like scoping rules or runtime semantics are only
|
||||||
described in an informal manner. The reason is that formal semantics are
|
described in an informal manner. The reason is that formal semantics are
|
||||||
|
|
@ -90,8 +95,7 @@ Indentation consists only of spaces; tabulators are not allowed.
|
||||||
The terminals ``IND`` (indentation), ``DED`` (dedentation) and ``SAD``
|
The terminals ``IND`` (indentation), ``DED`` (dedentation) and ``SAD``
|
||||||
(same indentation) are generated by the scanner, denoting an indentation.
|
(same indentation) are generated by the scanner, denoting an indentation.
|
||||||
|
|
||||||
These terminals are only generated for lines that are not empty or contain
|
These terminals are only generated for lines that are not empty.
|
||||||
only whitespace and comments.
|
|
||||||
|
|
||||||
The parser and the scanner communicate over a stack which indentation terminal
|
The parser and the scanner communicate over a stack which indentation terminal
|
||||||
should be generated: The stack consists of integers counting the spaces. The
|
should be generated: The stack consists of integers counting the spaces. The
|
||||||
|
|
@ -100,14 +104,17 @@ If the current indentation token consists of more spaces than the entry at the
|
||||||
top of the stack, a ``IND`` token is generated, else if it consists of the same
|
top of the stack, a ``IND`` token is generated, else if it consists of the same
|
||||||
number of spaces, a ``SAD`` token is generated. If it consists of fewer spaces,
|
number of spaces, a ``SAD`` token is generated. If it consists of fewer spaces,
|
||||||
a ``DED`` token is generated for any item on the stack that is greater than the
|
a ``DED`` token is generated for any item on the stack that is greater than the
|
||||||
current. These items are then popped from the stack by the scanner. At the end
|
current. These items are later popped from the stack by the parser. At the end
|
||||||
of the file, a ``DED`` token is generated for each number remaining on the
|
of the file, a ``DED`` token is generated for each number remaining on the
|
||||||
stack that is larger than zero.
|
stack that is larger than zero.
|
||||||
|
|
||||||
Because the grammar contains some optional ``IND`` tokens, the scanner cannot
|
Because the grammar contains some optional ``IND`` tokens, the scanner cannot
|
||||||
push new indentation levels. This has to be done by the parser. The symbol
|
push new indentation levels. This has to be done by the parser. The symbol
|
||||||
``indPush`` indicates that an ``IND`` token is expected; the current number of
|
``indPush`` indicates that an ``IND`` token is expected; the current number of
|
||||||
leading spaces is pushed onto the stack by the parser.
|
leading spaces is pushed onto the stack by the parser. The symbol ``indPop``
|
||||||
|
denotes that the parser pops an item from the indentation stack. No token is
|
||||||
|
consumed by ``indPop``.
|
||||||
|
|
||||||
|
|
||||||
Comments
|
Comments
|
||||||
--------
|
--------
|
||||||
|
|
@ -131,8 +138,8 @@ aligned to the preceding one, it does not start a new comment:
|
||||||
Comments are tokens; they are only allowed at certain places in the input file
|
Comments are tokens; they are only allowed at certain places in the input file
|
||||||
as they belong to the syntax tree! This feature enables perfect source-to-source
|
as they belong to the syntax tree! This feature enables perfect source-to-source
|
||||||
transformations (such as pretty-printing) and superior documentation generators.
|
transformations (such as pretty-printing) and superior documentation generators.
|
||||||
A side-effect is that the human reader of the code always knows exactly which
|
A nice side-effect is that the human reader of the code always knows exactly
|
||||||
code snippet the comment refers to.
|
which code snippet the comment refers to.
|
||||||
|
|
||||||
|
|
||||||
Identifiers & Keywords
|
Identifiers & Keywords
|
||||||
|
|
@ -159,9 +166,9 @@ case-sensitive and even underscores are ignored:
|
||||||
**type** is a reserved word, and so is **TYPE** or **T_Y_P_E**. The idea behind
|
**type** is a reserved word, and so is **TYPE** or **T_Y_P_E**. The idea behind
|
||||||
this is that this allows programmers to use their own prefered spelling style
|
this is that this allows programmers to use their own prefered spelling style
|
||||||
and libraries written by different programmers cannot use incompatible
|
and libraries written by different programmers cannot use incompatible
|
||||||
conventions. The editors or IDE can show the identifiers as preferred. Another
|
conventions. A Nimrod-aware editor or IDE can show the identifiers as
|
||||||
advantage is that it frees the programmer from remembering the exact spelling
|
preferred. Another advantage is that it frees the programmer from remembering
|
||||||
of an identifier.
|
the exact spelling of an identifier.
|
||||||
|
|
||||||
|
|
||||||
Literal strings
|
Literal strings
|
||||||
|
|
@ -174,7 +181,7 @@ contain the following `escape sequences`:idx:\ :
|
||||||
Escape sequence Meaning
|
Escape sequence Meaning
|
||||||
================== ===================================================
|
================== ===================================================
|
||||||
``\n`` `newline`:idx:
|
``\n`` `newline`:idx:
|
||||||
``\r`` `carriage return`:idx:
|
``\r``, ``\c`` `carriage return`:idx:
|
||||||
``\l`` `line feed`:idx:
|
``\l`` `line feed`:idx:
|
||||||
``\f`` `form feed`:idx:
|
``\f`` `form feed`:idx:
|
||||||
``\t`` `tabulator`:idx:
|
``\t`` `tabulator`:idx:
|
||||||
|
|
@ -184,8 +191,7 @@ contain the following `escape sequences`:idx:\ :
|
||||||
``\'`` `apostrophe`:idx:
|
``\'`` `apostrophe`:idx:
|
||||||
``\d+`` `character with decimal value d`:idx:;
|
``\d+`` `character with decimal value d`:idx:;
|
||||||
all decimal digits directly
|
all decimal digits directly
|
||||||
following are used for the
|
following are used for the character
|
||||||
character
|
|
||||||
``\a`` `alert`:idx:
|
``\a`` `alert`:idx:
|
||||||
``\b`` `backspace`:idx:
|
``\b`` `backspace`:idx:
|
||||||
``\e`` `escape`:idx: `[ESC]`:idx:
|
``\e`` `escape`:idx: `[ESC]`:idx:
|
||||||
|
|
@ -194,15 +200,14 @@ contain the following `escape sequences`:idx:\ :
|
||||||
================== ===================================================
|
================== ===================================================
|
||||||
|
|
||||||
|
|
||||||
Strings in Nimrod may contain any 8-bit value, except embedded zeros
|
Strings in Nimrod may contain any 8-bit value, except embedded zeros.
|
||||||
which are not allowed for compability with `C`:idx:.
|
|
||||||
|
|
||||||
Literal strings can also be delimited by three double squotes
|
Literal strings can also be delimited by three double squotes
|
||||||
``"""`` ... ``"""``.
|
``"""`` ... ``"""``.
|
||||||
Literals in this form may run for several lines, may contain ``"`` and do not
|
Literals in this form may run for several lines, may contain ``"`` and do not
|
||||||
interpret any escape sequences.
|
interpret any escape sequences.
|
||||||
For convenience, when the opening ``"""`` is immediately
|
For convenience, when the opening ``"""`` is immediately followed by a newline,
|
||||||
followed by a newline, the newline is not included in the string.
|
the newline is not included in the string.
|
||||||
There are also `raw string literals` that are preceded with the letter ``r``
|
There are also `raw string literals` that are preceded with the letter ``r``
|
||||||
(or ``R``) and are delimited by matching double quotes (just like ordinary
|
(or ``R``) and are delimited by matching double quotes (just like ordinary
|
||||||
string literals) and do not interpret the escape sequences. This is especially
|
string literals) and do not interpret the escape sequences. This is especially
|
||||||
|
|
@ -253,8 +258,8 @@ Numerical constants
|
||||||
|
|
||||||
As can be seen in the productions, numerical constants can contain unterscores
|
As can be seen in the productions, numerical constants can contain unterscores
|
||||||
for readability. Integer and floating point literals may be given in decimal (no
|
for readability. Integer and floating point literals may be given in decimal (no
|
||||||
prefix), binary (prefix ``0b``), octal (prefix ``0o``) and
|
prefix), binary (prefix ``0b``), octal (prefix ``0o``) and hexadecimal
|
||||||
hexadecimal (prefix ``0x``) notation.
|
(prefix ``0x``) notation.
|
||||||
|
|
||||||
There exists a literal for each numerical type that is
|
There exists a literal for each numerical type that is
|
||||||
defined. The suffix starting with an apostophe ('\'') is called a
|
defined. The suffix starting with an apostophe ('\'') is called a
|
||||||
|
|
@ -262,7 +267,7 @@ defined. The suffix starting with an apostophe ('\'') is called a
|
||||||
unless the literal contains a dot or an ``E`` in which case it is of
|
unless the literal contains a dot or an ``E`` in which case it is of
|
||||||
type ``float``.
|
type ``float``.
|
||||||
|
|
||||||
The following table specifies type suffixes:
|
The type suffixes are:
|
||||||
|
|
||||||
================= =========================
|
================= =========================
|
||||||
Type Suffix Resulting type of literal
|
Type Suffix Resulting type of literal
|
||||||
|
|
@ -295,11 +300,11 @@ the three tokens `{`:tok:, `..`:tok:, `}`:tok: and not the two tokens
|
||||||
`{.`:tok:, `.}`:tok:.
|
`{.`:tok:, `.}`:tok:.
|
||||||
|
|
||||||
In Nimrod one can define his own operators. An `operator`:idx: is any
|
In Nimrod one can define his own operators. An `operator`:idx: is any
|
||||||
combination of the following characters that are not listed above::
|
combination of the following characters that is not listed above::
|
||||||
|
|
||||||
+ - * / < >
|
+ - * / < >
|
||||||
= @ $ ~ & %
|
= @ $ ~ & %
|
||||||
! ? ^ . |
|
! ? ^ . | \
|
||||||
|
|
||||||
These keywords are also operators:
|
These keywords are also operators:
|
||||||
``and or not xor shl shr div mod in notin is isnot``.
|
``and or not xor shl shr div mod in notin is isnot``.
|
||||||
|
|
@ -348,16 +353,13 @@ Constants
|
||||||
cannot change. The compiler must be able to evaluate the expression in a
|
cannot change. The compiler must be able to evaluate the expression in a
|
||||||
constant declaration at compile time.
|
constant declaration at compile time.
|
||||||
|
|
||||||
..
|
Nimrod contains a sophisticated compile-time evaluator, so procedures which
|
||||||
Nimrod contains a sophisticated
|
have no side-effect can be used in constant expressions too:
|
||||||
compile-time evaluator, so procedures declared with the ``{.noSideEffect.}``
|
|
||||||
pragma can be used in constant expressions:
|
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
import strutils
|
||||||
from strutils import findSubStr
|
|
||||||
const
|
const
|
||||||
x = findSubStr('a', "hallo") # x is 1; this is computed at compile time!
|
constEval = contains("abc", 'b') # computed at compile time!
|
||||||
|
|
||||||
|
|
||||||
Types
|
Types
|
||||||
|
|
@ -414,8 +416,8 @@ intXX
|
||||||
|
|
||||||
There are no `unsigned integer`:idx: types, only `unsigned operations`:idx:
|
There are no `unsigned integer`:idx: types, only `unsigned operations`:idx:
|
||||||
that treat their arguments as unsigned. Unsigned operations all wrap around;
|
that treat their arguments as unsigned. Unsigned operations all wrap around;
|
||||||
they may not lead to over- or underflow errors. Unsigned operations use the
|
they cannot lead to over- or underflow errors. Unsigned operations use the
|
||||||
``%`` postfix as convention:
|
``%`` suffix as convention:
|
||||||
|
|
||||||
====================== ======================================================
|
====================== ======================================================
|
||||||
operation meaning
|
operation meaning
|
||||||
|
|
@ -498,16 +500,15 @@ the resulting programs will still handle UTF-8 properly as UTF-8 was specially
|
||||||
designed for this.
|
designed for this.
|
||||||
Another reason is that Nimrod can support ``array[char, int]`` or
|
Another reason is that Nimrod can support ``array[char, int]`` or
|
||||||
``set[char]`` efficiently as many algorithms rely on this feature. The
|
``set[char]`` efficiently as many algorithms rely on this feature. The
|
||||||
`TUniChar` type is used for Unicode characters, it can represent any Unicode
|
`TRune` type is used for Unicode characters, it can represent any Unicode
|
||||||
character. ``TUniChar`` is declared the ``unicode`` standard module.
|
character. ``TRune`` is declared the ``unicode`` module.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Enumeration types
|
Enumeration types
|
||||||
~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~
|
||||||
`Enumeration`:idx: types define a new type whose values consist only of the ones
|
`Enumeration`:idx: types define a new type whose values consist of the ones
|
||||||
specified.
|
specified. The values are ordered. Example:
|
||||||
The values are ordered by the order in enum's declaration. Example:
|
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
||||||
|
|
@ -528,8 +529,8 @@ with enumeration types.
|
||||||
|
|
||||||
For better interfacing to other programming languages, the fields of enum
|
For better interfacing to other programming languages, the fields of enum
|
||||||
types can be assigned an explicit ordinal value. However, the ordinal values
|
types can be assigned an explicit ordinal value. However, the ordinal values
|
||||||
have to be in ascending order. A field whose ordinal value that is not
|
have to be in ascending order. A field whose ordinal value is not
|
||||||
explicitly given, is assigned the value of the previous field + 1.
|
explicitly given is assigned the value of the previous field + 1.
|
||||||
|
|
||||||
An explicit ordered enum can have *wholes*:
|
An explicit ordered enum can have *wholes*:
|
||||||
|
|
||||||
|
|
@ -545,7 +546,7 @@ and ``pred`` are not available for them either.
|
||||||
|
|
||||||
Subrange types
|
Subrange types
|
||||||
~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~
|
||||||
A `subrange`:idx: type is a range of values from an ordinal type (the host
|
A `subrange`:idx: type is a range of values from an ordinal type (the base
|
||||||
type). To define a subrange type, one must specify it's limiting values: the
|
type). To define a subrange type, one must specify it's limiting values: the
|
||||||
highest and lowest value of the type:
|
highest and lowest value of the type:
|
||||||
|
|
||||||
|
|
@ -566,7 +567,7 @@ A subrange type has the same size as its base type (``int`` in the example).
|
||||||
String type
|
String type
|
||||||
~~~~~~~~~~~
|
~~~~~~~~~~~
|
||||||
All string literals are of the type `string`:idx:. A string in Nimrod is very
|
All string literals are of the type `string`:idx:. A string in Nimrod is very
|
||||||
similar to a sequence of characters. However, strings in Nimrod both are
|
similar to a sequence of characters. However, strings in Nimrod are both
|
||||||
zero-terminated and have a length field. One can retrieve the length with the
|
zero-terminated and have a length field. One can retrieve the length with the
|
||||||
builtin ``len`` procedure; the length never counts the terminating zero.
|
builtin ``len`` procedure; the length never counts the terminating zero.
|
||||||
The assignment operator for strings always copies the string.
|
The assignment operator for strings always copies the string.
|
||||||
|
|
@ -585,7 +586,7 @@ arrays, they can be used in case statements:
|
||||||
Per convention, all strings are UTF-8 strings, but this is not enforced. For
|
Per convention, all strings are UTF-8 strings, but this is not enforced. For
|
||||||
example, when reading strings from binary files, they are merely a sequence of
|
example, when reading strings from binary files, they are merely a sequence of
|
||||||
bytes. The index operation ``s[i]`` means the i-th *char* of ``s``, not the
|
bytes. The index operation ``s[i]`` means the i-th *char* of ``s``, not the
|
||||||
i-th *unichar*. The iterator ``unichars`` from the ``unicode`` standard
|
i-th *unichar*. The iterator ``runes`` from the ``unicode``
|
||||||
module can be used for iteration over all unicode characters.
|
module can be used for iteration over all unicode characters.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -611,9 +612,7 @@ constructed by the array constructor ``[]`` in conjunction with the array to
|
||||||
sequence operator ``@``. Another way to allocate space for a sequence is to
|
sequence operator ``@``. Another way to allocate space for a sequence is to
|
||||||
call the built-in ``newSeq`` procedure.
|
call the built-in ``newSeq`` procedure.
|
||||||
|
|
||||||
A sequence may be passed to a parameter that is of type *open array*, but
|
A sequence may be passed to a parameter that is of type *open array*.
|
||||||
not to a multi-dimensional open array, because it is impossible to do so in an
|
|
||||||
efficient manner.
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
|
@ -639,6 +638,24 @@ Arrays are always bounds checked (at compile-time or at runtime). These
|
||||||
checks can be disabled via pragmas or invoking the compiler with the
|
checks can be disabled via pragmas or invoking the compiler with the
|
||||||
``--bound_checks:off`` command line switch.
|
``--bound_checks:off`` command line switch.
|
||||||
|
|
||||||
|
An open array is also a means to implement passing a variable number of
|
||||||
|
arguments to a procedure. The compiler converts the list of arguments
|
||||||
|
to an array automatically:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
proc myWriteln(f: TFile, a: openarray[string]) =
|
||||||
|
for s in items(a):
|
||||||
|
write(f, s)
|
||||||
|
write(f, "\n")
|
||||||
|
|
||||||
|
myWriteln(stdout, "abc", "def", "xyz")
|
||||||
|
# is transformed by the compiler to:
|
||||||
|
myWriteln(stdout, ["abc", "def", "xyz"])
|
||||||
|
|
||||||
|
This transformation is only done if the openarray parameter is the
|
||||||
|
last parameter in the procedure header. The current implementation does not
|
||||||
|
support nested open arrays.
|
||||||
|
|
||||||
|
|
||||||
Tuples and object types
|
Tuples and object types
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
@ -691,7 +708,7 @@ the ``is`` operator can be used to determine the object's type.
|
||||||
person: TPerson
|
person: TPerson
|
||||||
assert(student is TStudent) # is true
|
assert(student is TStudent) # is true
|
||||||
|
|
||||||
Object fields that should be visible outside from the defining module, have to
|
Object fields that should be visible from outside the defining module, have to
|
||||||
marked by ``*``. In contrast to tuples, different object types are
|
marked by ``*``. In contrast to tuples, different object types are
|
||||||
never *equivalent*.
|
never *equivalent*.
|
||||||
|
|
||||||
|
|
@ -904,9 +921,9 @@ Most calling conventions exist only for the Windows 32-bit platform.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Statements
|
Statements and expressions
|
||||||
----------
|
--------------------------
|
||||||
Nimrod uses the common statement/expression paradigma: `Statements`:idx: do not
|
Nimrod uses the common statement/expression paradigm: `Statements`:idx: do not
|
||||||
produce a value in contrast to expressions. Call expressions are statements.
|
produce a value in contrast to expressions. Call expressions are statements.
|
||||||
If the called procedure returns a value, it is not a valid statement
|
If the called procedure returns a value, it is not a valid statement
|
||||||
as statements do not produce values. To evaluate an expression for
|
as statements do not produce values. To evaluate an expression for
|
||||||
|
|
@ -943,7 +960,7 @@ Discard statement
|
||||||
|
|
||||||
Syntax::
|
Syntax::
|
||||||
|
|
||||||
discardStmt ::= DISCARD expr
|
discardStmt ::= 'discard' expr
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
|
@ -962,11 +979,13 @@ Var statement
|
||||||
|
|
||||||
Syntax::
|
Syntax::
|
||||||
|
|
||||||
colonOrEquals ::= COLON typeDesc [EQUALS expr] | EQUALS expr
|
colonOrEquals ::= ':' typeDesc ['=' expr] | '=' expr
|
||||||
varField ::= symbol ["*"] [pragma]
|
varField ::= symbol ['*'] [pragma]
|
||||||
varPart ::= symbol (comma symbol)* [comma] colonOrEquals [COMMENT | IND COMMENT]
|
varPart ::= symbol (comma symbol)* [comma] colonOrEquals [COMMENT | IND COMMENT]
|
||||||
varSection ::= VAR (varPart
|
varSection ::= 'var' (varPart
|
||||||
| indPush (COMMENT|varPart) (SAD (COMMENT|varPart))* DED)
|
| indPush (COMMENT|varPart)
|
||||||
|
(SAD (COMMENT|varPart))* DED indPop)
|
||||||
|
|
||||||
|
|
||||||
`Var`:idx: statements declare new local and global variables and
|
`Var`:idx: statements declare new local and global variables and
|
||||||
initialize them. A comma seperated list of variables can be used to specify
|
initialize them. A comma seperated list of variables can be used to specify
|
||||||
|
|
@ -992,7 +1011,7 @@ char '\0'
|
||||||
bool false
|
bool false
|
||||||
ref or pointer type nil
|
ref or pointer type nil
|
||||||
procedural type nil
|
procedural type nil
|
||||||
sequence nil
|
sequence nil (**not** ``@[]``)
|
||||||
string nil (**not** "")
|
string nil (**not** "")
|
||||||
tuple[x: A, y: B, ...] (default(A), default(B), ...)
|
tuple[x: A, y: B, ...] (default(A), default(B), ...)
|
||||||
(analogous for objects)
|
(analogous for objects)
|
||||||
|
|
@ -1007,12 +1026,12 @@ Const section
|
||||||
|
|
||||||
Syntax::
|
Syntax::
|
||||||
|
|
||||||
colonAndEquals ::= [COLON typeDesc] EQUALS expr
|
colonAndEquals ::= [':' typeDesc] '=' expr
|
||||||
constDecl ::= CONST
|
|
||||||
indPush
|
constDecl ::= symbol ['*'] [pragma] colonAndEquals [COMMENT | IND COMMENT]
|
||||||
symbol ["*"] [pragma] colonAndEquals
|
| COMMENT
|
||||||
(SAD symbol ["*"] [pragma] colonAndEquals)*
|
constSection ::= 'const' indPush constDecl (SAD constDecl)* DED indPop
|
||||||
DED
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
|
@ -1031,7 +1050,7 @@ If statement
|
||||||
|
|
||||||
Syntax::
|
Syntax::
|
||||||
|
|
||||||
ifStmt ::= IF expr COLON stmt (ELIF expr COLON stmt)* [ELSE COLON stmt]
|
ifStmt ::= 'if' expr ':' stmt ('elif' expr ':' stmt)* ['else' ':' stmt]
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
|
@ -1061,9 +1080,9 @@ Case statement
|
||||||
|
|
||||||
Syntax::
|
Syntax::
|
||||||
|
|
||||||
caseStmt ::= CASE expr (OF sliceList COLON stmt)*
|
caseStmt ::= 'case' expr ('of' sliceExprList ':' stmt)*
|
||||||
(ELIF expr COLON stmt)*
|
('elif' expr ':' stmt)*
|
||||||
[ELSE COLON stmt]
|
['else' ':' stmt]
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
|
@ -1094,7 +1113,7 @@ When statement
|
||||||
|
|
||||||
Syntax::
|
Syntax::
|
||||||
|
|
||||||
whenStmt ::= WHEN expr COLON stmt (ELIF expr COLON stmt)* [ELSE COLON stmt]
|
whenStmt ::= 'when' expr ':' stmt ('elif' expr ':' stmt)* ['else' ':' stmt]
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
|
@ -1116,8 +1135,7 @@ exceptions:
|
||||||
* The statements do not open a new scope if they introduce new identifiers.
|
* The statements do not open a new scope if they introduce new identifiers.
|
||||||
* The statements that belong to the expression that evaluated to true are
|
* The statements that belong to the expression that evaluated to true are
|
||||||
translated by the compiler, the other statements are not checked for
|
translated by the compiler, the other statements are not checked for
|
||||||
syntax or semantics at all! This holds also for any ``expr`` coming
|
semantics! However, each ``expr`` is checked for semantics.
|
||||||
after the expression that evaluated to true.
|
|
||||||
|
|
||||||
The ``when`` statement enables conditional compilation techniques. As
|
The ``when`` statement enables conditional compilation techniques. As
|
||||||
a special syntatic extension, the ``when`` construct is also available
|
a special syntatic extension, the ``when`` construct is also available
|
||||||
|
|
@ -1129,7 +1147,7 @@ Raise statement
|
||||||
|
|
||||||
Syntax::
|
Syntax::
|
||||||
|
|
||||||
raiseStmt ::= RAISE [expr]
|
raiseStmt ::= 'raise' [expr]
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
|
@ -1152,11 +1170,11 @@ Try statement
|
||||||
|
|
||||||
Syntax::
|
Syntax::
|
||||||
|
|
||||||
|
qualifiedIdent ::= symbol ['.' symbol]
|
||||||
exceptList ::= [qualifiedIdent (comma qualifiedIdent)* [comma]]
|
exceptList ::= [qualifiedIdent (comma qualifiedIdent)* [comma]]
|
||||||
tryStmt ::= TRY COLON stmt
|
tryStmt ::= 'try' ':' stmt
|
||||||
(EXCEPT exceptList COLON stmt)*
|
('except' exceptList ':' stmt)*
|
||||||
[FINALLY COLON stmt]
|
['finally' ':' stmt]
|
||||||
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
|
@ -1176,6 +1194,8 @@ Example:
|
||||||
echo("could not convert string to integer")
|
echo("could not convert string to integer")
|
||||||
except EIO:
|
except EIO:
|
||||||
echo("IO error!")
|
echo("IO error!")
|
||||||
|
except:
|
||||||
|
echo("Unknown exception!")
|
||||||
finally:
|
finally:
|
||||||
closeFile(f)
|
closeFile(f)
|
||||||
|
|
||||||
|
|
@ -1203,7 +1223,7 @@ Return statement
|
||||||
|
|
||||||
Syntax::
|
Syntax::
|
||||||
|
|
||||||
returnStmt ::= RETURN [expr]
|
returnStmt ::= 'return' [expr]
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
|
@ -1224,7 +1244,8 @@ value of the procedure. It is automatically declared by the compiler. As all
|
||||||
variables, ``result`` is initialized to (binary) zero::
|
variables, ``result`` is initialized to (binary) zero::
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
proc returnZero(): int = nil # implicitely returns 0
|
proc returnZero(): int =
|
||||||
|
# implicitely returns 0
|
||||||
|
|
||||||
|
|
||||||
Yield statement
|
Yield statement
|
||||||
|
|
@ -1232,7 +1253,7 @@ Yield statement
|
||||||
|
|
||||||
Syntax::
|
Syntax::
|
||||||
|
|
||||||
yieldStmt ::= YIELD expr
|
yieldStmt ::= 'yield' expr
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
|
@ -1252,7 +1273,7 @@ Block statement
|
||||||
|
|
||||||
Syntax::
|
Syntax::
|
||||||
|
|
||||||
blockStmt ::= BLOCK [symbol] COLON stmt
|
blockStmt ::= 'block' [symbol] ':' stmt
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
|
@ -1277,7 +1298,7 @@ Break statement
|
||||||
|
|
||||||
Syntax::
|
Syntax::
|
||||||
|
|
||||||
breakStmt ::= BREAK [symbol]
|
breakStmt ::= 'break' [symbol]
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
|
@ -1294,7 +1315,7 @@ While statement
|
||||||
|
|
||||||
Syntax::
|
Syntax::
|
||||||
|
|
||||||
whileStmt ::= WHILE expr COLON stmt
|
whileStmt ::= 'while' expr ':' stmt
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
|
@ -1316,7 +1337,7 @@ Continue statement
|
||||||
|
|
||||||
Syntax::
|
Syntax::
|
||||||
|
|
||||||
continueStmt ::= CONTINUE
|
continueStmt ::= 'continue'
|
||||||
|
|
||||||
A `continue`:idx: statement leads to the immediate next iteration of the
|
A `continue`:idx: statement leads to the immediate next iteration of the
|
||||||
surrounding loop construct. It is only allowed within a loop. A continue
|
surrounding loop construct. It is only allowed within a loop. A continue
|
||||||
|
|
@ -1340,7 +1361,7 @@ Assembler statement
|
||||||
~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~
|
||||||
Syntax::
|
Syntax::
|
||||||
|
|
||||||
asmStmt ::= ASM [pragma] (STR_LIT | RSTR_LIT | TRIPLESTR_LIT)
|
asmStmt ::= 'asm' [pragma] (STR_LIT | RSTR_LIT | TRIPLESTR_LIT)
|
||||||
|
|
||||||
The direct embedding of `assembler`:idx: code into Nimrod code is supported
|
The direct embedding of `assembler`:idx: code into Nimrod code is supported
|
||||||
by the unsafe ``asm`` statement. Identifiers in the assembler code that refer to
|
by the unsafe ``asm`` statement. Identifiers in the assembler code that refer to
|
||||||
|
|
@ -1348,6 +1369,49 @@ Nimrod identifiers shall be enclosed in a special character which can be
|
||||||
specified in the statement's pragmas. The default special character is ``'`'``.
|
specified in the statement's pragmas. The default special character is ``'`'``.
|
||||||
|
|
||||||
|
|
||||||
|
If expression
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
An `if expression` is almost like an if statement, but it is an expression.
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
p(if x > 8: 9 else: 10)
|
||||||
|
|
||||||
|
An if expression always results in a value, so the ``else`` part is
|
||||||
|
required. ``Elif`` parts are also allowed (but unlikely to be good
|
||||||
|
style).
|
||||||
|
|
||||||
|
|
||||||
|
Type convertions
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
Syntactically a `type conversion` is like a procedure call, but a
|
||||||
|
type name replaces the procedure name. A type conversion is always
|
||||||
|
safe in the sense that a failure to convert a type to another
|
||||||
|
results in an exception (if it cannot be determined statically).
|
||||||
|
|
||||||
|
|
||||||
|
Type casts
|
||||||
|
~~~~~~~~~~
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
cast[int](x)
|
||||||
|
|
||||||
|
Type casts are a crude mechanism to interpret the bit pattern of
|
||||||
|
an expression as if it would be of another type. Type casts are
|
||||||
|
only needed for low-level programming and are inherently unsafe.
|
||||||
|
|
||||||
|
|
||||||
|
The addr operator
|
||||||
|
~~~~~~~~~~~~~~~~~
|
||||||
|
The `addr` operator returns the address of an l-value. If the
|
||||||
|
type of the location is ``T``, the `addr` operator result is
|
||||||
|
of the type ``ptr T``. Taking the address of an object that resides
|
||||||
|
on the stack is **unsafe**, as the pointer may live longer than the
|
||||||
|
object on the stack and can thus reference a non-existing object.
|
||||||
|
|
||||||
|
|
||||||
Procedures
|
Procedures
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
What most programming languages call `methods`:idx: or `funtions`:idx: are
|
What most programming languages call `methods`:idx: or `funtions`:idx: are
|
||||||
|
|
@ -1355,16 +1419,16 @@ called `procedures`:idx: in Nimrod (which is the correct terminology). A
|
||||||
procedure declaration defines an identifier and associates it with a block
|
procedure declaration defines an identifier and associates it with a block
|
||||||
of code. A procedure may call itself recursively. The syntax is::
|
of code. A procedure may call itself recursively. The syntax is::
|
||||||
|
|
||||||
param ::= symbol (comma symbol)* [comma] COLON typeDesc
|
param ::= symbol (comma symbol)* [comma] ':' typeDesc
|
||||||
paramList ::= [PAR_LE [param (comma param)* [comma]] PAR_RI] [COLON typeDesc]
|
paramList ::= ['(' [param (comma param)* [comma]] ')'] [':' typeDesc]
|
||||||
|
|
||||||
genericParams ::= BRACKET_LE (symbol [EQUALS typeDesc] )* BRACKET_RI
|
genericParam ::= symbol [':' typeDesc]
|
||||||
|
genericParams ::= '[' genericParam (comma genericParam)* [comma] ']'
|
||||||
|
|
||||||
procDecl ::= PROC symbol ["*"] [genericParams]
|
procDecl ::= 'proc' symbol ['*'] [genericParams] paramList [pragma]
|
||||||
paramList [pragma]
|
['=' stmt]
|
||||||
[EQUALS stmt]
|
|
||||||
|
|
||||||
If the ``EQUALS stmt`` part is missing, it is a `forward`:idx: declaration. If
|
If the ``= stmt`` part is missing, it is a `forward`:idx: declaration. If
|
||||||
the proc returns a value, the procedure body can access an implicit declared
|
the proc returns a value, the procedure body can access an implicit declared
|
||||||
variable named `result`:idx: that represents the return value. Procs can be
|
variable named `result`:idx: that represents the return value. Procs can be
|
||||||
overloaded. The overloading resolution algorithm tries to find the proc that is
|
overloaded. The overloading resolution algorithm tries to find the proc that is
|
||||||
|
|
@ -1384,19 +1448,12 @@ is used if the caller does not provide a value for this parameter. Example:
|
||||||
for i in 0..len(s) - 1:
|
for i in 0..len(s) - 1:
|
||||||
result[i] = toLower(s[i]) # calls toLower for characters; no recursion!
|
result[i] = toLower(s[i]) # calls toLower for characters; no recursion!
|
||||||
|
|
||||||
`Operators`:idx: are procedures with a special operator symbol as identifier:
|
|
||||||
|
|
||||||
.. code-block:: nimrod
|
|
||||||
proc `$` (x: int): string =
|
|
||||||
# converts an integer to a string; this is a prefix operator.
|
|
||||||
return intToStr(x)
|
|
||||||
|
|
||||||
Calling a procedure can be done in many different ways:
|
Calling a procedure can be done in many different ways:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
proc callme(x, y: int, s: string = "", c: char, b: bool = false) = ...
|
proc callme(x, y: int, s: string = "", c: char, b: bool = false) = ...
|
||||||
|
|
||||||
# call with positional arguments# parameter bindings:
|
# call with positional arguments # parameter bindings:
|
||||||
callme(0, 1, "abc", '\t', true) # (x=0, y=1, s="abc", c='\t', b=true)
|
callme(0, 1, "abc", '\t', true) # (x=0, y=1, s="abc", c='\t', b=true)
|
||||||
# call with named and positional arguments:
|
# call with named and positional arguments:
|
||||||
callme(y=1, x=0, "abd", '\t') # (x=0, y=1, s="abd", c='\t', b=false)
|
callme(y=1, x=0, "abd", '\t') # (x=0, y=1, s="abd", c='\t', b=false)
|
||||||
|
|
@ -1406,20 +1463,106 @@ Calling a procedure can be done in many different ways:
|
||||||
callme 0, 1, "abc", '\t'
|
callme 0, 1, "abc", '\t'
|
||||||
|
|
||||||
|
|
||||||
|
A procedure cannot modify its parameters (unless the parameters have the
|
||||||
|
type `var`).
|
||||||
|
|
||||||
|
`Operators`:idx: are procedures with a special operator symbol as identifier:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
proc `$` (x: int): string =
|
||||||
|
# converts an integer to a string; this is a prefix operator.
|
||||||
|
return intToStr(x)
|
||||||
|
|
||||||
|
Operators with one parameter are prefix operators, operators with two
|
||||||
|
parameters are infix operators. There is no way to declare postfix
|
||||||
|
operators: All postfix operators are built-in and handled by the
|
||||||
|
grammar explicitely.
|
||||||
|
|
||||||
|
Any operator can be called like an ordinary proc with the '`opr`'
|
||||||
|
notation. (Thus an operator can have more than two parameters):
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
proc `*+` (a, b, c: int): int =
|
||||||
|
# Multiply and add
|
||||||
|
return a * b + c
|
||||||
|
|
||||||
|
assert `*+`(3, 4, 6) == `*`(a, `+`(b, c))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Var parameters
|
||||||
|
~~~~~~~~~~~~~~
|
||||||
|
The type of a parameter may be prefixed with the ``var`` keyword:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
proc divmod(a, b: int, res, remainder: var int) =
|
||||||
|
res = a div b
|
||||||
|
remainder = a mod b
|
||||||
|
|
||||||
|
var
|
||||||
|
x, y: int
|
||||||
|
|
||||||
|
divmod(8, 5, x, y) # modifies x and y
|
||||||
|
assert x == 1
|
||||||
|
assert y == 3
|
||||||
|
|
||||||
|
In the example, ``res`` and ``remainder`` are `var parameters`.
|
||||||
|
Var parameters can be modified by the procedure and the changes are
|
||||||
|
visible to the caller. The argument passed to a var parameter has to be
|
||||||
|
an l-value. Var parameters are implemented as hidden pointers. The
|
||||||
|
above example is equivalent to:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
proc divmod(a, b: int, res, remainder: ptr int) =
|
||||||
|
res = a div b
|
||||||
|
remainder = a mod b
|
||||||
|
|
||||||
|
var
|
||||||
|
x, y: int
|
||||||
|
divmod(8, 5, addr(x), addr(y))
|
||||||
|
assert x == 1
|
||||||
|
assert y == 3
|
||||||
|
|
||||||
|
In the examples, var parameters or pointers are used to provide two
|
||||||
|
return values. This can be done in a cleaner way by returning a tuple:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
proc divmod(a, b: int): tuple[res, remainder: int] =
|
||||||
|
return (a div b, a mod b)
|
||||||
|
|
||||||
|
var t = divmod(8, 5)
|
||||||
|
assert t.res == 1
|
||||||
|
assert t.remainder = 3
|
||||||
|
|
||||||
|
Even more elegant is to use `tuple unpacking` to access the tuple's fields:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
var (x, y) = divmod(8, 5) # tuple unpacking
|
||||||
|
assert x == 1
|
||||||
|
assert y == 3
|
||||||
|
|
||||||
|
Unfortunately, this form of tuple unpacking is not yet implemented.
|
||||||
|
|
||||||
|
..
|
||||||
|
XXX remove this as soon as tuple unpacking is implemented
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Iterators and the for statement
|
Iterators and the for statement
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Syntax::
|
Syntax::
|
||||||
|
|
||||||
forStmt ::= FOR symbol (comma symbol)* [comma] IN expr [DOTDOT expr] COLON stmt
|
forStmt ::= 'for' symbol (comma symbol)* [comma] 'in' expr ['..' expr] ':' stmt
|
||||||
|
|
||||||
param ::= symbol (comma symbol)* [comma] COLON typeDesc
|
param ::= symbol (comma symbol)* [comma] ':' typeDesc
|
||||||
paramList ::= [PAR_LE [param (comma param)* [comma]] PAR_RI] [COLON typeDesc]
|
paramList ::= ['(' [param (comma param)* [comma]] ')'] [':' typeDesc]
|
||||||
|
|
||||||
genericParams ::= BRACKET_LE (symbol [EQUALS typeDesc] )* BRACKET_RI
|
genericParam ::= symbol [':' typeDesc]
|
||||||
|
genericParams ::= '[' genericParam (comma genericParam)* [comma] ']'
|
||||||
|
|
||||||
iteratorDecl ::= ITERATOR symbol ["*"] [genericParams] paramList [pragma]
|
iteratorDecl ::= 'iterator' symbol ['*'] [genericParams] paramList [pragma]
|
||||||
[EQUALS stmt]
|
['=' stmt]
|
||||||
|
|
||||||
The `for`:idx: statement is an abstract mechanism to iterate over the elements
|
The `for`:idx: statement is an abstract mechanism to iterate over the elements
|
||||||
of a container. It relies on an `iterator`:idx: to do so. Like ``while``
|
of a container. It relies on an `iterator`:idx: to do so. Like ``while``
|
||||||
|
|
@ -1473,13 +1616,15 @@ Type sections
|
||||||
Syntax::
|
Syntax::
|
||||||
|
|
||||||
typeDef ::= typeDesc | objectDef | enumDef
|
typeDef ::= typeDesc | objectDef | enumDef
|
||||||
genericParams ::= BRACKET_LE (symbol [EQUALS typeDesc] )* BRACKET_RI
|
|
||||||
|
|
||||||
typeDecl ::= TYPE
|
genericParam ::= symbol [':' typeDesc]
|
||||||
indPush
|
genericParams ::= '[' genericParam (comma genericParam)* [comma] ']'
|
||||||
symbol ["*"] [genericParams] [EQUALS typeDef]
|
|
||||||
(SAD symbol ["*"] [genericParams] [EQUALS typeDef])*
|
typeDecl ::= COMMENT
|
||||||
DED
|
| symbol ['*'] [genericParams] ['=' typeDef] [COMMENT|IND COMMENT]
|
||||||
|
|
||||||
|
typeSection ::= 'type' indPush typeDecl (SAD typeDecl)* DED indPop
|
||||||
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
|
@ -1504,6 +1649,8 @@ possible within a single ``type`` section.
|
||||||
Generics
|
Generics
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
|
|
||||||
|
`Version 0.7.4: Complex generic types like in the example do not work.`:red:
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
@ -1578,17 +1725,110 @@ Example:
|
||||||
# this definition exists in the System module
|
# this definition exists in the System module
|
||||||
not (a == b)
|
not (a == b)
|
||||||
|
|
||||||
writeln(5 != 6) # the compiler rewrites that to: writeln(not (5 == 6))
|
assert(5 != 6) # the compiler rewrites that to: assert(not (5 == 6))
|
||||||
|
|
||||||
|
|
||||||
Macros
|
Macros
|
||||||
~~~~~~
|
------
|
||||||
|
|
||||||
`Macros`:idx: are the most powerful feature of Nimrod. They should be used
|
`Macros`:idx: are the most powerful feature of Nimrod. They can be used
|
||||||
only to implement `domain specific languages`:idx:. They may lead to code
|
to implement `domain specific languages`:idx:. But they may lead to code
|
||||||
that is harder to understand and maintain. So one ought to use them sparingly.
|
that is harder to understand and maintain. So one ought to use them sparingly.
|
||||||
The usage of ordinary procs, iterators or generics is preferred to the usage of
|
|
||||||
macros.
|
While macros enable advanced compile-time code tranformations, they
|
||||||
|
cannot change Nimrod's syntax. However, this is no real restriction because
|
||||||
|
Nimrod's syntax is flexible enough anyway.
|
||||||
|
|
||||||
|
To write macros, one needs to know how the Nimrod concrete syntax is converted
|
||||||
|
to an abstract syntax tree. (Unfortunately the AST is not yet documented.)
|
||||||
|
|
||||||
|
There are two ways to invoke a macro:
|
||||||
|
(1) invoking a macro like a procedure call (`expression macros`)
|
||||||
|
(2) invoking a macro with the special ``macrostmt`` syntax (`statement macros`)
|
||||||
|
|
||||||
|
|
||||||
|
Expression Macros
|
||||||
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The following example implements a powerful ``debug`` command that accepts a
|
||||||
|
variable number of arguments:
|
||||||
|
|
||||||
|
.. 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:
|
||||||
|
add(result, newCall("write", newIdentNode("stdout"), toStrLit(n[i])))
|
||||||
|
# add a call to the statement list that writes ": "
|
||||||
|
add(result, newCall("write", newIdentNode("stdout"), newStrLitNode(": ")))
|
||||||
|
# add a call to the statement list that writes the expressions value:
|
||||||
|
add(result, 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)
|
||||||
|
|
||||||
|
|
||||||
|
Statement Macros
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Statement macros are defined just as expression macros. However, they are
|
||||||
|
invoked by an expression following a colon::
|
||||||
|
|
||||||
|
exprStmt ::= lowestExpr ['=' expr | [expr (comma expr)* [comma]] [macroStmt]]
|
||||||
|
macroStmt ::= ':' [stmt] ('of' [sliceExprList] ':' stmt
|
||||||
|
| 'elif' expr ':' stmt
|
||||||
|
| 'except' exceptList ':' stmt )*
|
||||||
|
['else' ':' stmt]
|
||||||
|
|
||||||
|
The following example outlines a macro that generates a lexical analyser from
|
||||||
|
regular expressions:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
import macros
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Modules
|
Modules
|
||||||
|
|
@ -1622,12 +1862,12 @@ This is best illustrated by an example:
|
||||||
|
|
||||||
# Module B
|
# Module B
|
||||||
import A # A is not parsed here! Only the already known symbols
|
import A # A is not parsed here! Only the already known symbols
|
||||||
# of A are imported here.
|
# of A are imported.
|
||||||
|
|
||||||
proc p*(x: A.T1): A.T1 # this works because the compiler has already
|
proc p*(x: A.T1): A.T1 =
|
||||||
|
# this works because the compiler has already
|
||||||
# added T1 to A's interface symbol table
|
# added T1 to A's interface symbol table
|
||||||
|
return x + 1
|
||||||
proc p(x: A.T1): A.T1 = return x + 1
|
|
||||||
|
|
||||||
|
|
||||||
Scope rules
|
Scope rules
|
||||||
|
|
@ -1649,7 +1889,7 @@ procedure or iterator overloading purposes.
|
||||||
|
|
||||||
|
|
||||||
Tuple or object scope
|
Tuple or object scope
|
||||||
~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
The field identifiers inside a tuple or object definition are valid in the
|
The field identifiers inside a tuple or object definition are valid in the
|
||||||
following places:
|
following places:
|
||||||
|
|
||||||
|
|
@ -1659,16 +1899,14 @@ following places:
|
||||||
|
|
||||||
Module scope
|
Module scope
|
||||||
~~~~~~~~~~~~
|
~~~~~~~~~~~~
|
||||||
All identifiers in the interface part of a module are valid from the point of
|
All identifiers of a module are valid from the point of declaration until
|
||||||
declaration, until the end of the module. Furthermore, the identifiers are
|
the end of the module. Identifiers from indirectly dependent modules are *not*
|
||||||
known in other modules that import the module. Identifiers from indirectly
|
available. The `system`:idx: module is automatically imported in every other
|
||||||
dependent modules are *not* available. The `system`:idx: module is automatically
|
module.
|
||||||
imported in all other modules.
|
|
||||||
|
|
||||||
If a module imports an identifier by two different modules,
|
If a module imports an identifier by two different modules, each occurance of
|
||||||
each occurance of the identifier has to be qualified, unless it is an
|
the identifier has to be qualified, unless it is an overloaded procedure or
|
||||||
overloaded procedure or iterator in which case the overloading
|
iterator in which case the overloading resolution takes place:
|
||||||
resolution takes place:
|
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
# Module A
|
# Module A
|
||||||
|
|
@ -1680,7 +1918,7 @@ resolution takes place:
|
||||||
# Module C
|
# Module C
|
||||||
import A, B
|
import A, B
|
||||||
write(stdout, x) # error: x is ambigious
|
write(stdout, x) # error: x is ambigious
|
||||||
write(sdtout, A.x) # no error: qualifier used
|
write(stdout, A.x) # no error: qualifier used
|
||||||
|
|
||||||
var x = 4
|
var x = 4
|
||||||
write(stdout, x) # not ambigious: uses the module C's x
|
write(stdout, x) # not ambigious: uses the module C's x
|
||||||
|
|
@ -1698,14 +1936,14 @@ Pragmas
|
||||||
|
|
||||||
Syntax::
|
Syntax::
|
||||||
|
|
||||||
colonExpr ::= expr [COLON expr]
|
colonExpr ::= expr [':' expr]
|
||||||
colonExprList ::= [ colonExpr (comma colonExpr)* [comma] ]
|
colonExprList ::= [colonExpr (comma colonExpr)* [comma]]
|
||||||
|
|
||||||
pragma ::= CURLYDOT_LE colonExprList (CURLYDOT_RI | CURLY_RI)
|
pragma ::= '{.' optInd (colonExpr [comma])* [SAD] ('.}' | '}')
|
||||||
|
|
||||||
Pragmas are Nimrod's method to give the compiler additional information/
|
Pragmas are Nimrod's method to give the compiler additional information/
|
||||||
commands without introducing a massive number of new keywords. Pragmas are
|
commands without introducing a massive number of new keywords. Pragmas are
|
||||||
processed on the fly during parsing. Pragmas are always enclosed in the
|
processed on the fly during semantic checking. Pragmas are enclosed in the
|
||||||
special ``{.`` and ``.}`` curly brackets.
|
special ``{.`` and ``.}`` curly brackets.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1759,10 +1997,6 @@ compilation option pragmas
|
||||||
--------------------------
|
--------------------------
|
||||||
The listed pragmas here can be used to override the code generation options
|
The listed pragmas here can be used to override the code generation options
|
||||||
for a section of code.
|
for a section of code.
|
||||||
::
|
|
||||||
|
|
||||||
"{." pragma: val {pragma: val} ".}"
|
|
||||||
|
|
||||||
|
|
||||||
The implementation currently provides the following possible options (later
|
The implementation currently provides the following possible options (later
|
||||||
various others may be added).
|
various others may be added).
|
||||||
|
|
@ -1785,8 +2019,7 @@ warnings on|off Turns the warning messages of the compiler
|
||||||
hints on|off Turns the hint messages of the compiler
|
hints on|off Turns the hint messages of the compiler
|
||||||
on or off.
|
on or off.
|
||||||
optimization none|speed|size Optimize the code for speed or size, or
|
optimization none|speed|size Optimize the code for speed or size, or
|
||||||
disable optimization. For non-optimizing
|
disable optimization.
|
||||||
compilers this option has no effect.
|
|
||||||
callconv cdecl|... Specifies the default calling convention for
|
callconv cdecl|... Specifies the default calling convention for
|
||||||
all procedures (and procedure types) that
|
all procedures (and procedure types) that
|
||||||
follow.
|
follow.
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ Introduction
|
||||||
|
|
||||||
This document describes the usage of the *Nimrod compiler*
|
This document describes the usage of the *Nimrod compiler*
|
||||||
on the different supported platforms. It is not a definition of the Nimrod
|
on the different supported platforms. It is not a definition of the Nimrod
|
||||||
programming system (therefore is the Nimrod manual).
|
programming language (therefore is the manual).
|
||||||
|
|
||||||
Nimrod is free software; it is licensed under the
|
Nimrod is free software; it is licensed under the
|
||||||
`GNU General Public License <gpl.html>`_.
|
`GNU General Public License <gpl.html>`_.
|
||||||
|
|
@ -61,14 +61,6 @@ However, the generated C code is not platform independant. C code generated for
|
||||||
Linux does not compile on Windows, for instance. The comment on top of the
|
Linux does not compile on Windows, for instance. The comment on top of the
|
||||||
C file lists the OS, CPU and CC the file has been compiled for.
|
C file lists the OS, CPU and CC the file has been compiled for.
|
||||||
|
|
||||||
The library lies in ``lib``. Directly in the library directory are essential
|
|
||||||
Nimrod modules like the ``system`` and ``os`` modules. Under ``lib/base``
|
|
||||||
are additional specialized libraries or interfaces to foreign libraries which
|
|
||||||
are included in the standard distribution. The ``lib/extra`` directory is
|
|
||||||
initially empty. Third party libraries should go there. In the default
|
|
||||||
configuration the compiler always searches for libraries in ``lib``,
|
|
||||||
``lib/base`` and ``lib/extra``.
|
|
||||||
|
|
||||||
|
|
||||||
Additional Features
|
Additional Features
|
||||||
===================
|
===================
|
||||||
|
|
@ -128,7 +120,7 @@ the C code. Thus it makes the following possible, for example:
|
||||||
|
|
||||||
.. code-block:: Nimrod
|
.. code-block:: Nimrod
|
||||||
var
|
var
|
||||||
EOF {.importc: "EOF", no_decl.}: cint # pretend EOF was a variable, as
|
EACCES {.importc, no_decl.}: cint # pretend EACCES was a variable, as
|
||||||
# Nimrod does not know its value
|
# Nimrod does not know its value
|
||||||
|
|
||||||
However, the ``header`` pragma is often the better alternative.
|
However, the ``header`` pragma is often the better alternative.
|
||||||
|
|
@ -164,14 +156,6 @@ strings automatically:
|
||||||
printf("hallo %s", "world") # "world" will be passed as C string
|
printf("hallo %s", "world") # "world" will be passed as C string
|
||||||
|
|
||||||
|
|
||||||
No_static Pragma
|
|
||||||
~~~~~~~~~~~~~~~~
|
|
||||||
The `no_static`:idx: pragma can be applied to almost any symbol and specifies
|
|
||||||
that it shall not be declared ``static`` in the generated C code. Note that
|
|
||||||
symbols in the interface part of a module never get declared ``static``, so
|
|
||||||
only in very special cases this pragma is necessary.
|
|
||||||
|
|
||||||
|
|
||||||
Line_dir Option
|
Line_dir Option
|
||||||
~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~
|
||||||
The `line_dir`:idx: option can be turned on or off. If on the generated C code
|
The `line_dir`:idx: option can be turned on or off. If on the generated C code
|
||||||
|
|
@ -240,6 +224,22 @@ information that this cannot happen to the GC. If the programmer uses the
|
||||||
memory, but nothing worse happens.
|
memory, but nothing worse happens.
|
||||||
|
|
||||||
|
|
||||||
|
Dead_code_elim Pragma
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
The `dead_code_elim`:idx: pragma only applies to whole modules: It tells the
|
||||||
|
compiler to active (or deactivate) dead code elimination for the module the
|
||||||
|
pragma appers in.
|
||||||
|
|
||||||
|
The ``--dead_code_elim:on`` command line switch has the same effect as marking
|
||||||
|
any module with ``{.dead_code_elim:on}``. However, for some modules such as
|
||||||
|
the GTK wrapper it makes sense to *always* turn on dead code elimination -
|
||||||
|
no matter if it is globally active or not.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
{.dead_code_elim: on.}
|
||||||
|
|
||||||
|
|
||||||
Disabling certain messages
|
Disabling certain messages
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
@ -280,8 +280,8 @@ However, sometimes one has to optimize. Do it in the following order:
|
||||||
|
|
||||||
This section can only help you with the last item. Note that rewriting parts
|
This section can only help you with the last item. Note that rewriting parts
|
||||||
of your program in C is *never* necessary to speed up your program, because
|
of your program in C is *never* necessary to speed up your program, because
|
||||||
everything that can be done in C can be done in Nimrod. Rewriting parts in
|
everything that can be done in C can be done in Nimrod.
|
||||||
assembler *might*.
|
|
||||||
|
|
||||||
Optimizing string handling
|
Optimizing string handling
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,7 @@ compatible to the original implementation as one would like.
|
||||||
|
|
||||||
Even though Nimrod's |rst| parser does not parse all constructs, it is pretty
|
Even though Nimrod's |rst| parser does not parse all constructs, it is pretty
|
||||||
usable. The missing features can easily be circumvented. An indication of this
|
usable. The missing features can easily be circumvented. An indication of this
|
||||||
fact is that Nimrod's
|
fact is that Nimrod's *whole* documentation itself (including this document) is
|
||||||
*whole* documentation itself (including this document) is
|
|
||||||
processed by Nimrod's |rst| parser. (Which is an order of magnitude faster than
|
processed by Nimrod's |rst| parser. (Which is an order of magnitude faster than
|
||||||
Docutils' parser.)
|
Docutils' parser.)
|
||||||
|
|
||||||
|
|
|
||||||
906
doc/theindex.txt
906
doc/theindex.txt
File diff suppressed because it is too large
Load diff
1382
doc/tut1.txt
Normal file
1382
doc/tut1.txt
Normal file
File diff suppressed because it is too large
Load diff
718
doc/tut2.txt
Normal file
718
doc/tut2.txt
Normal 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
|
||||||
|
|
||||||
|
|
||||||
215
doc/tutorial.txt
215
doc/tutorial.txt
|
|
@ -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
|
|
||||||
126
install.sh
126
install.sh
|
|
@ -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
|
|
||||||
79
koch.py
79
koch.py
|
|
@ -18,7 +18,7 @@ False = 0 == 1
|
||||||
|
|
||||||
# --------------------- constants ----------------------------------------
|
# --------------------- constants ----------------------------------------
|
||||||
|
|
||||||
NIMROD_VERSION = '0.7.2'
|
NIMROD_VERSION = '0.7.4'
|
||||||
# This string contains Nimrod's version. It is the only place
|
# This string contains Nimrod's version. It is the only place
|
||||||
# where the version needs to be updated. The rest is done by
|
# where the version needs to be updated. The rest is done by
|
||||||
# the build process automatically. It is replaced **everywhere**
|
# the build process automatically. It is replaced **everywhere**
|
||||||
|
|
@ -35,8 +35,6 @@ force = False
|
||||||
|
|
||||||
GENERATE_DIFF = False
|
GENERATE_DIFF = False
|
||||||
# if set, a diff.log file is generated when bootstrapping
|
# if set, a diff.log file is generated when bootstrapping
|
||||||
# this uses quite a good amount of RAM (ca. 12 MB), so it should not be done
|
|
||||||
# on underpowered systems.
|
|
||||||
|
|
||||||
USE_FPC = True
|
USE_FPC = True
|
||||||
|
|
||||||
|
|
@ -45,31 +43,6 @@ BOOTCMD = "%s cc --compile:build/platdef.c %s rod/nimrod.nim"
|
||||||
|
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
|
|
||||||
DOC = split("""endb intern lib manual nimrodc steps overview""")
|
|
||||||
SRCDOC = split("""system os strutils base/regexprs math complex times
|
|
||||||
parseopt hashes strtabs lexbase parsecfg base/dialogs
|
|
||||||
posix/posix
|
|
||||||
streams base/odbcsql
|
|
||||||
base/zip/zipfiles base/zip/zlib base/zip/libzip
|
|
||||||
""")
|
|
||||||
|
|
||||||
ADD_SRCDOC = split("""
|
|
||||||
base/cairo/cairo base/cairo/cairoft
|
|
||||||
base/cairo/cairowin32 base/cairo/cairoxlib
|
|
||||||
base/gtk/atk base/gtk/gdk2 base/gtk/gdk2pixbuf
|
|
||||||
base/gtk/gdkglext base/gtk/glib2 base/gtk/gtk2
|
|
||||||
base/gtk/gtkglext base/gtk/gtkhtml base/gtk/libglade2
|
|
||||||
base/gtk/pango base/gtk/pangoutils
|
|
||||||
windows/windows windows/mmsystem windows/nb30
|
|
||||||
windows/ole2 windows/shellapi windows/shfolder
|
|
||||||
base/x11/*.nim
|
|
||||||
base/opengl/*.nim
|
|
||||||
base/sdl/*.nim
|
|
||||||
base/lua/*.nim
|
|
||||||
""")
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------
|
|
||||||
|
|
||||||
def Error(msg): sys.exit("[Koch] *** ERROR: " + msg)
|
def Error(msg): sys.exit("[Koch] *** ERROR: " + msg)
|
||||||
def Warn(msg): print "[Koch] *** WARNING: " + msg
|
def Warn(msg): print "[Koch] *** WARNING: " + msg
|
||||||
def Echo(msg): print "[Koch] " + msg
|
def Echo(msg): print "[Koch] " + msg
|
||||||
|
|
@ -140,7 +113,7 @@ BaseDir = _baseDir
|
||||||
def Path(a):
|
def Path(a):
|
||||||
# Gets a UNIX like path and converts it to a path on this platform.
|
# Gets a UNIX like path and converts it to a path on this platform.
|
||||||
# With UNIX like, I mean: slashes, not backslashes, only relative
|
# With UNIX like, I mean: slashes, not backslashes, only relative
|
||||||
# paths ('../etc' can be used)
|
# paths ('../etc') can be used
|
||||||
result = a
|
result = a
|
||||||
if os.sep != "/": result = replace(result, "/", os.sep)
|
if os.sep != "/": result = replace(result, "/", os.sep)
|
||||||
if os.pardir != "..": result = replace(result, "..", os.pardir)
|
if os.pardir != "..": result = replace(result, "..", os.pardir)
|
||||||
|
|
@ -401,12 +374,12 @@ Options:
|
||||||
Possible Commands:
|
Possible Commands:
|
||||||
nim builds the Pascal version of Nimrod
|
nim builds the Pascal version of Nimrod
|
||||||
rod [options] builds the Nimrod version of Nimrod (with options)
|
rod [options] builds the Nimrod version of Nimrod (with options)
|
||||||
doc builds the documentation in HTML
|
|
||||||
clean cleans Nimrod project; removes generated files
|
clean cleans Nimrod project; removes generated files
|
||||||
boot [options] bootstraps with given command line options
|
boot [options] bootstraps with given command line options
|
||||||
rodsrc generates Nimrod version from Pascal version
|
rodsrc generates Nimrod version from Pascal version
|
||||||
web generates the website
|
web generates the website
|
||||||
profile profile the Nimrod compiler
|
profile profile the Nimrod compiler
|
||||||
|
csource build the C sources for installation
|
||||||
zip build the installation ZIP package
|
zip build the installation ZIP package
|
||||||
inno build the Inno Setup installer
|
inno build the Inno Setup installer
|
||||||
""" % (NIMROD_VERSION + ' ' * (44-len(NIMROD_VERSION)), sys.version)
|
""" % (NIMROD_VERSION + ' ' * (44-len(NIMROD_VERSION)), sys.version)
|
||||||
|
|
@ -436,7 +409,6 @@ def main(args):
|
||||||
cmd = args[i]
|
cmd = args[i]
|
||||||
if cmd == "rod": cmd_rod(join(args[i+1:]))
|
if cmd == "rod": cmd_rod(join(args[i+1:]))
|
||||||
elif cmd == "nim": cmd_nim()
|
elif cmd == "nim": cmd_nim()
|
||||||
elif cmd == "doc": cmd_doc()
|
|
||||||
elif cmd == "clean": cmd_clean()
|
elif cmd == "clean": cmd_clean()
|
||||||
elif cmd == "boot": cmd_boot(join(args[i+1:]))
|
elif cmd == "boot": cmd_boot(join(args[i+1:]))
|
||||||
elif cmd == "rodsrc": cmd_rodsrc()
|
elif cmd == "rodsrc": cmd_rodsrc()
|
||||||
|
|
@ -444,11 +416,14 @@ def main(args):
|
||||||
elif cmd == "profile": cmd_profile()
|
elif cmd == "profile": cmd_profile()
|
||||||
elif cmd == "zip": cmd_zip()
|
elif cmd == "zip": cmd_zip()
|
||||||
elif cmd == "inno": cmd_inno()
|
elif cmd == "inno": cmd_inno()
|
||||||
|
elif cmd == "csource": cmd_csource()
|
||||||
else: Error("illegal command: " + cmd)
|
else: Error("illegal command: " + cmd)
|
||||||
|
|
||||||
def cmd_zip():
|
def cmd_csource():
|
||||||
Exec("nimrod cc -r tools/niminst --var:version=%s csource rod/nimrod" %
|
Exec("nimrod cc -r tools/niminst --var:version=%s csource rod/nimrod" %
|
||||||
NIMROD_VERSION)
|
NIMROD_VERSION)
|
||||||
|
|
||||||
|
def cmd_zip():
|
||||||
Exec("nimrod cc -r tools/niminst --var:version=%s zip rod/nimrod" %
|
Exec("nimrod cc -r tools/niminst --var:version=%s zip rod/nimrod" %
|
||||||
NIMROD_VERSION)
|
NIMROD_VERSION)
|
||||||
|
|
||||||
|
|
@ -586,50 +561,10 @@ def cmd_profile():
|
||||||
|
|
||||||
# ------------------ web ------------------------------------------------------
|
# ------------------ web ------------------------------------------------------
|
||||||
|
|
||||||
def buildDoc(destPath):
|
|
||||||
# call nim for the documentation:
|
|
||||||
for d in DOC:
|
|
||||||
Exec("nimrod rst2html --putenv:nimrodversion=%s -o:%s/%s.html "
|
|
||||||
"--index=%s/theindex doc/%s" %
|
|
||||||
(NIMROD_VERSION, destPath, d, destPath, d))
|
|
||||||
for d in SRCDOC:
|
|
||||||
Exec("nimrod doc --putenv:nimrodversion=%s -o:%s/%s.html "
|
|
||||||
"--index=%s/theindex lib/%s" %
|
|
||||||
(NIMROD_VERSION, destPath, FilenameNoExt(d), destPath, d))
|
|
||||||
Exec("nimrod rst2html -o:%s/theindex.html %s/theindex" % (destPath, destPath))
|
|
||||||
|
|
||||||
def buildAddDoc(destPath):
|
|
||||||
# build additional documentation (without the index):
|
|
||||||
def build(d):
|
|
||||||
c = Changed("web__"+d, ["lib/"+d+".nim"], EXPLAIN)
|
|
||||||
if c.check() or force:
|
|
||||||
Exec("nimrod doc --putenv:nimrodversion=%s -o:%s/%s.html "
|
|
||||||
" lib/%s" % (NIMROD_VERSION, destPath, FilenameNoExt(d), d))
|
|
||||||
c.success()
|
|
||||||
|
|
||||||
for a in ADD_SRCDOC:
|
|
||||||
if '*' in a:
|
|
||||||
for d in Glob("lib/" + a): build(d)
|
|
||||||
else:
|
|
||||||
build(a)
|
|
||||||
|
|
||||||
def cmd_web():
|
def cmd_web():
|
||||||
Exec("nimrod cc -r tools/nimweb.nim web/nimrod --putenv:nimrodversion=%s"
|
Exec("nimrod cc -r tools/nimweb.nim web/nimrod --putenv:nimrodversion=%s"
|
||||||
% NIMROD_VERSION)
|
% NIMROD_VERSION)
|
||||||
|
|
||||||
# ------------------ doc ------------------------------------------------------
|
|
||||||
|
|
||||||
def cmd_doc():
|
|
||||||
c = Changed("doc", ["koch.py"] +
|
|
||||||
Glob("doc/*.txt") + Glob("lib/*.txt") + Glob("lib/*.nim")+
|
|
||||||
Glob("config/*.cfg"),
|
|
||||||
EXPLAIN)
|
|
||||||
if c.check() or force:
|
|
||||||
cmd_nim() # we need Nimrod for processing the documentation
|
|
||||||
buildDoc("doc")
|
|
||||||
if Exists("doc/overview.html"):
|
|
||||||
c.success()
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
def getVersion():
|
def getVersion():
|
||||||
|
|
|
||||||
129
lib/arithm.nim
129
lib/arithm.nim
|
|
@ -102,51 +102,16 @@ proc absInt(a: int): int {.compilerProc, inline.} =
|
||||||
raiseOverflow()
|
raiseOverflow()
|
||||||
|
|
||||||
const
|
const
|
||||||
asmVersion = defined(I386) and (defined(vcc) or defined(wcc) or defined(dmc))
|
asmVersion = defined(I386) and (defined(vcc) or defined(wcc) or
|
||||||
|
defined(dmc) or defined(gcc) or defined(llvm_gcc))
|
||||||
# my Version of Borland C++Builder does not have
|
# my Version of Borland C++Builder does not have
|
||||||
# tasm32, which is needed for assembler blocks
|
# tasm32, which is needed for assembler blocks
|
||||||
# this is why Borland is not included in the 'when'
|
# this is why Borland is not included in the 'when'
|
||||||
useInline = not asmVersion
|
|
||||||
|
|
||||||
when asmVersion and defined(gcc):
|
when asmVersion and not defined(gcc) and not defined(llvm_gcc):
|
||||||
proc addInt(a, b: int): int {.compilerProc, pure, inline.}
|
|
||||||
proc subInt(a, b: int): int {.compilerProc, pure, inline.}
|
|
||||||
proc mulInt(a, b: int): int {.compilerProc, pure, inline.}
|
|
||||||
proc divInt(a, b: int): int {.compilerProc, pure, inline.}
|
|
||||||
proc modInt(a, b: int): int {.compilerProc, pure, inline.}
|
|
||||||
proc negInt(a: int): int {.compilerProc, pure, inline.}
|
|
||||||
|
|
||||||
elif asmVersion:
|
|
||||||
proc addInt(a, b: int): int {.compilerProc, pure.}
|
|
||||||
proc subInt(a, b: int): int {.compilerProc, pure.}
|
|
||||||
proc mulInt(a, b: int): int {.compilerProc, pure.}
|
|
||||||
proc divInt(a, b: int): int {.compilerProc, pure.}
|
|
||||||
proc modInt(a, b: int): int {.compilerProc, pure.}
|
|
||||||
proc negInt(a: int): int {.compilerProc, pure.}
|
|
||||||
|
|
||||||
elif useInline:
|
|
||||||
proc addInt(a, b: int): int {.compilerProc, inline.}
|
|
||||||
proc subInt(a, b: int): int {.compilerProc, inline.}
|
|
||||||
proc mulInt(a, b: int): int {.compilerProc.}
|
|
||||||
# mulInt is to large for inlining?
|
|
||||||
proc divInt(a, b: int): int {.compilerProc, inline.}
|
|
||||||
proc modInt(a, b: int): int {.compilerProc, inline.}
|
|
||||||
proc negInt(a: int): int {.compilerProc, inline.}
|
|
||||||
|
|
||||||
else:
|
|
||||||
proc addInt(a, b: int): int {.compilerProc.}
|
|
||||||
proc subInt(a, b: int): int {.compilerProc.}
|
|
||||||
proc mulInt(a, b: int): int {.compilerProc.}
|
|
||||||
proc divInt(a, b: int): int {.compilerProc.}
|
|
||||||
proc modInt(a, b: int): int {.compilerProc.}
|
|
||||||
proc negInt(a: int): int {.compilerProc.}
|
|
||||||
|
|
||||||
# implementation:
|
|
||||||
|
|
||||||
when asmVersion and not defined(gcc):
|
|
||||||
# assembler optimized versions for compilers that
|
# assembler optimized versions for compilers that
|
||||||
# have an intel syntax assembler:
|
# have an intel syntax assembler:
|
||||||
proc addInt(a, b: int): int =
|
proc addInt(a, b: int): int {.compilerProc, pure.} =
|
||||||
# a in eax, and b in edx
|
# a in eax, and b in edx
|
||||||
asm """
|
asm """
|
||||||
mov eax, `a`
|
mov eax, `a`
|
||||||
|
|
@ -156,7 +121,7 @@ when asmVersion and not defined(gcc):
|
||||||
theEnd:
|
theEnd:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc subInt(a, b: int): int =
|
proc subInt(a, b: int): int {.compilerProc, pure.} =
|
||||||
asm """
|
asm """
|
||||||
mov eax, `a`
|
mov eax, `a`
|
||||||
sub eax, `b`
|
sub eax, `b`
|
||||||
|
|
@ -165,7 +130,7 @@ when asmVersion and not defined(gcc):
|
||||||
theEnd:
|
theEnd:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc negInt(a: int): int =
|
proc negInt(a: int): int {.compilerProc, pure.} =
|
||||||
asm """
|
asm """
|
||||||
mov eax, `a`
|
mov eax, `a`
|
||||||
neg eax
|
neg eax
|
||||||
|
|
@ -174,7 +139,7 @@ when asmVersion and not defined(gcc):
|
||||||
theEnd:
|
theEnd:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc divInt(a, b: int): int =
|
proc divInt(a, b: int): int {.compilerProc, pure.} =
|
||||||
asm """
|
asm """
|
||||||
mov eax, `a`
|
mov eax, `a`
|
||||||
mov ecx, `b`
|
mov ecx, `b`
|
||||||
|
|
@ -185,7 +150,7 @@ when asmVersion and not defined(gcc):
|
||||||
theEnd:
|
theEnd:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc modInt(a, b: int): int =
|
proc modInt(a, b: int): int {.compilerProc, pure.} =
|
||||||
asm """
|
asm """
|
||||||
mov eax, `a`
|
mov eax, `a`
|
||||||
mov ecx, `b`
|
mov ecx, `b`
|
||||||
|
|
@ -197,7 +162,7 @@ when asmVersion and not defined(gcc):
|
||||||
mov eax, edx
|
mov eax, edx
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc mulInt(a, b: int): int =
|
proc mulInt(a, b: int): int {.compilerProc, pure.} =
|
||||||
asm """
|
asm """
|
||||||
mov eax, `a`
|
mov eax, `a`
|
||||||
mov ecx, `b`
|
mov ecx, `b`
|
||||||
|
|
@ -208,99 +173,105 @@ when asmVersion and not defined(gcc):
|
||||||
theEnd:
|
theEnd:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
elif asmVersion and defined(gcc):
|
elif false: # asmVersion and (defined(gcc) or defined(llvm_gcc)):
|
||||||
proc addInt(a, b: int): int =
|
proc addInt(a, b: int): int {.compilerProc, inline.} =
|
||||||
asm """ "addl %1,%%eax\n"
|
# don't use a pure proc here!
|
||||||
|
asm """
|
||||||
|
"addl %%ecx, %%eax\n"
|
||||||
"jno 1\n"
|
"jno 1\n"
|
||||||
"call _raiseOverflow\n"
|
"call _raiseOverflow\n"
|
||||||
"1: \n"
|
"1: \n"
|
||||||
:"=a"(`a`)
|
:"=a"(`result`)
|
||||||
:"a"(`a`), "r"(`b`)
|
:"a"(`a`), "c"(`b`)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc subInt(a, b: int): int =
|
proc subInt(a, b: int): int {.compilerProc, inline.} =
|
||||||
asm """ "subl %1,%%eax\n"
|
asm """ "subl %%ecx,%%eax\n"
|
||||||
"jno 1\n"
|
"jno 1\n"
|
||||||
"call _raiseOverflow\n"
|
"call _raiseOverflow\n"
|
||||||
"1: \n"
|
"1: \n"
|
||||||
:"=a"(`a`)
|
:"=a"(`result`)
|
||||||
:"a"(`a`), "r"(`b`)
|
:"a"(`a`), "c"(`b`)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc negInt(a: int): int =
|
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"(`result`)
|
||||||
|
:"a"(`a`), "c"(`b`)
|
||||||
|
:"%edx"
|
||||||
|
"""
|
||||||
|
|
||||||
|
proc negInt(a: int): int {.compilerProc, inline.} =
|
||||||
asm """ "negl %%eax\n"
|
asm """ "negl %%eax\n"
|
||||||
"jno 1\n"
|
"jno 1\n"
|
||||||
"call _raiseOverflow\n"
|
"call _raiseOverflow\n"
|
||||||
"1: \n"
|
"1: \n"
|
||||||
:"=a"(`a`)
|
:"=a"(`result`)
|
||||||
:"a"(`a`)
|
:"a"(`a`)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc divInt(a, b: int): int =
|
proc divInt(a, b: int): int {.compilerProc, inline.} =
|
||||||
asm """ "xorl %%edx, %%edx\n"
|
asm """ "xorl %%edx, %%edx\n"
|
||||||
"idivl %%ecx\n"
|
"idivl %%ecx\n"
|
||||||
"jno 1\n"
|
"jno 1\n"
|
||||||
"call _raiseOverflow\n"
|
"call _raiseOverflow\n"
|
||||||
"1: \n"
|
"1: \n"
|
||||||
:"=a"(`a`)
|
:"=a"(`result`)
|
||||||
:"a"(`a`), "c"(`b`)
|
:"a"(`a`), "c"(`b`)
|
||||||
:"%edx"
|
:"%edx"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc modInt(a, b: int): int =
|
proc modInt(a, b: int): int {.compilerProc, inline.} =
|
||||||
asm """ "xorl %%edx, %%edx\n"
|
asm """ "xorl %%edx, %%edx\n"
|
||||||
"idivl %%ecx\n"
|
"idivl %%ecx\n"
|
||||||
"jno 1\n"
|
"jno 1\n"
|
||||||
"call _raiseOverflow\n"
|
"call _raiseOverflow\n"
|
||||||
"1: \n"
|
"1: \n"
|
||||||
"movl %%edx, %%eax"
|
"movl %%edx, %%eax"
|
||||||
:"=a"(`a`)
|
:"=a"(`result`)
|
||||||
:"a"(`a`), "c"(`b`)
|
:"a"(`a`), "c"(`b`)
|
||||||
:"%edx"
|
:"%edx"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc mulInt(a, b: int): int =
|
# Platform independant versions of the above (slower!)
|
||||||
asm """ "xorl %%edx, %%edx\n"
|
when not defined(addInt):
|
||||||
"imull %%ecx\n"
|
proc addInt(a, b: int): int {.compilerProc, inline.} =
|
||||||
"jno 1\n"
|
|
||||||
"call _raiseOverflow\n"
|
|
||||||
"1: \n"
|
|
||||||
:"=a"(`a`)
|
|
||||||
:"a"(`a`), "c"(`b`)
|
|
||||||
:"%edx"
|
|
||||||
"""
|
|
||||||
|
|
||||||
else:
|
|
||||||
# Platform independant versions of the above (slower!)
|
|
||||||
|
|
||||||
proc addInt(a, b: int): int =
|
|
||||||
result = a +% b
|
result = a +% b
|
||||||
if (result xor a) >= 0 or (result xor b) >= 0:
|
if (result xor a) >= 0 or (result xor b) >= 0:
|
||||||
return result
|
return result
|
||||||
raiseOverflow()
|
raiseOverflow()
|
||||||
|
|
||||||
proc subInt(a, b: int): int =
|
when not defined(subInt):
|
||||||
|
proc subInt(a, b: int): int {.compilerProc, inline.} =
|
||||||
result = a -% b
|
result = a -% b
|
||||||
if (result xor a) >= 0 or (result xor not b) >= 0:
|
if (result xor a) >= 0 or (result xor not b) >= 0:
|
||||||
return result
|
return result
|
||||||
raiseOverflow()
|
raiseOverflow()
|
||||||
|
|
||||||
proc negInt(a: int): int =
|
when not defined(negInt):
|
||||||
|
proc negInt(a: int): int {.compilerProc, inline.} =
|
||||||
if a != low(int): return -a
|
if a != low(int): return -a
|
||||||
raiseOverflow()
|
raiseOverflow()
|
||||||
|
|
||||||
proc divInt(a, b: int): int =
|
when not defined(divInt):
|
||||||
|
proc divInt(a, b: int): int {.compilerProc, inline.} =
|
||||||
if b == 0:
|
if b == 0:
|
||||||
raiseDivByZero()
|
raiseDivByZero()
|
||||||
if a == low(int) and b == -1:
|
if a == low(int) and b == -1:
|
||||||
raiseOverflow()
|
raiseOverflow()
|
||||||
return a div b
|
return a div b
|
||||||
|
|
||||||
proc modInt(a, b: int): int =
|
when not defined(modInt):
|
||||||
|
proc modInt(a, b: int): int {.compilerProc, inline.} =
|
||||||
if b == 0:
|
if b == 0:
|
||||||
raiseDivByZero()
|
raiseDivByZero()
|
||||||
return a mod b
|
return a mod b
|
||||||
|
|
||||||
|
when not defined(mulInt):
|
||||||
#
|
#
|
||||||
# This code has been inspired by Python's source code.
|
# This code has been inspired by Python's source code.
|
||||||
# The native int product x*y is either exactly right or *way* off, being
|
# The native int product x*y is either exactly right or *way* off, being
|
||||||
|
|
@ -321,7 +292,7 @@ else:
|
||||||
# the only one that can lose catastrophic amounts of information, it's the
|
# the only one that can lose catastrophic amounts of information, it's the
|
||||||
# native int product that must have overflowed.
|
# native int product that must have overflowed.
|
||||||
#
|
#
|
||||||
proc mulInt(a, b: int): int =
|
proc mulInt(a, b: int): int {.compilerProc.} =
|
||||||
var
|
var
|
||||||
resAsFloat, floatProd: float
|
resAsFloat, floatProd: float
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -281,7 +281,7 @@ proc getServerSoftware*(): string =
|
||||||
|
|
||||||
proc setTestData*(keysvalues: openarray[string]) =
|
proc setTestData*(keysvalues: openarray[string]) =
|
||||||
## fills the appropriate environment variables to test your CGI application.
|
## fills the appropriate environment variables to test your CGI application.
|
||||||
## This can only simulate the 'GET' 'REQUEST_METHOD'. `keysvalues` should
|
## This can only simulate the 'GET' request method. `keysvalues` should
|
||||||
## provide embedded (name, value)-pairs. Example:
|
## provide embedded (name, value)-pairs. Example:
|
||||||
##
|
##
|
||||||
## .. code-block:: Nimrod
|
## .. code-block:: Nimrod
|
||||||
|
|
@ -300,6 +300,7 @@ proc setTestData*(keysvalues: openarray[string]) =
|
||||||
proc writeContentType*() =
|
proc writeContentType*() =
|
||||||
## call this before starting to send your HTML data to `stdout`. This
|
## call this before starting to send your HTML data to `stdout`. This
|
||||||
## is just a shorthand for:
|
## is just a shorthand for:
|
||||||
|
##
|
||||||
## .. code-block:: Nimrod
|
## .. code-block:: Nimrod
|
||||||
## write(stdout, "Content-type: text/html\n\n")
|
## write(stdout, "Content-type: text/html\n\n")
|
||||||
write(stdout, "Content-type: text/html\n\n")
|
write(stdout, "Content-type: text/html\n\n")
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
{.deadCodeElim: on.}
|
||||||
|
|
||||||
import
|
import
|
||||||
glib2
|
glib2
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
{.deadCodeElim: on.}
|
||||||
|
|
||||||
import
|
import
|
||||||
glib2, gdk2pixbuf, pango
|
glib2, gdk2pixbuf, pango
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
{.deadCodeElim: on.}
|
||||||
|
|
||||||
import
|
import
|
||||||
glib2
|
glib2
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
{.deadCodeElim: on.}
|
||||||
|
|
||||||
import
|
import
|
||||||
Glib2, Gdk2
|
Glib2, Gdk2
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
{.deadCodeElim: on.}
|
||||||
|
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
const
|
const
|
||||||
gliblib = "libglib-2.0-0.dll"
|
gliblib = "libglib-2.0-0.dll"
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
{.deadCodeElim: on.}
|
||||||
|
|
||||||
import
|
import
|
||||||
glib2, atk, pango, gdk2pixbuf, gdk2
|
glib2, atk, pango, gdk2pixbuf, gdk2
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
{.deadCodeElim: on.}
|
||||||
|
|
||||||
import
|
import
|
||||||
Glib2, Gdk2, Gtk2, GdkGLExt
|
Glib2, Gdk2, Gtk2, GdkGLExt
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
{.deadCodeElim: on.}
|
||||||
|
|
||||||
import
|
import
|
||||||
gtk2, glib2, atk, pango, gdk2pixbuf, gdk2
|
gtk2, glib2, atk, pango, gdk2pixbuf, gdk2
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
{.deadCodeElim: on.}
|
||||||
|
|
||||||
import
|
import
|
||||||
glib2, gtk2
|
glib2, gtk2
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
{.deadCodeElim: on.}
|
||||||
|
|
||||||
import
|
import
|
||||||
glib2
|
glib2
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
{.deadCodeElim: on.}
|
||||||
|
|
||||||
import
|
import
|
||||||
glib2, pango
|
glib2, pango
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -270,7 +270,8 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
#
|
{.deadCodeElim: on.}
|
||||||
|
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
const SDLLibName = "SDL.dll"
|
const SDLLibName = "SDL.dll"
|
||||||
elif defined(macosx):
|
elif defined(macosx):
|
||||||
|
|
|
||||||
|
|
@ -318,11 +318,6 @@ proc Mix_LoadWAV_RW*(src: PSDL_RWops, freesrc: int): PMix_Chunk{.cdecl,
|
||||||
proc Mix_LoadWAV*(filename: cstring): PMix_Chunk
|
proc Mix_LoadWAV*(filename: cstring): PMix_Chunk
|
||||||
proc Mix_LoadMUS*(filename: cstring): PMix_Music{.cdecl,
|
proc Mix_LoadMUS*(filename: cstring): PMix_Music{.cdecl,
|
||||||
importc, dynlib: SDL_MixerLibName.}
|
importc, dynlib: SDL_MixerLibName.}
|
||||||
##if 0 { This hasn't been hooked into music.c yet }
|
|
||||||
#{ Load a 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
|
# Load a wave file of the mixer format from a memory buffer
|
||||||
proc Mix_QuickLoad_WAV*(mem: PUint8): PMix_Chunk{.cdecl,
|
proc Mix_QuickLoad_WAV*(mem: PUint8): PMix_Chunk{.cdecl,
|
||||||
importc, dynlib: SDL_MixerLibName.}
|
importc, dynlib: SDL_MixerLibName.}
|
||||||
|
|
|
||||||
|
|
@ -126,5 +126,5 @@ elif defined(mac):
|
||||||
nss = NSLookupSymbolInModule(NSModule(lib), name)
|
nss = NSLookupSymbolInModule(NSModule(lib), name)
|
||||||
result = TProcAddr(NSAddressOfSymbol(nss))
|
result = TProcAddr(NSAddressOfSymbol(nss))
|
||||||
|
|
||||||
else: # workaround a newly introduced bug :-(
|
else:
|
||||||
{.error: "no implementation for dyncalls".}
|
{.error: "no implementation for dyncalls".}
|
||||||
|
|
|
||||||
|
|
@ -326,6 +326,9 @@ proc echo*(x: cstring) = ewriteln(x)
|
||||||
proc echo[Ty](x: Ty) =
|
proc echo[Ty](x: Ty) =
|
||||||
echo(x)
|
echo(x)
|
||||||
|
|
||||||
|
proc echo[Ty](x: openArray[Ty]) =
|
||||||
|
for a in items(x): echo(a)
|
||||||
|
|
||||||
# Arithmetic:
|
# Arithmetic:
|
||||||
proc addInt(a, b: int): int {.pure, compilerproc.} =
|
proc addInt(a, b: int): int {.pure, compilerproc.} =
|
||||||
asm """
|
asm """
|
||||||
|
|
|
||||||
|
|
@ -61,9 +61,6 @@ type
|
||||||
filename: CString
|
filename: CString
|
||||||
len: int # length of slots (when not debugging always zero)
|
len: int # length of slots (when not debugging always zero)
|
||||||
|
|
||||||
TTempFrame = tuple[ # used for recursion elimination in WriteStackTrace
|
|
||||||
procname: CString, line: int]
|
|
||||||
|
|
||||||
var
|
var
|
||||||
buf: string # cannot be allocated on the stack!
|
buf: string # cannot be allocated on the stack!
|
||||||
assertBuf: string # we need a different buffer for
|
assertBuf: string # we need a different buffer for
|
||||||
|
|
@ -72,28 +69,40 @@ var
|
||||||
|
|
||||||
framePtr {.exportc.}: PFrame
|
framePtr {.exportc.}: PFrame
|
||||||
|
|
||||||
tempFrames: array [0..255, TTempFrame] # cannot be allocated
|
tempFrames: array [0..127, PFrame] # cannot be allocated on the stack!
|
||||||
# on the stack!
|
|
||||||
|
|
||||||
proc auxWriteStackTrace(f: PFrame, s: var string) =
|
proc auxWriteStackTrace(f: PFrame, s: var string) =
|
||||||
|
const
|
||||||
|
firstCalls = 32
|
||||||
var
|
var
|
||||||
it = f
|
it = f
|
||||||
i = 0
|
i = 0
|
||||||
total = 0
|
total = 0
|
||||||
while it != nil and i <= high(tempFrames):
|
while it != nil and i <= high(tempFrames)-(firstCalls-1):
|
||||||
tempFrames[i] = (it.procname, it.line)
|
# the (-1) is for a nil entry that marks where the '...' should occur
|
||||||
|
tempFrames[i] = it
|
||||||
inc(i)
|
inc(i)
|
||||||
inc(total)
|
inc(total)
|
||||||
it = it.prev
|
it = it.prev
|
||||||
|
var b = it
|
||||||
while it != nil:
|
while it != nil:
|
||||||
inc(total)
|
inc(total)
|
||||||
it = it.prev
|
it = it.prev
|
||||||
# if the buffer overflowed print '...':
|
for j in 1..total-i-(firstCalls-1):
|
||||||
|
if b != nil: b = b.prev
|
||||||
if total != i:
|
if total != i:
|
||||||
add(s, "(")
|
tempFrames[i] = nil
|
||||||
add(s, $(total-i))
|
inc(i)
|
||||||
add(s, " calls omitted) ...\n")
|
while b != nil and i <= high(tempFrames):
|
||||||
|
tempFrames[i] = b
|
||||||
|
inc(i)
|
||||||
|
b = b.prev
|
||||||
for j in countdown(i-1, 0):
|
for j in countdown(i-1, 0):
|
||||||
|
if tempFrames[j] == nil:
|
||||||
|
add(s, "(")
|
||||||
|
add(s, $(total-i-1))
|
||||||
|
add(s, " calls omitted) ...\n")
|
||||||
|
else:
|
||||||
add(s, $tempFrames[j].procname)
|
add(s, $tempFrames[j].procname)
|
||||||
if tempFrames[j].line > 0:
|
if tempFrames[j].line > 0:
|
||||||
add(s, ", line: ")
|
add(s, ", line: ")
|
||||||
|
|
@ -156,8 +165,7 @@ proc internalAssert(file: cstring, line: int, cond: bool) {.compilerproc.} =
|
||||||
raise gAssertionFailed # newException(EAssertionFailed, assertBuf)
|
raise gAssertionFailed # newException(EAssertionFailed, assertBuf)
|
||||||
|
|
||||||
proc WriteStackTrace() =
|
proc WriteStackTrace() =
|
||||||
var
|
var s = ""
|
||||||
s: string = ""
|
|
||||||
rawWriteStackTrace(s)
|
rawWriteStackTrace(s)
|
||||||
writeToStdErr(s)
|
writeToStdErr(s)
|
||||||
|
|
||||||
|
|
@ -208,13 +216,13 @@ assertBuf = newString(2048)
|
||||||
setLen(buf, 0)
|
setLen(buf, 0)
|
||||||
setLen(assertBuf, 0)
|
setLen(assertBuf, 0)
|
||||||
|
|
||||||
proc raiseRangeError(val: biggestInt) {.compilerproc, noreturn.} =
|
proc raiseRangeError(val: biggestInt) {.compilerproc, noreturn, noinline.} =
|
||||||
raise newException(EOutOfRange, "value " & $val & " out of range")
|
raise newException(EOutOfRange, "value " & $val & " out of range")
|
||||||
|
|
||||||
proc raiseIndexError() {.compilerproc, noreturn.} =
|
proc raiseIndexError() {.compilerproc, noreturn, noinline.} =
|
||||||
raise newException(EInvalidIndex, "index out of bounds")
|
raise newException(EInvalidIndex, "index out of bounds")
|
||||||
|
|
||||||
proc raiseFieldError(f: string) {.compilerproc, noreturn.} =
|
proc raiseFieldError(f: string) {.compilerproc, noreturn, noinline.} =
|
||||||
raise newException(EInvalidField, f & " is not accessible")
|
raise newException(EInvalidField, f & " is not accessible")
|
||||||
|
|
||||||
proc chckIndx(i, a, b: int): int =
|
proc chckIndx(i, a, b: int): int =
|
||||||
|
|
|
||||||
39
lib/gc.nim
39
lib/gc.nim
|
|
@ -13,11 +13,10 @@
|
||||||
# * incremental
|
# * incremental
|
||||||
# * non-recursive
|
# * non-recursive
|
||||||
# * generational
|
# * generational
|
||||||
# * excellent performance
|
|
||||||
|
|
||||||
# Future Improvements:
|
# Future Improvements:
|
||||||
# * Both dlmalloc and TLSF lack zero-overhead object allocation. Thus, for
|
# * Both dlmalloc and TLSF lack zero-overhead object allocation. Thus, for
|
||||||
# small objects we will should use our own allocator.
|
# small objects we should use our own allocator.
|
||||||
# * Support for multi-threading. However, locks for the reference counting
|
# * Support for multi-threading. However, locks for the reference counting
|
||||||
# might turn out to be too slow.
|
# might turn out to be too slow.
|
||||||
|
|
||||||
|
|
@ -332,7 +331,7 @@ proc CellSetPut(t: var TCellSet, key: TAddress): PPageDesc =
|
||||||
|
|
||||||
# ---------- slightly higher level procs --------------------------------------
|
# ---------- slightly higher level procs --------------------------------------
|
||||||
|
|
||||||
proc in_Operator(s: TCellSet, cell: PCell): bool =
|
proc contains(s: TCellSet, cell: PCell): bool =
|
||||||
var u = cast[TAddress](cell)
|
var u = cast[TAddress](cell)
|
||||||
var t = CellSetGet(s, u shr PageShift)
|
var t = CellSetGet(s, u shr PageShift)
|
||||||
if t != nil:
|
if t != nil:
|
||||||
|
|
@ -468,23 +467,6 @@ proc prepareDealloc(cell: PCell) =
|
||||||
proc setStackBottom(theStackBottom: pointer) {.compilerproc.} =
|
proc setStackBottom(theStackBottom: pointer) {.compilerproc.} =
|
||||||
stackBottom = theStackBottom
|
stackBottom = theStackBottom
|
||||||
|
|
||||||
proc initGC() =
|
|
||||||
when traceGC:
|
|
||||||
for i in low(TCellState)..high(TCellState): CellSetInit(states[i])
|
|
||||||
gch.stackScans = 0
|
|
||||||
gch.cycleCollections = 0
|
|
||||||
gch.maxThreshold = 0
|
|
||||||
gch.maxStackSize = 0
|
|
||||||
gch.maxStackPages = 0
|
|
||||||
gch.cycleTableSize = 0
|
|
||||||
# init the rt
|
|
||||||
init(gch.zct)
|
|
||||||
init(gch.tempStack)
|
|
||||||
CellSetInit(gch.cycleRoots)
|
|
||||||
CellSetInit(gch.stackCells)
|
|
||||||
gch.mask = 0
|
|
||||||
new(gOutOfMem) # reserve space for the EOutOfMemory exception here!
|
|
||||||
|
|
||||||
proc PossibleRoot(gch: var TGcHeap, c: PCell) {.inline.} =
|
proc PossibleRoot(gch: var TGcHeap, c: PCell) {.inline.} =
|
||||||
if canbeCycleRoot(c): incl(gch.cycleRoots, c)
|
if canbeCycleRoot(c): incl(gch.cycleRoots, c)
|
||||||
|
|
||||||
|
|
@ -535,6 +517,23 @@ proc unsureAsgnRef(dest: ppointer, src: pointer) =
|
||||||
if dest^ != nil: decRef(usrToCell(dest^))
|
if dest^ != nil: decRef(usrToCell(dest^))
|
||||||
dest^ = src
|
dest^ = src
|
||||||
|
|
||||||
|
proc initGC() =
|
||||||
|
when traceGC:
|
||||||
|
for i in low(TCellState)..high(TCellState): CellSetInit(states[i])
|
||||||
|
gch.stackScans = 0
|
||||||
|
gch.cycleCollections = 0
|
||||||
|
gch.maxThreshold = 0
|
||||||
|
gch.maxStackSize = 0
|
||||||
|
gch.maxStackPages = 0
|
||||||
|
gch.cycleTableSize = 0
|
||||||
|
# init the rt
|
||||||
|
init(gch.zct)
|
||||||
|
init(gch.tempStack)
|
||||||
|
CellSetInit(gch.cycleRoots)
|
||||||
|
CellSetInit(gch.stackCells)
|
||||||
|
gch.mask = 0
|
||||||
|
new(gOutOfMem) # reserve space for the EOutOfMemory exception here!
|
||||||
|
|
||||||
proc getDiscriminant(aa: Pointer, n: ptr TNimNode): int =
|
proc getDiscriminant(aa: Pointer, n: ptr TNimNode): int =
|
||||||
assert(n.kind == nkCase)
|
assert(n.kind == nkCase)
|
||||||
var d: int
|
var d: int
|
||||||
|
|
|
||||||
|
|
@ -151,8 +151,7 @@ proc open(L: var TBaseLexer, input: PStream, bufLen: int = 8192) =
|
||||||
skip_UTF_8_BOM(L)
|
skip_UTF_8_BOM(L)
|
||||||
|
|
||||||
proc getColNumber(L: TBaseLexer, pos: int): int =
|
proc getColNumber(L: TBaseLexer, pos: int): int =
|
||||||
result = pos - L.lineStart
|
result = abs(pos - L.lineStart)
|
||||||
assert(result >= 0)
|
|
||||||
|
|
||||||
proc getCurrentLine(L: TBaseLexer, marker: bool = true): string =
|
proc getCurrentLine(L: TBaseLexer, marker: bool = true): string =
|
||||||
var i: int
|
var i: int
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,40 @@
|
||||||
# cog.out(toEnum(key, val))
|
# cog.out(toEnum(key, val))
|
||||||
#]]]
|
#]]]
|
||||||
type
|
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
|
TNimrodTypeKind* = enum
|
||||||
ntyNone, ntyBool, ntyChar, ntyEmpty,
|
ntyNone, ntyBool, ntyChar, ntyEmpty,
|
||||||
ntyArrayConstr, ntyNil, ntyGeneric, ntyGenericInst,
|
ntyArrayConstr, ntyNil, ntyGeneric, ntyGenericInst,
|
||||||
|
|
@ -49,40 +83,6 @@ type
|
||||||
nskMacro, nskTemplate, nskField, nskEnumField,
|
nskMacro, nskTemplate, nskField, nskEnumField,
|
||||||
nskForVar, nskModule, nskLabel, nskStub
|
nskForVar, nskModule, nskLabel, nskStub
|
||||||
TNimSymKinds* = set[TNimrodSymKind]
|
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]
|
|
||||||
#[[[end]]]
|
#[[[end]]]
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
|
||||||
|
|
@ -421,18 +421,4 @@ struct NimException {
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if 0
|
|
||||||
typedef struct TStringDesc {
|
|
||||||
NI len;
|
|
||||||
NI space;
|
|
||||||
NIM_CHAR data[1]; /* SEQ_DECL_SIZE]; */
|
|
||||||
} TStringDesc;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
NI len, space;
|
|
||||||
} TGenericSeq;
|
|
||||||
|
|
||||||
typedef TGenericSeq* PGenericSeq;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
## retrieving environment variables, reading command line arguments,
|
## retrieving environment variables, reading command line arguments,
|
||||||
## working with directories, running shell commands, etc.
|
## working with directories, running shell commands, etc.
|
||||||
## This module is -- like any other basic library -- platform independant.
|
## This module is -- like any other basic library -- platform independant.
|
||||||
|
{.deadCodeElim: on.}
|
||||||
|
|
||||||
{.push debugger: off.}
|
{.push debugger: off.}
|
||||||
|
|
||||||
|
|
@ -863,9 +864,9 @@ var
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
# because we support Windows GUI applications, things get really
|
# because we support Windows GUI applications, things get really
|
||||||
# messy here...
|
# messy here...
|
||||||
proc GetEnvironmentStringsA*(): cstring {.
|
proc GetEnvironmentStringsA(): cstring {.
|
||||||
stdcall, dynlib: "kernel32", importc.}
|
stdcall, dynlib: "kernel32", importc.}
|
||||||
proc FreeEnvironmentStringsA*(para1: cstring): int32 {.
|
proc FreeEnvironmentStringsA(para1: cstring): int32 {.
|
||||||
stdcall, dynlib: "kernel32", importc.}
|
stdcall, dynlib: "kernel32", importc.}
|
||||||
|
|
||||||
proc strEnd(cstr: CString, c = 0): CString {.importc: "strchr", nodecl.}
|
proc strEnd(cstr: CString, c = 0): CString {.importc: "strchr", nodecl.}
|
||||||
|
|
@ -1091,8 +1092,8 @@ proc expandFilename(filename: string): string =
|
||||||
|
|
||||||
proc parseCmdLine*(c: string): seq[string] =
|
proc parseCmdLine*(c: string): seq[string] =
|
||||||
## Splits a command line into several components; components are separated by
|
## Splits a command line into several components; components are separated by
|
||||||
## whitespace or are quoted with the ``"`` or ``'`` characters. This proc is
|
## whitespace unless the whitespace occurs within ``"`` or ``'`` quotes.
|
||||||
## only occassionally useful, better use the `parseopt` module.
|
## This proc is only occassionally useful, better use the `parseopt` module.
|
||||||
result = @[]
|
result = @[]
|
||||||
var i = 0
|
var i = 0
|
||||||
while c[i] != '\0':
|
while c[i] != '\0':
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ type
|
||||||
TTokKind = enum
|
TTokKind = enum
|
||||||
tkInvalid, tkEof,
|
tkInvalid, tkEof,
|
||||||
tkSymbol, tkEquals, tkColon, tkBracketLe, tkBracketRi, tkDashDash
|
tkSymbol, tkEquals, tkColon, tkBracketLe, tkBracketRi, tkDashDash
|
||||||
TToken{.final.} = object # a token
|
TToken {.final.} = object # a token
|
||||||
kind: TTokKind # the type of the token
|
kind: TTokKind # the type of the token
|
||||||
literal: string # the parsed (string) literal
|
literal: string # the parsed (string) literal
|
||||||
|
|
||||||
|
|
@ -139,7 +139,7 @@ proc getEscapedChar(c: var TCfgParser, tok: var TToken) =
|
||||||
inc(c.bufpos) # skip '\'
|
inc(c.bufpos) # skip '\'
|
||||||
case c.buf[c.bufpos]
|
case c.buf[c.bufpos]
|
||||||
of 'n', 'N':
|
of 'n', 'N':
|
||||||
tok.literal = tok.literal & nl
|
add(tok.literal, nl)
|
||||||
Inc(c.bufpos)
|
Inc(c.bufpos)
|
||||||
of 'r', 'R', 'c', 'C':
|
of 'r', 'R', 'c', 'C':
|
||||||
add(tok.literal, '\c')
|
add(tok.literal, '\c')
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ proc init(cmdline: string = ""): TOptParser =
|
||||||
else:
|
else:
|
||||||
result.cmd = ""
|
result.cmd = ""
|
||||||
for i in countup(1, ParamCount()):
|
for i in countup(1, ParamCount()):
|
||||||
result.cmd = result.cmd & quoteIfSpaceExists(paramStr(i)) & ' '
|
result.cmd = result.cmd & quoteIfContainsWhite(paramStr(i)) & ' '
|
||||||
result.kind = cmdEnd
|
result.kind = cmdEnd
|
||||||
result.key = ""
|
result.key = ""
|
||||||
result.val = ""
|
result.val = ""
|
||||||
|
|
|
||||||
|
|
@ -22,12 +22,12 @@ proc reprPointer(x: pointer): string {.compilerproc.} =
|
||||||
|
|
||||||
proc reprStrAux(result: var string, s: string) =
|
proc reprStrAux(result: var string, s: string) =
|
||||||
if cast[pointer](s) == nil:
|
if cast[pointer](s) == nil:
|
||||||
add result "nil"
|
add result, "nil"
|
||||||
return
|
return
|
||||||
add result, reprPointer(cast[pointer](s)) & "\""
|
add result, reprPointer(cast[pointer](s)) & "\""
|
||||||
for c in items(s):
|
for c in items(s):
|
||||||
case c
|
case c
|
||||||
of '"': add result "\\\""
|
of '"': add result, "\\\""
|
||||||
of '\\': add result, "\\\\" # BUGFIX: forgotten
|
of '\\': add result, "\\\\" # BUGFIX: forgotten
|
||||||
of '\10': add result, "\\10\"\n\"" # " \n " # better readability
|
of '\10': add result, "\\10\"\n\"" # " \n " # better readability
|
||||||
of '\128' .. '\255', '\0'..'\9', '\11'..'\31':
|
of '\128' .. '\255', '\0'..'\9', '\11'..'\31':
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@
|
||||||
## All the routines here are avaiable for the EMCAScript target
|
## All the routines here are avaiable for the EMCAScript target
|
||||||
## too!
|
## too!
|
||||||
|
|
||||||
|
{.deadCodeElim: on.}
|
||||||
|
|
||||||
{.push debugger:off .} # the user does not want to trace a part
|
{.push debugger:off .} # the user does not want to trace a part
|
||||||
# of the standard library!
|
# of the standard library!
|
||||||
|
|
||||||
|
|
@ -41,19 +43,19 @@ proc strip*(s: string): string {.noSideEffect.}
|
||||||
|
|
||||||
proc toLower*(s: string): string {.noSideEffect.}
|
proc toLower*(s: string): string {.noSideEffect.}
|
||||||
## Converts `s` into lower case. This works only for the letters A-Z.
|
## Converts `s` into lower case. This works only for the letters A-Z.
|
||||||
## See `charsets.nativeToLower` for a version that is locale-dependant.
|
## See `unicode.toLower` for a version that works for any Unicode character.
|
||||||
|
|
||||||
proc toLower*(c: Char): Char {.noSideEffect.}
|
proc toLower*(c: Char): Char {.noSideEffect.}
|
||||||
## Converts `c` into lower case. This works only for the letters A-Z.
|
## Converts `c` into lower case. This works only for the letters A-Z.
|
||||||
## See `charsets.nativeToLower()` for a version that is locale-dependant.
|
## See `unicode.toLower` for a version that works for any Unicode character.
|
||||||
|
|
||||||
proc toUpper*(s: string): string {.noSideEffect.}
|
proc toUpper*(s: string): string {.noSideEffect.}
|
||||||
## Converts `s` into upper case. This works only for the letters a-z.
|
## Converts `s` into upper case. This works only for the letters a-z.
|
||||||
## See `charsets.nativeToUpper()` for a version that is locale-dependant.
|
## See `unicode.toUpper` for a version that works for any Unicode character.
|
||||||
|
|
||||||
proc toUpper*(c: Char): Char {.noSideEffect.}
|
proc toUpper*(c: Char): Char {.noSideEffect.}
|
||||||
## Converts `c` into upper case. This works only for the letters a-z.
|
## Converts `c` into upper case. This works only for the letters a-z.
|
||||||
## See `charsets.nativeToUpper()` for a version that is locale-dependant.
|
## See `unicode.toUpper` for a version that works for any Unicode character.
|
||||||
|
|
||||||
proc capitalize*(s: string): string {.noSideEffect.}
|
proc capitalize*(s: string): string {.noSideEffect.}
|
||||||
## Converts the first character of `s` into upper case.
|
## Converts the first character of `s` into upper case.
|
||||||
|
|
@ -71,6 +73,10 @@ proc findSubStr*(sub: char, s: string, start: int = 0): int {.noSideEffect.}
|
||||||
## Searches for `sub` in `s` starting at position `start`. Searching is
|
## Searches for `sub` in `s` starting at position `start`. Searching is
|
||||||
## case-sensitive. If `sub` is not in `s`, -1 is returned.
|
## case-sensitive. If `sub` is not in `s`, -1 is returned.
|
||||||
|
|
||||||
|
proc findChars*(chars: set[char], s: string, start: int = 0): int {.noSideEffect.}
|
||||||
|
## Searches for `chars` in `s` starting at position `start`. If `s` contains
|
||||||
|
## none of the characters in `chars`, -1 is returned.
|
||||||
|
|
||||||
proc replaceStr*(s, sub, by: string): string {.noSideEffect.}
|
proc replaceStr*(s, sub, by: string): string {.noSideEffect.}
|
||||||
## Replaces `sub` in `s` by the string `by`.
|
## Replaces `sub` in `s` by the string `by`.
|
||||||
|
|
||||||
|
|
@ -173,11 +179,14 @@ proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect.}
|
||||||
## | < 0 iff a < b
|
## | < 0 iff a < b
|
||||||
## | > 0 iff a > b
|
## | > 0 iff a > b
|
||||||
|
|
||||||
proc in_Operator*(s: string, c: char): bool {.noSideEffect.}
|
proc contains*(s: string, c: char): bool {.noSideEffect.}
|
||||||
## Same as `findSubStr(c, s) >= 0`.
|
## Same as ``findSubStr(c, s) >= 0``.
|
||||||
|
|
||||||
proc in_Operator*(s, sub: string): bool {.noSideEffect.}
|
proc contains*(s, sub: string): bool {.noSideEffect.}
|
||||||
## Same as `findSubStr(sub, s) >= 0`.
|
## Same as ``findSubStr(sub, s) >= 0``.
|
||||||
|
|
||||||
|
proc contains*(s: string, chars: set[char]): bool {.noSideEffect.}
|
||||||
|
## Same as ``findChars(s, chars) >= 0``.
|
||||||
|
|
||||||
proc toHex*(x: BiggestInt, len: int): string {.noSideEffect.}
|
proc toHex*(x: BiggestInt, len: int): string {.noSideEffect.}
|
||||||
## Converts `x` to its hexadecimal representation. The resulting string
|
## Converts `x` to its hexadecimal representation. The resulting string
|
||||||
|
|
@ -259,10 +268,10 @@ proc allCharsInSet*(s: string, theSet: TCharSet): bool =
|
||||||
if not (c in theSet): return false
|
if not (c in theSet): return false
|
||||||
return true
|
return true
|
||||||
|
|
||||||
proc quoteIfSpaceExists*(s: string): string =
|
proc quoteIfContainsWhite*(s: string): string =
|
||||||
## returns ``'"' & s & '"'`` if `s` contains a space and does not
|
## returns ``'"' & s & '"'`` if `s` contains a space and does not
|
||||||
## start with a quote, else returns `s`
|
## start with a quote, else returns `s`
|
||||||
if findSubStr(' ', s) >= 0 and s[0] != '"':
|
if findChars({' ', '\t'}, s) >= 0 and s[0] != '"':
|
||||||
result = '"' & s & '"'
|
result = '"' & s & '"'
|
||||||
else:
|
else:
|
||||||
result = s
|
result = s
|
||||||
|
|
@ -489,10 +498,18 @@ proc findSubStr(sub: char, s: string, start: int = 0): int =
|
||||||
if sub == s[i]: return i
|
if sub == s[i]: return i
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
proc in_Operator(s: string, c: char): bool =
|
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 contains(s: string, c: char): bool =
|
||||||
return findSubStr(c, s) >= 0
|
return findSubStr(c, s) >= 0
|
||||||
|
|
||||||
proc in_Operator(s, sub: string): bool =
|
proc contains(s, sub: string): bool =
|
||||||
return findSubStr(sub, s) >= 0
|
return findSubStr(sub, s) >= 0
|
||||||
|
|
||||||
proc replaceStr(s, sub, by: string): string =
|
proc replaceStr(s, sub, by: string): string =
|
||||||
|
|
|
||||||
|
|
@ -91,10 +91,13 @@ proc writeln[Ty](f: TFile, x: Ty) =
|
||||||
write(f, "\n")
|
write(f, "\n")
|
||||||
|
|
||||||
proc writeln[Ty](f: TFile, x: openArray[Ty]) =
|
proc writeln[Ty](f: TFile, x: openArray[Ty]) =
|
||||||
write(f, x)
|
for i in items(x): write(f, i)
|
||||||
write(f, "\n")
|
write(f, "\n")
|
||||||
|
|
||||||
proc echo[Ty](x: Ty) = writeln(stdout, x)
|
proc echo[Ty](x: Ty) = writeln(stdout, x)
|
||||||
|
proc echo[Ty](x: openArray[Ty]) =
|
||||||
|
for i in items(x): write(stdout, i)
|
||||||
|
write(stdout, "\n")
|
||||||
|
|
||||||
# interface to the C procs:
|
# interface to the C procs:
|
||||||
proc fopen(filename, mode: CString): pointer {.importc: "fopen", noDecl.}
|
proc fopen(filename, mode: CString): pointer {.importc: "fopen", noDecl.}
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,6 @@
|
||||||
# we don't use refcounts because that's a behaviour
|
# we don't use refcounts because that's a behaviour
|
||||||
# the programmer may not want
|
# the programmer may not want
|
||||||
|
|
||||||
type
|
|
||||||
# len and space without counting the terminating zero:
|
|
||||||
NimStringDesc {.compilerproc, final.} = object of TGenericSeq
|
|
||||||
data: array[0..100_000_000, char] # for the '\0' character
|
|
||||||
|
|
||||||
NimString = ptr NimStringDesc
|
|
||||||
|
|
||||||
# implementation:
|
# implementation:
|
||||||
|
|
||||||
proc resize(old: int): int {.inline.} =
|
proc resize(old: int): int {.inline.} =
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,17 @@ proc defined*[T] (x: T): bool {.magic: "Defined", noSideEffect.}
|
||||||
proc `not` *(x: bool): bool {.magic: "Not", noSideEffect.}
|
proc `not` *(x: bool): bool {.magic: "Not", noSideEffect.}
|
||||||
## Boolean not; returns true iff ``x == false``.
|
## Boolean not; returns true iff ``x == false``.
|
||||||
|
|
||||||
|
proc `and`*(x, y: bool): bool {.magic: "And", noSideEffect.}
|
||||||
|
## Boolean ``and``; returns true iff ``x == y == true``.
|
||||||
|
## Evaluation is short-circuited: This means that if ``x`` is false,
|
||||||
|
## ``y`` will not even be evaluated.
|
||||||
|
proc `or`*(x, y: bool): bool {.magic: "Or", noSideEffect.}
|
||||||
|
## Boolean ``or``; returns true iff ``not (not x and not y)``.
|
||||||
|
## Evaluation is short-circuited: This means that if ``x`` is true,
|
||||||
|
## ``y`` will not even be evaluated.
|
||||||
|
proc `xor`*(x, y: bool): bool {.magic: "Xor", noSideEffect.}
|
||||||
|
## Boolean `exclusive or`; returns true iff ``x != y``.
|
||||||
|
|
||||||
proc new*[T](a: var ref T) {.magic: "New".}
|
proc new*[T](a: var ref T) {.magic: "New".}
|
||||||
## creates a new object of type ``T`` and returns a safe (traced)
|
## creates a new object of type ``T`` and returns a safe (traced)
|
||||||
## reference to it in ``a``.
|
## reference to it in ``a``.
|
||||||
|
|
@ -94,6 +105,19 @@ type
|
||||||
seq*{.magic: "Seq".}[T] ## Generic type to construct sequences.
|
seq*{.magic: "Seq".}[T] ## Generic type to construct sequences.
|
||||||
set*{.magic: "Set".}[T] ## Generic type to construct bit sets.
|
set*{.magic: "Set".}[T] ## Generic type to construct bit sets.
|
||||||
|
|
||||||
|
when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
|
type
|
||||||
|
TGenericSeq {.compilerproc, pure.} = object
|
||||||
|
len, space: int
|
||||||
|
PGenericSeq {.exportc.} = ptr TGenericSeq
|
||||||
|
# len and space without counting the terminating zero:
|
||||||
|
NimStringDesc {.compilerproc, final.} = object of TGenericSeq
|
||||||
|
data: array[0..100_000_000, char]
|
||||||
|
NimString = ptr NimStringDesc
|
||||||
|
|
||||||
|
include hti
|
||||||
|
|
||||||
|
type
|
||||||
Byte* = Int8 ## this is an alias for ``int8``, that is a signed
|
Byte* = Int8 ## this is an alias for ``int8``, that is a signed
|
||||||
## int 8 bits wide.
|
## int 8 bits wide.
|
||||||
|
|
||||||
|
|
@ -403,8 +427,8 @@ proc abs*(x: int8): int8 {.magic: "AbsI", noSideEffect.}
|
||||||
proc abs*(x: int16): int16 {.magic: "AbsI", noSideEffect.}
|
proc abs*(x: int16): int16 {.magic: "AbsI", noSideEffect.}
|
||||||
proc abs*(x: int32): int32 {.magic: "AbsI", noSideEffect.}
|
proc abs*(x: int32): int32 {.magic: "AbsI", noSideEffect.}
|
||||||
proc abs*(x: int64): int64 {.magic: "AbsI64", noSideEffect.}
|
proc abs*(x: int64): int64 {.magic: "AbsI64", noSideEffect.}
|
||||||
## returns the absolute value of `x`. If `x` is ``low(x)`` (that is
|
## returns the absolute value of `x`. If `x` is ``low(x)`` (that
|
||||||
## -MININT for its type), an overflow exception is thrown (if overflow
|
## is -MININT for its type), an overflow exception is thrown (if overflow
|
||||||
## checking is turned on).
|
## checking is turned on).
|
||||||
|
|
||||||
proc min*(x, y: int): int {.magic: "MinI", noSideEffect.}
|
proc min*(x, y: int): int {.magic: "MinI", noSideEffect.}
|
||||||
|
|
@ -500,18 +524,6 @@ proc abs*(x: float): float {.magic: "AbsF64", noSideEffect.}
|
||||||
proc min*(x, y: float): float {.magic: "MinF64", noSideEffect.}
|
proc min*(x, y: float): float {.magic: "MinF64", noSideEffect.}
|
||||||
proc max*(x, y: float): float {.magic: "MaxF64", noSideEffect.}
|
proc max*(x, y: float): float {.magic: "MaxF64", noSideEffect.}
|
||||||
|
|
||||||
# boolean operators:
|
|
||||||
proc `and`*(x, y: bool): bool {.magic: "And", noSideEffect.}
|
|
||||||
## Boolean ``and``; returns true iff ``x == y == true``.
|
|
||||||
## Evaluation is short-circuited: This means that if ``x`` is false,
|
|
||||||
## ``y`` will not even be evaluated.
|
|
||||||
proc `or`*(x, y: bool): bool {.magic: "Or", noSideEffect.}
|
|
||||||
## Boolean ``or``; returns true iff ``not (not x and not y)``.
|
|
||||||
## Evaluation is short-circuited: This means that if ``x`` is true,
|
|
||||||
## ``y`` will not even be evaluated.
|
|
||||||
proc `xor`*(x, y: bool): bool {.magic: "Xor", noSideEffect.}
|
|
||||||
## Boolean `exclusive or`; returns true iff ``x != y``.
|
|
||||||
|
|
||||||
# set operators
|
# set operators
|
||||||
proc `*` *[T](x, y: set[T]): set[T] {.magic: "MulSet", noSideEffect.}
|
proc `*` *[T](x, y: set[T]): set[T] {.magic: "MulSet", noSideEffect.}
|
||||||
## This operator computes the intersection of two sets.
|
## This operator computes the intersection of two sets.
|
||||||
|
|
@ -563,11 +575,12 @@ template `>` * (x, y: expr): expr =
|
||||||
## "is greater" operator. This is the same as ``y < x``.
|
## "is greater" operator. This is the same as ``y < x``.
|
||||||
y < x
|
y < x
|
||||||
|
|
||||||
proc in_Operator*[T](x: set[T], y: T): bool {.magic: "InSet", noSideEffect.}
|
proc contains*[T](x: set[T], y: T): bool {.magic: "InSet", noSideEffect.}
|
||||||
## One should overload this proc if one wants to overload the ``in`` operator.
|
## One should overload this proc if one wants to overload the ``in`` operator.
|
||||||
## The parameters are in reverse order! This is because the unification
|
## The parameters are in reverse order! ``a in b`` is a template for
|
||||||
## algorithm that Nimrod uses for overload resolution works from left to
|
## ``contains(b, a)``.
|
||||||
## right.
|
## This is because the unification algorithm that Nimrod uses for overload
|
||||||
|
## resolution works from left to right.
|
||||||
## But for the ``in`` operator that would be the wrong direction for this
|
## But for the ``in`` operator that would be the wrong direction for this
|
||||||
## piece of code:
|
## piece of code:
|
||||||
##
|
##
|
||||||
|
|
@ -578,11 +591,11 @@ proc in_Operator*[T](x: set[T], y: T): bool {.magic: "InSet", noSideEffect.}
|
||||||
## If ``in`` had been declared as ``[T](elem: T, s: set[T])`` then ``T`` would
|
## If ``in`` had been declared as ``[T](elem: T, s: set[T])`` then ``T`` would
|
||||||
## have been bound to ``char``. But ``s`` is not compatible to type
|
## have been bound to ``char``. But ``s`` is not compatible to type
|
||||||
## ``set[char]``! The solution is to bind ``T`` to ``range['a'..'z']``. This
|
## ``set[char]``! The solution is to bind ``T`` to ``range['a'..'z']``. This
|
||||||
## is achieved by reversing the parameters for ``in_operator``; ``in`` then
|
## is achieved by reversing the parameters for ``contains``; ``in`` then
|
||||||
## passes its arguments in reverse order.
|
## passes its arguments in reverse order.
|
||||||
|
|
||||||
template `in` * (x, y: expr): expr = in_Operator(y, x)
|
template `in` * (x, y: expr): expr = contains(y, x)
|
||||||
template `not_in` * (x, y: expr): expr = not in_Operator(y, x)
|
template `not_in` * (x, y: expr): expr = not contains(y, x)
|
||||||
|
|
||||||
proc `is` *[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.}
|
proc `is` *[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.}
|
||||||
template `is_not` *(x, y: expr): expr = not (x is y)
|
template `is_not` *(x, y: expr): expr = not (x is y)
|
||||||
|
|
@ -616,15 +629,17 @@ proc `&` * (x: char, y: string): string {.
|
||||||
magic: "ConStrStr", noSideEffect, merge.}
|
magic: "ConStrStr", noSideEffect, merge.}
|
||||||
## is the `concatenation operator`. It concatenates `x` and `y`.
|
## is the `concatenation operator`. It concatenates `x` and `y`.
|
||||||
|
|
||||||
proc add * (x: var string, y: char) {.magic: "AppendStrCh".}
|
proc add*(x: var string, y: char) {.magic: "AppendStrCh".}
|
||||||
proc add * (x: var string, y: string) {.magic: "AppendStrStr".}
|
proc add*(x: var string, y: string) {.magic: "AppendStrStr".}
|
||||||
|
|
||||||
when not defined(ECMAScript):
|
when not defined(ECMAScript):
|
||||||
|
{.push overflow_checks:off}
|
||||||
proc add* (x: var string, y: cstring) =
|
proc add* (x: var string, y: cstring) =
|
||||||
var i = 0
|
var i = 0
|
||||||
while y[i] != '\0':
|
while y[i] != '\0':
|
||||||
add(x, y[i])
|
add(x, y[i])
|
||||||
inc(i)
|
inc(i)
|
||||||
|
{.pop.}
|
||||||
else:
|
else:
|
||||||
proc add* (x: var string, y: cstring) {.pure.} =
|
proc add* (x: var string, y: cstring) {.pure.} =
|
||||||
asm """
|
asm """
|
||||||
|
|
@ -646,7 +661,7 @@ proc add *[T](x: var seq[T], y: seq[T]) {.magic: "AppendSeqSeq".}
|
||||||
|
|
||||||
proc repr*[T](x: T): string {.magic: "Repr", noSideEffect.}
|
proc repr*[T](x: T): string {.magic: "Repr", noSideEffect.}
|
||||||
## takes any Nimrod variable and returns its string representation. It
|
## takes any Nimrod variable and returns its string representation. It
|
||||||
## works even for complex data graphs with cycles. This is an invaluable
|
## works even for complex data graphs with cycles. This is a great
|
||||||
## debugging tool.
|
## debugging tool.
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
@ -730,6 +745,15 @@ const
|
||||||
## is the endianness of the target CPU. This is a valuable piece of
|
## is the endianness of the target CPU. This is a valuable piece of
|
||||||
## information for low-level code only. This works thanks to compiler magic.
|
## information for low-level code only. This works thanks to compiler magic.
|
||||||
|
|
||||||
|
hostOS* {.magic: "HostOS"}: string = ""
|
||||||
|
## a string that describes the host operating system. Possible values:
|
||||||
|
## "windows", "macosx", "linux", "netbsd", "freebsd", "openbsd", "solaris",
|
||||||
|
## "aix"
|
||||||
|
|
||||||
|
hostCPU* {.magic: "HostCPU"}: string = ""
|
||||||
|
## a string that describes the host CPU. Possible values:
|
||||||
|
## "i386", "alpha", "powerpc", "sparc", "amd64", "mips", "arm"
|
||||||
|
|
||||||
proc toFloat*(i: int): float {.
|
proc toFloat*(i: int): float {.
|
||||||
magic: "ToFloat", noSideEffect, importc: "toFloat".}
|
magic: "ToFloat", noSideEffect, importc: "toFloat".}
|
||||||
## converts an integer `i` into a ``float``. If the conversion
|
## converts an integer `i` into a ``float``. If the conversion
|
||||||
|
|
@ -896,6 +920,12 @@ proc `$` *(x: string): string {.magic: "StrToStr", noSideEffect.}
|
||||||
## as it is. This operator is useful for generic code, so
|
## as it is. This operator is useful for generic code, so
|
||||||
## that ``$expr`` also works if ``expr`` is already a string.
|
## that ``$expr`` also works if ``expr`` is already a string.
|
||||||
|
|
||||||
|
proc `$` *(x: TAnyEnum): string {.magic: "EnumToStr", noSideEffect.}
|
||||||
|
## The stingify operator for an enumeration argument. This works for
|
||||||
|
## any enumeration type thanks to compiler magic. If a
|
||||||
|
## a ``$`` operator for a concrete enumeration is provided, this is
|
||||||
|
## used instead. (In other words: *Overwriting* is possible.)
|
||||||
|
|
||||||
# undocumented:
|
# undocumented:
|
||||||
proc getRefcount*[T](x: ref T): int {.importc: "getRefcount".}
|
proc getRefcount*[T](x: ref T): int {.importc: "getRefcount".}
|
||||||
## retrieves the reference count of an heap-allocated object. The
|
## retrieves the reference count of an heap-allocated object. The
|
||||||
|
|
@ -1136,6 +1166,10 @@ proc echo*[Ty](x: Ty) {.inline.}
|
||||||
## equivalent to ``writeln(stdout, x); flush(stdout)``. BUT: This is
|
## equivalent to ``writeln(stdout, x); flush(stdout)``. BUT: This is
|
||||||
## available for the ECMAScript target too!
|
## available for the ECMAScript target too!
|
||||||
|
|
||||||
|
proc echo*[Ty](x: openarray[Ty]) {.inline.}
|
||||||
|
## equivalent to ``writeln(stdout, x); flush(stdout)``. BUT: This is
|
||||||
|
## available for the ECMAScript target too!
|
||||||
|
|
||||||
|
|
||||||
template newException(exceptn, message: expr): expr =
|
template newException(exceptn, message: expr): expr =
|
||||||
block: # open a new scope
|
block: # open a new scope
|
||||||
|
|
@ -1169,8 +1203,6 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
|
|
||||||
when not defined(EcmaScript) and not defined(NimrodVM):
|
when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
|
|
||||||
include hti
|
|
||||||
|
|
||||||
proc initGC()
|
proc initGC()
|
||||||
|
|
||||||
var
|
var
|
||||||
|
|
@ -1370,13 +1402,6 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
include arithm
|
include arithm
|
||||||
{.pop.} # stack trace
|
{.pop.} # stack trace
|
||||||
|
|
||||||
# sequence type declarations here because the GC needs them too:
|
|
||||||
type
|
|
||||||
TGenericSeq {.compilerproc, pure.} = object
|
|
||||||
len, space: int
|
|
||||||
|
|
||||||
PGenericSeq {.exportc.} = ptr TGenericSeq
|
|
||||||
|
|
||||||
const
|
const
|
||||||
GenericSeqSize = (2 * sizeof(int))
|
GenericSeqSize = (2 * sizeof(int))
|
||||||
|
|
||||||
|
|
@ -1417,13 +1442,12 @@ elif defined(NimrodVM):
|
||||||
proc getFreeMem(): int = return -1
|
proc getFreeMem(): int = return -1
|
||||||
proc getTotalMem(): int = return -1
|
proc getTotalMem(): int = return -1
|
||||||
proc echo[Ty](x: Ty) = nil
|
proc echo[Ty](x: Ty) = nil
|
||||||
|
proc echo[Ty](x: openarray[Ty]) = nil
|
||||||
|
|
||||||
proc cmp(x, y: string): int =
|
proc cmp(x, y: string): int =
|
||||||
if x == y: return 0
|
if x == y: return 0
|
||||||
if x < y: return -1
|
if x < y: return -1
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
include macros
|
|
||||||
|
|
||||||
{.pop.} # checks
|
{.pop.} # checks
|
||||||
{.pop.} # hints
|
{.pop.} # hints
|
||||||
|
|
|
||||||
|
|
@ -276,8 +276,8 @@ else:
|
||||||
|
|
||||||
proc getDateStr(): string =
|
proc getDateStr(): string =
|
||||||
var ti = getLocalTime(getTime())
|
var ti = getLocalTime(getTime())
|
||||||
result = $ti.year & "-" & intToStr(ord(ti.month)+1, 2) &
|
result = $ti.year & '-' & intToStr(ord(ti.month)+1, 2) &
|
||||||
"-" & intToStr(ti.monthDay, 2)
|
'-' & intToStr(ti.monthDay, 2)
|
||||||
|
|
||||||
proc getClockStr(): string =
|
proc getClockStr(): string =
|
||||||
var ti = getLocalTime(getTime())
|
var ti = getLocalTime(getTime())
|
||||||
|
|
|
||||||
1179
lib/unicode.nim
1179
lib/unicode.nim
File diff suppressed because it is too large
Load diff
|
|
@ -10,6 +10,8 @@
|
||||||
## Define ``winUnicode`` before importing this module for the
|
## Define ``winUnicode`` before importing this module for the
|
||||||
## unicode version.
|
## unicode version.
|
||||||
|
|
||||||
|
{.deadCodeElim: on.}
|
||||||
|
|
||||||
type
|
type
|
||||||
ATOM* = int16
|
ATOM* = int16
|
||||||
TAtom* = ATOM
|
TAtom* = ATOM
|
||||||
|
|
|
||||||
2
makefile
2
makefile
|
|
@ -7,7 +7,7 @@ all:
|
||||||
|
|
||||||
.PHONY : install
|
.PHONY : install
|
||||||
install:
|
install:
|
||||||
sh install.sh /usr/bin
|
sh build.sh
|
||||||
|
|
||||||
.PHONY : clean
|
.PHONY : clean
|
||||||
clean:
|
clean:
|
||||||
|
|
|
||||||
277
nim/ast.pas
277
nim/ast.pas
|
|
@ -66,12 +66,93 @@ for key, val in enums.items():
|
||||||
cog.out(b)
|
cog.out(b)
|
||||||
]]]*)
|
]]]*)
|
||||||
type
|
type
|
||||||
TTypeFlag = (
|
TNodeKind = (
|
||||||
tfVarargs, tfFinal, tfAcyclic, tfEnumHasWholes);
|
nkNone, nkEmpty, nkIdent, nkSym,
|
||||||
TTypeFlags = set of TTypeFlag;
|
nkType, nkCharLit, nkIntLit, nkInt8Lit,
|
||||||
|
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
|
const
|
||||||
TypeFlagToStr: array [TTypeFlag] of string = (
|
NodeKindToStr: array [TNodeKind] of string = (
|
||||||
'tfVarargs', 'tfFinal', 'tfAcyclic', 'tfEnumHasWholes');
|
'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
|
type
|
||||||
TTypeKind = (
|
TTypeKind = (
|
||||||
tyNone, tyBool, tyChar, tyEmpty,
|
tyNone, tyBool, tyChar, tyEmpty,
|
||||||
|
|
@ -95,25 +176,6 @@ const
|
||||||
'tyCString', 'tyForward', 'tyInt', 'tyInt8',
|
'tyCString', 'tyForward', 'tyInt', 'tyInt8',
|
||||||
'tyInt16', 'tyInt32', 'tyInt64', 'tyFloat',
|
'tyInt16', 'tyInt32', 'tyInt64', 'tyFloat',
|
||||||
'tyFloat32', 'tyFloat64', 'tyFloat128');
|
'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
|
type
|
||||||
TNodeFlag = (
|
TNodeFlag = (
|
||||||
nfNone, nfBase2, nfBase8, nfBase16,
|
nfNone, nfBase2, nfBase8, nfBase16,
|
||||||
|
|
@ -123,6 +185,13 @@ const
|
||||||
NodeFlagToStr: array [TNodeFlag] of string = (
|
NodeFlagToStr: array [TNodeFlag] of string = (
|
||||||
'nfNone', 'nfBase2', 'nfBase8', 'nfBase16',
|
'nfNone', 'nfBase2', 'nfBase8', 'nfBase16',
|
||||||
'nfAllConst', 'nfTransf', 'nfSem');
|
'nfAllConst', 'nfTransf', 'nfSem');
|
||||||
|
type
|
||||||
|
TTypeFlag = (
|
||||||
|
tfVarargs, tfFinal, tfAcyclic, tfEnumHasWholes);
|
||||||
|
TTypeFlags = set of TTypeFlag;
|
||||||
|
const
|
||||||
|
TypeFlagToStr: array [TTypeFlag] of string = (
|
||||||
|
'tfVarargs', 'tfFinal', 'tfAcyclic', 'tfEnumHasWholes');
|
||||||
type
|
type
|
||||||
TSymKind = (
|
TSymKind = (
|
||||||
skUnknownSym, skConditional, skDynLib, skParam,
|
skUnknownSym, skConditional, skDynLib, skParam,
|
||||||
|
|
@ -138,75 +207,6 @@ const
|
||||||
'skVar', 'skProc', 'skIterator', 'skConverter',
|
'skVar', 'skProc', 'skIterator', 'skConverter',
|
||||||
'skMacro', 'skTemplate', 'skField', 'skEnumField',
|
'skMacro', 'skTemplate', 'skField', 'skEnumField',
|
||||||
'skForVar', 'skModule', 'skLabel', 'skStub');
|
'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');
|
|
||||||
{[[[end]]]}
|
{[[[end]]]}
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
@ -240,22 +240,23 @@ type
|
||||||
mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16,
|
mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16,
|
||||||
mToU32, mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr,
|
mToU32, mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr,
|
||||||
mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr,
|
mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr,
|
||||||
mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet,
|
mEnumToStr, mAnd, mOr, mEqStr, mLeStr, mLtStr,
|
||||||
mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, mSymDiffSet,
|
mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet,
|
||||||
mConStrStr, mConArrArr, mConArrT, mConTArr, mConTT, mSlice,
|
mSymDiffSet, mConStrStr, mConArrArr, mConArrT, mConTArr, mConTT,
|
||||||
mAppendStrCh, mAppendStrStr, mAppendSeqElem, mAppendSeqSeq, mInRange, mInSet,
|
mSlice, mAppendStrCh, mAppendStrStr, mAppendSeqElem, mAppendSeqSeq, mInRange,
|
||||||
mAsgn, mRepr, mExit, mSetLengthStr, mSetLengthSeq, mAssert,
|
mInSet, mAsgn, mRepr, mExit, mSetLengthStr, mSetLengthSeq,
|
||||||
mSwap, mIsNil, mArrToSeq, mArray, mOpenArray, mRange,
|
mAssert, mSwap, mIsNil, mArrToSeq, mArray, mOpenArray,
|
||||||
mSet, mSeq, mInt, mInt8, mInt16, mInt32,
|
mRange, mSet, mSeq, mInt, mInt8, mInt16,
|
||||||
mInt64, mFloat, mFloat32, mFloat64, mBool, mChar,
|
mInt32, mInt64, mFloat, mFloat32, mFloat64, mBool,
|
||||||
mString, mCstring, mPointer, mAnyEnum, mEmptySet, mIntSetBaseType,
|
mChar, mString, mCstring, mPointer, mAnyEnum, mEmptySet,
|
||||||
mNil, mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor,
|
mIntSetBaseType, mNil, mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion,
|
||||||
mNimrodMinor, mNimrodPatch, mCpuEndian, mNaN, mInf, mNegInf,
|
mNimrodMajor, mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU,
|
||||||
mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel,
|
mNaN, mInf, mNegInf, mNLen, mNChild, mNSetChild,
|
||||||
mNKind, mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType,
|
mNAdd, mNAddMultiple, mNDel, mNKind, mNIntVal, mNFloatVal,
|
||||||
mNStrVal, mNSetIntVal, mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType,
|
mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal, mNSetFloatVal,
|
||||||
mNSetStrVal, mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr,
|
mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNNewNimNode, mNCopyNimNode,
|
||||||
mEqIdent, mNHint, mNWarning, mNError
|
mNCopyNimTree, mStrToIdent, mIdentToStr, mEqIdent, mNHint, mNWarning,
|
||||||
|
mNError
|
||||||
//[[[end]]]
|
//[[[end]]]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -322,7 +323,6 @@ type
|
||||||
locProc, // location is a proc (an address of a procedure)
|
locProc, // location is a proc (an address of a procedure)
|
||||||
locData, // location is a constant
|
locData, // location is a constant
|
||||||
locCall, // location is a call expression
|
locCall, // location is a call expression
|
||||||
locImmediate, // location is an immediate value
|
|
||||||
locOther // location is something other
|
locOther // location is something other
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -498,22 +498,23 @@ const // "MagicToStr" array:
|
||||||
'Ze16ToI', 'Ze16ToI64', 'Ze32ToI64', 'ZeIToI64', 'ToU8', 'ToU16',
|
'Ze16ToI', 'Ze16ToI64', 'Ze32ToI64', 'ZeIToI64', 'ToU8', 'ToU16',
|
||||||
'ToU32', 'ToFloat', 'ToBiggestFloat', 'ToInt', 'ToBiggestInt', 'CharToStr',
|
'ToU32', 'ToFloat', 'ToBiggestFloat', 'ToInt', 'ToBiggestInt', 'CharToStr',
|
||||||
'BoolToStr', 'IntToStr', 'Int64ToStr', 'FloatToStr', 'CStrToStr', 'StrToStr',
|
'BoolToStr', 'IntToStr', 'Int64ToStr', 'FloatToStr', 'CStrToStr', 'StrToStr',
|
||||||
'And', 'Or', 'EqStr', 'LeStr', 'LtStr', 'EqSet',
|
'EnumToStr', 'And', 'Or', 'EqStr', 'LeStr', 'LtStr',
|
||||||
'LeSet', 'LtSet', 'MulSet', 'PlusSet', 'MinusSet', 'SymDiffSet',
|
'EqSet', 'LeSet', 'LtSet', 'MulSet', 'PlusSet', 'MinusSet',
|
||||||
'ConStrStr', 'ConArrArr', 'ConArrT', 'ConTArr', 'ConTT', 'Slice',
|
'SymDiffSet', 'ConStrStr', 'ConArrArr', 'ConArrT', 'ConTArr', 'ConTT',
|
||||||
'AppendStrCh', 'AppendStrStr', 'AppendSeqElem', 'AppendSeqSeq', 'InRange', 'InSet',
|
'Slice', 'AppendStrCh', 'AppendStrStr', 'AppendSeqElem', 'AppendSeqSeq', 'InRange',
|
||||||
'Asgn', 'Repr', 'Exit', 'SetLengthStr', 'SetLengthSeq', 'Assert',
|
'InSet', 'Asgn', 'Repr', 'Exit', 'SetLengthStr', 'SetLengthSeq',
|
||||||
'Swap', 'IsNil', 'ArrToSeq', 'Array', 'OpenArray', 'Range',
|
'Assert', 'Swap', 'IsNil', 'ArrToSeq', 'Array', 'OpenArray',
|
||||||
'Set', 'Seq', 'Int', 'Int8', 'Int16', 'Int32',
|
'Range', 'Set', 'Seq', 'Int', 'Int8', 'Int16',
|
||||||
'Int64', 'Float', 'Float32', 'Float64', 'Bool', 'Char',
|
'Int32', 'Int64', 'Float', 'Float32', 'Float64', 'Bool',
|
||||||
'String', 'Cstring', 'Pointer', 'AnyEnum', 'EmptySet', 'IntSetBaseType',
|
'Char', 'String', 'Cstring', 'Pointer', 'AnyEnum', 'EmptySet',
|
||||||
'Nil', 'IsMainModule', 'CompileDate', 'CompileTime', 'NimrodVersion', 'NimrodMajor',
|
'IntSetBaseType', 'Nil', 'IsMainModule', 'CompileDate', 'CompileTime', 'NimrodVersion',
|
||||||
'NimrodMinor', 'NimrodPatch', 'CpuEndian', 'NaN', 'Inf', 'NegInf',
|
'NimrodMajor', 'NimrodMinor', 'NimrodPatch', 'CpuEndian', 'HostOS', 'HostCPU',
|
||||||
'NLen', 'NChild', 'NSetChild', 'NAdd', 'NAddMultiple', 'NDel',
|
'NaN', 'Inf', 'NegInf', 'NLen', 'NChild', 'NSetChild',
|
||||||
'NKind', 'NIntVal', 'NFloatVal', 'NSymbol', 'NIdent', 'NGetType',
|
'NAdd', 'NAddMultiple', 'NDel', 'NKind', 'NIntVal', 'NFloatVal',
|
||||||
'NStrVal', 'NSetIntVal', 'NSetFloatVal', 'NSetSymbol', 'NSetIdent', 'NSetType',
|
'NSymbol', 'NIdent', 'NGetType', 'NStrVal', 'NSetIntVal', 'NSetFloatVal',
|
||||||
'NSetStrVal', 'NNewNimNode', 'NCopyNimNode', 'NCopyNimTree', 'StrToIdent', 'IdentToStr',
|
'NSetSymbol', 'NSetIdent', 'NSetType', 'NSetStrVal', 'NNewNimNode', 'NCopyNimNode',
|
||||||
'EqIdent', 'NHint', 'NWarning', 'NError'
|
'NCopyNimTree', 'StrToIdent', 'IdentToStr', 'EqIdent', 'NHint', 'NWarning',
|
||||||
|
'NError'
|
||||||
//[[[end]]]
|
//[[[end]]]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -1342,13 +1343,13 @@ end;
|
||||||
|
|
||||||
function IntSetContains(const s: TIntSet; key: int): bool;
|
function IntSetContains(const s: TIntSet; key: int): bool;
|
||||||
var
|
var
|
||||||
u: int;
|
u: TBitScalar;
|
||||||
t: PTrunk;
|
t: PTrunk;
|
||||||
begin
|
begin
|
||||||
t := IntSetGet(s, key shr TrunkShift);
|
t := IntSetGet(s, shru(key, TrunkShift));
|
||||||
if t <> nil then begin
|
if t <> nil then begin
|
||||||
u := key and TrunkMask;
|
u := key and TrunkMask;
|
||||||
result := (t.bits[u shr IntShift] and (1 shl (u and IntMask))) <> 0
|
result := (t.bits[shru(u, IntShift)] and shlu(1, u and IntMask)) <> 0
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
result := false
|
result := false
|
||||||
|
|
@ -1356,27 +1357,27 @@ end;
|
||||||
|
|
||||||
procedure IntSetIncl(var s: TIntSet; key: int);
|
procedure IntSetIncl(var s: TIntSet; key: int);
|
||||||
var
|
var
|
||||||
u: int;
|
u: TBitScalar;
|
||||||
t: PTrunk;
|
t: PTrunk;
|
||||||
begin
|
begin
|
||||||
t := IntSetPut(s, key shr TrunkShift);
|
t := IntSetPut(s, shru(key, TrunkShift));
|
||||||
u := key and TrunkMask;
|
u := key and TrunkMask;
|
||||||
t.bits[u shr IntShift] := t.bits[u shr IntShift]
|
t.bits[shru(u, IntShift)] := t.bits[shru(u, IntShift)]
|
||||||
or (1 shl (u and IntMask));
|
or shlu(1, u and IntMask);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function IntSetContainsOrIncl(var s: TIntSet; key: int): bool;
|
function IntSetContainsOrIncl(var s: TIntSet; key: int): bool;
|
||||||
var
|
var
|
||||||
u: int;
|
u: TBitScalar;
|
||||||
t: PTrunk;
|
t: PTrunk;
|
||||||
begin
|
begin
|
||||||
t := IntSetGet(s, key shr TrunkShift);
|
t := IntSetGet(s, shru(key, TrunkShift));
|
||||||
if t <> nil then begin
|
if t <> nil then begin
|
||||||
u := key and TrunkMask;
|
u := key and TrunkMask;
|
||||||
result := (t.bits[u shr IntShift] and (1 shl (u and IntMask))) <> 0;
|
result := (t.bits[shru(u, IntShift)] and shlu(1, u and IntMask)) <> 0;
|
||||||
if not result then
|
if not result then
|
||||||
t.bits[u shr IntShift] := t.bits[u shr IntShift]
|
t.bits[shru(u, IntShift)] := t.bits[shru(u, IntShift)]
|
||||||
or (1 shl (u and IntMask));
|
or shlu(1, u and IntMask);
|
||||||
end
|
end
|
||||||
else begin
|
else begin
|
||||||
IntSetIncl(s, key);
|
IntSetIncl(s, key);
|
||||||
|
|
|
||||||
|
|
@ -456,23 +456,21 @@ begin
|
||||||
[istr, lineInfoToStr(n.info)]);
|
[istr, lineInfoToStr(n.info)]);
|
||||||
case n.kind of
|
case n.kind of
|
||||||
nkCharLit..nkInt64Lit:
|
nkCharLit..nkInt64Lit:
|
||||||
appf(result, '$n$1"intVal": $2', [istr, toRope(n.intVal)]);
|
appf(result, ',$n$1"intVal": $2', [istr, toRope(n.intVal)]);
|
||||||
nkFloatLit, nkFloat32Lit, nkFloat64Lit:
|
nkFloatLit, nkFloat32Lit, nkFloat64Lit:
|
||||||
appf(result, '$n$1"floatVal": $2',
|
appf(result, ',$n$1"floatVal": $2', [istr, toRopeF(n.floatVal)]);
|
||||||
[istr, toRopeF(n.floatVal)]);
|
|
||||||
nkStrLit..nkTripleStrLit:
|
nkStrLit..nkTripleStrLit:
|
||||||
appf(result, '$n$1"strVal": $2',
|
appf(result, ',$n$1"strVal": $2', [istr, makeYamlString(n.strVal)]);
|
||||||
[istr, makeYamlString(n.strVal)]);
|
|
||||||
nkSym:
|
nkSym:
|
||||||
appf(result, ',$n$1"sym": $2',
|
appf(result, ',$n$1"sym": $2',
|
||||||
[istr, symToYamlAux(n.sym, marker, indent+2, maxRecDepth)]);
|
[istr, symToYamlAux(n.sym, marker, indent+2, maxRecDepth)]);
|
||||||
|
|
||||||
nkIdent: begin
|
nkIdent: begin
|
||||||
if n.ident <> nil then
|
if n.ident <> nil then
|
||||||
appf(result, '$n$1"ident": $2',
|
appf(result, ',$n$1"ident": $2',
|
||||||
[istr, makeYamlString(n.ident.s)])
|
[istr, makeYamlString(n.ident.s)])
|
||||||
else
|
else
|
||||||
appf(result, '$n$1"ident": null', [istr])
|
appf(result, ',$n$1"ident": null', [istr])
|
||||||
end
|
end
|
||||||
else begin
|
else begin
|
||||||
if sonsLen(n) > 0 then begin
|
if sonsLen(n) > 0 then begin
|
||||||
|
|
@ -552,12 +550,12 @@ begin
|
||||||
if maxRecDepth <> 0 then begin
|
if maxRecDepth <> 0 then begin
|
||||||
case n.kind of
|
case n.kind of
|
||||||
nkCharLit..nkInt64Lit:
|
nkCharLit..nkInt64Lit:
|
||||||
appf(result, '$n$1"intVal": $2', [istr, toRope(n.intVal)]);
|
appf(result, ',$n$1"intVal": $2', [istr, toRope(n.intVal)]);
|
||||||
nkFloatLit, nkFloat32Lit, nkFloat64Lit:
|
nkFloatLit, nkFloat32Lit, nkFloat64Lit:
|
||||||
appf(result, '$n$1"floatVal": $2',
|
appf(result, ',$n$1"floatVal": $2',
|
||||||
[istr, toRopeF(n.floatVal)]);
|
[istr, toRopeF(n.floatVal)]);
|
||||||
nkStrLit..nkTripleStrLit:
|
nkStrLit..nkTripleStrLit:
|
||||||
appf(result, '$n$1"strVal": $2',
|
appf(result, ',$n$1"strVal": $2',
|
||||||
[istr, makeYamlString(n.strVal)]);
|
[istr, makeYamlString(n.strVal)]);
|
||||||
nkSym:
|
nkSym:
|
||||||
appf(result, ',$n$1"sym": $2_$3',
|
appf(result, ',$n$1"sym": $2_$3',
|
||||||
|
|
@ -565,10 +563,10 @@ begin
|
||||||
|
|
||||||
nkIdent: begin
|
nkIdent: begin
|
||||||
if n.ident <> nil then
|
if n.ident <> nil then
|
||||||
appf(result, '$n$1"ident": $2',
|
appf(result, ',$n$1"ident": $2',
|
||||||
[istr, makeYamlString(n.ident.s)])
|
[istr, makeYamlString(n.ident.s)])
|
||||||
else
|
else
|
||||||
appf(result, '$n$1"ident": null', [istr])
|
appf(result, ',$n$1"ident": null', [istr])
|
||||||
end
|
end
|
||||||
else begin
|
else begin
|
||||||
if sonsLen(n) > 0 then begin
|
if sonsLen(n) > 0 then begin
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ var
|
||||||
j: int;
|
j: int;
|
||||||
begin
|
begin
|
||||||
result := 0;
|
result := 0;
|
||||||
if CPU[hostCPU].endian = CPU[targetCPU].endian then begin
|
if CPU[platform.hostCPU].endian = CPU[targetCPU].endian then begin
|
||||||
for j := 0 to size-1 do
|
for j := 0 to size-1 do
|
||||||
if j < length(s) then
|
if j < length(s) then
|
||||||
result := result or shlu(Ze64(s[j]), j * 8)
|
result := result or shlu(Ze64(s[j]), j * 8)
|
||||||
|
|
@ -773,6 +773,34 @@ begin
|
||||||
putIntoDest(p, d, field.typ, r);
|
putIntoDest(p, d, field.typ, r);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure genTupleElem(p: BProc; e: PNode; var d: TLoc);
|
||||||
|
var
|
||||||
|
a: TLoc;
|
||||||
|
field: PSym;
|
||||||
|
ty: PType;
|
||||||
|
r: PRope;
|
||||||
|
i: int;
|
||||||
|
begin
|
||||||
|
initLocExpr(p, e.sons[0], a);
|
||||||
|
if d.k = locNone then d.s := a.s;
|
||||||
|
{@discard} getTypeDesc(p.module, a.t); // fill the record's fields.loc
|
||||||
|
ty := getUniqueType(a.t);
|
||||||
|
r := rdLoc(a);
|
||||||
|
case e.sons[1].kind of
|
||||||
|
nkIntLit..nkInt64Lit: i := int(e.sons[1].intVal);
|
||||||
|
else internalError(e.info, 'genTupleElem');
|
||||||
|
end;
|
||||||
|
if ty.n <> nil then begin
|
||||||
|
field := ty.n.sons[i].sym;
|
||||||
|
if field = nil then InternalError(e.info, 'genTupleElem');
|
||||||
|
if field.loc.r = nil then InternalError(e.info, 'genTupleElem');
|
||||||
|
appf(r, '.$1', [field.loc.r]);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
appf(r, '.Field$1', [toRope(i)]);
|
||||||
|
putIntoDest(p, d, ty.sons[i], r);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure genInExprAux(p: BProc; e: PNode; var a, b, d: TLoc); forward;
|
procedure genInExprAux(p: BProc; e: PNode; var a, b, d: TLoc); forward;
|
||||||
|
|
||||||
procedure genCheckedRecordField(p: BProc; e: PNode; var d: TLoc);
|
procedure genCheckedRecordField(p: BProc; e: PNode; var d: TLoc);
|
||||||
|
|
@ -848,10 +876,11 @@ begin
|
||||||
first := intLiteral(firstOrd(ty));
|
first := intLiteral(firstOrd(ty));
|
||||||
// emit range check:
|
// emit range check:
|
||||||
if (optBoundsCheck in p.options) then begin
|
if (optBoundsCheck in p.options) then begin
|
||||||
if b.k <> locImmediate then begin // semantic pass has already checked:
|
if not isConstExpr(e.sons[1]) then begin
|
||||||
|
// semantic pass has already checked for const index expressions
|
||||||
useMagic(p.module, 'raiseIndexError');
|
useMagic(p.module, 'raiseIndexError');
|
||||||
if firstOrd(ty) = 0 then begin
|
if firstOrd(ty) = 0 then begin
|
||||||
if lastOrd(b.t) > lastOrd(ty) then
|
if (firstOrd(b.t) < firstOrd(ty)) or (lastOrd(b.t) > lastOrd(ty)) then
|
||||||
appf(p.s[cpsStmts],
|
appf(p.s[cpsStmts],
|
||||||
'if ((NU)($1) > (NU)($2)) raiseIndexError();$n',
|
'if ((NU)($1) > (NU)($2)) raiseIndexError();$n',
|
||||||
[rdCharLoc(b), intLiteral(lastOrd(ty))])
|
[rdCharLoc(b), intLiteral(lastOrd(ty))])
|
||||||
|
|
@ -1289,14 +1318,22 @@ var
|
||||||
a, b, f: TLoc;
|
a, b, f: TLoc;
|
||||||
refType, bt: PType;
|
refType, bt: PType;
|
||||||
ti: PRope;
|
ti: PRope;
|
||||||
|
oldModule: BModule;
|
||||||
begin
|
begin
|
||||||
useMagic(p.module, 'newObj');
|
useMagic(p.module, 'newObj');
|
||||||
refType := skipVarGenericRange(e.sons[1].typ);
|
refType := skipVarGenericRange(e.sons[1].typ);
|
||||||
InitLocExpr(p, e.sons[1], a);
|
InitLocExpr(p, e.sons[1], a);
|
||||||
|
|
||||||
|
// This is a little hack:
|
||||||
|
oldModule := p.module;
|
||||||
|
p.module := gmti;
|
||||||
InitLocExpr(p, e.sons[2], f);
|
InitLocExpr(p, e.sons[2], f);
|
||||||
|
p.module := oldModule;
|
||||||
|
|
||||||
initLoc(b, locExpr, a.t, OnHeap);
|
initLoc(b, locExpr, a.t, OnHeap);
|
||||||
ti := genTypeInfo(p.module, refType);
|
ti := genTypeInfo(p.module, refType);
|
||||||
appf(p.module.s[cfsTypeInit3], '$1->finalizer = (void*)$2;$n', [
|
|
||||||
|
appf(gmti.s[cfsTypeInit3], '$1->finalizer = (void*)$2;$n', [
|
||||||
ti, rdLoc(f)]);
|
ti, rdLoc(f)]);
|
||||||
b.r := ropef('($1) newObj($2, sizeof($3))',
|
b.r := ropef('($1) newObj($2, sizeof($3))',
|
||||||
[getTypeDesc(p.module, refType), ti,
|
[getTypeDesc(p.module, refType), ti,
|
||||||
|
|
@ -1331,7 +1368,7 @@ begin
|
||||||
UseMagic(p.module, 'reprChar');
|
UseMagic(p.module, 'reprChar');
|
||||||
putIntoDest(p, d, e.typ, ropef('reprChar($1)', [rdLoc(a)]))
|
putIntoDest(p, d, e.typ, ropef('reprChar($1)', [rdLoc(a)]))
|
||||||
end;
|
end;
|
||||||
tyEnum: begin
|
tyEnum, tyAnyEnum: begin
|
||||||
UseMagic(p.module, 'reprEnum');
|
UseMagic(p.module, 'reprEnum');
|
||||||
putIntoDest(p, d, e.typ,
|
putIntoDest(p, d, e.typ,
|
||||||
ropef('reprEnum($1, $2)', [rdLoc(a), genTypeInfo(p.module, t)]))
|
ropef('reprEnum($1, $2)', [rdLoc(a), genTypeInfo(p.module, t)]))
|
||||||
|
|
@ -1853,6 +1890,7 @@ begin
|
||||||
mFloatToStr: genDollar(p, e, d, 'nimFloatToStr', 'nimFloatToStr($1)');
|
mFloatToStr: genDollar(p, e, d, 'nimFloatToStr', 'nimFloatToStr($1)');
|
||||||
mCStrToStr: genDollar(p, e, d, 'cstrToNimstr', 'cstrToNimstr($1)');
|
mCStrToStr: genDollar(p, e, d, 'cstrToNimstr', 'cstrToNimstr($1)');
|
||||||
mStrToStr: expr(p, e.sons[1], d);
|
mStrToStr: expr(p, e.sons[1], d);
|
||||||
|
mEnumToStr: genRepr(p, e, d);
|
||||||
mAssert: begin
|
mAssert: begin
|
||||||
if (optAssert in p.Options) then begin
|
if (optAssert in p.Options) then begin
|
||||||
useMagic(p.module, 'internalAssert');
|
useMagic(p.module, 'internalAssert');
|
||||||
|
|
@ -1996,24 +2034,32 @@ var
|
||||||
it: PNode;
|
it: PNode;
|
||||||
t: PType;
|
t: PType;
|
||||||
begin
|
begin
|
||||||
// the code generator assumes that there are only tuple constructors with
|
|
||||||
// field names!
|
|
||||||
if not handleConstExpr(p, n, d) then begin
|
if not handleConstExpr(p, n, d) then begin
|
||||||
t := getUniqueType(n.typ);
|
t := getUniqueType(n.typ);
|
||||||
{@discard} getTypeDesc(p.module, t); // so that any fields are initialized
|
{@discard} getTypeDesc(p.module, t); // so that any fields are initialized
|
||||||
if d.k = locNone then getTemp(p, t, d);
|
if d.k = locNone then getTemp(p, t, d);
|
||||||
if t.n = nil then InternalError(n.info, 'genTupleConstr');
|
|
||||||
if sonsLen(t.n) <> sonsLen(n) then
|
|
||||||
InternalError(n.info, 'genTupleConstr');
|
|
||||||
for i := 0 to sonsLen(n)-1 do begin
|
for i := 0 to sonsLen(n)-1 do begin
|
||||||
it := n.sons[i];
|
it := n.sons[i];
|
||||||
if it.kind <> nkExprColonExpr then InternalError(n.info, 'genTupleConstr');
|
if it.kind = nkExprColonExpr then begin
|
||||||
initLoc(rec, locExpr, it.sons[1].typ, d.s);
|
initLoc(rec, locExpr, it.sons[1].typ, d.s);
|
||||||
if (t.n.sons[i].kind <> nkSym) then
|
if (t.n.sons[i].kind <> nkSym) then
|
||||||
InternalError(n.info, 'genTupleConstr');
|
InternalError(n.info, 'genTupleConstr');
|
||||||
rec.r := ropef('$1.$2', [rdLoc(d), mangleRecFieldName(t.n.sons[i].sym, t)]);
|
rec.r := ropef('$1.$2', [rdLoc(d), mangleRecFieldName(t.n.sons[i].sym, t)]);
|
||||||
expr(p, it.sons[1], rec);
|
expr(p, it.sons[1], rec);
|
||||||
end
|
end
|
||||||
|
else if t.n = nil then begin
|
||||||
|
initLoc(rec, locExpr, it.typ, d.s);
|
||||||
|
rec.r := ropef('$1.Field$2', [rdLoc(d), toRope(i)]);
|
||||||
|
expr(p, it, rec);
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
initLoc(rec, locExpr, it.typ, d.s);
|
||||||
|
if (t.n.sons[i].kind <> nkSym) then
|
||||||
|
InternalError(n.info, 'genTupleConstr: 2');
|
||||||
|
rec.r := ropef('$1.$2', [rdLoc(d), mangleRecFieldName(t.n.sons[i].sym, t)]);
|
||||||
|
expr(p, it, rec);
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
@ -2123,11 +2169,10 @@ begin
|
||||||
sym := e.sym;
|
sym := e.sym;
|
||||||
case sym.Kind of
|
case sym.Kind of
|
||||||
skProc, skConverter: begin
|
skProc, skConverter: begin
|
||||||
// generate prototype if not already declared in this translation unit
|
genProc(p.module, sym);
|
||||||
genProcPrototype(p.module, sym);
|
|
||||||
if ((sym.loc.r = nil) or (sym.loc.t = nil)) then
|
if ((sym.loc.r = nil) or (sym.loc.t = nil)) then
|
||||||
InternalError(e.info, 'expr: proc not init ' + sym.name.s);
|
InternalError(e.info, 'expr: proc not init ' + sym.name.s);
|
||||||
putLocIntoDest(p, d, sym.loc)
|
putLocIntoDest(p, d, sym.loc);
|
||||||
end;
|
end;
|
||||||
skConst:
|
skConst:
|
||||||
if isSimpleConst(sym.typ) then
|
if isSimpleConst(sym.typ) then
|
||||||
|
|
@ -2160,8 +2205,6 @@ begin
|
||||||
nkStrLit..nkTripleStrLit, nkIntLit..nkInt64Lit,
|
nkStrLit..nkTripleStrLit, nkIntLit..nkInt64Lit,
|
||||||
nkFloatLit..nkFloat64Lit, nkNilLit, nkCharLit: begin
|
nkFloatLit..nkFloat64Lit, nkNilLit, nkCharLit: begin
|
||||||
putIntoDest(p, d, e.typ, genLiteral(p, e));
|
putIntoDest(p, d, e.typ, genLiteral(p, e));
|
||||||
if d.k in [locNone, locExpr] then
|
|
||||||
d.k := locImmediate // for removal of index checks
|
|
||||||
end;
|
end;
|
||||||
nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkPostfix, nkCommand: begin
|
nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkPostfix, nkCommand: begin
|
||||||
if (e.sons[0].kind = nkSym) and
|
if (e.sons[0].kind = nkSym) and
|
||||||
|
|
@ -2189,6 +2232,7 @@ begin
|
||||||
tyOpenArray: genOpenArrayElem(p, e, d);
|
tyOpenArray: genOpenArrayElem(p, e, d);
|
||||||
tySequence, tyString: genSeqElem(p, e, d);
|
tySequence, tyString: genSeqElem(p, e, d);
|
||||||
tyCString: genCStringElem(p, e, d);
|
tyCString: genCStringElem(p, e, d);
|
||||||
|
tyTuple: genTupleElem(p, e, d);
|
||||||
else InternalError(e.info,
|
else InternalError(e.info,
|
||||||
'expr(nkBracketExpr, ' + typeKindToStr[ty.kind] + ')');
|
'expr(nkBracketExpr, ' + typeKindToStr[ty.kind] + ')');
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -801,9 +801,16 @@ begin
|
||||||
assert(key.kind = nkIdent);
|
assert(key.kind = nkIdent);
|
||||||
case whichKeyword(key.ident) of
|
case whichKeyword(key.ident) of
|
||||||
wBreakpoint: genBreakPoint(p, it);
|
wBreakpoint: genBreakPoint(p, it);
|
||||||
|
wDeadCodeElim: begin
|
||||||
|
if not (optDeadCodeElim in gGlobalOptions) then begin
|
||||||
|
// we need to keep track of ``deadCodeElim`` pragma
|
||||||
|
if (sfDeadCodeElim in p.module.module.flags) then
|
||||||
|
addPendingModule(p.module)
|
||||||
|
end
|
||||||
|
end
|
||||||
else begin end
|
else begin end
|
||||||
end
|
end
|
||||||
end
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure genAsgn(p: BProc; e: PNode);
|
procedure genAsgn(p: BProc; e: PNode);
|
||||||
|
|
@ -816,6 +823,17 @@ begin
|
||||||
expr(p, e.sons[1], a);
|
expr(p, e.sons[1], a);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure genFastAsgn(p: BProc; e: PNode);
|
||||||
|
var
|
||||||
|
a: TLoc;
|
||||||
|
begin
|
||||||
|
genLineDir(p, e); // BUGFIX
|
||||||
|
InitLocExpr(p, e.sons[0], a);
|
||||||
|
include(a.flags, lfNoDeepCopy);
|
||||||
|
assert(a.t <> nil);
|
||||||
|
expr(p, e.sons[1], a);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure genStmts(p: BProc; t: PNode);
|
procedure genStmts(p: BProc; t: PNode);
|
||||||
var
|
var
|
||||||
a: TLoc;
|
a: TLoc;
|
||||||
|
|
@ -844,6 +862,7 @@ begin
|
||||||
initLocExpr(p, t, a);
|
initLocExpr(p, t, a);
|
||||||
end;
|
end;
|
||||||
nkAsgn: genAsgn(p, t);
|
nkAsgn: genAsgn(p, t);
|
||||||
|
nkFastAsgn: genFastAsgn(p, t);
|
||||||
nkDiscardStmt: begin
|
nkDiscardStmt: begin
|
||||||
genLineDir(p, t);
|
genLineDir(p, t);
|
||||||
initLocExpr(p, t.sons[0], a);
|
initLocExpr(p, t.sons[0], a);
|
||||||
|
|
@ -865,17 +884,13 @@ begin
|
||||||
nkProcDef, nkConverterDef: begin
|
nkProcDef, nkConverterDef: begin
|
||||||
if (t.sons[genericParamsPos] = nil) then begin
|
if (t.sons[genericParamsPos] = nil) then begin
|
||||||
prc := t.sons[namePos].sym;
|
prc := t.sons[namePos].sym;
|
||||||
if (t.sons[codePos] <> nil)
|
if not (optDeadCodeElim in gGlobalOptions) and
|
||||||
or (lfDynamicLib in prc.loc.flags) then begin // BUGFIX
|
not (sfDeadCodeElim in getModule(prc).flags)
|
||||||
if IntSetContainsOrIncl(p.module.debugDeclared, prc.id) then begin
|
or ([sfExportc, sfCompilerProc] * prc.flags = [sfExportc]) then begin
|
||||||
internalError(t.info, 'genStmts(): ' + toString(prc.id));
|
if (t.sons[codePos] <> nil) or (lfDynamicLib in prc.loc.flags) then begin
|
||||||
// XXX: remove this check!
|
|
||||||
end;
|
|
||||||
//if IntSetContains(p.module.debugDeclared, 2642) then
|
|
||||||
// InternalError(t.info, 'this sucks ' + toString(prc.id));
|
|
||||||
genProc(p.module, prc)
|
genProc(p.module, prc)
|
||||||
end
|
end
|
||||||
//else if sfCompilerProc in prc.flags then genProcPrototype(prc);
|
end
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
else
|
else
|
||||||
|
|
|
||||||
120
nim/ccgtypes.pas
120
nim/ccgtypes.pas
|
|
@ -8,7 +8,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
//var
|
//var
|
||||||
// newDummyVar: int; // just to check the rodgen mechanism
|
// newDummyVar: int; // just to check the symbol file mechanism
|
||||||
|
|
||||||
// ------------------------- Name Mangling --------------------------------
|
// ------------------------- Name Mangling --------------------------------
|
||||||
|
|
||||||
|
|
@ -461,6 +461,22 @@ begin
|
||||||
app(result, '};' + tnl);
|
app(result, '};' + tnl);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function getTupleDesc(m: BModule; typ: PType; name: PRope;
|
||||||
|
var check: TIntSet): PRope;
|
||||||
|
var
|
||||||
|
desc: PRope;
|
||||||
|
i: int;
|
||||||
|
begin
|
||||||
|
result := ropef('struct $1 {$n', [name]);
|
||||||
|
desc := nil;
|
||||||
|
for i := 0 to sonsLen(typ)-1 do
|
||||||
|
appf(desc, '$1 Field$2;$n',
|
||||||
|
[getTypeDescAux(m, typ.sons[i], check), toRope(i)]);
|
||||||
|
if (desc = nil) then app(result, 'char dummy;' + tnl)
|
||||||
|
else app(result, desc);
|
||||||
|
app(result, '};' + tnl);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure pushType(m: BModule; typ: PType);
|
procedure pushType(m: BModule; typ: PType);
|
||||||
var
|
var
|
||||||
L: int;
|
L: int;
|
||||||
|
|
@ -571,13 +587,15 @@ begin
|
||||||
if result = nil then begin
|
if result = nil then begin
|
||||||
result := getTypeName(t);
|
result := getTypeName(t);
|
||||||
if not isImportedType(t) then
|
if not isImportedType(t) then
|
||||||
appf(m.s[cfsForwardTypes],
|
appf(m.s[cfsForwardTypes], getForwardStructFormat(), [result]);
|
||||||
getForwardStructFormat(), [result]);
|
|
||||||
IdTablePut(m.forwTypeCache, t, result)
|
IdTablePut(m.forwTypeCache, t, result)
|
||||||
end;
|
end;
|
||||||
IdTablePut(m.typeCache, t, result);
|
IdTablePut(m.typeCache, t, result);
|
||||||
// always call for sideeffects:
|
// always call for sideeffects:
|
||||||
recdesc := getRecordDesc(m, t, result, check);
|
if t.n <> nil then
|
||||||
|
recdesc := getRecordDesc(m, t, result, check)
|
||||||
|
else
|
||||||
|
recdesc := getTupleDesc(m, t, result, check);
|
||||||
if not isImportedType(t) then app(m.s[cfsTypes], recdesc);
|
if not isImportedType(t) then app(m.s[cfsTypes], recdesc);
|
||||||
end;
|
end;
|
||||||
tySet: begin
|
tySet: begin
|
||||||
|
|
@ -735,9 +753,11 @@ begin
|
||||||
assert(n.sons[0].kind = nkSym);
|
assert(n.sons[0].kind = nkSym);
|
||||||
field := n.sons[0].sym;
|
field := n.sons[0].sym;
|
||||||
tmp := getTempName();
|
tmp := getTempName();
|
||||||
|
useMagic(m, 'chckNil');
|
||||||
appf(m.s[cfsTypeInit3], '$1.kind = 3;$n' +
|
appf(m.s[cfsTypeInit3], '$1.kind = 3;$n' +
|
||||||
'$1.offset = offsetof($2, $3);$n' +
|
'$1.offset = offsetof($2, $3);$n' +
|
||||||
'$1.typ = $4;$n' +
|
'$1.typ = $4;$n' +
|
||||||
|
'chckNil($1.typ);$n' +
|
||||||
'$1.name = $5;$n' +
|
'$1.name = $5;$n' +
|
||||||
'$1.sons = &$6[0];$n' +
|
'$1.sons = &$6[0];$n' +
|
||||||
'$1.len = $7;$n',
|
'$1.len = $7;$n',
|
||||||
|
|
@ -781,9 +801,11 @@ begin
|
||||||
end;
|
end;
|
||||||
nkSym: begin
|
nkSym: begin
|
||||||
field := n.sym;
|
field := n.sym;
|
||||||
|
useMagic(m, 'chckNil');
|
||||||
appf(m.s[cfsTypeInit3], '$1.kind = 1;$n' +
|
appf(m.s[cfsTypeInit3], '$1.kind = 1;$n' +
|
||||||
'$1.offset = offsetof($2, $3);$n' +
|
'$1.offset = offsetof($2, $3);$n' +
|
||||||
'$1.typ = $4;$n' +
|
'$1.typ = $4;$n' +
|
||||||
|
'chckNil($1.typ);$n' +
|
||||||
'$1.name = $5;$n',
|
'$1.name = $5;$n',
|
||||||
[expr, getTypeDesc(m, typ), field.loc.r,
|
[expr, getTypeDesc(m, typ), field.loc.r,
|
||||||
genTypeInfo(m, field.typ),
|
genTypeInfo(m, field.typ),
|
||||||
|
|
@ -804,6 +826,41 @@ begin
|
||||||
appf(m.s[cfsTypeInit3], '$1->node = &$2;$n', [name, tmp]);
|
appf(m.s[cfsTypeInit3], '$1->node = &$2;$n', [name, tmp]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure genTupleInfo(m: BModule; typ: PType; name: PRope);
|
||||||
|
var
|
||||||
|
tmp, expr, tmp2: PRope;
|
||||||
|
i, len: int;
|
||||||
|
a: PType;
|
||||||
|
begin
|
||||||
|
genTypeInfoAuxBase(m, typ, name, toRope('0'+''));
|
||||||
|
expr := getNimNode(m);
|
||||||
|
len := sonsLen(typ);
|
||||||
|
if len > 0 then begin
|
||||||
|
tmp := getTempName();
|
||||||
|
appf(m.s[cfsTypeInit1], 'static TNimNode* $1[$2];$n', [tmp, toRope(len)]);
|
||||||
|
for i := 0 to len-1 do begin
|
||||||
|
a := typ.sons[i];
|
||||||
|
tmp2 := getNimNode(m);
|
||||||
|
appf(m.s[cfsTypeInit3], '$1[$2] = &$3;$n', [tmp, toRope(i), tmp2]);
|
||||||
|
useMagic(m, 'chckNil');
|
||||||
|
appf(m.s[cfsTypeInit3], '$1.kind = 1;$n' +
|
||||||
|
'$1.offset = offsetof($2, Field$3);$n' +
|
||||||
|
'$1.typ = $4;$n' +
|
||||||
|
'chckNil($1.typ);$n' +
|
||||||
|
'$1.name = "Field$3";$n',
|
||||||
|
[tmp2, getTypeDesc(m, typ), toRope(i),
|
||||||
|
genTypeInfo(m, a)]);
|
||||||
|
end;
|
||||||
|
appf(m.s[cfsTypeInit3],
|
||||||
|
'$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n', [
|
||||||
|
expr, toRope(len), tmp]);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
appf(m.s[cfsTypeInit3],
|
||||||
|
'$1.len = $2; $1.kind = 2;$n', [expr, toRope(len)]);
|
||||||
|
appf(m.s[cfsTypeInit3], '$1->node = &$2;$n', [name, tmp]);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure genEnumInfo(m: BModule; typ: PType; name: PRope);
|
procedure genEnumInfo(m: BModule; typ: PType; name: PRope);
|
||||||
var
|
var
|
||||||
nodePtrs, elemNode, enumNames, enumArray, counter, specialCases: PRope;
|
nodePtrs, elemNode, enumNames, enumArray, counter, specialCases: PRope;
|
||||||
|
|
@ -817,7 +874,8 @@ begin
|
||||||
genTypeInfoAux(m, typ, name);
|
genTypeInfoAux(m, typ, name);
|
||||||
nodePtrs := getTempName();
|
nodePtrs := getTempName();
|
||||||
len := sonsLen(typ.n);
|
len := sonsLen(typ.n);
|
||||||
appf(m.s[cfsTypeInit1], 'static TNimNode* $1[$2];$n', [nodePtrs, toRope(len)]);
|
appf(m.s[cfsTypeInit1], 'static TNimNode* $1[$2];$n',
|
||||||
|
[nodePtrs, toRope(len)]);
|
||||||
enumNames := nil;
|
enumNames := nil;
|
||||||
specialCases := nil;
|
specialCases := nil;
|
||||||
firstNimNode := m.typeNodes;
|
firstNimNode := m.typeNodes;
|
||||||
|
|
@ -879,61 +937,55 @@ function genTypeInfo(m: BModule; typ: PType): PRope;
|
||||||
var
|
var
|
||||||
t: PType;
|
t: PType;
|
||||||
id: int;
|
id: int;
|
||||||
dataGen: bool;
|
dataGenerated: bool;
|
||||||
begin
|
begin
|
||||||
t := getUniqueType(typ);
|
t := getUniqueType(typ);
|
||||||
id := IiTableGet(gToTypeInfoId, t.id);
|
id := IiTableGet(gToTypeInfoId, t.id);
|
||||||
if id = invalidKey then begin
|
if id = invalidKey then begin
|
||||||
dataGen := false;
|
dataGenerated := false;
|
||||||
case t.kind of
|
id := t.id; // getID();
|
||||||
tyEnum, tyBool: begin
|
|
||||||
id := t.id;
|
|
||||||
dataGen := true
|
|
||||||
end;
|
|
||||||
tyObject: begin
|
|
||||||
if isPureObject(t) then
|
|
||||||
id := getID()
|
|
||||||
else begin
|
|
||||||
id := t.id;
|
|
||||||
dataGen := true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
id := getID();
|
|
||||||
end;
|
|
||||||
IiTablePut(gToTypeInfoId, t.id, id);
|
IiTablePut(gToTypeInfoId, t.id, id);
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
dataGen := true;
|
dataGenerated := true;
|
||||||
result := ropef('NTI$1', [toRope(id)]);
|
result := ropef('NTI$1', [toRope(id)]);
|
||||||
if not IntSetContainsOrIncl(m.typeInfoMarker, t.id) then begin
|
if not IntSetContainsOrIncl(m.typeInfoMarker, id) then begin
|
||||||
// declare type information structures:
|
// declare type information structures:
|
||||||
useMagic(m, 'TNimType');
|
useMagic(m, 'TNimType');
|
||||||
useMagic(m, 'TNimNode');
|
useMagic(m, 'TNimNode');
|
||||||
if dataGen then
|
|
||||||
appf(m.s[cfsVars], 'extern TNimType* $1; /* $2 */$n',
|
appf(m.s[cfsVars], 'extern TNimType* $1; /* $2 */$n',
|
||||||
[result, toRope(typeToString(t))]);
|
[result, toRope(typeToString(t))]);
|
||||||
end;
|
end;
|
||||||
if dataGen then exit;
|
if dataGenerated then exit;
|
||||||
case t.kind of
|
case t.kind of
|
||||||
tyPointer, tyProc, tyBool, tyChar, tyCString, tyString,
|
tyPointer, tyProc, tyBool, tyChar, tyCString, tyString,
|
||||||
tyInt..tyFloat128, tyVar:
|
tyInt..tyFloat128, tyVar:
|
||||||
genTypeInfoAuxBase(m, t, result, toRope('0'+''));
|
genTypeInfoAuxBase(gmti, t, result, toRope('0'+''));
|
||||||
tyRef, tyPtr, tySequence, tyRange: genTypeInfoAux(m, t, result);
|
tyRef, tyPtr, tySequence, tyRange: genTypeInfoAux(gmti, t, result);
|
||||||
tyArrayConstr, tyArray: genArrayInfo(m, t, result);
|
tyArrayConstr, tyArray: genArrayInfo(gmti, t, result);
|
||||||
tySet: genSetInfo(m, t, result);
|
tySet: genSetInfo(gmti, t, result);
|
||||||
tyEnum: genEnumInfo(m, t, result);
|
tyEnum: genEnumInfo(gmti, t, result);
|
||||||
tyObject, tyTuple: genObjectInfo(m, t, result);
|
tyObject: genObjectInfo(gmti, t, result);
|
||||||
|
tyTuple: begin
|
||||||
|
if t.n <> nil then genObjectInfo(gmti, t, result)
|
||||||
|
else genTupleInfo(gmti, t, result);
|
||||||
|
end;
|
||||||
else InternalError('genTypeInfo(' + typekindToStr[t.kind] + ')');
|
else InternalError('genTypeInfo(' + typekindToStr[t.kind] + ')');
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure genTypeSection(m: BModule; n: PNode);
|
||||||
|
begin
|
||||||
|
end;
|
||||||
|
|
||||||
|
(*
|
||||||
procedure genTypeSection(m: BModule; n: PNode);
|
procedure genTypeSection(m: BModule; n: PNode);
|
||||||
var
|
var
|
||||||
i: int;
|
i: int;
|
||||||
a: PNode;
|
a: PNode;
|
||||||
t: PType;
|
t: PType;
|
||||||
begin
|
begin
|
||||||
|
if not (optDeadCodeElim in gGlobalOptions) then begin
|
||||||
for i := 0 to sonsLen(n)-1 do begin
|
for i := 0 to sonsLen(n)-1 do begin
|
||||||
a := n.sons[i];
|
a := n.sons[i];
|
||||||
if a.kind = nkCommentStmt then continue;
|
if a.kind = nkCommentStmt then continue;
|
||||||
|
|
@ -958,4 +1010,6 @@ begin
|
||||||
else begin end
|
else begin end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end;
|
end;
|
||||||
|
*)
|
||||||
|
|
@ -27,16 +27,48 @@ function GetUniqueType(key: PType): PType;
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
var
|
var
|
||||||
gTypeTable: TIdTable;
|
gTypeTable: array [TTypeKind] of TIdTable;
|
||||||
|
|
||||||
|
procedure initTypeTables();
|
||||||
|
var
|
||||||
|
i: TTypeKind;
|
||||||
|
begin
|
||||||
|
for i := low(TTypeKind) to high(TTypeKind) do
|
||||||
|
InitIdTable(gTypeTable[i]);
|
||||||
|
end;
|
||||||
|
|
||||||
function GetUniqueType(key: PType): PType;
|
function GetUniqueType(key: PType): PType;
|
||||||
var
|
var
|
||||||
t: PType;
|
t: PType;
|
||||||
h: THash;
|
h: THash;
|
||||||
|
k: TTypeKind;
|
||||||
begin
|
begin
|
||||||
// this was a hotspot in the compiler!
|
// this is a hotspot in the compiler!
|
||||||
result := key;
|
result := key;
|
||||||
if key = nil then exit;
|
if key = nil then exit;
|
||||||
|
k := key.kind;
|
||||||
|
case k of
|
||||||
|
tyObject, tyEnum: begin
|
||||||
|
result := PType(IdTableGet(gTypeTable[k], key));
|
||||||
|
if result = nil then begin
|
||||||
|
IdTablePut(gTypeTable[k], key, key);
|
||||||
|
result := key;
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
tyGenericInst: result := GetUniqueType(lastSon(key));
|
||||||
|
tyProc: begin end;
|
||||||
|
else begin
|
||||||
|
// we have to do a slow linear search because types may need
|
||||||
|
// to be compared by their structure:
|
||||||
|
if IdTableHasObjectAsKey(gTypeTable[k], key) then exit;
|
||||||
|
for h := 0 to high(gTypeTable[k].data) do begin
|
||||||
|
t := PType(gTypeTable[k].data[h].key);
|
||||||
|
if (t <> nil) and sameType(t, key) then begin result := t; exit end
|
||||||
|
end;
|
||||||
|
IdTablePut(gTypeTable[k], key, key);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
(*
|
||||||
case key.Kind of
|
case key.Kind of
|
||||||
tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
|
tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
|
||||||
tyInt..tyFloat128, tyProc, tyAnyEnum: begin end;
|
tyInt..tyFloat128, tyProc, tyAnyEnum: begin end;
|
||||||
|
|
@ -62,7 +94,7 @@ begin
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
tyGenericInst: result := GetUniqueType(lastSon(key));
|
tyGenericInst: result := GetUniqueType(lastSon(key));
|
||||||
end;
|
end; *)
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TableGetType(const tab: TIdTable; key: PType): PObject;
|
function TableGetType(const tab: TIdTable; key: PType): PObject;
|
||||||
|
|
@ -122,6 +154,6 @@ begin
|
||||||
app(result, toRope(res));
|
app(result, toRope(res));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
initialization
|
begin
|
||||||
InitIdTable(gTypeTable);
|
InitTypeTables();
|
||||||
end.
|
end.
|
||||||
|
|
|
||||||
307
nim/cgen.pas
307
nim/cgen.pas
|
|
@ -73,7 +73,6 @@ type
|
||||||
cpsStmts // section of local statements for C proc
|
cpsStmts // section of local statements for C proc
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
TCProcSections = array [TCProcSection] of PRope;
|
TCProcSections = array [TCProcSection] of PRope;
|
||||||
// TCProcSections represents a generated C proc
|
// TCProcSections represents a generated C proc
|
||||||
|
|
||||||
|
|
@ -112,12 +111,13 @@ type
|
||||||
typeCache: TIdTable; // cache the generated types
|
typeCache: TIdTable; // cache the generated types
|
||||||
forwTypeCache: TIdTable; // cache for forward declarations of types
|
forwTypeCache: TIdTable; // cache for forward declarations of types
|
||||||
declaredThings: TIntSet; // things we have declared in this .c file
|
declaredThings: TIntSet; // things we have declared in this .c file
|
||||||
debugDeclared: TIntSet; // for debugging purposes
|
declaredProtos: TIntSet; // prototypes we have declared in this .c file
|
||||||
headerFiles: TLinkedList; // needed headers to include
|
headerFiles: TLinkedList; // needed headers to include
|
||||||
typeInfoMarker: TIntSet; // needed for generating type information
|
typeInfoMarker: TIntSet; // needed for generating type information
|
||||||
initProc: BProc; // code for init procedure
|
initProc: BProc; // code for init procedure
|
||||||
typeStack: TTypeSeq; // used for type generation
|
typeStack: TTypeSeq; // used for type generation
|
||||||
dataCache: TNodeTable;
|
dataCache: TNodeTable;
|
||||||
|
forwardedProcs: TSymSeq; // keep forwarded procs here
|
||||||
typeNodes, nimTypes: int;// used for type info generation
|
typeNodes, nimTypes: int;// used for type info generation
|
||||||
typeNodesName, nimTypesName: PRope; // used for type info generation
|
typeNodesName, nimTypesName: PRope; // used for type info generation
|
||||||
end;
|
end;
|
||||||
|
|
@ -126,7 +126,49 @@ var
|
||||||
mainModProcs, mainModInit: PRope; // parts of the main module
|
mainModProcs, mainModInit: PRope; // parts of the main module
|
||||||
gMapping: PRope; // the generated mapping file (if requested)
|
gMapping: PRope; // the generated mapping file (if requested)
|
||||||
gProcProfile: Natural; // proc profile counter
|
gProcProfile: Natural; // proc profile counter
|
||||||
|
gGeneratedSyms: TIntSet; // set of ID's of generated symbols
|
||||||
|
gPendingModules: array of BModule = {@ignore} nil {@emit @[]};
|
||||||
|
// list of modules that are not finished with code generation
|
||||||
|
gForwardedProcsCounter: int = 0;
|
||||||
|
gmti: BModule; // generated type info: no need to initialize: defaults fit
|
||||||
|
|
||||||
|
procedure addForwardedProc(m: BModule; prc: PSym);
|
||||||
|
var
|
||||||
|
L: int;
|
||||||
|
begin
|
||||||
|
L := length(m.forwardedProcs);
|
||||||
|
setLength(m.forwardedProcs, L+1);
|
||||||
|
m.forwardedProcs[L] := prc;
|
||||||
|
inc(gForwardedProcsCounter);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure addPendingModule(m: BModule);
|
||||||
|
var
|
||||||
|
L, i: int;
|
||||||
|
begin
|
||||||
|
for i := 0 to high(gPendingModules) do
|
||||||
|
if gPendingModules[i] = m then
|
||||||
|
InternalError('module already pending: ' + m.module.name.s);
|
||||||
|
L := length(gPendingModules);
|
||||||
|
setLength(gPendingModules, L+1);
|
||||||
|
gPendingModules[L] := m;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function findPendingModule(m: BModule; s: PSym): BModule;
|
||||||
|
var
|
||||||
|
ms: PSym;
|
||||||
|
i: int;
|
||||||
|
begin
|
||||||
|
ms := getModule(s);
|
||||||
|
if ms.id = m.module.id then begin
|
||||||
|
result := m; exit
|
||||||
|
end;
|
||||||
|
for i := 0 to high(gPendingModules) do begin
|
||||||
|
result := gPendingModules[i];
|
||||||
|
if result.module.id = ms.id then exit;
|
||||||
|
end;
|
||||||
|
InternalError(s.info, 'no pending module found for: ' + s.name.s);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure initLoc(var result: TLoc; k: TLocKind; typ: PType; s: TStorageLoc);
|
procedure initLoc(var result: TLoc; k: TLocKind; typ: PType; s: TStorageLoc);
|
||||||
begin
|
begin
|
||||||
|
|
@ -209,25 +251,12 @@ end;
|
||||||
|
|
||||||
// -------------------------- Variable manager ----------------------------
|
// -------------------------- Variable manager ----------------------------
|
||||||
|
|
||||||
procedure declareGlobalVar(m: BModule; s: PSym);
|
|
||||||
begin
|
|
||||||
if not IntSetContainsOrIncl(m.declaredThings, s.id) then begin
|
|
||||||
app(m.s[cfsVars], getTypeDesc(m, s.loc.t));
|
|
||||||
if sfRegister in s.flags then
|
|
||||||
app(m.s[cfsVars], ' register');
|
|
||||||
if sfVolatile in s.flags then
|
|
||||||
app(m.s[cfsVars], ' volatile');
|
|
||||||
if sfThreadVar in s.flags then
|
|
||||||
app(m.s[cfsVars], ' NIM_THREADVAR');
|
|
||||||
appf(m.s[cfsVars], ' $1;$n', [s.loc.r])
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure assignLocalVar(p: BProc; s: PSym);
|
procedure assignLocalVar(p: BProc; s: PSym);
|
||||||
begin
|
begin
|
||||||
//assert(s.loc.k == locNone) // not yet assigned
|
//assert(s.loc.k == locNone) // not yet assigned
|
||||||
// this need not be fullfilled for inline procs; they are regenerated
|
// this need not be fullfilled for inline procs; they are regenerated
|
||||||
// for each module that uses them!
|
// for each module that uses them!
|
||||||
|
if s.loc.k = locNone then
|
||||||
fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack);
|
fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack);
|
||||||
app(p.s[cpsLocals], getTypeDesc(p.module, s.loc.t));
|
app(p.s[cpsLocals], getTypeDesc(p.module, s.loc.t));
|
||||||
if sfRegister in s.flags then
|
if sfRegister in s.flags then
|
||||||
|
|
@ -248,11 +277,19 @@ end;
|
||||||
|
|
||||||
procedure assignGlobalVar(m: BModule; s: PSym);
|
procedure assignGlobalVar(m: BModule; s: PSym);
|
||||||
begin
|
begin
|
||||||
|
if s.loc.k = locNone then
|
||||||
fillLoc(s.loc, locGlobalVar, s.typ, mangleName(s), OnHeap);
|
fillLoc(s.loc, locGlobalVar, s.typ, mangleName(s), OnHeap);
|
||||||
useHeader(m, s);
|
useHeader(m, s);
|
||||||
if lfNoDecl in s.loc.flags then exit;
|
if lfNoDecl in s.loc.flags then exit;
|
||||||
if sfImportc in s.flags then app(m.s[cfsVars], 'extern ');
|
if sfImportc in s.flags then app(m.s[cfsVars], 'extern ');
|
||||||
declareGlobalVar(m, s);
|
app(m.s[cfsVars], getTypeDesc(m, s.loc.t));
|
||||||
|
if sfRegister in s.flags then
|
||||||
|
app(m.s[cfsVars], ' register');
|
||||||
|
if sfVolatile in s.flags then
|
||||||
|
app(m.s[cfsVars], ' volatile');
|
||||||
|
if sfThreadVar in s.flags then
|
||||||
|
app(m.s[cfsVars], ' NIM_THREADVAR');
|
||||||
|
appf(m.s[cfsVars], ' $1;$n', [s.loc.r]);
|
||||||
if [optStackTrace, optEndb] * m.module.options =
|
if [optStackTrace, optEndb] * m.module.options =
|
||||||
[optStackTrace, optEndb] then begin
|
[optStackTrace, optEndb] then begin
|
||||||
useMagic(m, 'dbgRegisterGlobal');
|
useMagic(m, 'dbgRegisterGlobal');
|
||||||
|
|
@ -282,6 +319,12 @@ begin
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure fillProcLoc(sym: PSym);
|
||||||
|
begin
|
||||||
|
if sym.loc.k = locNone then
|
||||||
|
fillLoc(sym.loc, locProc, sym.typ, mangleName(sym), OnStack);
|
||||||
|
end;
|
||||||
|
|
||||||
// -------------------------- label manager -------------------------------
|
// -------------------------- label manager -------------------------------
|
||||||
|
|
||||||
// note that a label is a location too
|
// note that a label is a location too
|
||||||
|
|
@ -296,11 +339,11 @@ begin
|
||||||
appf(p.s[cpsStmts], '$1: ;$n', [labl])
|
appf(p.s[cpsStmts], '$1: ;$n', [labl])
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure genProcPrototype(m: BModule; sym: PSym); forward;
|
|
||||||
procedure genVarPrototype(m: BModule; sym: PSym); forward;
|
procedure genVarPrototype(m: BModule; sym: PSym); forward;
|
||||||
procedure genConstPrototype(m: BModule; sym: PSym); forward;
|
procedure genConstPrototype(m: BModule; sym: PSym); forward;
|
||||||
procedure genProc(m: BModule; prc: PSym); forward;
|
procedure genProc(m: BModule; prc: PSym); forward;
|
||||||
procedure genStmts(p: BProc; t: PNode); forward;
|
procedure genStmts(p: BProc; t: PNode); forward;
|
||||||
|
procedure genProcPrototype(m: BModule; sym: PSym); forward;
|
||||||
|
|
||||||
{$include 'ccgexprs.pas'}
|
{$include 'ccgexprs.pas'}
|
||||||
{$include 'ccgstmts.pas'}
|
{$include 'ccgstmts.pas'}
|
||||||
|
|
@ -343,11 +386,11 @@ begin
|
||||||
tmp := ropef('Dl_$1', [toRope(sym.id)]);
|
tmp := ropef('Dl_$1', [toRope(sym.id)]);
|
||||||
sym.loc.r := tmp; // from now on we only need the internal name
|
sym.loc.r := tmp; // from now on we only need the internal name
|
||||||
sym.typ.sym := nil; // generate a new name
|
sym.typ.sym := nil; // generate a new name
|
||||||
appf(m.s[cfsDynLibInit],
|
appf(m.s[cfsDynLibInit], '$1 = ($2) nimGetProcAddr($3, $4);$n',
|
||||||
'$1 = ($2) nimGetProcAddr($3, $4);$n',
|
[tmp, getTypeDesc(m, sym.typ), lib.name, makeCString(ropeToStr(extname))]);
|
||||||
[tmp, getTypeDesc(m, sym.typ), lib.name,
|
|
||||||
makeCString(ropeToStr(extname))]);
|
app(m.s[cfsVars], getTypeDesc(m, sym.loc.t));
|
||||||
declareGlobalVar(m, sym)
|
appf(m.s[cfsVars], ' $1;$n', [sym.loc.r]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// ----------------------------- sections ---------------------------------
|
// ----------------------------- sections ---------------------------------
|
||||||
|
|
@ -356,16 +399,16 @@ procedure UseMagic(m: BModule; const name: string);
|
||||||
var
|
var
|
||||||
sym: PSym;
|
sym: PSym;
|
||||||
begin
|
begin
|
||||||
if (sfSystemModule in m.module.flags) then exit;
|
|
||||||
// we don't know the magic symbols in the system module, but they will be
|
|
||||||
// there anyway, because that is the way the code generator works
|
|
||||||
sym := magicsys.getCompilerProc(name);
|
sym := magicsys.getCompilerProc(name);
|
||||||
|
if sym <> nil then
|
||||||
case sym.kind of
|
case sym.kind of
|
||||||
skProc, skConverter: genProcPrototype(m, sym);
|
skProc, skConverter: genProc(m, sym);
|
||||||
skVar: genVarPrototype(m, sym);
|
skVar: genVarPrototype(m, sym);
|
||||||
skType: {@discard} getTypeDesc(m, sym.typ);
|
skType: {@discard} getTypeDesc(m, sym.typ);
|
||||||
else InternalError('useMagic: ' + name)
|
else InternalError('useMagic: ' + name)
|
||||||
end
|
end
|
||||||
|
else if not (sfSystemModule in m.module.flags) then
|
||||||
|
rawMessage(errSystemNeeds, name); // don't be too picky here
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure generateHeaders(m: BModule);
|
procedure generateHeaders(m: BModule);
|
||||||
|
|
@ -405,27 +448,15 @@ begin
|
||||||
result := (s.typ.sons[0] <> nil) and not isInvalidReturnType(s.typ.sons[0])
|
result := (s.typ.sons[0] <> nil) and not isInvalidReturnType(s.typ.sons[0])
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure genProc(m: BModule; prc: PSym);
|
procedure genProcAux(m: BModule; prc: PSym);
|
||||||
var
|
var
|
||||||
p: BProc;
|
p: BProc;
|
||||||
generatedProc, header, returnStmt: PRope;
|
generatedProc, header, returnStmt: PRope;
|
||||||
i, profileId: int;
|
i: int;
|
||||||
res, param: PSym;
|
res, param: PSym;
|
||||||
begin
|
begin
|
||||||
useHeader(m, prc);
|
|
||||||
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);
|
p := newProc(prc, m);
|
||||||
header := genProcHeader(m, prc);
|
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;
|
returnStmt := nil;
|
||||||
assert(prc.ast <> nil);
|
assert(prc.ast <> nil);
|
||||||
|
|
||||||
|
|
@ -493,7 +524,55 @@ begin
|
||||||
app(generatedProc, '}' + tnl);
|
app(generatedProc, '}' + tnl);
|
||||||
end;
|
end;
|
||||||
app(m.s[cfsProcs], generatedProc);
|
app(m.s[cfsProcs], generatedProc);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure genProcPrototype(m: BModule; sym: PSym);
|
||||||
|
begin
|
||||||
|
useHeader(m, sym);
|
||||||
|
if (lfNoDecl in sym.loc.Flags) then exit;
|
||||||
|
if lfDynamicLib in sym.loc.Flags then begin
|
||||||
|
if (sym.owner.id <> m.module.id) and
|
||||||
|
not intSetContainsOrIncl(m.declaredThings, sym.id) then begin
|
||||||
|
appf(m.s[cfsVars], 'extern $1 Dl_$2;$n',
|
||||||
|
[getTypeDesc(m, sym.loc.t), toRope(sym.id)])
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
if not IntSetContainsOrIncl(m.declaredProtos, sym.id) then
|
||||||
|
appf(m.s[cfsProcHeaders], '$1;$n', [genProcHeader(m, sym)]);
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure genProcNoForward(m: BModule; prc: PSym);
|
||||||
|
begin
|
||||||
|
fillProcLoc(prc);
|
||||||
|
useHeader(m, prc);
|
||||||
|
genProcPrototype(m, prc);
|
||||||
|
if (lfNoDecl in prc.loc.Flags) then exit;
|
||||||
|
if prc.typ.callConv = ccInline then begin
|
||||||
|
// We add inline procs to the calling module to enable C based inlining.
|
||||||
|
// This also means that a check with ``gGeneratedSyms`` is wrong, we need
|
||||||
|
// a check for ``m.declaredThings``.
|
||||||
|
if not intSetContainsOrIncl(m.declaredThings, prc.id) then
|
||||||
|
genProcAux(m, prc);
|
||||||
|
end
|
||||||
|
else if lfDynamicLib in prc.loc.flags then begin
|
||||||
|
if not IntSetContainsOrIncl(gGeneratedSyms, prc.id) then
|
||||||
|
SymInDynamicLib(findPendingModule(m, prc), prc);
|
||||||
|
end
|
||||||
|
else if not (sfImportc in prc.flags) then begin
|
||||||
|
if not IntSetContainsOrIncl(gGeneratedSyms, prc.id) then
|
||||||
|
genProcAux(findPendingModule(m, prc), prc);
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure genProc(m: BModule; prc: PSym);
|
||||||
|
begin
|
||||||
|
fillProcLoc(prc);
|
||||||
|
if [sfForward, sfFromGeneric] * prc.flags <> [] then
|
||||||
|
addForwardedProc(m, prc)
|
||||||
|
else
|
||||||
|
genProcNoForward(m, prc)
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure genVarPrototype(m: BModule; sym: PSym);
|
procedure genVarPrototype(m: BModule; sym: PSym);
|
||||||
|
|
@ -522,6 +601,7 @@ end;
|
||||||
procedure genConstPrototype(m: BModule; sym: PSym);
|
procedure genConstPrototype(m: BModule; sym: PSym);
|
||||||
begin
|
begin
|
||||||
useHeader(m, sym);
|
useHeader(m, sym);
|
||||||
|
if sym.loc.k = locNone then
|
||||||
fillLoc(sym.loc, locData, sym.typ, mangleName(sym), OnUnknown);
|
fillLoc(sym.loc, locData, sym.typ, mangleName(sym), OnUnknown);
|
||||||
if (lfNoDecl in sym.loc.Flags) or
|
if (lfNoDecl in sym.loc.Flags) or
|
||||||
intSetContainsOrIncl(m.declaredThings, sym.id) then
|
intSetContainsOrIncl(m.declaredThings, sym.id) then
|
||||||
|
|
@ -535,32 +615,6 @@ begin
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure genProcPrototype(m: BModule; sym: PSym);
|
|
||||||
begin
|
|
||||||
useHeader(m, sym);
|
|
||||||
fillLoc(sym.loc, locProc, sym.typ, mangleName(sym), OnStack);
|
|
||||||
if lfDynamicLib in sym.loc.Flags then begin
|
|
||||||
// it is a proc variable!
|
|
||||||
if (sym.owner.id <> m.module.id) and
|
|
||||||
not intSetContainsOrIncl(m.declaredThings, sym.id) then begin
|
|
||||||
app(m.s[cfsVars], 'extern ');
|
|
||||||
// BUGFIX: declareGlobalVar() inlined, because of intSetContainsOrIncl
|
|
||||||
// check
|
|
||||||
app(m.s[cfsVars], getTypeDesc(m, sym.loc.t));
|
|
||||||
appf(m.s[cfsVars], ' $1;$n', [sym.loc.r])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else begin
|
|
||||||
// it is a proc:
|
|
||||||
if (lfNoDecl in sym.loc.Flags) then exit;
|
|
||||||
if intSetContainsOrIncl(m.declaredThings, sym.id) then exit;
|
|
||||||
appf(m.s[cfsProcHeaders], '$1;$n', [genProcHeader(m, sym)]);
|
|
||||||
if (sym.typ.callConv = ccInline)
|
|
||||||
and (sym.owner.id <> m.module.id) then
|
|
||||||
genProc(m, sym) // generate the code again!
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
|
|
||||||
function getFileHeader(const cfilenoext: string): PRope;
|
function getFileHeader(const cfilenoext: string): PRope;
|
||||||
begin
|
begin
|
||||||
if optCompileOnly in gGlobalOptions then
|
if optCompileOnly in gGlobalOptions then
|
||||||
|
|
@ -593,6 +647,7 @@ procedure genMainProc(m: BModule);
|
||||||
const
|
const
|
||||||
CommonMainBody =
|
CommonMainBody =
|
||||||
' setStackBottom(dummy);$n' +
|
' setStackBottom(dummy);$n' +
|
||||||
|
' nim__datInit();$n' +
|
||||||
' systemInit();$n' +
|
' systemInit();$n' +
|
||||||
'$1' +
|
'$1' +
|
||||||
'$2';
|
'$2';
|
||||||
|
|
@ -652,8 +707,7 @@ var
|
||||||
initname: PRope;
|
initname: PRope;
|
||||||
begin
|
begin
|
||||||
initname := getInitName(m);
|
initname := getInitName(m);
|
||||||
appf(mainModProcs, 'N_NOINLINE(void, $1)(void);$n',
|
appf(mainModProcs, 'N_NOINLINE(void, $1)(void);$n', [initname]);
|
||||||
[initname]);
|
|
||||||
if not (sfSystemModule in m.flags) then
|
if not (sfSystemModule in m.flags) then
|
||||||
appf(mainModInit, '$1();$n', [initname]);
|
appf(mainModInit, '$1();$n', [initname]);
|
||||||
end;
|
end;
|
||||||
|
|
@ -669,14 +723,18 @@ begin
|
||||||
{@discard} lists.IncludeStr(m.headerFiles, '<cycle.h>');
|
{@discard} lists.IncludeStr(m.headerFiles, '<cycle.h>');
|
||||||
end;
|
end;
|
||||||
initname := getInitName(m.module);
|
initname := getInitName(m.module);
|
||||||
registerModuleToMain(m.module);
|
|
||||||
prc := ropef('N_NOINLINE(void, $1)(void) {$n', [initname]);
|
prc := ropef('N_NOINLINE(void, $1)(void) {$n', [initname]);
|
||||||
if m.typeNodes > 0 then
|
|
||||||
|
if m.typeNodes > 0 then begin
|
||||||
|
useMagic(m, 'TNimNode');
|
||||||
appf(m.s[cfsTypeInit1], 'static TNimNode $1[$2];$n',
|
appf(m.s[cfsTypeInit1], 'static TNimNode $1[$2];$n',
|
||||||
[m.typeNodesName, toRope(m.typeNodes)]);
|
[m.typeNodesName, toRope(m.typeNodes)]);
|
||||||
if m.nimTypes > 0 then
|
end;
|
||||||
|
if m.nimTypes > 0 then begin
|
||||||
|
useMagic(m, 'TNimType');
|
||||||
appf(m.s[cfsTypeInit1], 'static TNimType $1[$2];$n',
|
appf(m.s[cfsTypeInit1], 'static TNimType $1[$2];$n',
|
||||||
[m.nimTypesName, toRope(m.nimTypes)]);
|
[m.nimTypesName, toRope(m.nimTypes)]);
|
||||||
|
end;
|
||||||
if optStackTrace in m.initProc.options then begin
|
if optStackTrace in m.initProc.options then begin
|
||||||
getFrameDecl(m.initProc);
|
getFrameDecl(m.initProc);
|
||||||
app(prc, m.initProc.s[cpsLocals]);
|
app(prc, m.initProc.s[cpsLocals]);
|
||||||
|
|
@ -716,7 +774,7 @@ begin
|
||||||
for i := low(TCFileSection) to cfsProcs do app(result, m.s[i])
|
for i := low(TCFileSection) to cfsProcs do app(result, m.s[i])
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function newModule(module: PSym; const filename: string): BModule;
|
function rawNewModule(module: PSym; const filename: string): BModule;
|
||||||
begin
|
begin
|
||||||
new(result);
|
new(result);
|
||||||
{@ignore}
|
{@ignore}
|
||||||
|
|
@ -724,7 +782,7 @@ begin
|
||||||
{@emit}
|
{@emit}
|
||||||
InitLinkedList(result.headerFiles);
|
InitLinkedList(result.headerFiles);
|
||||||
intSetInit(result.declaredThings);
|
intSetInit(result.declaredThings);
|
||||||
intSetInit(result.debugDeclared);
|
intSetInit(result.declaredProtos);
|
||||||
result.cfilename := filename;
|
result.cfilename := filename;
|
||||||
result.filename := filename;
|
result.filename := filename;
|
||||||
initIdTable(result.typeCache);
|
initIdTable(result.typeCache);
|
||||||
|
|
@ -735,12 +793,36 @@ begin
|
||||||
result.initProc.options := gOptions;
|
result.initProc.options := gOptions;
|
||||||
initNodeTable(result.dataCache);
|
initNodeTable(result.dataCache);
|
||||||
{@emit result.typeStack := @[];}
|
{@emit result.typeStack := @[];}
|
||||||
|
{@emit result.forwardedProcs := @[];}
|
||||||
result.typeNodesName := getTempName();
|
result.typeNodesName := getTempName();
|
||||||
result.nimTypesName := getTempName();
|
result.nimTypesName := getTempName();
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function newModule(module: PSym; const filename: string): BModule;
|
||||||
|
begin
|
||||||
|
result := rawNewModule(module, filename);
|
||||||
|
if (optDeadCodeElim in gGlobalOptions) then begin
|
||||||
|
if (sfDeadCodeElim in module.flags) then
|
||||||
|
InternalError('added pending module twice: ' + filename);
|
||||||
|
addPendingModule(result)
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure registerTypeInfoModule();
|
||||||
|
const
|
||||||
|
moduleName = 'nim__dat';
|
||||||
|
var
|
||||||
|
s: PSym;
|
||||||
|
begin
|
||||||
|
s := NewSym(skModule, getIdent(moduleName), nil);
|
||||||
|
gmti := rawNewModule(s, joinPath(options.projectPath, moduleName)+'.nim');
|
||||||
|
addPendingModule(gmti);
|
||||||
|
appf(mainModProcs, 'N_NOINLINE(void, $1)(void);$n', [getInitName(s)]);
|
||||||
|
end;
|
||||||
|
|
||||||
function myOpen(module: PSym; const filename: string): PPassContext;
|
function myOpen(module: PSym; const filename: string): PPassContext;
|
||||||
begin
|
begin
|
||||||
|
if gmti = nil then registerTypeInfoModule();
|
||||||
result := newModule(module, filename);
|
result := newModule(module, filename);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
@ -749,6 +831,7 @@ function myOpenCached(module: PSym; const filename: string;
|
||||||
var
|
var
|
||||||
cfile, cfilenoext, objFile: string;
|
cfile, cfilenoext, objFile: string;
|
||||||
begin
|
begin
|
||||||
|
if gmti = nil then registerTypeInfoModule();
|
||||||
//MessageOut('cgen.myOpenCached has been called ' + filename);
|
//MessageOut('cgen.myOpenCached has been called ' + filename);
|
||||||
cfile := changeFileExt(completeCFilePath(filename), cExt);
|
cfile := changeFileExt(completeCFilePath(filename), cExt);
|
||||||
cfilenoext := changeFileExt(cfile, '');
|
cfilenoext := changeFileExt(cfile, '');
|
||||||
|
|
@ -761,6 +844,8 @@ begin
|
||||||
end; *)
|
end; *)
|
||||||
addFileToLink(cfilenoext);
|
addFileToLink(cfilenoext);
|
||||||
registerModuleToMain(module);
|
registerModuleToMain(module);
|
||||||
|
// XXX: this cannot be right here, initalization has to be appended during
|
||||||
|
// the ``myClose`` call
|
||||||
result := nil;
|
result := nil;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
@ -790,11 +875,52 @@ begin
|
||||||
genStmts(m.initProc, n);
|
genStmts(m.initProc, n);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function myClose(b: PPassContext; n: PNode): PNode;
|
procedure finishModule(m: BModule);
|
||||||
|
var
|
||||||
|
i: int;
|
||||||
|
prc: PSym;
|
||||||
|
begin
|
||||||
|
i := 0;
|
||||||
|
while i <= high(m.forwardedProcs) do begin
|
||||||
|
// Note: ``genProc`` may add to ``m.forwardedProcs``, so we cannot use
|
||||||
|
// a for loop here
|
||||||
|
prc := m.forwardedProcs[i];
|
||||||
|
if sfForward in prc.flags then InternalError(prc.info, 'still forwarded');
|
||||||
|
genProcNoForward(m, prc);
|
||||||
|
inc(i);
|
||||||
|
end;
|
||||||
|
assert(gForwardedProcsCounter >= i);
|
||||||
|
dec(gForwardedProcsCounter, i);
|
||||||
|
setLength(m.forwardedProcs, 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure writeModule(m: BModule);
|
||||||
var
|
var
|
||||||
cfile, cfilenoext: string;
|
cfile, cfilenoext: string;
|
||||||
m: BModule;
|
|
||||||
code: PRope;
|
code: PRope;
|
||||||
|
begin
|
||||||
|
// generate code for the init statements of the module:
|
||||||
|
genInitCode(m);
|
||||||
|
finishTypeDescriptions(m);
|
||||||
|
|
||||||
|
cfile := completeCFilePath(m.cfilename);
|
||||||
|
cfilenoext := changeFileExt(cfile, '');
|
||||||
|
if sfMainModule in m.module.flags then begin
|
||||||
|
// generate main file:
|
||||||
|
app(m.s[cfsProcHeaders], mainModProcs);
|
||||||
|
end;
|
||||||
|
code := genModule(m, cfilenoext);
|
||||||
|
if shouldRecompile(code, changeFileExt(cfile, cExt), cfilenoext) then begin
|
||||||
|
addFileToCompile(cfilenoext);
|
||||||
|
end;
|
||||||
|
addFileToLink(cfilenoext);
|
||||||
|
if sfMainModule in m.module.flags then writeMapping(cfile, gMapping);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function myClose(b: PPassContext; n: PNode): PNode;
|
||||||
|
var
|
||||||
|
m: BModule;
|
||||||
|
i: int;
|
||||||
begin
|
begin
|
||||||
result := n;
|
result := n;
|
||||||
if b = nil then exit;
|
if b = nil then exit;
|
||||||
|
|
@ -803,22 +929,24 @@ begin
|
||||||
m.initProc.options := gOptions;
|
m.initProc.options := gOptions;
|
||||||
genStmts(m.initProc, n);
|
genStmts(m.initProc, n);
|
||||||
end;
|
end;
|
||||||
// generate code for the init statements of the module:
|
registerModuleToMain(m.module);
|
||||||
genInitCode(m);
|
if not (optDeadCodeElim in gGlobalOptions) and
|
||||||
finishTypeDescriptions(m);
|
not (sfDeadCodeElim in m.module.flags) then
|
||||||
cfile := completeCFilePath(m.cfilename);
|
finishModule(m);
|
||||||
cfilenoext := changeFileExt(cfile, '');
|
|
||||||
if sfMainModule in m.module.flags then begin
|
if sfMainModule in m.module.flags then begin
|
||||||
// generate main file:
|
|
||||||
app(m.s[cfsProcHeaders], mainModProcs);
|
|
||||||
genMainProc(m);
|
genMainProc(m);
|
||||||
|
// we need to process the transitive closure because recursive module
|
||||||
|
// deps are allowed (and the system module is processed in the wrong
|
||||||
|
// order anyway)
|
||||||
|
while gForwardedProcsCounter > 0 do
|
||||||
|
for i := 0 to high(gPendingModules) do
|
||||||
|
finishModule(gPendingModules[i]);
|
||||||
|
for i := 0 to high(gPendingModules) do writeModule(gPendingModules[i]);
|
||||||
|
setLength(gPendingModules, 0);
|
||||||
end;
|
end;
|
||||||
code := genModule(m, cfilenoext);
|
if not (optDeadCodeElim in gGlobalOptions) and
|
||||||
if shouldRecompile(code, changeFileExt(cfile, cExt), cfilenoext) then begin
|
not (sfDeadCodeElim in m.module.flags) then
|
||||||
addFileToCompile(cfilenoext); // is to compile
|
writeModule(m);
|
||||||
end;
|
|
||||||
addFileToLink(cfilenoext);
|
|
||||||
if sfMainModule in m.module.flags then writeMapping(cfile, gMapping);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function cgenPass(): TPass;
|
function cgenPass(): TPass;
|
||||||
|
|
@ -832,4 +960,5 @@ end;
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
InitIiTable(gToTypeInfoId);
|
InitIiTable(gToTypeInfoId);
|
||||||
|
IntSetInit(gGeneratedSyms);
|
||||||
end.
|
end.
|
||||||
|
|
|
||||||
|
|
@ -39,14 +39,14 @@ const
|
||||||
{$ifdef fpc}
|
{$ifdef fpc}
|
||||||
compileDate = {$I %date%};
|
compileDate = {$I %date%};
|
||||||
{$else}
|
{$else}
|
||||||
compileDate = '2008-0-0';
|
compileDate = '2009-0-0';
|
||||||
{$endif}
|
{$endif}
|
||||||
{@emit}
|
{@emit}
|
||||||
|
|
||||||
const
|
const
|
||||||
HelpMessage = 'Nimrod Compiler Version $1 (' +{&}
|
HelpMessage = 'Nimrod Compiler Version $1 (' +{&}
|
||||||
compileDate +{&} ') [$2: $3]' +{&} nl +{&}
|
compileDate +{&} ') [$2: $3]' +{&} nl +{&}
|
||||||
'Copyright (c) 2004-2008 by Andreas Rumpf' +{&} nl;
|
'Copyright (c) 2004-2009 by Andreas Rumpf' +{&} nl;
|
||||||
|
|
||||||
const
|
const
|
||||||
Usage = ''
|
Usage = ''
|
||||||
|
|
@ -82,6 +82,7 @@ const
|
||||||
+{&} ' --bound_checks:on|off code generation for bound checks ON|OFF' +{&} nl
|
+{&} ' --bound_checks:on|off code generation for bound checks ON|OFF' +{&} nl
|
||||||
+{&} ' --overflow_checks:on|off code generation for over-/underflow checks ON|OFF' +{&} nl
|
+{&} ' --overflow_checks:on|off code generation for over-/underflow checks ON|OFF' +{&} nl
|
||||||
+{&} ' -a, --assertions:on|off code generation for assertions ON|OFF' +{&} nl
|
+{&} ' -a, --assertions:on|off code generation for assertions ON|OFF' +{&} nl
|
||||||
|
+{&} ' --dead_code_elim:on|off whole program dead code elimination ON|OFF' +{&} nl
|
||||||
+{&} ' --opt:none|speed|size optimize not at all or for speed|size' +{&} nl
|
+{&} ' --opt:none|speed|size optimize not at all or for speed|size' +{&} nl
|
||||||
+{&} ' --app:console|gui|lib generate a console|GUI application or a shared lib' +{&} nl
|
+{&} ' --app:console|gui|lib generate a console|GUI application or a shared lib' +{&} nl
|
||||||
+{&} ' -r, --run run the compiled program with given arguments' +{&} nl
|
+{&} ' -r, --run run the compiled program with given arguments' +{&} nl
|
||||||
|
|
@ -96,7 +97,7 @@ const
|
||||||
// cog.outl(f(line))
|
// cog.outl(f(line))
|
||||||
//]]]
|
//]]]
|
||||||
+{&} 'Advanced commands::' +{&} nl
|
+{&} 'Advanced commands::' +{&} nl
|
||||||
+{&} ' pas convert a Pascal file to Nimrod standard syntax' +{&} nl
|
+{&} ' pas convert a Pascal file to Nimrod syntax' +{&} nl
|
||||||
+{&} ' pretty pretty print the inputfile' +{&} nl
|
+{&} ' pretty pretty print the inputfile' +{&} nl
|
||||||
+{&} ' gen_depend generate a DOT file containing the' +{&} nl
|
+{&} ' gen_depend generate a DOT file containing the' +{&} nl
|
||||||
+{&} ' module dependency graph' +{&} nl
|
+{&} ' module dependency graph' +{&} nl
|
||||||
|
|
@ -135,8 +136,8 @@ const
|
||||||
|
|
||||||
function getCommandLineDesc: string;
|
function getCommandLineDesc: string;
|
||||||
begin
|
begin
|
||||||
result := format(HelpMessage, [VersionAsString, platform.os[hostOS].name,
|
result := format(HelpMessage, [VersionAsString,
|
||||||
cpu[hostCPU].name]) +{&} Usage
|
platform.os[platform.hostOS].name, cpu[platform.hostCPU].name]) +{&} Usage
|
||||||
end;
|
end;
|
||||||
|
|
||||||
var
|
var
|
||||||
|
|
@ -157,8 +158,10 @@ procedure writeAdvancedUsage(pass: TCmdLinePass);
|
||||||
begin
|
begin
|
||||||
if (pass = passCmd1) and not advHelpWritten then begin
|
if (pass = passCmd1) and not advHelpWritten then begin
|
||||||
// BUGFIX 19
|
// BUGFIX 19
|
||||||
MessageOut(format(HelpMessage, [VersionAsString, platform.os[hostOS].name,
|
MessageOut(format(HelpMessage, [VersionAsString,
|
||||||
cpu[hostCPU].name]) +{&} AdvancedUsage);
|
platform.os[platform.hostOS].name,
|
||||||
|
cpu[platform.hostCPU].name]) +{&}
|
||||||
|
AdvancedUsage);
|
||||||
advHelpWritten := true;
|
advHelpWritten := true;
|
||||||
helpWritten := true;
|
helpWritten := true;
|
||||||
halt(0);
|
halt(0);
|
||||||
|
|
@ -170,8 +173,9 @@ begin
|
||||||
if (pass = passCmd1) and not versionWritten then begin
|
if (pass = passCmd1) and not versionWritten then begin
|
||||||
versionWritten := true;
|
versionWritten := true;
|
||||||
helpWritten := true;
|
helpWritten := true;
|
||||||
messageOut(format(HelpMessage, [VersionAsString, platform.os[hostOS].name,
|
messageOut(format(HelpMessage, [VersionAsString,
|
||||||
cpu[hostCPU].name]))
|
platform.os[platform.hostOS].name,
|
||||||
|
cpu[platform.hostCPU].name]))
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
@ -388,6 +392,7 @@ begin
|
||||||
wOverflowChecks: ProcessOnOffSwitch({@set}[optOverflowCheck], arg, pass, info);
|
wOverflowChecks: ProcessOnOffSwitch({@set}[optOverflowCheck], arg, pass, info);
|
||||||
wLineDir: ProcessOnOffSwitch({@set}[optLineDir], arg, pass, info);
|
wLineDir: ProcessOnOffSwitch({@set}[optLineDir], arg, pass, info);
|
||||||
wAssertions, wA: ProcessOnOffSwitch({@set}[optAssert], arg, pass, info);
|
wAssertions, wA: ProcessOnOffSwitch({@set}[optAssert], arg, pass, info);
|
||||||
|
wDeadCodeElim: ProcessOnOffSwitchG({@set}[optDeadCodeElim], arg, pass, info);
|
||||||
wOpt: begin
|
wOpt: begin
|
||||||
case whichKeyword(arg) of
|
case whichKeyword(arg) of
|
||||||
wSpeed: begin
|
wSpeed: begin
|
||||||
|
|
@ -453,7 +458,7 @@ begin
|
||||||
theOS := platform.NameToOS(arg);
|
theOS := platform.NameToOS(arg);
|
||||||
if theOS = osNone then
|
if theOS = osNone then
|
||||||
liMessage(info, errUnknownOS, arg);
|
liMessage(info, errUnknownOS, arg);
|
||||||
if theOS <> hostOS then begin
|
if theOS <> platform.hostOS then begin
|
||||||
setTarget(theOS, targetCPU);
|
setTarget(theOS, targetCPU);
|
||||||
include(gGlobalOptions, optCompileOnly);
|
include(gGlobalOptions, optCompileOnly);
|
||||||
condsyms.InitDefines()
|
condsyms.InitDefines()
|
||||||
|
|
@ -465,7 +470,7 @@ begin
|
||||||
cpu := platform.NameToCPU(arg);
|
cpu := platform.NameToCPU(arg);
|
||||||
if cpu = cpuNone then
|
if cpu = cpuNone then
|
||||||
liMessage(info, errUnknownCPU, arg);
|
liMessage(info, errUnknownCPU, arg);
|
||||||
if cpu <> hostCPU then begin
|
if cpu <> platform.hostCPU then begin
|
||||||
setTarget(targetOS, cpu);
|
setTarget(targetOS, cpu);
|
||||||
include(gGlobalOptions, optCompileOnly);
|
include(gGlobalOptions, optCompileOnly);
|
||||||
condsyms.InitDefines()
|
condsyms.InitDefines()
|
||||||
|
|
|
||||||
|
|
@ -218,8 +218,6 @@ begin
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function nextSplitPoint(const s: string; start: int): int;
|
function nextSplitPoint(const s: string; start: int): int;
|
||||||
var
|
|
||||||
i: int;
|
|
||||||
begin
|
begin
|
||||||
result := start;
|
result := start;
|
||||||
while result < length(s)+strStart do begin
|
while result < length(s)+strStart do begin
|
||||||
|
|
@ -393,7 +391,8 @@ begin
|
||||||
fillChar(r, sizeof(r), 0);
|
fillChar(r, sizeof(r), 0);
|
||||||
{@emit}
|
{@emit}
|
||||||
comm := genRecComment(d, n); // call this here for the side-effect!
|
comm := genRecComment(d, n); // call this here for the side-effect!
|
||||||
initTokRender(r, n, {@set}[renderNoPragmas, renderNoBody]);
|
initTokRender(r, n, {@set}[renderNoPragmas, renderNoBody, renderNoComments,
|
||||||
|
renderDocComments]);
|
||||||
while true do begin
|
while true do begin
|
||||||
getNextTok(r, kind, literal);
|
getNextTok(r, kind, literal);
|
||||||
case kind of
|
case kind of
|
||||||
|
|
@ -661,21 +660,26 @@ begin
|
||||||
result := ropef('<ul class="simple">$1</ul>', [result]);
|
result := ropef('<ul class="simple">$1</ul>', [result]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function fieldAux(const s: string): PRope;
|
||||||
|
begin
|
||||||
|
result := toRope(strip(s))
|
||||||
|
end;
|
||||||
|
|
||||||
function renderImage(d: PDoc; n: PRstNode): PRope;
|
function renderImage(d: PDoc; n: PRstNode): PRope;
|
||||||
var
|
var
|
||||||
s: string;
|
s: string;
|
||||||
begin
|
begin
|
||||||
result := ropef('<img src="$1"', [toRope(getArgument(n))]);
|
result := ropef('<img src="$1"', [toRope(getArgument(n))]);
|
||||||
s := getFieldValue(n, 'height');
|
s := getFieldValue(n, 'height');
|
||||||
if s <> '' then appf(result, ' height="$1"', [toRope(s)]);
|
if s <> '' then appf(result, ' height="$1"', [fieldAux(s)]);
|
||||||
s := getFieldValue(n, 'width');
|
s := getFieldValue(n, 'width');
|
||||||
if s <> '' then appf(result, ' width="$1"', [toRope(s)]);
|
if s <> '' then appf(result, ' width="$1"', [fieldAux(s)]);
|
||||||
s := getFieldValue(n, 'scale');
|
s := getFieldValue(n, 'scale');
|
||||||
if s <> '' then appf(result, ' scale="$1"', [toRope(s)]);
|
if s <> '' then appf(result, ' scale="$1"', [fieldAux(s)]);
|
||||||
s := getFieldValue(n, 'alt');
|
s := getFieldValue(n, 'alt');
|
||||||
if s <> '' then appf(result, ' alt="$1"', [toRope(s)]);
|
if s <> '' then appf(result, ' alt="$1"', [fieldAux(s)]);
|
||||||
s := getFieldValue(n, 'align');
|
s := getFieldValue(n, 'align');
|
||||||
if s <> '' then appf(result, ' align="$1"', [toRope(s)]);
|
if s <> '' then appf(result, ' align="$1"', [fieldAux(s)]);
|
||||||
app(result, ' />');
|
app(result, ' />');
|
||||||
if rsonsLen(n) >= 3 then app(result, renderRstToHtml(d, n.sons[2]))
|
if rsonsLen(n) >= 3 then app(result, renderRstToHtml(d, n.sons[2]))
|
||||||
end;
|
end;
|
||||||
|
|
@ -863,14 +867,17 @@ begin
|
||||||
nkConverterDef: genItem(d, n, n.sons[namePos], skConverter);
|
nkConverterDef: genItem(d, n, n.sons[namePos], skConverter);
|
||||||
nkVarSection: begin
|
nkVarSection: begin
|
||||||
for i := 0 to sonsLen(n)-1 do
|
for i := 0 to sonsLen(n)-1 do
|
||||||
|
if n.sons[i].kind <> nkCommentStmt then
|
||||||
genItem(d, n.sons[i], n.sons[i].sons[0], skVar);
|
genItem(d, n.sons[i], n.sons[i].sons[0], skVar);
|
||||||
end;
|
end;
|
||||||
nkConstSection: begin
|
nkConstSection: begin
|
||||||
for i := 0 to sonsLen(n)-1 do
|
for i := 0 to sonsLen(n)-1 do
|
||||||
|
if n.sons[i].kind <> nkCommentStmt then
|
||||||
genItem(d, n.sons[i], n.sons[i].sons[0], skConst);
|
genItem(d, n.sons[i], n.sons[i].sons[0], skConst);
|
||||||
end;
|
end;
|
||||||
nkTypeSection: begin
|
nkTypeSection: begin
|
||||||
for i := 0 to sonsLen(n)-1 do
|
for i := 0 to sonsLen(n)-1 do
|
||||||
|
if n.sons[i].kind <> nkCommentStmt then
|
||||||
genItem(d, n.sons[i], n.sons[i].sons[0], skType);
|
genItem(d, n.sons[i], n.sons[i].sons[0], skType);
|
||||||
end;
|
end;
|
||||||
nkStmtList: begin
|
nkStmtList: begin
|
||||||
|
|
|
||||||
|
|
@ -896,7 +896,8 @@ begin
|
||||||
or (skipGeneric(y.typ).kind in [tyRef, tyPtr, tyVar])
|
or (skipGeneric(y.typ).kind in [tyRef, tyPtr, tyVar])
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure genAsgnAux(var p: TProc; x, y: PNode; var r: TCompRes);
|
procedure genAsgnAux(var p: TProc; x, y: PNode; var r: TCompRes;
|
||||||
|
noCopyNeeded: bool);
|
||||||
var
|
var
|
||||||
a, b: TCompRes;
|
a, b: TCompRes;
|
||||||
begin
|
begin
|
||||||
|
|
@ -906,7 +907,7 @@ begin
|
||||||
etyObject: begin
|
etyObject: begin
|
||||||
if a.com <> nil then appf(r.com, '$1;$n', [a.com]);
|
if a.com <> nil then appf(r.com, '$1;$n', [a.com]);
|
||||||
if b.com <> nil then appf(r.com, '$1;$n', [b.com]);
|
if b.com <> nil then appf(r.com, '$1;$n', [b.com]);
|
||||||
if needsNoCopy(y) then
|
if needsNoCopy(y) or noCopyNeeded then
|
||||||
appf(r.com, '$1 = $2;$n', [a.res, b.res])
|
appf(r.com, '$1 = $2;$n', [a.res, b.res])
|
||||||
else begin
|
else begin
|
||||||
useMagic(p, 'NimCopy');
|
useMagic(p, 'NimCopy');
|
||||||
|
|
@ -930,7 +931,13 @@ end;
|
||||||
procedure genAsgn(var p: TProc; n: PNode; var r: TCompRes);
|
procedure genAsgn(var p: TProc; n: PNode; var r: TCompRes);
|
||||||
begin
|
begin
|
||||||
genLineDir(p, n, r);
|
genLineDir(p, n, r);
|
||||||
genAsgnAux(p, n.sons[0], n.sons[1], r);
|
genAsgnAux(p, n.sons[0], n.sons[1], r, false);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure genFastAsgn(var p: TProc; n: PNode; var r: TCompRes);
|
||||||
|
begin
|
||||||
|
genLineDir(p, n, r);
|
||||||
|
genAsgnAux(p, n.sons[0], n.sons[1], r, true);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure genSwap(var p: TProc; n: PNode; var r: TCompRes);
|
procedure genSwap(var p: TProc; n: PNode; var r: TCompRes);
|
||||||
|
|
@ -1692,6 +1699,7 @@ begin
|
||||||
nkReturnStmt: genReturnStmt(p, n, r);
|
nkReturnStmt: genReturnStmt(p, n, r);
|
||||||
nkBreakStmt: genBreakStmt(p, n, r);
|
nkBreakStmt: genBreakStmt(p, n, r);
|
||||||
nkAsgn: genAsgn(p, n, r);
|
nkAsgn: genAsgn(p, n, r);
|
||||||
|
nkFastAsgn: genFastAsgn(p, n, r);
|
||||||
nkDiscardStmt: begin
|
nkDiscardStmt: begin
|
||||||
genLineDir(p, n, r);
|
genLineDir(p, n, r);
|
||||||
gen(p, n.sons[0], r);
|
gen(p, n.sons[0], r);
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ type
|
||||||
TStackFrame = record
|
TStackFrame = record
|
||||||
mapping: TIdNodeTable; // mapping from symbols to nodes
|
mapping: TIdNodeTable; // mapping from symbols to nodes
|
||||||
prc: PSym; // current prc; proc that is evaluated
|
prc: PSym; // current prc; proc that is evaluated
|
||||||
call: PNode; // current for stmt
|
call: PNode;
|
||||||
next: PStackFrame; // for stacking
|
next: PStackFrame; // for stacking
|
||||||
params: TNodeSeq; // parameters passed to the proc
|
params: TNodeSeq; // parameters passed to the proc
|
||||||
end;
|
end;
|
||||||
|
|
@ -127,7 +127,7 @@ begin
|
||||||
inc(i)
|
inc(i)
|
||||||
end;
|
end;
|
||||||
if (i < len) and (sonsLen(n.sons[i]) < 2) then // eval else-part
|
if (i < len) and (sonsLen(n.sons[i]) < 2) then // eval else-part
|
||||||
result := evalAux(c, n.sons[0])
|
result := evalAux(c, n.sons[i].sons[0])
|
||||||
else
|
else
|
||||||
result := emptyNode
|
result := emptyNode
|
||||||
end;
|
end;
|
||||||
|
|
@ -1227,7 +1227,7 @@ begin
|
||||||
nkDerefExpr, nkHiddenDeref: result := evalDeref(c, n);
|
nkDerefExpr, nkHiddenDeref: result := evalDeref(c, n);
|
||||||
nkAddr, nkHiddenAddr: result := evalAddr(c, n);
|
nkAddr, nkHiddenAddr: result := evalAddr(c, n);
|
||||||
nkHiddenStdConv, nkHiddenSubConv, nkConv: result := evalConv(c, n);
|
nkHiddenStdConv, nkHiddenSubConv, nkConv: result := evalConv(c, n);
|
||||||
nkAsgn: result := evalAsgn(c, n);
|
nkAsgn, nkFastAsgn: result := evalAsgn(c, n);
|
||||||
nkWhenStmt, nkIfStmt, nkIfExpr: result := evalIf(c, n);
|
nkWhenStmt, nkIfStmt, nkIfExpr: result := evalIf(c, n);
|
||||||
nkWhileStmt: result := evalWhile(c, n);
|
nkWhileStmt: result := evalWhile(c, n);
|
||||||
nkCaseStmt: result := evalCase(c, n);
|
nkCaseStmt: result := evalCase(c, n);
|
||||||
|
|
@ -1259,7 +1259,7 @@ begin
|
||||||
nkTemplateDef, nkConstSection, nkIteratorDef, nkConverterDef,
|
nkTemplateDef, nkConstSection, nkIteratorDef, nkConverterDef,
|
||||||
nkIncludeStmt, nkImportStmt, nkFromStmt: begin end;
|
nkIncludeStmt, nkImportStmt, nkFromStmt: begin end;
|
||||||
nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr,
|
nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr,
|
||||||
nkQualified, nkLambda, nkContinueStmt:
|
nkQualified, nkLambda, nkContinueStmt, nkIdent:
|
||||||
stackTrace(c, n, errCannotInterpretNodeX, nodeKindToStr[n.kind]);
|
stackTrace(c, n, errCannotInterpretNodeX, nodeKindToStr[n.kind]);
|
||||||
else InternalError(n.info, 'evalAux: ' + nodekindToStr[n.kind]);
|
else InternalError(n.info, 'evalAux: ' + nodekindToStr[n.kind]);
|
||||||
end;
|
end;
|
||||||
|
|
|
||||||
|
|
@ -343,17 +343,11 @@ begin
|
||||||
result := ccNone
|
result := ccNone
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure addStr(var dest: string; const src: string);
|
|
||||||
begin
|
|
||||||
dest := dest +{&} src;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure addOpt(var dest: string; const src: string);
|
procedure addOpt(var dest: string; const src: string);
|
||||||
begin
|
begin
|
||||||
if (length(dest) = 0) or (dest[length(dest)-1+strStart] <> ' ') then
|
if (length(dest) = 0) or (dest[length(dest)-1+strStart] <> ' ') then
|
||||||
addStr(dest, ' '+'');
|
add(dest, ' '+'');
|
||||||
addStr(dest, src);
|
add(dest, src);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure addCompileOption(const option: string);
|
procedure addCompileOption(const option: string);
|
||||||
|
|
@ -473,40 +467,52 @@ begin
|
||||||
key := cc[c].name + '.exe';
|
key := cc[c].name + '.exe';
|
||||||
if existsConfigVar(key) then
|
if existsConfigVar(key) then
|
||||||
exe := getConfigVar(key);
|
exe := getConfigVar(key);
|
||||||
|
if targetOS = osWindows then exe := appendFileExt(exe, 'exe');
|
||||||
|
|
||||||
if (optGenDynLib in gGlobalOptions)
|
if (optGenDynLib in gGlobalOptions)
|
||||||
and (ospNeedsPIC in platform.OS[targetOS].props) then
|
and (ospNeedsPIC in platform.OS[targetOS].props) then
|
||||||
addStr(options, ' ' + cc[c].pic);
|
add(options, ' ' + cc[c].pic);
|
||||||
|
|
||||||
if targetOS = hostOS then begin
|
if targetOS = platform.hostOS then begin
|
||||||
// compute include paths:
|
// compute include paths:
|
||||||
includeCmd := cc[c].includeCmd; // this is more complex than needed, but
|
includeCmd := cc[c].includeCmd; // this is more complex than needed, but
|
||||||
// a workaround of a FPC bug...
|
// a workaround of a FPC bug...
|
||||||
addStr(includeCmd, libpath);
|
add(includeCmd, quoteIfContainsWhite(libpath));
|
||||||
compilePattern := quoteIfSpaceExists(JoinPath(ccompilerpath, exe));
|
compilePattern := JoinPath(ccompilerpath, exe);
|
||||||
end
|
end
|
||||||
else begin
|
else begin
|
||||||
includeCmd := '';
|
includeCmd := '';
|
||||||
compilePattern := cc[c].compilerExe
|
compilePattern := cc[c].compilerExe
|
||||||
end;
|
end;
|
||||||
if targetOS = hostOS then
|
if targetOS = platform.hostOS then
|
||||||
cfile := cfilename
|
cfile := cfilename
|
||||||
else
|
else
|
||||||
cfile := extractFileName(cfilename);
|
cfile := extractFileName(cfilename);
|
||||||
|
|
||||||
if not isExternal or (targetOS <> hostOS) then
|
if not isExternal or (targetOS <> platform.hostOS) then
|
||||||
objfile := toObjFile(cfile)
|
objfile := toObjFile(cfile)
|
||||||
else
|
else
|
||||||
objfile := completeCFilePath(toObjFile(cfile));
|
objfile := completeCFilePath(toObjFile(cfile));
|
||||||
|
cfile := quoteIfContainsWhite(AppendFileExt(cfile, cExt));
|
||||||
|
objfile := quoteIfContainsWhite(objfile);
|
||||||
|
|
||||||
result := format(compilePattern +{&} ' ' +{&} cc[c].compileTmpl,
|
result := quoteIfContainsWhite(format(compilePattern,
|
||||||
['file', AppendFileExt(cfile, cExt),
|
['file', cfile,
|
||||||
'objfile', objfile,
|
'objfile', objfile,
|
||||||
'options', options,
|
'options', options,
|
||||||
'include', includeCmd,
|
'include', includeCmd,
|
||||||
'nimrod', getPrefixDir(),
|
'nimrod', getPrefixDir(),
|
||||||
'lib', libpath
|
'lib', libpath
|
||||||
]);
|
]));
|
||||||
|
add(result, ' ');
|
||||||
|
add(result, format(cc[c].compileTmpl,
|
||||||
|
['file', cfile,
|
||||||
|
'objfile', objfile,
|
||||||
|
'options', options,
|
||||||
|
'include', includeCmd,
|
||||||
|
'nimrod', quoteIfContainsWhite(getPrefixDir()),
|
||||||
|
'lib', quoteIfContainsWhite(libpath)
|
||||||
|
]));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure CompileCFile(const list: TLinkedList;
|
procedure CompileCFile(const list: TLinkedList;
|
||||||
|
|
@ -551,11 +557,12 @@ begin
|
||||||
// call the linker:
|
// call the linker:
|
||||||
linkerExe := getConfigVar(cc[c].name + '.linkerexe');
|
linkerExe := getConfigVar(cc[c].name + '.linkerexe');
|
||||||
if length(linkerExe) = 0 then linkerExe := cc[c].linkerExe;
|
if length(linkerExe) = 0 then linkerExe := cc[c].linkerExe;
|
||||||
|
if targetOS = osWindows then linkerExe := appendFileExt(linkerExe, 'exe');
|
||||||
|
|
||||||
if (hostOS <> targetOS) then
|
if (platform.hostOS <> targetOS) then
|
||||||
linkCmd := linkerExe
|
linkCmd := quoteIfContainsWhite(linkerExe)
|
||||||
else
|
else
|
||||||
linkCmd := quoteIfSpaceExists(JoinPath(ccompilerpath, linkerExe));
|
linkCmd := quoteIfContainsWhite(JoinPath(ccompilerpath, linkerExe));
|
||||||
|
|
||||||
if optGenDynLib in gGlobalOptions then
|
if optGenDynLib in gGlobalOptions then
|
||||||
buildDll := cc[c].buildDll
|
buildDll := cc[c].buildDll
|
||||||
|
|
@ -570,27 +577,29 @@ begin
|
||||||
exefile := platform.os[targetOS].dllPrefix
|
exefile := platform.os[targetOS].dllPrefix
|
||||||
else
|
else
|
||||||
exefile := '';
|
exefile := '';
|
||||||
if targetOS = hostOS then
|
if targetOS = platform.hostOS then
|
||||||
addStr(exefile, projectFile)
|
add(exefile, projectFile)
|
||||||
else
|
else
|
||||||
addStr(exefile, extractFileName(projectFile));
|
add(exefile, extractFileName(projectFile));
|
||||||
if optGenDynLib in gGlobalOptions then
|
if optGenDynLib in gGlobalOptions then
|
||||||
addStr(exefile, platform.os[targetOS].dllExt)
|
add(exefile, platform.os[targetOS].dllExt)
|
||||||
else
|
else
|
||||||
addStr(exefile, platform.os[targetOS].exeExt);
|
add(exefile, platform.os[targetOS].exeExt);
|
||||||
|
exefile := quoteIfContainsWhite(exefile);
|
||||||
|
|
||||||
it := PStrEntry(toLink.head);
|
it := PStrEntry(toLink.head);
|
||||||
objfiles := '';
|
objfiles := '';
|
||||||
while it <> nil do begin
|
while it <> nil do begin
|
||||||
addStr(objfiles, ' '+'');
|
add(objfiles, ' '+'');
|
||||||
if targetOS = hostOS then
|
if targetOS = platform.hostOS then
|
||||||
addStr(objfiles, toObjfile(it.data))
|
add(objfiles, quoteIfContainsWhite(toObjfile(it.data)))
|
||||||
else
|
else
|
||||||
addStr(objfiles, toObjfile(extractFileName(it.data)));
|
add(objfiles, quoteIfContainsWhite(
|
||||||
|
toObjfile(extractFileName(it.data))));
|
||||||
it := PStrEntry(it.next);
|
it := PStrEntry(it.next);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
linkCmd := format(linkCmd +{&} ' ' +{&} cc[c].linkTmpl, [
|
linkCmd := quoteIfContainsWhite(format(linkCmd, [
|
||||||
'builddll', builddll,
|
'builddll', builddll,
|
||||||
'buildgui', buildgui,
|
'buildgui', buildgui,
|
||||||
'options', linkOptions,
|
'options', linkOptions,
|
||||||
|
|
@ -598,7 +607,18 @@ begin
|
||||||
'exefile', exefile,
|
'exefile', exefile,
|
||||||
'nimrod', getPrefixDir(),
|
'nimrod', getPrefixDir(),
|
||||||
'lib', libpath
|
'lib', libpath
|
||||||
]);
|
]));
|
||||||
|
add(linkCmd, ' ');
|
||||||
|
add(linkCmd, format(cc[c].linkTmpl, [
|
||||||
|
'builddll', builddll,
|
||||||
|
'buildgui', buildgui,
|
||||||
|
'options', linkOptions,
|
||||||
|
'objfiles', objfiles,
|
||||||
|
'exefile', exefile,
|
||||||
|
'nimrod', quoteIfContainsWhite(getPrefixDir()),
|
||||||
|
'lib', quoteIfContainsWhite(libpath)
|
||||||
|
]));
|
||||||
|
|
||||||
if not (optCompileOnly in gGlobalOptions) then
|
if not (optCompileOnly in gGlobalOptions) then
|
||||||
execExternalProgram(linkCmd);
|
execExternalProgram(linkCmd);
|
||||||
end // end if not noLinking
|
end // end if not noLinking
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ begin
|
||||||
result := x -{%} 1;
|
result := x -{%} 1;
|
||||||
// complicated, to make it a nop if sizeof(int) == 4,
|
// complicated, to make it a nop if sizeof(int) == 4,
|
||||||
// because shifting more than 31 bits is undefined in C
|
// because shifting more than 31 bits is undefined in C
|
||||||
result := result or (result shr ((sizeof(int)-4)* 32));
|
result := result or (result shr ((sizeof(int)-4)* 8));
|
||||||
result := result or (result shr 16);
|
result := result or (result shr 16);
|
||||||
result := result or (result shr 8);
|
result := result or (result shr 8);
|
||||||
result := result or (result shr 4);
|
result := result or (result shr 4);
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ function getCurrentLine(const L: TBaseLexer; marker: boolean = true): string;
|
||||||
function getColNumber(const L: TBaseLexer; pos: int): int;
|
function getColNumber(const L: TBaseLexer; pos: int): int;
|
||||||
|
|
||||||
function HandleCR(var L: TBaseLexer; pos: int): int;
|
function HandleCR(var L: TBaseLexer; pos: int): int;
|
||||||
// Call this if you scanned over CR in the buffer; it returns the the
|
// Call this if you scanned over CR in the buffer; it returns the
|
||||||
// position to continue the scanning from. `pos` must be the position
|
// position to continue the scanning from. `pos` must be the position
|
||||||
// of the CR.
|
// of the CR.
|
||||||
|
|
||||||
|
|
@ -211,8 +211,7 @@ end;
|
||||||
|
|
||||||
function getColNumber(const L: TBaseLexer; pos: int): int;
|
function getColNumber(const L: TBaseLexer; pos: int): int;
|
||||||
begin
|
begin
|
||||||
result := pos - L.lineStart;
|
result := abs(pos - L.lineStart);
|
||||||
assert(result >= 0);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function getCurrentLine(const L: TBaseLexer; marker: boolean = true): string;
|
function getCurrentLine(const L: TBaseLexer; marker: boolean = true): string;
|
||||||
|
|
|
||||||
|
|
@ -96,9 +96,10 @@ begin
|
||||||
result := StrTableGet(compilerprocs, ident);
|
result := StrTableGet(compilerprocs, ident);
|
||||||
if result = nil then begin
|
if result = nil then begin
|
||||||
result := StrTableGet(rodCompilerProcs, ident);
|
result := StrTableGet(rodCompilerProcs, ident);
|
||||||
if result = nil then rawMessage(errSystemNeeds, name);
|
if result <> nil then begin
|
||||||
strTableAdd(compilerprocs, result);
|
strTableAdd(compilerprocs, result);
|
||||||
if result.kind = skStub then loadStub(result);
|
if result.kind = skStub then loadStub(result);
|
||||||
|
end;
|
||||||
// A bit hacky that this code is needed here, but it is the easiest
|
// A bit hacky that this code is needed here, but it is the easiest
|
||||||
// solution in order to avoid special cases for sfCompilerProc in the
|
// solution in order to avoid special cases for sfCompilerProc in the
|
||||||
// rodgen module. Another solution would be to always recompile the system
|
// rodgen module. Another solution would be to always recompile the system
|
||||||
|
|
|
||||||
|
|
@ -173,7 +173,7 @@ type
|
||||||
errSelectorMustBeOrdinal,
|
errSelectorMustBeOrdinal,
|
||||||
errOrdXMustNotBeNegative,
|
errOrdXMustNotBeNegative,
|
||||||
errLenXinvalid,
|
errLenXinvalid,
|
||||||
errWrongNumberOfLoopVariables,
|
errWrongNumberOfVariables,
|
||||||
errExprCannotBeRaised,
|
errExprCannotBeRaised,
|
||||||
errBreakOnlyInLoop,
|
errBreakOnlyInLoop,
|
||||||
errTypeXhasUnknownSize,
|
errTypeXhasUnknownSize,
|
||||||
|
|
@ -431,7 +431,7 @@ const
|
||||||
'selector must be of an ordinal type',
|
'selector must be of an ordinal type',
|
||||||
'ord($1) must not be negative',
|
'ord($1) must not be negative',
|
||||||
'len($1) must be less than 32768',
|
'len($1) must be less than 32768',
|
||||||
'wrong number of loop variables',
|
'wrong number of variables',
|
||||||
'only objects can be raised',
|
'only objects can be raised',
|
||||||
'''break'' only allowed in loop construct',
|
'''break'' only allowed in loop construct',
|
||||||
'type ''$1'' has unknown size',
|
'type ''$1'' has unknown size',
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,8 @@ begin
|
||||||
}
|
}
|
||||||
end;
|
end;
|
||||||
if optRun in gGlobalOptions then
|
if optRun in gGlobalOptions then
|
||||||
execExternalProgram(changeFileExt(filename, '') +{&} ' ' +{&} arguments)
|
execExternalProgram(quoteIfContainsWhite(changeFileExt(filename, '')) +{&}
|
||||||
|
' ' +{&} arguments)
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,9 +35,11 @@ const
|
||||||
{$ifdef mswindows}
|
{$ifdef mswindows}
|
||||||
dirsep = '\'; // seperator within paths
|
dirsep = '\'; // seperator within paths
|
||||||
altsep = '/';
|
altsep = '/';
|
||||||
|
exeExt = 'exe';
|
||||||
{$else}
|
{$else}
|
||||||
dirsep = '/';
|
dirsep = '/';
|
||||||
altsep = #0; // work around fpc bug
|
altsep = #0; // work around fpc bug
|
||||||
|
exeExt = '';
|
||||||
{$endif}
|
{$endif}
|
||||||
pathSep = ';'; // seperator between paths
|
pathSep = ';'; // seperator between paths
|
||||||
sep = dirsep; // alternative name
|
sep = dirsep; // alternative name
|
||||||
|
|
|
||||||
|
|
@ -149,8 +149,12 @@ function subU(a, b: biggestInt): biggestInt;
|
||||||
function mulU(a, b: biggestInt): biggestInt;
|
function mulU(a, b: biggestInt): biggestInt;
|
||||||
function divU(a, b: biggestInt): biggestInt;
|
function divU(a, b: biggestInt): biggestInt;
|
||||||
function modU(a, b: biggestInt): biggestInt;
|
function modU(a, b: biggestInt): biggestInt;
|
||||||
function shlU(a, b: biggestInt): biggestInt;
|
function shlU(a, b: biggestInt): biggestInt; overload;
|
||||||
function shrU(a, b: biggestInt): biggestInt;
|
function shrU(a, b: biggestInt): biggestInt; overload;
|
||||||
|
|
||||||
|
function shlU(a, b: Int32): Int32;overload;
|
||||||
|
function shrU(a, b: int32): int32;overload;
|
||||||
|
|
||||||
function ltU(a, b: biggestInt): bool;
|
function ltU(a, b: biggestInt): bool;
|
||||||
function leU(a, b: biggestInt): bool;
|
function leU(a, b: biggestInt): bool;
|
||||||
|
|
||||||
|
|
@ -281,6 +285,16 @@ begin
|
||||||
result := biggestInt(biggestUInt(a) shr biggestUInt(b));
|
result := biggestInt(biggestUInt(a) shr biggestUInt(b));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function shlU(a, b: Int32): Int32;
|
||||||
|
begin
|
||||||
|
result := Int32(UInt32(a) shl UInt32(b));
|
||||||
|
end;
|
||||||
|
|
||||||
|
function shrU(a, b: int32): int32;
|
||||||
|
begin
|
||||||
|
result := Int32(UInt32(a) shr UInt32(b));
|
||||||
|
end;
|
||||||
|
|
||||||
function ltU(a, b: biggestInt): bool;
|
function ltU(a, b: biggestInt): bool;
|
||||||
begin
|
begin
|
||||||
result := biggestUInt(a) < biggestUInt(b);
|
result := biggestUInt(a) < biggestUInt(b);
|
||||||
|
|
|
||||||
|
|
@ -31,10 +31,10 @@ const
|
||||||
//cog.outl('VersionMinor = %s;' % ver[1])
|
//cog.outl('VersionMinor = %s;' % ver[1])
|
||||||
//cog.outl('VersionPatch = %s;' % ver[2])
|
//cog.outl('VersionPatch = %s;' % ver[2])
|
||||||
//]]]
|
//]]]
|
||||||
VersionAsString = '0.7.2';
|
VersionAsString = '0.7.4';
|
||||||
VersionMajor = 0;
|
VersionMajor = 0;
|
||||||
VersionMinor = 7;
|
VersionMinor = 7;
|
||||||
VersionPatch = 2;
|
VersionPatch = 4;
|
||||||
//[[[[end]]]]
|
//[[[[end]]]]
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
|
||||||
|
|
@ -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.
|
|
||||||
|
|
||||||
|
|
@ -201,6 +201,12 @@ begin
|
||||||
if startsWith(dir, prefix) then begin
|
if startsWith(dir, prefix) then begin
|
||||||
result := ncopy(dir, length(prefix) + strStart); exit
|
result := ncopy(dir, length(prefix) + strStart); exit
|
||||||
end;
|
end;
|
||||||
|
prefix := projectPath +{&} dirSep;
|
||||||
|
//writeln(output, prefix);
|
||||||
|
//writeln(output, dir);
|
||||||
|
if startsWith(dir, prefix) then begin
|
||||||
|
result := ncopy(dir, length(prefix) + strStart); exit
|
||||||
|
end;
|
||||||
result := dir
|
result := dir
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
@ -209,7 +215,7 @@ var
|
||||||
head, tail: string;
|
head, tail: string;
|
||||||
begin
|
begin
|
||||||
splitPath(path, head, tail);
|
splitPath(path, head, tail);
|
||||||
result := joinPath([projectPath, genSubDir, shortenDir(head),
|
result := joinPath([projectPath, genSubDir, shortenDir(head +{&} dirSep),
|
||||||
changeFileExt(tail, ext)])
|
changeFileExt(tail, ext)])
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
@ -219,9 +225,11 @@ var
|
||||||
head, tail, subdir: string;
|
head, tail, subdir: string;
|
||||||
begin
|
begin
|
||||||
splitPath(f, head, tail);
|
splitPath(f, head, tail);
|
||||||
subdir := joinPath([projectPath, genSubDir, shortenDir(head)]);
|
subdir := joinPath([projectPath, genSubDir, shortenDir(head +{&} dirSep)]);
|
||||||
if createSubDir then
|
if createSubDir then begin
|
||||||
|
//Writeln(output, subdir);
|
||||||
createDir(subdir);
|
createDir(subdir);
|
||||||
|
end;
|
||||||
result := joinPath(subdir, tail)
|
result := joinPath(subdir, tail)
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ begin
|
||||||
else begin
|
else begin
|
||||||
result.cmd := '';
|
result.cmd := '';
|
||||||
for i := 1 to ParamCount() do
|
for i := 1 to ParamCount() do
|
||||||
result.cmd := result.cmd +{&} quoteIfSpaceExists(paramStr(i)) +{&} ' ';
|
result.cmd := result.cmd +{&} quoteIfContainsWhite(paramStr(i)) +{&} ' ';
|
||||||
{@ignore}
|
{@ignore}
|
||||||
result.cmd := result.cmd + #0;
|
result.cmd := result.cmd + #0;
|
||||||
{@emit}
|
{@emit}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ unit passaux;
|
||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
nsystem, strutils, ast, passes, msgs, options;
|
nsystem, strutils, ast, astalgo, passes, msgs, options;
|
||||||
|
|
||||||
function verbosePass: TPass;
|
function verbosePass: TPass;
|
||||||
function cleanupPass: TPass;
|
function cleanupPass: TPass;
|
||||||
|
|
@ -50,6 +50,8 @@ var
|
||||||
s: PSym;
|
s: PSym;
|
||||||
begin
|
begin
|
||||||
result := n;
|
result := n;
|
||||||
|
// we cannot clean up if dead code elimination is activated
|
||||||
|
if (optDeadCodeElim in gGlobalOptions) then exit;
|
||||||
case n.kind of
|
case n.kind of
|
||||||
nkStmtList: begin
|
nkStmtList: begin
|
||||||
for i := 0 to sonsLen(n)-1 do {@discard} cleanup(c, n.sons[i]);
|
for i := 0 to sonsLen(n)-1 do {@discard} cleanup(c, n.sons[i]);
|
||||||
|
|
@ -57,7 +59,8 @@ begin
|
||||||
nkProcDef: begin
|
nkProcDef: begin
|
||||||
if (n.sons[namePos].kind = nkSym) then begin
|
if (n.sons[namePos].kind = nkSym) then begin
|
||||||
s := n.sons[namePos].sym;
|
s := n.sons[namePos].sym;
|
||||||
if not astNeeded(s) then s.ast.sons[codePos] := nil; // free the memory
|
if not (sfDeadCodeElim in getModule(s).flags) and
|
||||||
|
not astNeeded(s) then s.ast.sons[codePos] := nil; // free the memory
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else begin end;
|
else begin end;
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ uses
|
||||||
|
|
||||||
type
|
type
|
||||||
TSystemOS = (
|
TSystemOS = (
|
||||||
// Also add OS for in initialization section and alias conditionals to
|
// Also add OS in initialization section and alias conditionals to
|
||||||
// condsyms (end of module).
|
// condsyms (end of module).
|
||||||
osNone,
|
osNone,
|
||||||
osDos,
|
osDos,
|
||||||
|
|
|
||||||
317
nim/pnimsyn.pas
317
nim/pnimsyn.pas
|
|
@ -9,7 +9,7 @@
|
||||||
unit pnimsyn;
|
unit pnimsyn;
|
||||||
|
|
||||||
// This module implements the parser of the standard Nimrod representation.
|
// This module implements the parser of the standard Nimrod representation.
|
||||||
// The parser is strictly reflects the grammar ("doc/grammar.txt"); however
|
// The parser strictly reflects the grammar ("doc/grammar.txt"); however
|
||||||
// it uses several helper routines to keep the parser small. A special
|
// it uses several helper routines to keep the parser small. A special
|
||||||
// efficient algorithm is used for the precedence levels. The parser here can
|
// efficient algorithm is used for the precedence levels. The parser here can
|
||||||
// be seen as a refinement of the grammar, as it specifies how the AST is build
|
// be seen as a refinement of the grammar, as it specifies how the AST is build
|
||||||
|
|
@ -98,15 +98,21 @@ end;
|
||||||
|
|
||||||
// ---------------- parser helpers --------------------------------------------
|
// ---------------- parser helpers --------------------------------------------
|
||||||
|
|
||||||
|
procedure parMessage(const p: TParser; const msg: TMsgKind;
|
||||||
|
const arg: string = '');
|
||||||
|
begin
|
||||||
|
lexMessage(p.lex^, msg, arg);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure skipComment(var p: TParser; node: PNode);
|
procedure skipComment(var p: TParser; node: PNode);
|
||||||
begin
|
begin
|
||||||
if p.tok.tokType = tkComment then begin
|
if p.tok.tokType = tkComment then begin
|
||||||
if node <> nil then begin
|
if node <> nil then begin
|
||||||
if node.comment = snil then node.comment := '';
|
if node.comment = snil then node.comment := '';
|
||||||
node.comment := node.comment +{&} p.tok.literal;
|
add(node.comment, p.tok.literal);
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
assert(false);
|
parMessage(p, errInternal, 'skipComment');
|
||||||
getTok(p);
|
getTok(p);
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
|
|
@ -116,6 +122,11 @@ begin
|
||||||
if p.tok.tokType = tkInd then getTok(p)
|
if p.tok.tokType = tkInd then getTok(p)
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure optSad(var p: TParser);
|
||||||
|
begin
|
||||||
|
if p.tok.tokType = tkSad then getTok(p)
|
||||||
|
end;
|
||||||
|
|
||||||
procedure optInd(var p: TParser; n: PNode);
|
procedure optInd(var p: TParser; n: PNode);
|
||||||
begin
|
begin
|
||||||
skipComment(p, n);
|
skipComment(p, n);
|
||||||
|
|
@ -146,12 +157,6 @@ begin
|
||||||
else lexMessage(p.lex^, errTokenExpected, TokTypeToStr[tokType])
|
else lexMessage(p.lex^, errTokenExpected, TokTypeToStr[tokType])
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure parMessage(const p: TParser; const msg: TMsgKind;
|
|
||||||
const arg: string = '');
|
|
||||||
begin
|
|
||||||
lexMessage(p.lex^, msg, arg);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function parLineInfo(const p: TParser): TLineInfo;
|
function parLineInfo(const p: TParser): TLineInfo;
|
||||||
begin
|
begin
|
||||||
result := getLineInfo(p.lex^)
|
result := getLineInfo(p.lex^)
|
||||||
|
|
@ -385,7 +390,7 @@ begin
|
||||||
result := newNodeP(nkExprEqExpr, p);
|
result := newNodeP(nkExprEqExpr, p);
|
||||||
addSon(result, a);
|
addSon(result, a);
|
||||||
getTok(p);
|
getTok(p);
|
||||||
optInd(p, result);
|
//optInd(p, result);
|
||||||
case p.tok.tokType of
|
case p.tok.tokType of
|
||||||
tkVar, tkRef, tkPtr, tkProc:
|
tkVar, tkRef, tkPtr, tkProc:
|
||||||
addSon(result, parseTypeDescK(p));
|
addSon(result, parseTypeDescK(p));
|
||||||
|
|
@ -413,21 +418,16 @@ begin
|
||||||
addSon(result, first);
|
addSon(result, first);
|
||||||
getTok(p);
|
getTok(p);
|
||||||
optInd(p, result);
|
optInd(p, result);
|
||||||
while true do begin
|
while (p.tok.tokType <> tkBracketRi) and (p.tok.tokType <> tkEof)
|
||||||
if p.tok.tokType = tkBracketRi then begin
|
and (p.tok.tokType <> tkSad) do begin
|
||||||
getTok(p); break
|
|
||||||
end;
|
|
||||||
if p.tok.tokType = tkEof then begin
|
|
||||||
parMessage(p, errTokenExpected, TokTypeToStr[tkBracketRi]); break
|
|
||||||
end;
|
|
||||||
a := namedTypeOrExpr(p);
|
a := namedTypeOrExpr(p);
|
||||||
optInd(p, a);
|
addSon(result, a);
|
||||||
if p.tok.tokType = tkComma then begin
|
if p.tok.tokType <> tkComma then break;
|
||||||
getTok(p);
|
getTok(p);
|
||||||
optInd(p, a)
|
optInd(p, a)
|
||||||
end;
|
end;
|
||||||
addSon(result, a);
|
optSad(p);
|
||||||
end;
|
eat(p, tkBracketRi);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function exprColonEqExpr(var p: TParser; kind: TNodeKind;
|
function exprColonEqExpr(var p: TParser; kind: TNodeKind;
|
||||||
|
|
@ -439,7 +439,7 @@ begin
|
||||||
if p.tok.tokType = tok then begin
|
if p.tok.tokType = tok then begin
|
||||||
result := newNodeP(kind, p);
|
result := newNodeP(kind, p);
|
||||||
getTok(p);
|
getTok(p);
|
||||||
optInd(p, result);
|
//optInd(p, result);
|
||||||
addSon(result, a);
|
addSon(result, a);
|
||||||
addSon(result, parseExpr(p));
|
addSon(result, parseExpr(p));
|
||||||
end
|
end
|
||||||
|
|
@ -454,21 +454,14 @@ var
|
||||||
begin
|
begin
|
||||||
getTok(p);
|
getTok(p);
|
||||||
optInd(p, result);
|
optInd(p, result);
|
||||||
while true do begin
|
while (p.tok.tokType <> endTok) and (p.tok.tokType <> tkEof) do begin
|
||||||
if p.tok.tokType = endTok then begin
|
|
||||||
getTok(p); break
|
|
||||||
end;
|
|
||||||
if p.tok.tokType = tkEof then begin
|
|
||||||
parMessage(p, errTokenExpected, TokTypeToStr[endtok]); break
|
|
||||||
end;
|
|
||||||
a := exprColonEqExpr(p, elemKind, sepTok);
|
a := exprColonEqExpr(p, elemKind, sepTok);
|
||||||
optInd(p, a);
|
addSon(result, a);
|
||||||
if p.tok.tokType = tkComma then begin
|
if p.tok.tokType <> tkComma then break;
|
||||||
getTok(p);
|
getTok(p);
|
||||||
optInd(p, a)
|
optInd(p, a)
|
||||||
end;
|
end;
|
||||||
addSon(result, a);
|
eat(p, endTok);
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function qualifiedIdent(var p: TParser): PNode;
|
function qualifiedIdent(var p: TParser): PNode;
|
||||||
|
|
@ -476,7 +469,7 @@ var
|
||||||
a: PNode;
|
a: PNode;
|
||||||
begin
|
begin
|
||||||
result := parseSymbol(p);
|
result := parseSymbol(p);
|
||||||
optInd(p, result);
|
//optInd(p, result);
|
||||||
if p.tok.tokType = tkDot then begin
|
if p.tok.tokType = tkDot then begin
|
||||||
getTok(p);
|
getTok(p);
|
||||||
optInd(p, result);
|
optInd(p, result);
|
||||||
|
|
@ -494,28 +487,41 @@ var
|
||||||
begin
|
begin
|
||||||
getTok(p);
|
getTok(p);
|
||||||
optInd(p, result);
|
optInd(p, result);
|
||||||
while true do begin
|
while (p.tok.tokType <> endTok) and (p.tok.tokType <> tkEof) do begin
|
||||||
if p.tok.tokType = endTok then begin
|
|
||||||
getTok(p); break
|
|
||||||
end;
|
|
||||||
if p.tok.tokType = tkEof then begin
|
|
||||||
parMessage(p, errTokenExpected, TokTypeToStr[endtok]); break
|
|
||||||
end;
|
|
||||||
a := qualifiedIdent(p);
|
a := qualifiedIdent(p);
|
||||||
optInd(p, a);
|
addSon(result, a);
|
||||||
if p.tok.tokType = tkComma then begin
|
//optInd(p, a);
|
||||||
|
if p.tok.tokType <> tkComma then break;
|
||||||
getTok(p);
|
getTok(p);
|
||||||
optInd(p, a)
|
optInd(p, a)
|
||||||
end;
|
end;
|
||||||
|
eat(p, endTok);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure exprColonEqExprListAux(var p: TParser; elemKind: TNodeKind;
|
||||||
|
endTok, sepTok: TTokType; result: PNode);
|
||||||
|
var
|
||||||
|
a: PNode;
|
||||||
|
begin
|
||||||
|
getTok(p);
|
||||||
|
optInd(p, result);
|
||||||
|
while (p.tok.tokType <> endTok) and (p.tok.tokType <> tkEof)
|
||||||
|
and (p.tok.tokType <> tkSad) do begin
|
||||||
|
a := exprColonEqExpr(p, elemKind, sepTok);
|
||||||
addSon(result, a);
|
addSon(result, a);
|
||||||
|
if p.tok.tokType <> tkComma then break;
|
||||||
|
getTok(p);
|
||||||
|
optInd(p, a)
|
||||||
end;
|
end;
|
||||||
|
optSad(p);
|
||||||
|
eat(p, endTok);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function exprColonEqExprList(var p: TParser; kind, elemKind: TNodeKind;
|
function exprColonEqExprList(var p: TParser; kind, elemKind: TNodeKind;
|
||||||
endTok, sepTok: TTokType): PNode;
|
endTok, sepTok: TTokType): PNode;
|
||||||
begin
|
begin
|
||||||
result := newNodeP(kind, p);
|
result := newNodeP(kind, p);
|
||||||
exprListAux(p, elemKind, endTok, sepTok, result);
|
exprColonEqExprListAux(p, elemKind, endTok, sepTok, result);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function parseCast(var p: TParser): PNode;
|
function parseCast(var p: TParser): PNode;
|
||||||
|
|
@ -525,12 +531,12 @@ begin
|
||||||
eat(p, tkBracketLe);
|
eat(p, tkBracketLe);
|
||||||
optInd(p, result);
|
optInd(p, result);
|
||||||
addSon(result, parseTypeDesc(p));
|
addSon(result, parseTypeDesc(p));
|
||||||
optInd(p, result);
|
optSad(p);
|
||||||
eat(p, tkBracketRi);
|
eat(p, tkBracketRi);
|
||||||
eat(p, tkParLe);
|
eat(p, tkParLe);
|
||||||
optInd(p, result);
|
optInd(p, result);
|
||||||
addSon(result, parseExpr(p));
|
addSon(result, parseExpr(p));
|
||||||
optInd(p, result);
|
optSad(p);
|
||||||
eat(p, tkParRi);
|
eat(p, tkParRi);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
@ -541,7 +547,7 @@ begin
|
||||||
eat(p, tkParLe);
|
eat(p, tkParLe);
|
||||||
optInd(p, result);
|
optInd(p, result);
|
||||||
addSon(result, parseExpr(p));
|
addSon(result, parseExpr(p));
|
||||||
optInd(p, result);
|
optSad(p);
|
||||||
eat(p, tkParRi);
|
eat(p, tkParRi);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
@ -667,7 +673,7 @@ begin
|
||||||
a := result;
|
a := result;
|
||||||
result := newNodeP(nkCall, p);
|
result := newNodeP(nkCall, p);
|
||||||
addSon(result, a);
|
addSon(result, a);
|
||||||
exprListAux(p, nkExprEqExpr, tkParRi, tkEquals, result);
|
exprColonEqExprListAux(p, nkExprEqExpr, tkParRi, tkEquals, result);
|
||||||
end;
|
end;
|
||||||
tkDot: begin
|
tkDot: begin
|
||||||
a := result;
|
a := result;
|
||||||
|
|
@ -709,8 +715,9 @@ begin
|
||||||
opNode := newIdentNodeP(op.ident, p);
|
opNode := newIdentNodeP(op.ident, p);
|
||||||
// skip operator:
|
// skip operator:
|
||||||
getTok(p);
|
getTok(p);
|
||||||
skipComment(p, opNode);
|
//skipComment(p, opNode);
|
||||||
skipInd(p);
|
//skipInd(p);
|
||||||
|
optInd(p, opNode);
|
||||||
|
|
||||||
// read sub-expression with higher priority
|
// read sub-expression with higher priority
|
||||||
nextop := lowestExprAux(p, v2, opPred);
|
nextop := lowestExprAux(p, v2, opPred);
|
||||||
|
|
@ -739,12 +746,12 @@ begin
|
||||||
while true do begin
|
while true do begin
|
||||||
getTok(p); // skip `if`, `elif`
|
getTok(p); // skip `if`, `elif`
|
||||||
branch := newNodeP(nkElifExpr, p);
|
branch := newNodeP(nkElifExpr, p);
|
||||||
optInd(p, branch);
|
//optInd(p, branch);
|
||||||
addSon(branch, parseExpr(p));
|
addSon(branch, parseExpr(p));
|
||||||
eat(p, tkColon);
|
eat(p, tkColon);
|
||||||
optInd(p, branch);
|
//optInd(p, branch);
|
||||||
addSon(branch, parseExpr(p));
|
addSon(branch, parseExpr(p));
|
||||||
optInd(p, branch);
|
//optInd(p, branch);
|
||||||
addSon(result, branch);
|
addSon(result, branch);
|
||||||
if p.tok.tokType <> tkElif then break
|
if p.tok.tokType <> tkElif then break
|
||||||
end;
|
end;
|
||||||
|
|
@ -770,31 +777,33 @@ var
|
||||||
begin
|
begin
|
||||||
result := newNodeP(nkPragma, p);
|
result := newNodeP(nkPragma, p);
|
||||||
getTok(p);
|
getTok(p);
|
||||||
while true do begin
|
optInd(p, result);
|
||||||
skipComment(p, result);
|
while (p.tok.tokType <> tkCurlyDotRi) and (p.tok.tokType <> tkCurlyRi)
|
||||||
skipInd(p);
|
and (p.tok.tokType <> tkEof) and (p.tok.tokType <> tkSad) do begin
|
||||||
case p.tok.TokType of
|
|
||||||
tkCurlyDotRi, tkCurlyRi: begin
|
|
||||||
getTok(p); // skip } or .}
|
|
||||||
break
|
|
||||||
end;
|
|
||||||
tkEof: begin
|
|
||||||
parMessage(p, errTokenExpected, '.}');
|
|
||||||
break
|
|
||||||
end
|
|
||||||
else begin
|
|
||||||
a := exprColonEqExpr(p, nkExprColonExpr, tkColon);
|
a := exprColonEqExpr(p, nkExprColonExpr, tkColon);
|
||||||
addSon(result, a);
|
addSon(result, a);
|
||||||
if p.tok.tokType = tkComma then begin
|
if p.tok.tokType = tkComma then begin
|
||||||
getTok(p);
|
getTok(p);
|
||||||
skipComment(p, a)
|
optInd(p, a)
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
end;
|
||||||
|
optSad(p);
|
||||||
|
if (p.tok.tokType = tkCurlyDotRi) or (p.tok.tokType = tkCurlyRi) then
|
||||||
|
getTok(p)
|
||||||
|
else
|
||||||
|
parMessage(p, errTokenExpected, '.}');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// ---------------------- statement parser ------------------------------------
|
// ---------------------- statement parser ------------------------------------
|
||||||
|
function isExprStart(const p: TParser): bool;
|
||||||
|
begin
|
||||||
|
case p.tok.tokType of
|
||||||
|
tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkLambda,
|
||||||
|
tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit: result := true;
|
||||||
|
else result := false;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function parseExprStmt(var p: TParser): PNode;
|
function parseExprStmt(var p: TParser): PNode;
|
||||||
var
|
var
|
||||||
a, b, e: PNode;
|
a, b, e: PNode;
|
||||||
|
|
@ -813,16 +822,16 @@ begin
|
||||||
result.info := a.info;
|
result.info := a.info;
|
||||||
addSon(result, a);
|
addSon(result, a);
|
||||||
while true do begin
|
while true do begin
|
||||||
case p.tok.tokType of
|
(*case p.tok.tokType of
|
||||||
tkColon, tkInd, tkSad, tkDed, tkEof, tkComment: break;
|
tkColon, tkInd, tkSad, tkDed, tkEof, tkComment: break;
|
||||||
else begin end
|
else begin end
|
||||||
end;
|
end;*)
|
||||||
|
if not isExprStart(p) then break;
|
||||||
e := parseExpr(p);
|
e := parseExpr(p);
|
||||||
if p.tok.tokType = tkComma then begin
|
|
||||||
getTok(p);
|
|
||||||
skipComment(p, e)
|
|
||||||
end;
|
|
||||||
addSon(result, e);
|
addSon(result, e);
|
||||||
|
if p.tok.tokType <> tkComma then break;
|
||||||
|
getTok(p);
|
||||||
|
optInd(p, a);
|
||||||
end;
|
end;
|
||||||
if sonsLen(result) <= 1 then result := a
|
if sonsLen(result) <= 1 then result := a
|
||||||
else a := result;
|
else a := result;
|
||||||
|
|
@ -897,7 +906,7 @@ begin
|
||||||
break
|
break
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
optInd(p, a);
|
//optInd(p, a);
|
||||||
if p.tok.tokType = tkAs then begin
|
if p.tok.tokType = tkAs then begin
|
||||||
getTok(p);
|
getTok(p);
|
||||||
optInd(p, a);
|
optInd(p, a);
|
||||||
|
|
@ -906,12 +915,11 @@ begin
|
||||||
addSon(a, b);
|
addSon(a, b);
|
||||||
addSon(a, parseSymbol(p));
|
addSon(a, parseSymbol(p));
|
||||||
end;
|
end;
|
||||||
if p.tok.tokType = tkComma then begin
|
addSon(result, a);
|
||||||
|
if p.tok.tokType <> tkComma then break;
|
||||||
getTok(p);
|
getTok(p);
|
||||||
optInd(p, a)
|
optInd(p, a)
|
||||||
end;
|
end;
|
||||||
addSon(result, a);
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function parseIncludeStmt(var p: TParser): PNode;
|
function parseIncludeStmt(var p: TParser): PNode;
|
||||||
|
|
@ -942,13 +950,12 @@ begin
|
||||||
break
|
break
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
optInd(p, a);
|
addSon(result, a);
|
||||||
if p.tok.tokType = tkComma then begin
|
//optInd(p, a);
|
||||||
|
if p.tok.tokType <> tkComma then break;
|
||||||
getTok(p);
|
getTok(p);
|
||||||
optInd(p, a)
|
optInd(p, a)
|
||||||
end;
|
end;
|
||||||
addSon(result, a);
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function parseFromStmt(var p: TParser): PNode;
|
function parseFromStmt(var p: TParser): PNode;
|
||||||
|
|
@ -977,7 +984,7 @@ begin
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
addSon(result, a);
|
addSon(result, a);
|
||||||
optInd(p, a);
|
//optInd(p, a);
|
||||||
eat(p, tkImport);
|
eat(p, tkImport);
|
||||||
optInd(p, result);
|
optInd(p, result);
|
||||||
while true do begin
|
while true do begin
|
||||||
|
|
@ -989,13 +996,12 @@ begin
|
||||||
break
|
break
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
optInd(p, a);
|
//optInd(p, a);
|
||||||
if p.tok.tokType = tkComma then begin
|
addSon(result, a);
|
||||||
|
if p.tok.tokType <> tkComma then break;
|
||||||
getTok(p);
|
getTok(p);
|
||||||
optInd(p, a)
|
optInd(p, a)
|
||||||
end;
|
end;
|
||||||
addSon(result, a);
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function parseReturnOrRaise(var p: TParser; kind: TNodeKind): PNode;
|
function parseReturnOrRaise(var p: TParser; kind: TNodeKind): PNode;
|
||||||
|
|
@ -1074,6 +1080,7 @@ begin
|
||||||
result := newNodeP(nkCaseStmt, p);
|
result := newNodeP(nkCaseStmt, p);
|
||||||
getTok(p);
|
getTok(p);
|
||||||
addSon(result, parseExpr(p));
|
addSon(result, parseExpr(p));
|
||||||
|
if p.tok.tokType = tkColon then getTok(p);
|
||||||
skipComment(p, result);
|
skipComment(p, result);
|
||||||
inElif := false;
|
inElif := false;
|
||||||
while true do begin
|
while true do begin
|
||||||
|
|
@ -1145,22 +1152,15 @@ begin
|
||||||
result := newNodeP(nkForStmt, p);
|
result := newNodeP(nkForStmt, p);
|
||||||
getTok(p);
|
getTok(p);
|
||||||
optInd(p, result);
|
optInd(p, result);
|
||||||
while true do begin
|
|
||||||
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);
|
a := parseSymbol(p);
|
||||||
if a = nil then break;
|
addSon(result, a);
|
||||||
|
while p.tok.tokType = tkComma do begin
|
||||||
|
getTok(p);
|
||||||
optInd(p, a);
|
optInd(p, a);
|
||||||
if p.tok.tokType = tkComma then begin
|
a := parseSymbol(p);
|
||||||
getTok(p); optInd(p, a)
|
|
||||||
end;
|
|
||||||
addSon(result, a);
|
addSon(result, a);
|
||||||
end;
|
end;
|
||||||
|
eat(p, tkIn);
|
||||||
addSon(result, exprColonEqExpr(p, nkRange, tkDotDot));
|
addSon(result, exprColonEqExpr(p, nkRange, tkDotDot));
|
||||||
eat(p, tkColon);
|
eat(p, tkColon);
|
||||||
skipComment(p, result);
|
skipComment(p, result);
|
||||||
|
|
@ -1246,13 +1246,12 @@ begin
|
||||||
if a = nil then exit;
|
if a = nil then exit;
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
optInd(p, a);
|
addSon(result, a);
|
||||||
if p.tok.tokType = tkComma then begin
|
//optInd(p, a);
|
||||||
|
if p.tok.tokType <> tkComma then break;
|
||||||
getTok(p);
|
getTok(p);
|
||||||
optInd(p, a)
|
optInd(p, a)
|
||||||
end;
|
end;
|
||||||
addSon(result, a);
|
|
||||||
end;
|
|
||||||
if p.tok.tokType = tkColon then begin
|
if p.tok.tokType = tkColon then begin
|
||||||
getTok(p); optInd(p, result);
|
getTok(p); optInd(p, result);
|
||||||
addSon(result, parseTypeDesc(p));
|
addSon(result, parseTypeDesc(p));
|
||||||
|
|
@ -1282,15 +1281,17 @@ begin
|
||||||
while true do begin
|
while true do begin
|
||||||
case p.tok.tokType of
|
case p.tok.tokType of
|
||||||
tkSymbol, tkAccent: a := parseIdentColonEquals(p, false);
|
tkSymbol, tkAccent: a := parseIdentColonEquals(p, false);
|
||||||
tkParRi: begin getTok(p); break end;
|
tkParRi: break;
|
||||||
else begin parMessage(p, errTokenExpected, ')'+''); break; end;
|
else begin parMessage(p, errTokenExpected, ')'+''); break; end;
|
||||||
end;
|
end;
|
||||||
optInd(p, a);
|
//optInd(p, a);
|
||||||
if p.tok.tokType = tkComma then begin
|
|
||||||
getTok(p); optInd(p, a)
|
|
||||||
end;
|
|
||||||
addSon(result, a);
|
addSon(result, a);
|
||||||
|
if p.tok.tokType <> tkComma then break;
|
||||||
|
getTok(p);
|
||||||
|
optInd(p, a)
|
||||||
end;
|
end;
|
||||||
|
optSad(p);
|
||||||
|
eat(p, tkParRi);
|
||||||
end;
|
end;
|
||||||
if p.tok.tokType = tkColon then begin
|
if p.tok.tokType = tkColon then begin
|
||||||
getTok(p);
|
getTok(p);
|
||||||
|
|
@ -1336,18 +1337,15 @@ begin
|
||||||
getTok(p);
|
getTok(p);
|
||||||
eat(p, tkBracketLe);
|
eat(p, tkBracketLe);
|
||||||
optInd(p, result);
|
optInd(p, result);
|
||||||
while true do begin
|
while (p.tok.tokType = tkSymbol) or (p.tok.tokType = tkAccent) do begin
|
||||||
case p.tok.tokType of
|
a := parseIdentColonEquals(p, false);
|
||||||
tkSymbol, tkAccent: a := parseIdentColonEquals(p, false);
|
|
||||||
tkBracketRi: begin getTok(p); break end;
|
|
||||||
else begin parMessage(p, errTokenExpected, ']'+''); break; end;
|
|
||||||
end;
|
|
||||||
optInd(p, a);
|
|
||||||
if p.tok.tokType = tkComma then begin
|
|
||||||
getTok(p); optInd(p, a)
|
|
||||||
end;
|
|
||||||
addSon(result, a);
|
addSon(result, a);
|
||||||
|
if p.tok.tokType <> tkComma then break;
|
||||||
|
getTok(p);
|
||||||
|
optInd(p, a)
|
||||||
end;
|
end;
|
||||||
|
optSad(p);
|
||||||
|
eat(p, tkBracketRi);
|
||||||
end;
|
end;
|
||||||
else begin
|
else begin
|
||||||
InternalError(parLineInfo(p), 'pnimsyn.parseTypeDescK');
|
InternalError(parLineInfo(p), 'pnimsyn.parseTypeDescK');
|
||||||
|
|
@ -1389,18 +1387,15 @@ begin
|
||||||
result := newNodeP(nkGenericParams, p);
|
result := newNodeP(nkGenericParams, p);
|
||||||
getTok(p);
|
getTok(p);
|
||||||
optInd(p, result);
|
optInd(p, result);
|
||||||
while true do begin
|
while (p.tok.tokType = tkSymbol) or (p.tok.tokType = tkAccent) do begin
|
||||||
case p.tok.tokType of
|
a := parseGenericParam(p);
|
||||||
tkSymbol, tkAccent: a := parseGenericParam(p);
|
|
||||||
tkBracketRi: begin getTok(p); break end;
|
|
||||||
else begin parMessage(p, errTokenExpected, ']'+''); break; end;
|
|
||||||
end;
|
|
||||||
optInd(p, a);
|
|
||||||
if p.tok.tokType = tkComma then begin
|
|
||||||
getTok(p); optInd(p, a)
|
|
||||||
end;
|
|
||||||
addSon(result, a);
|
addSon(result, a);
|
||||||
|
if p.tok.tokType <> tkComma then break;
|
||||||
|
getTok(p);
|
||||||
|
optInd(p, a)
|
||||||
end;
|
end;
|
||||||
|
optSad(p);
|
||||||
|
eat(p, tkBracketRi);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function parseRoutine(var p: TParser; kind: TNodeKind): PNode;
|
function parseRoutine(var p: TParser; kind: TNodeKind): PNode;
|
||||||
|
|
@ -1484,7 +1479,8 @@ begin
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end;
|
||||||
|
popInd(p.lex^);
|
||||||
end;
|
end;
|
||||||
tkSymbol, tkAccent: addSon(result, defparser(p));
|
tkSymbol, tkAccent: addSon(result, defparser(p));
|
||||||
else parMessage(p, errIdentifierExpected, tokToStr(p.tok));
|
else parMessage(p, errIdentifierExpected, tokToStr(p.tok));
|
||||||
|
|
@ -1628,7 +1624,8 @@ begin
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end;
|
||||||
|
popInd(p.lex^);
|
||||||
end;
|
end;
|
||||||
tkWhen: result := parseRecordWhen(p);
|
tkWhen: result := parseRecordWhen(p);
|
||||||
tkCase: result := parseRecordCase(p);
|
tkCase: result := parseRecordCase(p);
|
||||||
|
|
@ -1688,8 +1685,33 @@ begin
|
||||||
indAndComment(p, result); // special extension!
|
indAndComment(p, result); // special extension!
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function parseVarTuple(var p: TParser): PNode;
|
||||||
|
var
|
||||||
|
a: PNode;
|
||||||
|
begin
|
||||||
|
result := newNodeP(nkVarTuple, p);
|
||||||
|
getTok(p); // skip '('
|
||||||
|
optInd(p, result);
|
||||||
|
while (p.tok.tokType = tkSymbol) or (p.tok.tokType = tkAccent) do begin
|
||||||
|
a := identWithPragma(p);
|
||||||
|
addSon(result, a);
|
||||||
|
if p.tok.tokType <> tkComma then break;
|
||||||
|
getTok(p);
|
||||||
|
optInd(p, a)
|
||||||
|
end;
|
||||||
|
addSon(result, nil); // no type desc
|
||||||
|
optSad(p);
|
||||||
|
eat(p, tkParRi);
|
||||||
|
eat(p, tkEquals);
|
||||||
|
optInd(p, result);
|
||||||
|
addSon(result, parseExpr(p));
|
||||||
|
end;
|
||||||
|
|
||||||
function parseVariable(var p: TParser): PNode;
|
function parseVariable(var p: TParser): PNode;
|
||||||
begin
|
begin
|
||||||
|
if p.tok.tokType = tkParLe then
|
||||||
|
result := parseVarTuple(p)
|
||||||
|
else
|
||||||
result := parseIdentColonEquals(p, true);
|
result := parseIdentColonEquals(p, true);
|
||||||
indAndComment(p, result); // special extension!
|
indAndComment(p, result); // special extension!
|
||||||
end;
|
end;
|
||||||
|
|
@ -1708,9 +1730,14 @@ begin
|
||||||
tkFrom: result := parseFromStmt(p);
|
tkFrom: result := parseFromStmt(p);
|
||||||
tkInclude: result := parseIncludeStmt(p);
|
tkInclude: result := parseIncludeStmt(p);
|
||||||
tkComment: result := newCommentStmt(p);
|
tkComment: result := newCommentStmt(p);
|
||||||
//tkSad, tkInd, tkDed: assert(false);
|
else begin
|
||||||
else result := parseExprStmt(p)
|
if isExprStart(p) then
|
||||||
|
result := parseExprStmt(p)
|
||||||
|
else
|
||||||
|
result := nil;
|
||||||
|
end
|
||||||
end;
|
end;
|
||||||
|
if result <> nil then
|
||||||
skipComment(p, result);
|
skipComment(p, result);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
@ -1738,6 +1765,8 @@ begin
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function parseStmt(var p: TParser): PNode;
|
function parseStmt(var p: TParser): PNode;
|
||||||
|
var
|
||||||
|
a: PNode;
|
||||||
begin
|
begin
|
||||||
if p.tok.tokType = tkInd then begin
|
if p.tok.tokType = tkInd then begin
|
||||||
result := newNodeP(nkStmtList, p);
|
result := newNodeP(nkStmtList, p);
|
||||||
|
|
@ -1748,10 +1777,15 @@ begin
|
||||||
tkSad: getTok(p);
|
tkSad: getTok(p);
|
||||||
tkEof: break;
|
tkEof: break;
|
||||||
tkDed: begin getTok(p); break end;
|
tkDed: begin getTok(p); break end;
|
||||||
else addSon(result, complexOrSimpleStmt(p));
|
else begin
|
||||||
end;
|
a := complexOrSimpleStmt(p);
|
||||||
|
if a = nil then break;
|
||||||
|
addSon(result, a);
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end;
|
||||||
|
popInd(p.lex^);
|
||||||
|
end
|
||||||
else begin
|
else begin
|
||||||
// the case statement is only needed for better error messages:
|
// the case statement is only needed for better error messages:
|
||||||
case p.tok.tokType of
|
case p.tok.tokType of
|
||||||
|
|
@ -1762,7 +1796,7 @@ begin
|
||||||
end
|
end
|
||||||
else begin
|
else begin
|
||||||
result := simpleStmt(p);
|
result := simpleStmt(p);
|
||||||
skipComment(p, result);
|
if result = nil then parMessage(p, errExprExpected, tokToStr(p.tok));
|
||||||
if p.tok.tokType = tkSad then getTok(p);
|
if p.tok.tokType = tkSad then getTok(p);
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -1770,6 +1804,8 @@ begin
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function parseModule(var p: TParser): PNode;
|
function parseModule(var p: TParser): PNode;
|
||||||
|
var
|
||||||
|
a: PNode;
|
||||||
begin
|
begin
|
||||||
result := newNodeP(nkStmtList, p);
|
result := newNodeP(nkStmtList, p);
|
||||||
while true do begin
|
while true do begin
|
||||||
|
|
@ -1777,7 +1813,11 @@ begin
|
||||||
tkSad: getTok(p);
|
tkSad: getTok(p);
|
||||||
tkDed, tkInd: parMessage(p, errInvalidIndentation);
|
tkDed, tkInd: parMessage(p, errInvalidIndentation);
|
||||||
tkEof: break;
|
tkEof: break;
|
||||||
else addSon(result, complexOrSimpleStmt(p));
|
else begin
|
||||||
|
a := complexOrSimpleStmt(p);
|
||||||
|
if a = nil then parMessage(p, errExprExpected, tokToStr(p.tok));
|
||||||
|
addSon(result, a);
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
|
|
@ -1795,6 +1835,7 @@ begin
|
||||||
tkEof: break;
|
tkEof: break;
|
||||||
else begin
|
else begin
|
||||||
result := complexOrSimpleStmt(p);
|
result := complexOrSimpleStmt(p);
|
||||||
|
if result = nil then parMessage(p, errExprExpected, tokToStr(p.tok));
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -135,8 +135,8 @@ var
|
||||||
v: string;
|
v: string;
|
||||||
m: TMagic;
|
m: TMagic;
|
||||||
begin
|
begin
|
||||||
if not (sfSystemModule in c.module.flags) then
|
//if not (sfSystemModule in c.module.flags) then
|
||||||
liMessage(n.info, errMagicOnlyInSystem);
|
// liMessage(n.info, errMagicOnlyInSystem);
|
||||||
if n.kind <> nkExprColonExpr then
|
if n.kind <> nkExprColonExpr then
|
||||||
liMessage(n.info, errStringLiteralExpected);
|
liMessage(n.info, errStringLiteralExpected);
|
||||||
if n.sons[1].kind = nkIdent then v := n.sons[1].ident.s
|
if n.sons[1].kind = nkIdent then v := n.sons[1].ident.s
|
||||||
|
|
@ -172,6 +172,19 @@ begin
|
||||||
liMessage(n.info, errOnOrOffExpected)
|
liMessage(n.info, errOnOrOffExpected)
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure pragmaDeadCodeElim(c: PContext; n: PNode);
|
||||||
|
begin
|
||||||
|
if (n.kind = nkExprColonExpr) and (n.sons[1].kind = nkIdent) then begin
|
||||||
|
case whichKeyword(n.sons[1].ident) of
|
||||||
|
wOn: include(c.module.flags, sfDeadCodeElim);
|
||||||
|
wOff: exclude(c.module.flags, sfDeadCodeElim);
|
||||||
|
else liMessage(n.info, errOnOrOffExpected)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
liMessage(n.info, errOnOrOffExpected)
|
||||||
|
end;
|
||||||
|
|
||||||
procedure processCallConv(c: PContext; n: PNode);
|
procedure processCallConv(c: PContext; n: PNode);
|
||||||
var
|
var
|
||||||
sw: TSpecialWord;
|
sw: TSpecialWord;
|
||||||
|
|
@ -466,6 +479,7 @@ begin
|
||||||
wVolatile: begin noVal(it); Include(sym.flags, sfVolatile); end;
|
wVolatile: begin noVal(it); Include(sym.flags, sfVolatile); end;
|
||||||
wRegister: begin noVal(it); include(sym.flags, sfRegister); end;
|
wRegister: begin noVal(it); include(sym.flags, sfRegister); end;
|
||||||
wThreadVar: begin noVal(it); include(sym.flags, sfThreadVar); end;
|
wThreadVar: begin noVal(it); include(sym.flags, sfThreadVar); end;
|
||||||
|
wDeadCodeElim: pragmaDeadCodeElim(c, it);
|
||||||
wMagic: processMagic(c, it, sym);
|
wMagic: processMagic(c, it, sym);
|
||||||
wCompileTime: begin
|
wCompileTime: begin
|
||||||
noVal(it);
|
noVal(it);
|
||||||
|
|
@ -612,7 +626,7 @@ begin
|
||||||
wHint, wWarning, wError, wFatal, wDefine, wUndef,
|
wHint, wWarning, wError, wFatal, wDefine, wUndef,
|
||||||
wCompile, wLink, wLinkSys, wPure,
|
wCompile, wLink, wLinkSys, wPure,
|
||||||
wPush, wPop, wFixupSystem, wBreakpoint, wCheckpoint,
|
wPush, wPop, wFixupSystem, wBreakpoint, wCheckpoint,
|
||||||
wPassL, wPassC]);
|
wPassL, wPassC, wDeadCodeElim]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure pragmaLambda(c: PContext; s: PSym; n: PNode);
|
procedure pragmaLambda(c: PContext; s: PSym; n: PNode);
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ uses
|
||||||
|
|
||||||
type
|
type
|
||||||
TRenderFlag = (renderNone, renderNoBody, renderNoComments,
|
TRenderFlag = (renderNone, renderNoBody, renderNoComments,
|
||||||
renderNoPragmas, renderIds);
|
renderDocComments, renderNoPragmas, renderIds);
|
||||||
TRenderFlags = set of TRenderFlag;
|
TRenderFlags = set of TRenderFlag;
|
||||||
|
|
||||||
TRenderTok = record
|
TRenderTok = record
|
||||||
|
|
@ -354,12 +354,20 @@ end;
|
||||||
const
|
const
|
||||||
Space = ' '+'';
|
Space = ' '+'';
|
||||||
|
|
||||||
|
function shouldRenderComment(var g: TSrcGen; n: PNode): bool;
|
||||||
|
begin
|
||||||
|
result := false;
|
||||||
|
if n.comment <> snil then
|
||||||
|
result := not (renderNoComments in g.flags) or
|
||||||
|
(renderDocComments in g.flags) and startsWith(n.comment, '##');
|
||||||
|
end;
|
||||||
|
|
||||||
procedure gcom(var g: TSrcGen; n: PNode);
|
procedure gcom(var g: TSrcGen; n: PNode);
|
||||||
var
|
var
|
||||||
ml: int;
|
ml: int;
|
||||||
begin
|
begin
|
||||||
assert(n <> nil);
|
assert(n <> nil);
|
||||||
if (n.comment <> snil) and not (renderNoComments in g.flags) then begin
|
if shouldRenderComment(g, n) then begin
|
||||||
if (g.pendingNL < 0) and (length(g.buf) > 0)
|
if (g.pendingNL < 0) and (length(g.buf) > 0)
|
||||||
and (g.buf[length(g.buf)] <> ' ') then
|
and (g.buf[length(g.buf)] <> ' ') then
|
||||||
put(g, tkSpaces, Space);
|
put(g, tkSpaces, Space);
|
||||||
|
|
@ -488,7 +496,7 @@ begin
|
||||||
nkAddr: result := lsub(n.sons[0])+length('addr()');
|
nkAddr: result := lsub(n.sons[0])+length('addr()');
|
||||||
nkHiddenAddr, nkHiddenDeref: result := lsub(n.sons[0]);
|
nkHiddenAddr, nkHiddenDeref: result := lsub(n.sons[0]);
|
||||||
nkCommand: result := lsub(n.sons[0])+lcomma(n, 1)+1;
|
nkCommand: result := lsub(n.sons[0])+lcomma(n, 1)+1;
|
||||||
nkExprEqExpr, nkDefaultTypeParam, nkAsgn: result := lsons(n)+3;
|
nkExprEqExpr, nkDefaultTypeParam, nkAsgn, nkFastAsgn: result := lsons(n)+3;
|
||||||
nkPar, nkCurly, nkBracket: result := lcomma(n)+2;
|
nkPar, nkCurly, nkBracket: result := lcomma(n)+2;
|
||||||
nkTupleTy: result := lcomma(n)+length('tuple[]');
|
nkTupleTy: result := lcomma(n)+length('tuple[]');
|
||||||
nkQualified, nkDotExpr: result := lsons(n)+1;
|
nkQualified, nkDotExpr: result := lsons(n)+1;
|
||||||
|
|
@ -502,6 +510,7 @@ begin
|
||||||
if n.sons[L-1] <> nil then
|
if n.sons[L-1] <> nil then
|
||||||
result := result + lsub(n.sons[L-1]) + 3;
|
result := result + lsub(n.sons[L-1]) + 3;
|
||||||
end;
|
end;
|
||||||
|
nkVarTuple: result := lcomma(n, 0, -3) + length('() = ') + lsub(lastSon(n));
|
||||||
nkChckRangeF: result := length('chckRangeF') + 2 + lcomma(n);
|
nkChckRangeF: result := length('chckRangeF') + 2 + lcomma(n);
|
||||||
nkChckRange64: result := length('chckRange64') + 2 + lcomma(n);
|
nkChckRange64: result := length('chckRange64') + 2 + lcomma(n);
|
||||||
nkChckRange: result := length('chckRange') + 2 + lcomma(n);
|
nkChckRange: result := length('chckRange') + 2 + lcomma(n);
|
||||||
|
|
@ -981,7 +990,7 @@ begin
|
||||||
put(g, tkSpaces, space);
|
put(g, tkSpaces, space);
|
||||||
gcomma(g, n, 1);
|
gcomma(g, n, 1);
|
||||||
end;
|
end;
|
||||||
nkExprEqExpr, nkDefaultTypeParam, nkAsgn: begin
|
nkExprEqExpr, nkDefaultTypeParam, nkAsgn, nkFastAsgn: begin
|
||||||
gsub(g, n.sons[0]);
|
gsub(g, n.sons[0]);
|
||||||
put(g, tkSpaces, Space);
|
put(g, tkSpaces, Space);
|
||||||
putWithSpace(g, tkEquals, '='+'');
|
putWithSpace(g, tkEquals, '='+'');
|
||||||
|
|
@ -1056,6 +1065,14 @@ begin
|
||||||
gsub(g, n.sons[L-1], c)
|
gsub(g, n.sons[L-1], c)
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
nkVarTuple: begin
|
||||||
|
put(g, tkParLe, '('+'');
|
||||||
|
gcomma(g, n, 0, -3);
|
||||||
|
put(g, tkParRi, ')'+'');
|
||||||
|
put(g, tkSpaces, Space);
|
||||||
|
putWithSpace(g, tkEquals, '='+'');
|
||||||
|
gsub(g, lastSon(n), c);
|
||||||
|
end;
|
||||||
nkExprColonExpr: begin
|
nkExprColonExpr: begin
|
||||||
gsub(g, n.sons[0]);
|
gsub(g, n.sons[0]);
|
||||||
putWithSpace(g, tkColon, ':'+'');
|
putWithSpace(g, tkColon, ':'+'');
|
||||||
|
|
@ -1362,11 +1379,11 @@ begin
|
||||||
nkTupleTy: begin
|
nkTupleTy: begin
|
||||||
put(g, tkTuple, 'tuple');
|
put(g, tkTuple, 'tuple');
|
||||||
put(g, tkBracketLe, '['+'');
|
put(g, tkBracketLe, '['+'');
|
||||||
assert(n.sons[0].kind = nkIdentDefs);
|
|
||||||
gcomma(g, n);
|
gcomma(g, n);
|
||||||
put(g, tkBracketRi, ']'+'');
|
put(g, tkBracketRi, ']'+'');
|
||||||
end;
|
end;
|
||||||
else begin
|
else begin
|
||||||
|
//nkNone, nkMetaNode, nkTableConstr, nkExplicitTypeListCall: begin
|
||||||
InternalError(n.info, 'rnimsyn.gsub(' +{&} nodeKindToStr[n.kind] +{&} ')')
|
InternalError(n.info, 'rnimsyn.gsub(' +{&} nodeKindToStr[n.kind] +{&} ')')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -503,7 +503,7 @@ end;
|
||||||
|
|
||||||
function process(c: PPassContext; n: PNode): PNode;
|
function process(c: PPassContext; n: PNode): PNode;
|
||||||
var
|
var
|
||||||
i, j: int;
|
i: int;
|
||||||
w: PRodWriter;
|
w: PRodWriter;
|
||||||
a: PNode;
|
a: PNode;
|
||||||
s: PSym;
|
s: PSym;
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ unit ropes;
|
||||||
efficiently; especially concatenation is done in O(1) instead of O(N).
|
efficiently; especially concatenation is done in O(1) instead of O(N).
|
||||||
Ropes make use a lazy evaluation: They are essentially concatenation
|
Ropes make use a lazy evaluation: They are essentially concatenation
|
||||||
trees that are only flattened when converting to a native Nimrod
|
trees that are only flattened when converting to a native Nimrod
|
||||||
string or when written to disk. The empty string is represented with a
|
string or when written to disk. The empty string is represented by a
|
||||||
nil pointer.
|
nil pointer.
|
||||||
A little picture makes everything clear:
|
A little picture makes everything clear:
|
||||||
|
|
||||||
|
|
@ -541,7 +541,6 @@ begin
|
||||||
if (r.data <> snil) then begin
|
if (r.data <> snil) then begin
|
||||||
if r.len > bufSize then
|
if r.len > bufSize then
|
||||||
// A token bigger than 1 KB? - This cannot happen in reality.
|
// A token bigger than 1 KB? - This cannot happen in reality.
|
||||||
// Well, at least I hope so. 1 KB did happen!
|
|
||||||
internalError('ropes: token too long');
|
internalError('ropes: token too long');
|
||||||
readBytes := readBuffer(bin, buf, r.len);
|
readBytes := readBuffer(bin, buf, r.len);
|
||||||
result := (readBytes = r.len) // BUGFIX
|
result := (readBytes = r.len) // BUGFIX
|
||||||
|
|
|
||||||
14
nim/rst.pas
14
nim/rst.pas
|
|
@ -494,7 +494,13 @@ begin
|
||||||
if n.kind = rnLeaf then begin
|
if n.kind = rnLeaf then begin
|
||||||
for i := strStart to length(n.text)+strStart-1 do begin
|
for i := strStart to length(n.text)+strStart-1 do begin
|
||||||
case n.text[i] of
|
case n.text[i] of
|
||||||
'a'..'z', '0'..'9': begin
|
'0'..'9': begin
|
||||||
|
if b then begin addChar(r, '-'); b := false; end;
|
||||||
|
// BUGFIX: HTML id's cannot start with a digit
|
||||||
|
if length(r) = 0 then addChar(r, 'Z');
|
||||||
|
addChar(r, n.text[i])
|
||||||
|
end;
|
||||||
|
'a'..'z': begin
|
||||||
if b then begin addChar(r, '-'); b := false; end;
|
if b then begin addChar(r, '-'); b := false; end;
|
||||||
addChar(r, n.text[i])
|
addChar(r, n.text[i])
|
||||||
end;
|
end;
|
||||||
|
|
@ -1235,7 +1241,7 @@ begin
|
||||||
result := nil;
|
result := nil;
|
||||||
if (p.tok[p.idx].kind = tkIndent)
|
if (p.tok[p.idx].kind = tkIndent)
|
||||||
and (p.tok[p.idx+1].symbol = ':'+'') then begin
|
and (p.tok[p.idx+1].symbol = ':'+'') then begin
|
||||||
col := p.tok[p.idx].col;
|
col := p.tok[p.idx].ival; // BUGFIX!
|
||||||
result := newRstNode(rnFieldList);
|
result := newRstNode(rnFieldList);
|
||||||
inc(p.idx);
|
inc(p.idx);
|
||||||
while true do begin
|
while true do begin
|
||||||
|
|
@ -1252,10 +1258,10 @@ var
|
||||||
i: int;
|
i: int;
|
||||||
f: PRstNode;
|
f: PRstNode;
|
||||||
begin
|
begin
|
||||||
assert(n.kind = rnDirective);
|
|
||||||
result := '';
|
result := '';
|
||||||
if n.sons[1] = nil then exit;
|
if n.sons[1] = nil then exit;
|
||||||
assert(n.sons[1].kind = rnFieldList);
|
if (n.sons[1].kind <> rnFieldList) then
|
||||||
|
InternalError('getFieldValue (2): ' + rstnodeKindToStr[n.sons[1].kind]);
|
||||||
for i := 0 to rsonsLen(n.sons[1])-1 do begin
|
for i := 0 to rsonsLen(n.sons[1])-1 do begin
|
||||||
f := n.sons[1].sons[i];
|
f := n.sons[1].sons[i];
|
||||||
if cmpIgnoreStyle(addNodes(f.sons[0]), fieldname) = 0 then begin
|
if cmpIgnoreStyle(addNodes(f.sons[0]), fieldname) = 0 then begin
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,8 @@ interface
|
||||||
{$include 'config.inc'}
|
{$include 'config.inc'}
|
||||||
|
|
||||||
uses
|
uses
|
||||||
charsets, nsystem, sysutils,
|
charsets, nsystem, sysutils, hashes, options, msgs, strutils, platform,
|
||||||
hashes, options, msgs, strutils, platform, idents,
|
idents, lexbase, llstream, wordrecg;
|
||||||
lexbase, llstream, wordrecg;
|
|
||||||
|
|
||||||
const
|
const
|
||||||
MaxLineLength = 80; // lines longer than this lead to a warning
|
MaxLineLength = 80; // lines longer than this lead to a warning
|
||||||
|
|
@ -31,7 +30,7 @@ const
|
||||||
numChars: TCharSet = ['0'..'9','a'..'z','A'..'Z'];
|
numChars: TCharSet = ['0'..'9','a'..'z','A'..'Z'];
|
||||||
SymChars: TCharSet = ['a'..'z', 'A'..'Z', '0'..'9', #128..#255];
|
SymChars: TCharSet = ['a'..'z', 'A'..'Z', '0'..'9', #128..#255];
|
||||||
SymStartChars: TCharSet = ['a'..'z', 'A'..'Z', #128..#255];
|
SymStartChars: TCharSet = ['a'..'z', 'A'..'Z', #128..#255];
|
||||||
OpChars: TCharSet = ['+', '-', '*', '/', '<', '>', '!', '?', '^', '.',
|
OpChars: TCharSet = ['+', '-', '*', '/', '\', '<', '>', '!', '?', '^', '.',
|
||||||
'|', '=', '%', '&', '$', '@', '~', #128..#255];
|
'|', '=', '%', '&', '$', '@', '~', #128..#255];
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
@ -162,6 +161,8 @@ var
|
||||||
gLinesCompiled: int; // all lines that have been compiled
|
gLinesCompiled: int; // all lines that have been compiled
|
||||||
|
|
||||||
procedure pushInd(var L: TLexer; indent: int);
|
procedure pushInd(var L: TLexer; indent: int);
|
||||||
|
procedure popInd(var L: TLexer);
|
||||||
|
|
||||||
function isKeyword(kind: TTokType): boolean;
|
function isKeyword(kind: TTokType): boolean;
|
||||||
|
|
||||||
procedure openLexer(out lex: TLexer; const filename: string;
|
procedure openLexer(out lex: TLexer; const filename: string;
|
||||||
|
|
@ -206,6 +207,14 @@ begin
|
||||||
//writeln('push indent ', indent);
|
//writeln('push indent ', indent);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure popInd(var L: TLexer);
|
||||||
|
var
|
||||||
|
len: int;
|
||||||
|
begin
|
||||||
|
len := length(L.indentStack);
|
||||||
|
setLength(L.indentStack, len-1);
|
||||||
|
end;
|
||||||
|
|
||||||
function findIdent(const L: TLexer; indent: int): boolean;
|
function findIdent(const L: TLexer; indent: int): boolean;
|
||||||
var
|
var
|
||||||
i: int;
|
i: int;
|
||||||
|
|
@ -809,13 +818,11 @@ begin
|
||||||
end;
|
end;
|
||||||
dec(L.dedent);
|
dec(L.dedent);
|
||||||
tok.tokType := tkDed;
|
tok.tokType := tkDed;
|
||||||
if i >= 0 then
|
if i < 0 then begin
|
||||||
setLength(L.indentStack, i+1) // pop indentations
|
|
||||||
else begin
|
|
||||||
tok.tokType := tkSad; // for the parser it is better as SAD
|
tok.tokType := tkSad; // for the parser it is better as SAD
|
||||||
lexMessage(L, errInvalidIndentation);
|
lexMessage(L, errInvalidIndentation);
|
||||||
end
|
end
|
||||||
end;
|
end
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure scanComment(var L: TLexer; var tok: TToken);
|
procedure scanComment(var L: TLexer; var tok: TToken);
|
||||||
|
|
|
||||||
23
nim/sem.pas
23
nim/sem.pas
|
|
@ -76,6 +76,22 @@ function semStmt(c: PContext; n: PNode): PNode; forward;
|
||||||
function semConstExpr(c: PContext; n: PNode): PNode;
|
function semConstExpr(c: PContext; n: PNode): PNode;
|
||||||
var
|
var
|
||||||
e: PNode;
|
e: PNode;
|
||||||
|
begin
|
||||||
|
e := semExprWithType(c, n);
|
||||||
|
if e = nil then begin
|
||||||
|
liMessage(n.info, errConstExprExpected);
|
||||||
|
result := nil; exit
|
||||||
|
end;
|
||||||
|
result := getConstExpr(c.module, e);
|
||||||
|
if result = nil then
|
||||||
|
liMessage(n.info, errConstExprExpected);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function semAndEvalConstExpr(c: PContext; n: PNode): PNode;
|
||||||
|
var
|
||||||
|
e: PNode;
|
||||||
|
p: PEvalContext;
|
||||||
|
s: PStackFrame;
|
||||||
begin
|
begin
|
||||||
e := semExprWithType(c, n);
|
e := semExprWithType(c, n);
|
||||||
if e = nil then begin
|
if e = nil then begin
|
||||||
|
|
@ -85,6 +101,13 @@ begin
|
||||||
result := getConstExpr(c.module, e);
|
result := getConstExpr(c.module, e);
|
||||||
if result = nil then begin
|
if result = nil then begin
|
||||||
//writeln(output, renderTree(n));
|
//writeln(output, renderTree(n));
|
||||||
|
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);
|
liMessage(n.info, errConstExprExpected);
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ type
|
||||||
PContext = ^TContext;
|
PContext = ^TContext;
|
||||||
TContext = object(TPassContext) // a context represents a module
|
TContext = object(TPassContext) // a context represents a module
|
||||||
module: PSym; // the module sym belonging to the context
|
module: PSym; // the module sym belonging to the context
|
||||||
|
filename: string; // the module's filename
|
||||||
tab: TSymTab; // each module has its own symbol table
|
tab: TSymTab; // each module has its own symbol table
|
||||||
AmbigiousSymbols: TIntSet; // contains ids of all ambigious symbols (cannot
|
AmbigiousSymbols: TIntSet; // contains ids of all ambigious symbols (cannot
|
||||||
// store this info in the syms themselves!)
|
// store this info in the syms themselves!)
|
||||||
|
|
@ -160,6 +161,7 @@ begin
|
||||||
result.module := module;
|
result.module := module;
|
||||||
result.generics := newNode(nkStmtList);
|
result.generics := newNode(nkStmtList);
|
||||||
{@emit result.converters := @[];}
|
{@emit result.converters := @[];}
|
||||||
|
result.filename := nimfile;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure addConverter(c: PContext; conv: PSym);
|
procedure addConverter(c: PContext; conv: PSym);
|
||||||
|
|
|
||||||
|
|
@ -36,9 +36,9 @@ var
|
||||||
diff: int;
|
diff: int;
|
||||||
begin
|
begin
|
||||||
diff := inheritanceDiff(castDest, src);
|
diff := inheritanceDiff(castDest, src);
|
||||||
if diff = 0 then
|
//if diff = 0 then
|
||||||
liMessage(info, hintConvToBaseNotNeeded)
|
// liMessage(info, hintConvToBaseNotNeeded)
|
||||||
else if diff = high(int) then
|
if diff = high(int) then
|
||||||
liMessage(info, errGenerated,
|
liMessage(info, errGenerated,
|
||||||
format(MsgKindToString(errIllegalConvFromXtoY),
|
format(MsgKindToString(errIllegalConvFromXtoY),
|
||||||
[typeToString(src), typeToString(castDest)]));
|
[typeToString(src), typeToString(castDest)]));
|
||||||
|
|
@ -466,11 +466,11 @@ begin
|
||||||
if m.state <> csMatch then begin
|
if m.state <> csMatch then begin
|
||||||
msg := msgKindToString(errTypeMismatch);
|
msg := msgKindToString(errTypeMismatch);
|
||||||
for i := 1 to sonsLen(n)-1 do begin
|
for i := 1 to sonsLen(n)-1 do begin
|
||||||
msg := msg +{&} typeToString(n.sons[i].typ);
|
add(msg, typeToString(n.sons[i].typ));
|
||||||
if i <> sonsLen(n)-1 then msg := msg + ', ';
|
if i <> sonsLen(n)-1 then add(msg, ', ');
|
||||||
end;
|
end;
|
||||||
msg := msg +{&} ')' +{&} nl +{&} msgKindToString(errButExpected) +{&}
|
add(msg, ')' +{&} nl +{&} msgKindToString(errButExpected) +{&}
|
||||||
nl +{&} typeToString(n.sons[0].typ);
|
nl +{&} typeToString(n.sons[0].typ));
|
||||||
liMessage(n.Info, errGenerated, msg);
|
liMessage(n.Info, errGenerated, msg);
|
||||||
result := nil
|
result := nil
|
||||||
end
|
end
|
||||||
|
|
@ -1117,7 +1117,7 @@ begin
|
||||||
if s <> nil then
|
if s <> nil then
|
||||||
result := semSym(c, n, s, flags)
|
result := semSym(c, n, s, flags)
|
||||||
else
|
else
|
||||||
// test!
|
// this is a test comment; please don't touch it
|
||||||
result := semFieldAccess(c, n, flags);
|
result := semFieldAccess(c, n, flags);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,25 @@ begin
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function enumValToString(a: PNode): string;
|
||||||
|
var
|
||||||
|
n: PNode;
|
||||||
|
field: PSym;
|
||||||
|
x: biggestInt;
|
||||||
|
i: int;
|
||||||
|
begin
|
||||||
|
x := getInt(a);
|
||||||
|
n := a.typ.n;
|
||||||
|
for i := 0 to sonsLen(n)-1 do begin
|
||||||
|
if n.sons[i].kind <> nkSym then InternalError(a.info, 'enumValToString');
|
||||||
|
field := n.sons[i].sym;
|
||||||
|
if field.position = x then begin
|
||||||
|
result := field.name.s; exit
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
InternalError(a.info, 'no symbol for ordinal value: ' + toString(x));
|
||||||
|
end;
|
||||||
|
|
||||||
function evalOp(m: TMagic; n, a, b: PNode): PNode;
|
function evalOp(m: TMagic; n, a, b: PNode): PNode;
|
||||||
// if this is an unary operation, b is nil
|
// if this is an unary operation, b is nil
|
||||||
begin
|
begin
|
||||||
|
|
@ -246,11 +265,18 @@ begin
|
||||||
// available for interpretation. I don't know how to fix this.
|
// available for interpretation. I don't know how to fix this.
|
||||||
//result := newStrNodeT(renderTree(a, {@set}[renderNoComments]), n);
|
//result := newStrNodeT(renderTree(a, {@set}[renderNoComments]), n);
|
||||||
end;
|
end;
|
||||||
mIntToStr, mInt64ToStr, mBoolToStr, mCharToStr:
|
mIntToStr, mInt64ToStr:
|
||||||
result := newStrNodeT(toString(getOrdValue(a)), n);
|
result := newStrNodeT(toString(getOrdValue(a)), n);
|
||||||
|
mBoolToStr: begin
|
||||||
|
if getOrdValue(a) = 0 then
|
||||||
|
result := newStrNodeT('false', n)
|
||||||
|
else
|
||||||
|
result := newStrNodeT('true', n)
|
||||||
|
end;
|
||||||
mFloatToStr: result := newStrNodeT(toStringF(getFloat(a)), n);
|
mFloatToStr: result := newStrNodeT(toStringF(getFloat(a)), n);
|
||||||
mCStrToStr: result := newStrNodeT(getStrOrChar(a), n);
|
mCStrToStr, mCharToStr: result := newStrNodeT(getStrOrChar(a), n);
|
||||||
mStrToStr: result := a;
|
mStrToStr: result := a;
|
||||||
|
mEnumToStr: result := newStrNodeT(enumValToString(a), n);
|
||||||
mArrToSeq: begin
|
mArrToSeq: begin
|
||||||
result := copyTree(a);
|
result := copyTree(a);
|
||||||
result.typ := n.typ;
|
result.typ := n.typ;
|
||||||
|
|
@ -370,6 +396,10 @@ begin
|
||||||
mNimrodMinor: result := newIntNodeT(VersionMinor, n);
|
mNimrodMinor: result := newIntNodeT(VersionMinor, n);
|
||||||
mNimrodPatch: result := newIntNodeT(VersionPatch, n);
|
mNimrodPatch: result := newIntNodeT(VersionPatch, n);
|
||||||
mCpuEndian: result := newIntNodeT(ord(CPU[targetCPU].endian), n);
|
mCpuEndian: result := newIntNodeT(ord(CPU[targetCPU].endian), n);
|
||||||
|
mHostOS:
|
||||||
|
result := newStrNodeT(toLower(platform.OS[targetOS].name), n);
|
||||||
|
mHostCPU:
|
||||||
|
result := newStrNodeT(toLower(platform.CPU[targetCPU].name),n);
|
||||||
mNaN: result := newFloatNodeT(NaN, n);
|
mNaN: result := newFloatNodeT(NaN, n);
|
||||||
mInf: result := newFloatNodeT(Inf, n);
|
mInf: result := newFloatNodeT(Inf, n);
|
||||||
mNegInf: result := newFloatNodeT(NegInf, n);
|
mNegInf: result := newFloatNodeT(NegInf, n);
|
||||||
|
|
|
||||||
|
|
@ -324,7 +324,7 @@ begin
|
||||||
a := newNodeI(nkAsgn, n.sons[0].info);
|
a := newNodeI(nkAsgn, n.sons[0].info);
|
||||||
|
|
||||||
n.sons[0] := fitNode(c, restype, n.sons[0]);
|
n.sons[0] := fitNode(c, restype, n.sons[0]);
|
||||||
// optimize away ``return result``, because it would be transferred
|
// optimize away ``return result``, because it would be transformed
|
||||||
// to ``result = result; return``:
|
// to ``result = result; return``:
|
||||||
if (n.sons[0].kind = nkSym) and (sfResult in n.sons[0].sym.flags) then
|
if (n.sons[0].kind = nkSym) and (sfResult in n.sons[0].sym.flags) then
|
||||||
begin
|
begin
|
||||||
|
|
@ -378,14 +378,14 @@ function semVar(c: PContext; n: PNode): PNode;
|
||||||
var
|
var
|
||||||
i, j, len: int;
|
i, j, len: int;
|
||||||
a, b, def: PNode;
|
a, b, def: PNode;
|
||||||
typ: PType;
|
typ, tup: PType;
|
||||||
v: PSym;
|
v: PSym;
|
||||||
begin
|
begin
|
||||||
result := copyNode(n);
|
result := copyNode(n);
|
||||||
for i := 0 to sonsLen(n)-1 do begin
|
for i := 0 to sonsLen(n)-1 do begin
|
||||||
a := n.sons[i];
|
a := n.sons[i];
|
||||||
if a.kind = nkCommentStmt then continue;
|
if a.kind = nkCommentStmt then continue;
|
||||||
if (a.kind <> nkIdentDefs) then IllFormedAst(a);
|
if (a.kind <> nkIdentDefs) and (a.kind <> nkVarTuple) then IllFormedAst(a);
|
||||||
checkMinSonsLen(a, 3);
|
checkMinSonsLen(a, 3);
|
||||||
len := sonsLen(a);
|
len := sonsLen(a);
|
||||||
if a.sons[len-2] <> nil then
|
if a.sons[len-2] <> nil then
|
||||||
|
|
@ -401,14 +401,21 @@ begin
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
def := nil;
|
def := nil;
|
||||||
|
tup := skipGeneric(typ);
|
||||||
|
if a.kind = nkVarTuple then begin
|
||||||
|
if tup.kind <> tyTuple then liMessage(a.info, errXExpected, 'tuple');
|
||||||
|
if len-2 <> sonsLen(tup) then
|
||||||
|
liMessage(a.info, errWrongNumberOfVariables);
|
||||||
|
end;
|
||||||
for j := 0 to len-3 do begin
|
for j := 0 to len-3 do begin
|
||||||
if (c.p.owner = nil) then begin
|
if c.p.owner = nil then begin
|
||||||
v := semIdentWithPragma(c, skVar, a.sons[j], {@set}[sfStar, sfMinus]);
|
v := semIdentWithPragma(c, skVar, a.sons[j], {@set}[sfStar, sfMinus]);
|
||||||
include(v.flags, sfGlobal);
|
include(v.flags, sfGlobal);
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
v := semIdentWithPragma(c, skVar, a.sons[j], {@set}[]);
|
v := semIdentWithPragma(c, skVar, a.sons[j], {@set}[]);
|
||||||
v.typ := typ;
|
if a.kind <> nkVarTuple then v.typ := typ
|
||||||
|
else v.typ := tup.sons[j];
|
||||||
if v.flags * [sfStar, sfMinus] <> {@set}[] then
|
if v.flags * [sfStar, sfMinus] <> {@set}[] then
|
||||||
include(v.flags, sfInInterface);
|
include(v.flags, sfInInterface);
|
||||||
addInterfaceDecl(c, v);
|
addInterfaceDecl(c, v);
|
||||||
|
|
@ -443,7 +450,7 @@ begin
|
||||||
|
|
||||||
if a.sons[1] <> nil then typ := semTypeNode(c, a.sons[1], nil)
|
if a.sons[1] <> nil then typ := semTypeNode(c, a.sons[1], nil)
|
||||||
else typ := nil;
|
else typ := nil;
|
||||||
def := semConstExpr(c, a.sons[2]);
|
def := semAndEvalConstExpr(c, a.sons[2]);
|
||||||
// check type compability between def.typ and typ:
|
// check type compability between def.typ and typ:
|
||||||
if (typ <> nil) then begin
|
if (typ <> nil) then begin
|
||||||
def := fitRemoveHiddenConv(c, typ, def);
|
def := fitRemoveHiddenConv(c, typ, def);
|
||||||
|
|
@ -495,7 +502,7 @@ begin
|
||||||
iter := skipGeneric(n.sons[len-2].typ);
|
iter := skipGeneric(n.sons[len-2].typ);
|
||||||
openScope(c.tab);
|
openScope(c.tab);
|
||||||
if iter.kind <> tyTuple then begin
|
if iter.kind <> tyTuple then begin
|
||||||
if len <> 3 then liMessage(n.info, errWrongNumberOfLoopVariables);
|
if len <> 3 then liMessage(n.info, errWrongNumberOfVariables);
|
||||||
v := newSymS(skForVar, n.sons[0], c);
|
v := newSymS(skForVar, n.sons[0], c);
|
||||||
v.typ := iter;
|
v.typ := iter;
|
||||||
n.sons[0] := newSymNode(v);
|
n.sons[0] := newSymNode(v);
|
||||||
|
|
@ -503,7 +510,7 @@ begin
|
||||||
end
|
end
|
||||||
else begin
|
else begin
|
||||||
if len-2 <> sonsLen(iter) then
|
if len-2 <> sonsLen(iter) then
|
||||||
liMessage(n.info, errWrongNumberOfLoopVariables);
|
liMessage(n.info, errWrongNumberOfVariables);
|
||||||
for i := 0 to len-3 do begin
|
for i := 0 to len-3 do begin
|
||||||
v := newSymS(skForVar, n.sons[i], c);
|
v := newSymS(skForVar, n.sons[i], c);
|
||||||
v.typ := iter.sons[i];
|
v.typ := iter.sons[i];
|
||||||
|
|
@ -840,6 +847,7 @@ begin
|
||||||
closeScope(c.tab); // close scope for parameters
|
closeScope(c.tab); // close scope for parameters
|
||||||
popOwner();
|
popOwner();
|
||||||
c.p := oldP; // restore
|
c.p := oldP; // restore
|
||||||
|
result.typ := s.typ;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function semProcAux(c: PContext; n: PNode; kind: TSymKind): PNode;
|
function semProcAux(c: PContext; n: PNode; kind: TSymKind): PNode;
|
||||||
|
|
|
||||||
|
|
@ -256,8 +256,8 @@ begin
|
||||||
if templ = nil then begin result := nil; exit end;
|
if templ = nil then begin result := nil; exit end;
|
||||||
case templ.kind of
|
case templ.kind of
|
||||||
nkSym: begin
|
nkSym: begin
|
||||||
if (templ.sym.kind = skTypeParam)
|
if (templ.sym.kind = skTypeParam) then
|
||||||
and (templ.sym.owner.id = sym.id) then
|
//and (templ.sym.owner.id = sym.id) then
|
||||||
result := copyTree(actual.sons[templ.sym.position+1])
|
result := copyTree(actual.sons[templ.sym.position+1])
|
||||||
else
|
else
|
||||||
result := copyNode(templ)
|
result := copyNode(templ)
|
||||||
|
|
@ -285,15 +285,18 @@ begin
|
||||||
result.containerID := s.typ.containerID; // ... but the same containerID
|
result.containerID := s.typ.containerID; // ... but the same containerID
|
||||||
result.sym := s;
|
result.sym := s;
|
||||||
if (s.typ.containerID = 0) then
|
if (s.typ.containerID = 0) then
|
||||||
InternalError(n.info, 'semGeneric');
|
InternalError(n.info, 'semtypes.semGeneric');
|
||||||
for i := 1 to sonsLen(n)-1 do begin
|
for i := 1 to sonsLen(n)-1 do begin
|
||||||
elem := semTypeNode(c, n.sons[i], nil);
|
elem := semTypeNode(c, n.sons[i], nil);
|
||||||
if elem.kind = tyGenericParam then result.kind := tyGeneric;
|
if elem.kind = tyGenericParam then
|
||||||
|
result.kind := tyGeneric; // prevend type from instantiation
|
||||||
addSon(result, elem);
|
addSon(result, elem);
|
||||||
end;
|
end;
|
||||||
if s.ast <> nil then begin
|
if s.ast <> nil then begin
|
||||||
|
if (result.kind = tyGenericInst) then begin
|
||||||
inst := instGenericAux(c, s.ast.sons[2], n, s);
|
inst := instGenericAux(c, s.ast.sons[2], n, s);
|
||||||
if result.kind = tyGenericInst then begin
|
internalError(n.info, 'Generic containers not implemented');
|
||||||
|
// XXX: implementation does not work this way
|
||||||
// does checking of instantiated type for us:
|
// does checking of instantiated type for us:
|
||||||
elem := semTypeNode(c, inst, nil);
|
elem := semTypeNode(c, inst, nil);
|
||||||
elem.id := result.containerID;
|
elem.id := result.containerID;
|
||||||
|
|
@ -304,6 +307,8 @@ begin
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
liMessage(n.info, errCannotInstantiateX, s.name.s);
|
liMessage(n.info, errCannotInstantiateX, s.name.s);
|
||||||
|
(*if computeSize(result) < 0 then
|
||||||
|
liMessage(s.info, errIllegalRecursionInTypeX, s.name.s);*)
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function semIdentVis(c: PContext; kind: TSymKind; n: PNode;
|
function semIdentVis(c: PContext; kind: TSymKind; n: PNode;
|
||||||
|
|
|
||||||
|
|
@ -80,20 +80,23 @@ var
|
||||||
begin
|
begin
|
||||||
result := msgKindToString(errTypeMismatch);
|
result := msgKindToString(errTypeMismatch);
|
||||||
for i := 1 to sonsLen(n)-1 do begin
|
for i := 1 to sonsLen(n)-1 do begin
|
||||||
result := result +{&} typeToString(n.sons[i].typ);
|
debug(n.sons[i].typ);
|
||||||
if i <> sonsLen(n)-1 then result := result + ', ';
|
add(result, typeToString(n.sons[i].typ));
|
||||||
|
if i <> sonsLen(n)-1 then add(result, ', ');
|
||||||
end;
|
end;
|
||||||
addChar(result, ')');
|
addChar(result, ')');
|
||||||
candidates := '';
|
candidates := '';
|
||||||
sym := initOverloadIter(o, c, n.sons[0]);
|
sym := initOverloadIter(o, c, n.sons[0]);
|
||||||
while sym <> nil do begin
|
while sym <> nil do begin
|
||||||
if sym.kind in [skProc, skIterator, skConverter] then
|
if sym.kind in [skProc, skIterator, skConverter] then begin
|
||||||
candidates := candidates +{&} getProcHeader(sym) +{&} nl;
|
add(candidates, getProcHeader(sym));
|
||||||
|
add(candidates, nl)
|
||||||
|
end;
|
||||||
sym := nextOverloadIter(o, c, n.sons[0]);
|
sym := nextOverloadIter(o, c, n.sons[0]);
|
||||||
end;
|
end;
|
||||||
if candidates <> '' then
|
if candidates <> '' then
|
||||||
result := result +{&} nl +{&} msgKindToString(errButExpected) +{&} nl
|
add(result, nl +{&} msgKindToString(errButExpected) +{&} nl
|
||||||
+{&} candidates;
|
+{&} candidates);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function typeRel(var mapping: TIdTable; f, a: PType): TTypeRelation; overload;
|
function typeRel(var mapping: TIdTable; f, a: PType): TTypeRelation; overload;
|
||||||
|
|
@ -431,7 +434,7 @@ begin // is a subtype of f?
|
||||||
tyAnyEnum: begin
|
tyAnyEnum: begin
|
||||||
case a.kind of
|
case a.kind of
|
||||||
tyRange: result := typeRel(mapping, f, base(a));
|
tyRange: result := typeRel(mapping, f, base(a));
|
||||||
tyEnum: result := isEqual;
|
tyEnum: result := isSubtype;
|
||||||
else begin end
|
else begin end
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,7 @@
|
||||||
//
|
//
|
||||||
unit strtabs;
|
unit strtabs;
|
||||||
|
|
||||||
// A configuration file parser; the Nimrod version of this file
|
// String tables.
|
||||||
// will become part of the standard library.
|
|
||||||
|
|
||||||
interface
|
interface
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,13 +75,14 @@ const
|
||||||
function strip(const s: string; const chars: TCharSet = WhiteSpace): string;
|
function strip(const s: string; const chars: TCharSet = WhiteSpace): string;
|
||||||
function allCharsInSet(const s: string; const theSet: TCharSet): bool;
|
function allCharsInSet(const s: string; const theSet: TCharSet): bool;
|
||||||
|
|
||||||
function quoteIfSpaceExists(const s: string): string;
|
function quoteIfContainsWhite(const s: string): string;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
function quoteIfSpaceExists(const s: string): string;
|
function quoteIfContainsWhite(const s: string): string;
|
||||||
begin
|
begin
|
||||||
if (findSubStr(' ', s) >= strStart) and (s[strStart] <> '"') then
|
if ((findSubStr(' ', s) >= strStart)
|
||||||
|
or (findSubStr(#9, s) >= strStart)) and (s[strStart] <> '"') then
|
||||||
result := '"' +{&} s +{&} '"'
|
result := '"' +{&} s +{&} '"'
|
||||||
else
|
else
|
||||||
result := s
|
result := s
|
||||||
|
|
|
||||||
47
nim/tigen.pas
Normal file
47
nim/tigen.pas
Normal 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.
|
||||||
|
|
||||||
|
|
@ -22,7 +22,7 @@ interface
|
||||||
uses
|
uses
|
||||||
sysutils, nsystem, charsets, strutils,
|
sysutils, nsystem, charsets, strutils,
|
||||||
lists, options, ast, astalgo, trees, treetab,
|
lists, options, ast, astalgo, trees, treetab,
|
||||||
msgs, nos, idents, rnimsyn, types, passes, semfold;
|
msgs, nos, idents, rnimsyn, types, passes, semfold, magicsys;
|
||||||
|
|
||||||
const
|
const
|
||||||
genPrefix = ':tmp'; // prefix for generated names
|
genPrefix = ':tmp'; // prefix for generated names
|
||||||
|
|
@ -139,7 +139,7 @@ More efficient, but not implementable:
|
||||||
|
|
||||||
function newAsgnStmt(c: PTransf; le, ri: PNode): PNode;
|
function newAsgnStmt(c: PTransf; le, ri: PNode): PNode;
|
||||||
begin
|
begin
|
||||||
result := newNodeI(nkAsgn, ri.info);
|
result := newNodeI(nkFastAsgn, ri.info);
|
||||||
addSon(result, le);
|
addSon(result, le);
|
||||||
addSon(result, ri);
|
addSon(result, ri);
|
||||||
end;
|
end;
|
||||||
|
|
@ -224,6 +224,28 @@ begin
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function newTupleAccess(tup: PNode; i: int): PNode;
|
||||||
|
var
|
||||||
|
lit: PNode;
|
||||||
|
begin
|
||||||
|
result := newNodeIT(nkBracketExpr, tup.info, tup.typ.sons[i]);
|
||||||
|
addSon(result, copyTree(tup));
|
||||||
|
lit := newNodeIT(nkIntLit, tup.info, getSysType(tyInt));
|
||||||
|
lit.intVal := i;
|
||||||
|
addSon(result, lit);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure unpackTuple(c: PTransf; n, father: PNode);
|
||||||
|
var
|
||||||
|
i: int;
|
||||||
|
begin
|
||||||
|
// XXX: BUG: what if `n` is an expression with side-effects?
|
||||||
|
for i := 0 to sonsLen(n)-1 do begin
|
||||||
|
addSon(father, newAsgnStmt(c, c.transCon.forStmt.sons[i],
|
||||||
|
transform(c, newTupleAccess(n, i))));
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
function transformYield(c: PTransf; n: PNode): PNode;
|
function transformYield(c: PTransf; n: PNode): PNode;
|
||||||
var
|
var
|
||||||
e: PNode;
|
e: PNode;
|
||||||
|
|
@ -239,10 +261,8 @@ begin
|
||||||
transform(c, copyTree(e.sons[i]))));
|
transform(c, copyTree(e.sons[i]))));
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else begin
|
else
|
||||||
// XXX: tuple unpacking:
|
unpackTuple(c, e, result);
|
||||||
internalError(n.info, 'tuple unpacking is not implemented');
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
else begin
|
else begin
|
||||||
e := transform(c, copyTree(e));
|
e := transform(c, copyTree(e));
|
||||||
|
|
@ -523,7 +543,7 @@ end;
|
||||||
(*
|
(*
|
||||||
# example:
|
# example:
|
||||||
proc map(f: proc (x: int): int {.closure}, a: seq[int]): seq[int] =
|
proc map(f: proc (x: int): int {.closure}, a: seq[int]): seq[int] =
|
||||||
result = []
|
result = @[]
|
||||||
for elem in a:
|
for elem in a:
|
||||||
add result, f(a)
|
add result, f(a)
|
||||||
|
|
||||||
|
|
@ -534,12 +554,12 @@ end;
|
||||||
|
|
||||||
proc map(f: proc(x: int): int, closure: pointer,
|
proc map(f: proc(x: int): int, closure: pointer,
|
||||||
a: seq[int]): seq[int] =
|
a: seq[int]): seq[int] =
|
||||||
result = []
|
result = @[]
|
||||||
for elem in a:
|
for elem in a:
|
||||||
add result, f(a, closure)
|
add result, f(a, closure)
|
||||||
|
|
||||||
type
|
type
|
||||||
PMyClosure = ref record
|
PMyClosure = ref object
|
||||||
y: var int
|
y: var int
|
||||||
|
|
||||||
proc myLambda(x: int, closure: pointer) =
|
proc myLambda(x: int, closure: pointer) =
|
||||||
|
|
|
||||||
|
|
@ -638,15 +638,15 @@ begin
|
||||||
assert(sonsLen(t.n) = sonsLen(t));
|
assert(sonsLen(t.n) = sonsLen(t));
|
||||||
for i := 0 to sonsLen(t.n)-1 do begin
|
for i := 0 to sonsLen(t.n)-1 do begin
|
||||||
assert(t.n.sons[i].kind = nkSym);
|
assert(t.n.sons[i].kind = nkSym);
|
||||||
result := result +{&} t.n.sons[i].sym.name.s +{&} ': '
|
add(result, t.n.sons[i].sym.name.s +{&} ': '
|
||||||
+{&} typeToString(t.sons[i]);
|
+{&} typeToString(t.sons[i]));
|
||||||
if i < sonsLen(t.n)-1 then result := result +{&} ', ';
|
if i < sonsLen(t.n)-1 then add(result, ', ');
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else begin
|
else begin
|
||||||
for i := 0 to sonsLen(t)-1 do begin
|
for i := 0 to sonsLen(t)-1 do begin
|
||||||
result := result +{&} typeToString(t.sons[i]);
|
add(result, typeToString(t.sons[i]));
|
||||||
if i < sonsLen(t)-1 then result := result +{&} ', ';
|
if i < sonsLen(t)-1 then add(result, ', ');
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
addChar(result, ']')
|
addChar(result, ']')
|
||||||
|
|
@ -659,14 +659,14 @@ begin
|
||||||
tyProc: begin
|
tyProc: begin
|
||||||
result := 'proc (';
|
result := 'proc (';
|
||||||
for i := 1 to sonsLen(t)-1 do begin
|
for i := 1 to sonsLen(t)-1 do begin
|
||||||
result := result +{&} typeToString(t.sons[i]);
|
add(result, typeToString(t.sons[i]));
|
||||||
if i < sonsLen(t)-1 then result := result +{&} ', ';
|
if i < sonsLen(t)-1 then add(result, ', ');
|
||||||
end;
|
end;
|
||||||
addChar(result, ')');
|
addChar(result, ')');
|
||||||
if t.sons[0] <> nil then
|
if t.sons[0] <> nil then
|
||||||
result := result +{&} ': ' +{&} TypeToString(t.sons[0]);
|
add(result, ': ' +{&} TypeToString(t.sons[0]));
|
||||||
if t.callConv <> ccDefault then
|
if t.callConv <> ccDefault then
|
||||||
result := result +{&} '{.' +{&} CallingConvToStr[t.callConv] +{&} '.}';
|
add(result, '{.' +{&} CallingConvToStr[t.callConv] +{&} '.}');
|
||||||
end;
|
end;
|
||||||
else begin
|
else begin
|
||||||
result := typeToStr[t.kind]
|
result := typeToStr[t.kind]
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue