overload resolution for proc vars

This commit is contained in:
Andreas Rumpf
2009-06-24 17:13:22 +02:00
parent 36818817bd
commit 300430fbba
56 changed files with 2772 additions and 2430 deletions

View File

@@ -8,7 +8,7 @@
#
{
'SymFlag': [ # already 28 flags!
'SymFlag': [ # already 29 flags!
'sfUsed', # read access of sym (for warnings) or simply used
'sfStar', # symbol has * visibility
'sfMinus', # symbol has - visibility
@@ -27,6 +27,7 @@
'sfResult', # variable is 'result' in proc
'sfNoSideEffect', # proc has no side effects
'sfSideEffect', # proc may have side effects; cannot prove it has none
'sfMainModule', # module is the main module
'sfSystemModule', # module is the system module
'sfNoReturn', # proc never returns (an exit proc)
@@ -47,6 +48,7 @@
'TypeFlag': [
'tfVarargs', # procedure has C styled varargs
'tfNoSideEffect', # procedure type does not allow side effects
'tfFinal', # is the object final?
'tfAcyclic', # type is acyclic (for GC optimization)
'tfEnumHasWholes' # enum cannot be mapped into a range
@@ -146,10 +148,11 @@
'nkElseExpr',
'nkLambda', # lambda expression
'nkAccQuoted', # `a` as a node
'nkHeaderQuoted', # `a(x: int)` as a node
'nkTableConstr', # a table constructor {expr: expr}
'nkQualified', # describes a.b for qualified identifiers
'nkBind', # ``bind expr`` node
'nkSymChoice', # symbol choice node
'nkHiddenStdConv', # an implicit standard type conversion
'nkHiddenSubConv', # an implicit type conversion from a subtype
# to a supertype

View File

@@ -1,8 +1,8 @@
abstract addr and as asm
block break
bind block break
case cast const continue converter
discard div
elif else end enum except exception
elif else end enum except
finally for from generic
if implies import in include is isnot iterator
lambda

View File

@@ -36,19 +36,15 @@
{'errNoneSpeedOrSizeExpected': "'none', 'speed' or 'size' expected"},
{'errInvalidPragma': 'invalid pragma'},
{'errUnknownPragma': "unknown pragma: '$1'"},
{'errPragmaXHereNotAllowed': "pragma '$1' here not allowed"},
{'errUnknownDirective': "unknown directive: '$1'"},
{'errInvalidDirective': 'invalid directive'},
{'errAtPopWithoutPush': "'pop' without a 'push' pragma"},
{'errEmptyAsm': 'empty asm statement makes no sense'},
{'errAsgnInvalidInExpr': "'=' invalid in an expression; probably '==' meant"},
{'errInvalidIndentation': 'invalid indentation'},
{'errExceptionExpected': 'exception expected'},
{'errExceptionAlreadyHandled': 'exception already handled'},
{'errReturnNotAllowedHere': "'return' only allowed in routine"},
{'errYieldNotAllowedHere': "'yield' only allowed in a loop of an iterator"},
{'errInvalidNumberOfYieldExpr': "invalid number of 'yield' expresions"},
{'errReturnInvalidInIterator': "'return' not allowed in iterator"},
{'errCannotReturnExpr': 'current routine cannot return an expression'},
{'errAttemptToRedefine': "attempt to redefine '$1'"},
{'errStmtInvalidAfterReturn':
@@ -78,21 +74,18 @@
{'errColonOrEqualsExpected': "':' or '=' expected, but found '$1'"},
{'errExprExpected': "expression expected, but found '$1'"},
{'errUndeclaredIdentifier': "undeclared identifier: '$1'"},
{'errUseQualifier': "ambigious identifier: '$1' -- use a qualifier"},
{'errTwiceForwarded': "'$1' is forwarded twice"},
{'errUseQualifier': "ambiguous identifier: '$1' -- use a qualifier"},
{'errTypeExpected': 'type expected'},
{'errSystemNeeds': "system module needs '$1'"},
{'errExecutionOfProgramFailed': 'execution of an external program failed'},
{'errNotOverloadable': "overloaded '$1' leads to ambigious calls"},
{'errNotOverloadable': "overloaded '$1' leads to ambiguous calls"},
{'errInvalidArgForX': "invalid argument for '$1'"},
{'errStmtHasNoEffect': 'statement has no effect'},
{'errXExpectsTypeOrValue': "'$1' expects a type or value"},
{'errXExpectsArrayType': "'$1' expects an array type"},
{'errIteratorCannotBeInstantiated':
"'$1' cannot be instantiated because its body has not been compiled yet"},
{'errExprWithNoTypeCannotBeConverted':
'expression with no type cannot be converted'},
{'errExprWithNoTypeCannotBeCasted': 'expression with no type cannot be casted'},
{'errExprXAmbiguous': "expression '$1' ambiguous in this context"},
{'errConstantDivisionByZero': 'constant division by zero'},
{'errOrdinalTypeExpected': 'ordinal type expected'},
{'errOrdinalOrFloatTypeExpected': 'ordinal or float type expected'},
@@ -112,21 +105,17 @@
{'errValueOutOfSetBounds': 'value out of set bounds'},
{'errFieldInitTwice': "field initialized twice: '$1'"},
{'errFieldNotInit': "field '$1' not initialized"},
{'errExprCannotBeCalled': 'expression cannot be called'},
{'errExprXCannotBeCalled': "expression '$1' cannot be called"},
{'errExprHasNoType': 'expression has no type'},
{'errExprXHasNoType': "expression '$1' has no type"},
{'errExprXHasNoType': "expression '$1' has no type (or is ambiguous)"},
{'errCastNotInSafeMode': "'cast' not allowed in safe mode"},
{'errExprCannotBeCastedToX': 'expression cannot be casted to $1'},
{'errUndefinedPrefixOpr': 'undefined prefix operator: $1'},
{'errCommaOrParRiExpected': "',' or ')' expected"},
{'errCurlyLeOrParLeExpected': "'{' or '(' expected"},
{'errSectionExpected': "section ('type', 'proc', etc.) expected"},
{'errImplemenationExpected': "'implementation' or end of file expected"},
{'errRangeExpected': 'range expected'},
{'errInvalidTypeDescription': 'invalid type description'},
{'errAttemptToRedefineX': "attempt to redefine '$1'"},
{'errMagicOnlyInSystem': "'magic' only allowed in system module"},
{'errUnknownOperatorX': "unkown operator: '$1'"},
{'errPowerOfTwoExpected': 'power of two expected'},
{'errStringMayNotBeEmpty': 'string literal may not be empty'},
{'errCallConvExpected': 'calling convention expected'},
@@ -165,9 +154,8 @@
{'errTypeMismatch': 'type mismatch: got ('},
{'errButExpected': 'but expected one of: '},
{'errButExpectedX': "but expected '$1'"},
{'errAmbigiousCallXYZ': 'ambigious call; both $1 and $2 match for: $3'},
{'errAmbiguousCallXYZ': 'ambiguous call; both $1 and $2 match for: $3'},
{'errWrongNumberOfTypeParams': 'wrong number of type parameters'},
{'errOutParamNoDefaultValue': 'out parameters cannot have default values'},
{'errInlineProcHasNoAddress': 'an inline proc has no address'},
{'errXCannotBeInParamDecl': '$1 cannot be declared in parameter declaration'},
{'errPragmaOnlyInHeaderOfProc':
@@ -177,22 +165,15 @@
{'errNoSymbolToBorrowFromFound': "no symbol to borrow from found"},
{'errDiscardValue': 'value returned by statement has to be discarded'},
{'errInvalidDiscard': 'statement returns no value that can be discarded'},
{'errUnknownPrecedence':
"unknown precedence for operator; use 'infix: prec' pragma"},
{'errIllegalConvFromXtoY': 'conversion from $1 to $2 is invalid'},
{'errTypeMismatchExpectedXGotY': "type mismatch: expected '$1', but got '$2'"},
{'errCannotBindXTwice': "cannot bind parameter '$1' twice"},
{'errInvalidOrderInEnumX': "invalid order in enum '$1'"},
{'errEnumXHasWholes': "enum '$1' has wholes"},
{'errExceptExpected': "'except' or 'finally' expected"},
{'errInvalidTry': "after catch all 'except' or 'finally' no section may follow"},
{'errEofExpectedButXFound': "end of file expected, but found token '$1'"},
{'errOptionExpected': "option expected, but found '$1'"},
{'errCannotEvaluateForwardConst': 'cannot evaluate forwarded constant'},
{'errXisNoLabel': "'$1' is not a label"},
{'errXNeedsConcreteType': "'$1' needs to be of a non-generic type"},
{'errNotAllCasesCovered': 'not all cases are covered'},
{'errStringRange': 'string range in case statement not allowed'},
{'errUnkownSubstitionVar': "unknown substitution variable: '$1'"},
{'errComplexStmtRequiresInd': 'complex statement requires indentation'},
{'errXisNotCallable': "'$1' is not callable"},
@@ -204,7 +185,7 @@
{'errNoReturnTypeForX': 'no return type for $1 allowed'},
{'errConvNeedsOneArg': 'a type conversion needs exactly one argument'},
{'errInvalidPragmaX': 'invalid pragma: $1'},
{'errXNotAllowedHere': '$1 here not allowed'},
{'errXNotAllowedHere': '$1 not allowed here'},
{'errInvalidControlFlowX': 'invalid control flow: $1'},
{'errATypeHasNoValue': 'a type has no value'},
{'errXisNoType': "invalid type: '$1'"},
@@ -214,11 +195,11 @@
{'errInvalidExpressionX': "invalid expression: '$1'"},
{'errEnumHasNoValueX': "enum has no value '$1'"},
{'errNamedExprExpected': 'named expression expected'},
{'errNamedExprNotAllowed': 'named expression here not allowed'},
{'errNamedExprNotAllowed': 'named expression not allowed here'},
{'errXExpectsOneTypeParam': "'$1' expects one type parameter"},
{'errArrayExpectsTwoTypeParams': 'array expects two type parameters'},
{'errInvalidVisibilityX': "invalid invisibility: '$1'"},
{'errInitHereNotAllowed': 'initialization here not allowed'},
{'errInitHereNotAllowed': 'initialization not allowed here'},
{'errXCannotBeAssignedTo': "'$1' cannot be assigned to"},
{'errIteratorNotAllowed':
"iterators can only be defined at the module's top level"},
@@ -254,6 +235,7 @@
{'errUnhandledExceptionX': "unhandled exception: $1"},
{'errCyclicTree': "macro returned a cyclic abstract syntax tree"},
{'errXisNoMacroOrTemplate': "'$1' is no macro or template"},
{'errXhasSideEffects': "'$1' can have side effects"},
# user error message:
{'errUser': '$1'},

View File

@@ -29,8 +29,8 @@ addrExpr ::= 'addr' '(' optInd expr ')'
symbol ::= '`' (KEYWORD | IDENT | operator | '(' ')'
| '[' ']' | '=' | literal)+ '`'
| IDENT
primary ::= (prefixOperator optInd)* (symbol | constructor |
castExpr | addrExpr) (
primary ::= ((prefixOperator | 'bind') optInd)* (symbol | constructor |
castExpr | addrExpr) (
'.' optInd symbol
| '(' optInd namedExprList [SAD] ')'
| '[' optInd
@@ -42,7 +42,7 @@ primary ::= (prefixOperator optInd)* (symbol | constructor |
literal ::= INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
| FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
| STR_LIT | RSTR_LIT | TRIPLESTR_LIT
| CHAR_LIT | RCHAR_LIT
| CHAR_LIT
| NIL
constructor ::= literal

View File

@@ -336,7 +336,7 @@ Precedence level Operators First characte
The grammar's start symbol is ``module``. The grammar is LL(1) and therefore
not ambigious.
not ambiguous.
.. include:: grammar.txt
:literal:
@@ -920,6 +920,95 @@ each other:
Most calling conventions exist only for the Windows 32-bit platform.
Type relations
--------------
The following section defines several relations on types that are needed to
describe the type checking done by the compiler.
Type equality
~~~~~~~~~~~~~
Nimrod uses structural type equivalence for most types. Only for objects,
enumerations and abstract types name equivalence is used. The following
algorithm determines type equality:
.. code-block:: nimrod
proc typeEqualsAux(a, b: PType,
s: var set[tuple[PType, PType]]): bool =
if (a,b) in s: return true
incl(s, (a,b))
if a.kind == b.kind:
case a.kind
of int, intXX, float, floatXX, char, string, cstring, pointer, bool, nil:
# leaf type: kinds identical; nothing more to check
result = true
of ref, ptr, var, set, seq, openarray:
result = typeEqualsAux(a.baseType, b.baseType, s)
of range:
result = typeEqualsAux(a.baseType, b.baseType, s) and
(a.rangeA == b.rangeA) and (a.rangeB == b.rangeB)
of array:
result = typeEqualsAux(a.baseType, b.baseType, s) and
typeEqualsAux(a.indexType, b.indexType, s)
of tuple:
if a.tupleLen == b.tupleLen:
for i in 0..a.tupleLen-1:
if not typeEqualsAux(a[i], b[i], s): return false
result = true
of object, enum, abstract:
result = a == b
of proc:
result = typeEqualsAux(a.parameterTuple, b.parameterTuple, s) and
typeEqualsAux(a.resultType, b.resultType, s) and
a.callingConvention == b.callingConvention
proc typeEquals(a, b: PType): bool =
var s: set[tuple[PType, PType]] = {}
result = typeEqualsAux(a, b, s)
Since types are graphs which can have cycles, the above algorithm needs an
auxiliary set ``s`` to detect this case.
Subtype relation
~~~~~~~~~~~~~~~~
If object ``b`` inherits from ``a``, ``b`` is a subtype of ``a``. This subtype
relation is extended to the types ``var``, ``ref``, ``ptr``:
.. code-block:: nimrod
proc isSubtype(a, b: PType): bool =
if a.kind == b.kind:
case a.kind
of object:
var aa = a.baseType
while aa != nil and aa != b: aa = aa.baseType
result = aa == b
of var, ref, ptr:
result = isSubtype(a.baseType, b.baseType)
XXX nil is a special value!
Convertible relation
~~~~~~~~~~~~~~~~~~~~
A type ``a`` is convertible to type ``b`` iff the following algorithm returns
true:
.. code-block:: nimrod
proc isConvertible(a, b: PType): bool =
if a.kind == b.kind:
case a.kind
of proc:
var x = a.parameterTuple
var y = b.parameterTuple
if x.tupleLen == y.tupleLen:
for i in 0.. x.tupleLen-1:
if not isSubtype(x[i], y[i]): return false
result = isSubType(b.resultType, a.resultType)
Statements and expressions
--------------------------
@@ -927,8 +1016,7 @@ Nimrod uses the common statement/expression paradigm: `Statements`:idx: do not
produce a value in contrast to expressions. Call expressions are statements.
If the called procedure returns a value, it is not a valid statement
as statements do not produce values. To evaluate an expression for
side-effects and throwing its value away, one can use the ``discard``
statement.
side-effects and throw its value away, one can use the ``discard`` statement.
Statements are separated into `simple statements`:idx: and
`complex statements`:idx:.
@@ -1917,11 +2005,11 @@ iterator in which case the overloading resolution takes place:
# Module C
import A, B
write(stdout, x) # error: x is ambigious
write(stdout, x) # error: x is ambiguous
write(stdout, A.x) # no error: qualifier used
var x = 4
write(stdout, x) # not ambigious: uses the module C's x
write(stdout, x) # not ambiguous: uses the module C's x
Messages

View File

@@ -154,6 +154,9 @@ Index
* `system.html#313 <system.html#313>`_
* `system.html#314 <system.html#314>`_
`<=`:idx:
`times.html#115 <times.html#115>`_
`<=`:idx:
* `system.html#253 <system.html#253>`_
* `system.html#254 <system.html#254>`_
@@ -169,9 +172,6 @@ Index
* `system.html#345 <system.html#345>`_
* `system.html#346 <system.html#346>`_
`<=`:idx:
`times.html#115 <times.html#115>`_
`<=%`:idx:
* `system.html#305 <system.html#305>`_
* `system.html#306 <system.html#306>`_
@@ -201,7 +201,7 @@ Index
* `macros.html#117 <macros.html#117>`_
`=~`:idx:
`regexprs.html#111 <regexprs.html#111>`_
`regexprs.html#108 <regexprs.html#108>`_
`>`:idx:
`system.html#357 <system.html#357>`_
@@ -218,18 +218,18 @@ Index
`@`:idx:
`system.html#365 <system.html#365>`_
`[]`:idx:
`strtabs.html#107 <strtabs.html#107>`_
`[]`:idx:
`macros.html#113 <macros.html#113>`_
`[]=`:idx:
`macros.html#114 <macros.html#114>`_
`[]`:idx:
`strtabs.html#107 <strtabs.html#107>`_
`[]=`:idx:
`strtabs.html#106 <strtabs.html#106>`_
`[]=`:idx:
`macros.html#114 <macros.html#114>`_
`[ESC]`:idx:
`manual.html#134 <manual.html#134>`_
@@ -366,8 +366,7 @@ Index
`xmlgen.html#111 <xmlgen.html#111>`_
`backslash`:idx:
* `manual.html#127 <manual.html#127>`_
* `regexprs.html#101 <regexprs.html#101>`_
`manual.html#127 <manual.html#127>`_
`backspace`:idx:
`manual.html#132 <manual.html#132>`_
@@ -1228,7 +1227,7 @@ Index
`system.html#156 <system.html#156>`_
`EInvalidRegEx`:idx:
`regexprs.html#104 <regexprs.html#104>`_
`regexprs.html#101 <regexprs.html#101>`_
`EInvalidValue`:idx:
`system.html#148 <system.html#148>`_
@@ -1265,12 +1264,12 @@ Index
`enum_cursor_type`:idx:
`mysql.html#237 <mysql.html#237>`_
`Enumeration`:idx:
`manual.html#148 <manual.html#148>`_
`enumeration`:idx:
`tut1.html#113 <tut1.html#113>`_
`Enumeration`:idx:
`manual.html#148 <manual.html#148>`_
`enum_field_types`:idx:
`mysql.html#202 <mysql.html#202>`_
@@ -1546,8 +1545,8 @@ Index
* `strutils.html#124 <strutils.html#124>`_
* `strutils.html#125 <strutils.html#125>`_
* `strutils.html#126 <strutils.html#126>`_
* `regexprs.html#109 <regexprs.html#109>`_
* `regexprs.html#110 <regexprs.html#110>`_
* `regexprs.html#106 <regexprs.html#106>`_
* `regexprs.html#107 <regexprs.html#107>`_
`findChars`:idx:
`strutils.html#123 <strutils.html#123>`_
@@ -1631,9 +1630,6 @@ Index
* `system.html#478 <system.html#478>`_
* `system.html#479 <system.html#479>`_
`generic character types`:idx:
`regexprs.html#102 <regexprs.html#102>`_
`Generics`:idx:
* `manual.html#207 <manual.html#207>`_
* `tut2.html#108 <tut2.html#108>`_
@@ -2258,11 +2254,11 @@ Index
`xmlgen.html#150 <xmlgen.html#150>`_
`match`:idx:
* `regexprs.html#106 <regexprs.html#106>`_
* `regexprs.html#107 <regexprs.html#107>`_
* `regexprs.html#103 <regexprs.html#103>`_
* `regexprs.html#104 <regexprs.html#104>`_
`matchLen`:idx:
`regexprs.html#108 <regexprs.html#108>`_
`regexprs.html#105 <regexprs.html#105>`_
`math`:idx:
`nimrodc.html#118 <nimrodc.html#118>`_
@@ -2301,7 +2297,7 @@ Index
`mysql.html#191 <mysql.html#191>`_
`MaxSubpatterns`:idx:
`regexprs.html#105 <regexprs.html#105>`_
`regexprs.html#102 <regexprs.html#102>`_
`MAX_TINYINT_WIDTH`:idx:
`mysql.html#190 <mysql.html#190>`_
@@ -3095,12 +3091,12 @@ Index
`ord`:idx:
`system.html#172 <system.html#172>`_
`ordinal`:idx:
`tut1.html#114 <tut1.html#114>`_
`Ordinal`:idx:
`system.html#114 <system.html#114>`_
`ordinal`:idx:
`tut1.html#114 <tut1.html#114>`_
`Ordinal types`:idx:
`manual.html#141 <manual.html#141>`_
@@ -3623,16 +3619,16 @@ Index
`system.html#419 <system.html#419>`_
`reBinary`:idx:
`regexprs.html#116 <regexprs.html#116>`_
`regexprs.html#113 <regexprs.html#113>`_
`Recursive module dependancies`:idx:
`manual.html#216 <manual.html#216>`_
`reEmail`:idx:
`regexprs.html#119 <regexprs.html#119>`_
`regexprs.html#116 <regexprs.html#116>`_
`reFloat`:idx:
`regexprs.html#118 <regexprs.html#118>`_
`regexprs.html#115 <regexprs.html#115>`_
`REFRESH_DES_KEY_FILE`:idx:
`mysql.html#154 <mysql.html#154>`_
@@ -3680,13 +3676,13 @@ Index
`nimrodc.html#112 <nimrodc.html#112>`_
`reHex`:idx:
`regexprs.html#115 <regexprs.html#115>`_
`reIdentifier`:idx:
`regexprs.html#112 <regexprs.html#112>`_
`reIdentifier`:idx:
`regexprs.html#109 <regexprs.html#109>`_
`reInteger`:idx:
`regexprs.html#114 <regexprs.html#114>`_
`regexprs.html#111 <regexprs.html#111>`_
`removeDir`:idx:
`os.html#150 <os.html#150>`_
@@ -3695,10 +3691,10 @@ Index
`os.html#141 <os.html#141>`_
`reNatural`:idx:
`regexprs.html#113 <regexprs.html#113>`_
`regexprs.html#110 <regexprs.html#110>`_
`reOctal`:idx:
`regexprs.html#117 <regexprs.html#117>`_
`regexprs.html#114 <regexprs.html#114>`_
`repeatChar`:idx:
`strutils.html#148 <strutils.html#148>`_
@@ -3724,7 +3720,7 @@ Index
`manual.html#189 <manual.html#189>`_
`reURL`:idx:
`regexprs.html#120 <regexprs.html#120>`_
`regexprs.html#117 <regexprs.html#117>`_
`round`:idx:
`math.html#121 <math.html#121>`_
@@ -3889,9 +3885,6 @@ Index
* `system.html#226 <system.html#226>`_
* `system.html#227 <system.html#227>`_
`simple assertions`:idx:
`regexprs.html#103 <regexprs.html#103>`_
`simple statements`:idx:
`manual.html#174 <manual.html#174>`_
@@ -5154,6 +5147,9 @@ Index
* `manual.html#156 <manual.html#156>`_
* `tut2.html#103 <tut2.html#103>`_
`verbose`:idx:
`regexprs.html#118 <regexprs.html#118>`_
`vertical tabulator`:idx:
`manual.html#126 <manual.html#126>`_

View File

@@ -264,7 +264,7 @@ For integers or other ordinal types value ranges are also possible:
However, the above code does not compile: The reason is that you have to cover
every value that ``n`` may contain, but the code only handles the values
``0..8``. Since it is not very practical to list every other possible integer
(though it is possible thanks to the range notation!), we fix this by telling
(though it is possible thanks to the range notation), we fix this by telling
the compiler that for every other value nothing should be done:
.. code-block:: nimrod
@@ -624,7 +624,8 @@ Nimrod provides the ability to overload procedures similar to C++:
.. code-block:: nimrod
proc toString(x: int): string = ...
proc toString(x: bool): string =
if x: return "true" else: return "false"
if x: return "true"
else: return "false"
Echo(toString(13)) # calls the toString(x: int) proc
Echo(toString(true)) # calls the toString(x: bool) proc
@@ -634,7 +635,7 @@ The compiler chooses the most appropriate proc for the ``toString`` calls. How
this overloading resolution algorithm works exactly is not discussed here
(it will be specified in the manual soon).
However, it does not lead to nasty suprises and is based on a quite simple
unification algorithm. Ambigious calls are reported as errors.
unification algorithm. Ambiguous calls are reported as errors.
Operators
@@ -643,7 +644,7 @@ The Nimrod library makes heavy use of overloading - one reason for this is that
each operator like ``+`` is a just an overloaded proc. The parser lets you
use operators in `infix notation` (``a + b``) or `prefix notation` (``+ a``).
An infix operator always receives two arguments, a prefix operator always one.
Postfix operators are not possible, because this would be ambigious: Does
Postfix operators are not possible, because this would be ambiguous: Does
``a @ @ b`` mean ``(a) @ (@b)`` or ``(a@) @ (b)``? It always means
``(a) @ (@b)``, because there are no postfix operators in Nimrod.
@@ -1331,7 +1332,7 @@ This is best illustrated by an example:
A symbol of a module *can* be *qualified* with the ``module.symbol`` syntax. If
the symbol is ambigious, it even *has* to be qualified. A symbol is ambigious
the symbol is ambiguous, it even *has* to be qualified. A symbol is ambiguous
if it is defined in two (or more) different modules and both modules are
imported by a third one:
@@ -1344,11 +1345,11 @@ imported by a third one:
# Module C
import A, B
write(stdout, x) # error: x is ambigious
write(stdout, x) # error: x is ambiguous
write(stdout, A.x) # no error: qualifier used
var x = 4
write(stdout, x) # not ambigious: uses the module C's x
write(stdout, x) # not ambiguous: uses the module C's x
But this rule does not apply to procedures or iterators. Here the overloading
@@ -1367,7 +1368,7 @@ rules apply:
write(stdout, x("")) # no error: B.x is called
proc x*(a: int): string = nil
write(stdout, x(3)) # ambigious: which `x` is to call?
write(stdout, x(3)) # ambiguous: which `x` is to call?
From statement

View File

@@ -34,7 +34,7 @@ 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. In particular, prefering aggregation over inheritance
often results in a better design.
is often the better design.
Objects
@@ -446,8 +446,7 @@ containers:
# 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
var n = stack.pop()
while n != nil:
yield n
add(stack, n.ri) # push right subtree onto the stack
@@ -562,11 +561,11 @@ via a special ``:`` syntax:
block:
var fn = filename
var f: TFile
if openFile(f, fn, mode):
if open(f, fn, mode):
try:
actions
finally:
closeFile(f)
close(f)
else:
quit("cannot open: " & fn)
@@ -593,9 +592,7 @@ 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 write a macro, one needs to know how the Nimrod concrete syntax is converted
to an abstract syntax tree (AST). The AST is documented in the
`macros <macros.html>`_ module.

View File

@@ -66,6 +66,4 @@ Currently, the following C compilers are supported under Windows:
- | Digital Mars C++
| http://www.digitalmars.com/download/freecompiler.html
For better compile times I recommend Digital Mars C++ -- it is easy to install
and a small package.
However, most testing is done with GCC.

View File

@@ -253,8 +253,8 @@ class Changed:
c = Changed("unique_name", "file1.pas file2.pas file3.pas")
if c.check():
Exec("fpc file1.pas")
# Exec raises an exception if it fails, thus if we get to here, it was
# a success:
# Exec raises an exception if it fails, thus if we reach the
# next statement, it was a success:
c.success()
"""
def __init__(self, id, files, explain=false,

File diff suppressed because it is too large Load Diff

View File

@@ -45,27 +45,27 @@ type
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, nnkCommentStmt,
nnkStmtListExpr, nnkBlockExpr, nnkStmtListType, nnkBlockType,
nnkVm, nnkTypeOfExpr, nnkObjectTy, nnkTupleTy,
nnkRecList, nnkRecCase, nnkRecWhen, nnkRefTy,
nnkPtrTy, nnkVarTy, nnkAbstractTy, nnkProcTy,
nnkEnumTy, nnkEnumFieldDef, nnkReturnToken
nnkAccQuoted, nnkTableConstr, nnkQualified, nnkBind,
nnkSymChoice, 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,
nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr, nnkStmtListType,
nnkBlockType, nnkVm, nnkTypeOfExpr, nnkObjectTy,
nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen,
nnkRefTy, nnkPtrTy, nnkVarTy, nnkAbstractTy,
nnkProcTy, nnkEnumTy, nnkEnumFieldDef, nnkReturnToken
TNimNodeKinds* = set[TNimrodNodeKind]
TNimrodTypeKind* = enum
ntyNone, ntyBool, ntyChar, ntyEmpty,

View File

@@ -556,9 +556,9 @@ proc sameFileContent*(path1, path2: string): bool =
bufSize = 8192 # 8K buffer
var
a, b: TFile
if not openFile(a, path1): return false
if not openFile(b, path2):
closeFile(a)
if not open(a, path1): return false
if not open(b, path2):
close(a)
return false
var bufA = alloc(bufsize)
var bufB = alloc(bufsize)
@@ -576,8 +576,8 @@ proc sameFileContent*(path1, path2: string): bool =
if readA != bufSize: break # end of file
dealloc(bufA)
dealloc(bufB)
closeFile(a)
closeFile(b)
close(a)
close(b)
proc copyFile*(dest, source: string) =
## Copies a file from `source` to `dest`. If this fails,
@@ -590,9 +590,9 @@ proc copyFile*(dest, source: string) =
bufSize = 8192 # 8K buffer
var
d, s: TFile
if not openFile(s, source): OSError()
if not openFile(d, dest, fmWrite):
closeFile(s)
if not open(s, source): OSError()
if not open(d, dest, fmWrite):
close(s)
OSError()
var
buf: Pointer = alloc(bufsize)
@@ -603,8 +603,8 @@ proc copyFile*(dest, source: string) =
if bytesread != bufSize: break
if bytesread != bytesWritten: OSError()
dealloc(buf)
closeFile(s)
closeFile(d)
close(s)
close(d)
proc moveFile*(dest, source: string) =
## Moves a file from `source` to `dest`. If this fails, `EOS` is raised.
@@ -954,7 +954,7 @@ proc getHomeDir*(): string =
when defined(windows): return getEnv("USERPROFILE") & "\\"
else: return getEnv("HOME") & "/"
proc getConfigDir*(): string {.noSideEffect.} =
proc getConfigDir*(): string =
## Returns the config directory of the current user for applications.
when defined(windows): return getEnv("APPDATA") & "\\"
else: return getEnv("HOME") & "/.config/"

View File

@@ -405,17 +405,17 @@ else:
proc inputStream(p: PProcess): PStream =
var f: TFile
if not openFile(f, p.inputHandle, fmWrite): OSError()
if not open(f, p.inputHandle, fmWrite): OSError()
result = newFileStream(f)
proc outputStream(p: PProcess): PStream =
var f: TFile
if not openFile(f, p.outputHandle, fmRead): OSError()
if not open(f, p.outputHandle, fmRead): OSError()
result = newFileStream(f)
proc errorStream(p: PProcess): PStream =
var f: TFile
if not openFile(f, p.errorHandle, fmRead): OSError()
if not open(f, p.errorHandle, fmRead): OSError()
result = newFileStream(f)
proc csystem(cmd: cstring): cint {.nodecl, importc: "system".}

View File

@@ -152,3 +152,25 @@ const ## common regular expressions
reURL* = r"\b(http(s)?|ftp|gopher|telnet|file|notes|ms\-help):" &
r"((//)|(\\\\))+[\w\d:#@%/;$()~_?\+\-\=\\\.\&]*\b"
## describes an URL
proc verbose*(pattern: string): string {.noSideEffect.} =
## deletes whitespace from a pattern that is not escaped or in a character
## class. This is modelled after Perl's ``/x`` modifier.
result = ""
var i = 0
while i < pattern.len:
case pattern[i]
of ' ', '\t':
inc i
of '\\':
add result, '\\'
add result, pattern[i+1]
inc i, 2
of '[':
while pattern[i] != ']' and pattern[i] != '\0':
add result, pattern[i]
inc i
else:
add result, pattern[i]
inc i

View File

@@ -144,7 +144,7 @@ type
TFileStream* = object of TStream
f: TFile
proc fsClose(s: PFileStream) = closeFile(s.f)
proc fsClose(s: PFileStream) = close(s.f)
proc fsAtEnd(s: PFileStream): bool = return EndOfFile(s.f)
proc fsSetPosition(s: PFileStream, pos: int) = setFilePos(s.f, pos)
proc fsGetPosition(s: PFileStream): int = return int(getFilePos(s.f))
@@ -171,7 +171,7 @@ proc newFileStream*(filename: string, mode: TFileMode): PFileStream =
## creates a new stream from the file named `filename` with the mode `mode`.
## If the file cannot be opened, nil is returned.
var f: TFile
if OpenFile(f, filename, mode): result = newFileStream(f)
if Open(f, filename, mode): result = newFileStream(f)
when true:

View File

@@ -150,15 +150,18 @@ proc find*(s: string, chars: set[char], 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, deprecated.}
## Replaces `sub` in `s` by the string `by`.
## **Deprecated since version 0.8.0**: Use `replace` instead.
proc replaceStr*(s: string, sub, by: char): string {.noSideEffect.}
proc replaceStr*(s: string, sub, by: char): string {.noSideEffect, deprecated.}
## optimized version for characters.
## **Deprecated since version 0.8.0**: Use `replace` instead.
proc deleteStr*(s: var string, first, last: int)
proc deleteStr*(s: var string, first, last: int) {.deprecated.}
## Deletes in `s` the characters at position `first`..`last`. This modifies
## `s` itself, it does not return a copy.
## **Deprecated since version 0.8.0**: Use `delete` instead.
proc toOctal*(c: char): string
## Converts a character `c` to its octal representation. The resulting
@@ -185,7 +188,7 @@ iterator split*(s: string, seps: set[char] = Whitespace): string =
## for word in split(";;this;is;an;;example;;;", {';'}):
## writeln(stdout, word)
##
## produces in the same output.
## produces the same output.
var
first: int = 0
last: int = 0
@@ -315,17 +318,15 @@ proc intToStr*(x: int, minchars: int = 1): string
proc ParseInt*(s: string): int {.noSideEffect.}
## Parses a decimal integer value contained in `s`. If `s` is not
## a valid integer, `EInvalidValue` is raised.
# XXX: make this biggestint!
proc ParseBiggestInt*(s: string): biggestInt {.noSideEffect.}
## Parses a decimal integer value contained in `s`. If `s` is not
## a valid integer, `EInvalidValue` is raised.
proc ParseFloat*(s: string, start = 0): float {.noSideEffect.}
proc ParseFloat*(s: string): float {.noSideEffect.}
## Parses a decimal floating point value contained in `s`. If `s` is not
## a valid floating point number, `EInvalidValue` is raised. ``NAN``,
## ``INF``, ``-INF`` are also supported (case insensitive comparison).
# XXX: make this biggestfloat.
# the stringify and format operators:
proc toString*[Ty](x: Ty): string
@@ -439,10 +440,15 @@ proc findNormalized(x: string, inArray: openarray[string]): int =
proc addf(s: var string, formatstr: string, a: openarray[string]) =
const PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\128'..'\255', '_'}
var i = 0
var num = 0
while i < len(formatstr):
if formatstr[i] == '$':
case formatstr[i+1] # again we use the fact that strings
# are zero-terminated here
of '#':
add s, a[num]
inc i, 2
inc num
of '$':
add s, '$'
inc(i, 2)
@@ -452,6 +458,7 @@ proc addf(s: var string, formatstr: string, a: openarray[string]) =
while formatstr[i] in {'0'..'9'}:
j = j * 10 + ord(formatstr[i]) - ord('0')
inc(i)
num = j
add s, a[j - 1]
of '{':
var j = i+1
@@ -510,6 +517,31 @@ proc splitSeq(s: string, seps: set[char]): seq[string] =
# ---------------------------------------------------------------------------
proc join*(a: openArray[string], sep: string): string =
## concatenates all strings in `a` separating them with `sep`.
if len(a) > 0:
var L = sep.len * (a.len-1)
for i in 0..high(a): inc(L, a[i].len)
result = newString(L)
setLen(result, 0)
add(result, a[0])
for i in 1..high(a):
add(result, sep)
add(result, a[i])
else:
result = ""
proc join*(a: openArray[string]): string =
## concatenates all strings in `a`.
if len(a) > 0:
var L = 0
for i in 0..high(a): inc(L, a[i].len)
result = newString(L)
setLen(result, 0)
for i in 0..high(a): add(result, a[i])
else:
result = ""
proc strip(s: string, leading = true, trailing = true): string =
const
chars: set[Char] = Whitespace
@@ -638,7 +670,8 @@ proc contains(s: string, c: char): bool =
proc contains(s, sub: string): bool =
return find(s, sub) >= 0
proc replaceStr(s, sub, by: string): string =
proc replace*(s, sub, by: string): string =
## Replaces `sub` in `s` by the string `by`.
var a: TSkipTable
result = ""
preprocessSub(sub, a)
@@ -652,7 +685,8 @@ proc replaceStr(s, sub, by: string): string =
# copy the rest:
add result, copy(s, i)
proc replaceStr(s: string, sub, by: char): string =
proc replace*(s: string, sub, by: char): string =
## optimized version for characters.
result = newString(s.len)
var i = 0
while i < s.len:
@@ -660,17 +694,23 @@ proc replaceStr(s: string, sub, by: char): string =
else: result[i] = s[i]
inc(i)
proc deleteStr(s: var string, first, last: int) =
proc delete*(s: var string, first, last: int) =
## Deletes in `s` the characters at position `first`..`last`. This modifies
## `s` itself, it does not return a copy.
var
i = first
# example: "abc___uvwxyz\0" (___ is to be deleted)
# --> first == 3, last == 5
# s[first..] = s[last+1..]
var
i = first
while last+i+1 < len(s):
s[i] = s[last+i+1]
inc(i)
setlen(s, len(s)-(last-first+1))
proc replaceStr(s, sub, by: string): string = return replace(s, sub, by)
proc replaceStr(s: string, sub, by: char): string = return replace(s, sub, by)
proc deleteStr*(s: var string, first, last: int) = delete(s, first, last)
# parsing numbers:
proc toHex(x: BiggestInt, len: int): string =
@@ -734,11 +774,11 @@ proc ParseBiggestInt(s: string): biggestInt =
if index == -1:
raise newException(EInvalidValue, "invalid integer: " & s)
proc ParseFloat(s: string, start = 0): float =
proc ParseFloat(s: string): float =
var
esign = 1.0
sign = 1.0
i = start
i = 0
exponent: int
flags: int
result = 0.0

View File

@@ -69,11 +69,12 @@ proc `or`*(x, y: bool): bool {.magic: "Or", noSideEffect.}
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", noSideEffect.}
## creates a new object of type ``T`` and returns a safe (traced)
## reference to it in ``a``.
proc new*[T](a: var ref T, finalizer: proc (x: ref T)) {.magic: "NewFinalize".}
proc new*[T](a: var ref T, finalizer: proc (x: ref T)) {.
magic: "NewFinalize", noSideEffect.}
## creates a new object of type ``T`` and returns a safe (traced)
## reference to it in ``a``. When the garbage collector frees the object,
## `finalizer` is called. The `finalizer` may not keep a reference to the
@@ -230,17 +231,17 @@ proc pred*[T](x: ordinal[T], y = 1): T {.magic: "Pred", noSideEffect.}
## an ordinal type. If such a value does not exist, ``EOutOfRange`` is raised
## or a compile time error occurs.
proc inc*[T](x: var ordinal[T], y = 1) {.magic: "Inc".}
proc inc*[T](x: var ordinal[T], y = 1) {.magic: "Inc", noSideEffect.}
## increments the ordinal ``x`` by ``y``. If such a value does not
## exist, ``EOutOfRange`` is raised or a compile time error occurs. This is a
## short notation for: ``x = succ(x, y)``.
proc dec*[T](x: var ordinal[T], y = 1) {.magic: "Dec".}
proc dec*[T](x: var ordinal[T], y = 1) {.magic: "Dec", noSideEffect.}
## decrements the ordinal ``x`` by ``y``. If such a value does not
## exist, ``EOutOfRange`` is raised or a compile time error occurs. This is a
## short notation for: ``x = pred(x, y)``.
proc newSeq*[T](s: var seq[T], len: int) {.magic: "NewSeq".}
proc newSeq*[T](s: var seq[T], len: int) {.magic: "NewSeq", noSideEffect.}
## creates a new sequence of type ``seq[T]`` with length ``len``.
## This is equivalent to ``s = []; setlen(s, len)``, but more
## efficient since no relocation is needed.
@@ -255,11 +256,11 @@ proc len*[T](x: seq[T]): int {.magic: "LengthSeq", noSideEffect.}
## always an int.
# set routines:
proc incl*[T](x: var set[T], y: T) {.magic: "Incl".}
proc incl*[T](x: var set[T], y: T) {.magic: "Incl", noSideEffect.}
## includes element ``y`` to the set ``x``. This is the same as
## ``x = x + {y}``, but it might be more efficient.
proc excl*[T](x: var set[T], y: T) {.magic: "Excl".}
proc excl*[T](x: var set[T], y: T) {.magic: "Excl", noSideEffect.}
## excludes element ``y`` to the set ``x``. This is the same as
## ``x = x - {y}``, but it might be more efficient.
@@ -641,8 +642,8 @@ proc `&` * (x: char, y: string): string {.
magic: "ConStrStr", noSideEffect, merge.}
## is the `concatenation operator`. It concatenates `x` and `y`.
proc add*(x: var string, y: char) {.magic: "AppendStrCh".}
proc add*(x: var string, y: string) {.magic: "AppendStrStr".}
proc add*(x: var string, y: char) {.magic: "AppendStrCh", noSideEffect.}
proc add*(x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.}
when not defined(ECMAScript):
{.push overflow_checks:off}
@@ -663,8 +664,8 @@ else:
`x`[0][len] = 0
"""
proc add *[T](x: var seq[T], y: T) {.magic: "AppendSeqElem".}
proc add *[T](x: var seq[T], y: seq[T]) {.magic: "AppendSeqSeq".}
proc add *[T](x: var seq[T], y: T) {.magic: "AppendSeqElem", noSideEffect.}
proc add *[T](x: var seq[T], y: seq[T]) {.magic: "AppendSeqSeq", noSideEffect.}
## Generic proc for adding a data item `y` to a container `x`.
## For containers that have an order, `add` means *append*. New generic
## containers should also call their adding proc `add` for consistency.
@@ -811,7 +812,8 @@ proc copy*(s: string, first, last: int): string {.
## the first and last characters that shall be copied. If ``last``
## is omitted, it is treated as ``high(s)``.
proc setLen*(s: var string, newlen: int) {.magic: "SetLengthStr".}
proc setLen*(s: var string, newlen: int) {.
magic: "SetLengthStr", noSideEffect.}
## sets the length of `s` to `newlen`.
## If the current length is greater than the new length,
## ``s`` will be truncated.
@@ -873,20 +875,21 @@ proc dealloc*(p: Pointer) {.noconv.}
## or other memory may be corrupted. So this procedure is really
## *unsafe*.
proc setLen*[T](s: var seq[T], newlen: int) {.magic: "SetLengthSeq".}
proc setLen*[T](s: var seq[T], newlen: int) {.
magic: "SetLengthSeq", noSideEffect.}
## sets the length of `s` to `newlen`.
## ``T`` may be any sequence type.
## If the current length is greater than the new length,
## ``s`` will be truncated.
proc assert*(cond: bool) {.magic: "Assert".}
proc assert*(cond: bool) {.magic: "Assert", noSideEffect.}
## provides a means to implement `programming by contracts` in Nimrod.
## ``assert`` evaluates expression ``cond`` and if ``cond`` is false, it
## raises an ``EAssertionFailure`` exception. However, the compiler may
## not generate any code at all for ``assert`` if it is advised to do so.
## Thus one should use ``assert`` for debugging purposes only.
proc swap*[T](a, b: var T) {.magic: "Swap".}
proc swap*[T](a, b: var T) {.magic: "Swap", noSideEffect.}
## swaps the values `a` and `b`. This is often more efficient than
## ``tmp = a; a = b; b = tmp``. Particularly useful for sorting algorithms.
@@ -934,7 +937,7 @@ proc `$` *[T](x: ordinal[T]): string {.magic: "EnumToStr", noSideEffect.}
## used instead. (In other words: *Overwriting* is possible.)
# undocumented:
proc getRefcount*[T](x: ref T): int {.importc: "getRefcount".}
proc getRefcount*[T](x: ref T): int {.importc: "getRefcount", noSideEffect.}
## retrieves the reference count of an heap-allocated object. The
## value is implementation-dependant.
@@ -1107,18 +1110,19 @@ proc find*[T, S](a: T, item: S): int {.inline.} =
inc(result)
result = -1
proc pop*[T](s: var seq[T]): T {.inline.} =
proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} =
## returns the last item of `s` and decreases ``s.len`` by one. This treats
## `s` as a stack and implements the common *pop* operation.
var L = s.len-1
result = s[L]
setLen(s, L)
proc each*[T, S](data: openArray[T], op: proc (x: T): S): seq[S] =
proc each*[T, S](data: openArray[T], op: proc (x: T): S): seq[S] {.
noSideEffect.} =
## The well-known ``map`` operation from functional programming. Applies
## `op` to every item in `data` and returns the result as a sequence.
result = @[]
for d in items(data): add(result, op(d))
newSeq(result, data.len)
for i in 0..data.len-1: result[i] = op(data[i])
# ----------------- FPU ------------------------------------------------------
@@ -1293,7 +1297,16 @@ when not defined(EcmaScript) and not defined(NimrodVM):
## does not work because the program writes to ``stderr``.
proc OpenFile*(f: var TFile, filename: string,
mode: TFileMode = fmRead, bufSize: int = -1): Bool
mode: TFileMode = fmRead,
bufSize: int = -1): Bool {.deprecated.}
## **Deprecated since version 0.8.0**: Use `open` instead.
proc OpenFile*(f: var TFile, filehandle: TFileHandle,
mode: TFileMode = fmRead): Bool {.deprecated.}
## **Deprecated since version 0.8.0**: Use `open` instead.
proc Open*(f: var TFile, filename: string,
mode: TFileMode = fmRead, bufSize: int = -1): Bool
## Opens a file named `filename` with given `mode`.
##
## Default mode is readonly. Returns true iff the file could be opened.
@@ -1301,14 +1314,19 @@ when not defined(EcmaScript) and not defined(NimrodVM):
## that the programmer needs to provide an appropriate error message anyway
## (yes, even in scripts).
proc OpenFile*(f: var TFile, filehandle: TFileHandle,
mode: TFileMode = fmRead): Bool
proc Open*(f: var TFile, filehandle: TFileHandle,
mode: TFileMode = fmRead): Bool
## Creates a ``TFile`` from a `filehandle` with given `mode`.
##
## Default mode is readonly. Returns true iff the file could be opened.
proc CloseFile*(f: TFile) {.importc: "fclose", nodecl.}
proc CloseFile*(f: TFile) {.importc: "fclose", nodecl, deprecated.}
## Closes the file.
## **Deprecated since version 0.8.0**: Use `close` instead.
proc Close*(f: TFile) {.importc: "fclose", nodecl.}
## Closes the file.
proc EndOfFile*(f: TFile): Bool
## Returns true iff `f` is at the end.
proc readChar*(f: TFile): char {.importc: "fgetc", nodecl.}
@@ -1394,13 +1412,13 @@ when not defined(EcmaScript) and not defined(NimrodVM):
## If the file does not exist `EIO` is raised.
var
f: TFile
if not openFile(f, filename):
if not open(f, filename):
raise newException(EIO, "cannot open: " & filename)
var res = ""
while not endOfFile(f):
rawReadLine(f, res)
yield res
CloseFile(f)
Close(f)
proc fileHandle*(f: TFile): TFileHandle {.importc: "fileno",
header: "<stdio.h>"}

View File

@@ -13,10 +13,11 @@
{.push hints:off}
proc c_strcmp(a, b: CString): cint {.nodecl, importc: "strcmp".}
proc c_memcmp(a, b: CString, size: cint): cint {.nodecl, importc: "memcmp".}
proc c_strcmp(a, b: CString): cint {.nodecl, noSideEffect, importc: "strcmp".}
proc c_memcmp(a, b: CString, size: cint): cint {.
nodecl, noSideEffect, importc: "memcmp".}
proc c_memcpy(a, b: CString, size: cint) {.nodecl, importc: "memcpy".}
proc c_strlen(a: CString): int {.nodecl, importc: "strlen".}
proc c_strlen(a: CString): int {.nodecl, noSideEffect, importc: "strlen".}
proc c_memset(p: pointer, value: cint, size: int) {.nodecl, importc: "memset".}
type

View File

@@ -1,7 +1,7 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2008 Andreas Rumpf
# (c) Copyright 2009 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -10,11 +10,11 @@
# simple integer arithmetic with overflow checking
proc raiseOverflow {.compilerproc, noinline.} =
proc raiseOverflow {.compilerproc, noinline, noreturn.} =
# a single proc to reduce code size to a minimum
raise newException(EOverflow, "over- or underflow")
proc raiseDivByZero {.compilerproc, noinline.} =
proc raiseDivByZero {.compilerproc, noinline, noreturn.} =
raise newException(EDivByZero, "divison by zero")
proc addInt64(a, b: int64): int64 {.compilerProc, inline.} =

View File

@@ -81,7 +81,7 @@ proc ListBreakPoints() =
write(stdout, "***\n")
proc openAppend(filename: string): TFile =
if openFile(result, filename, fmAppend):
if open(result, filename, fmAppend):
write(result, "----------------------------------------\n")
proc dbgRepr(p: pointer, typ: PNimType): string =
@@ -329,7 +329,7 @@ proc dbgOut(s: string, start: int, currFrame: PExtendedFrame) =
debugOut("[Warning] could not open or create file ")
return
dbgEvaluate(stream, s, i, currFrame)
closeFile(stream)
close(stream)
proc dbgStackFrame(s: string, start: int, currFrame: PExtendedFrame) =
var dbgTemp: string
@@ -343,7 +343,7 @@ proc dbgStackFrame(s: string, start: int, currFrame: PExtendedFrame) =
debugOut("[Warning] could not open or create file ")
return
ListFrame(stream, currFrame)
closeFile(stream)
close(stream)
proc CommandPrompt() =
# if we return from this routine, user code executes again

View File

@@ -71,13 +71,13 @@ proc write(f: TFile, a: openArray[string]) =
proc readFile(filename: string): string =
var f: TFile
try:
if openFile(f, filename):
if open(f, filename):
var len = getFileSize(f)
if len < high(int):
result = newString(int(len))
if readBuffer(f, addr(result[0]), int(len)) != len:
result = nil
closeFile(f)
close(f)
else:
result = nil
except EIO:
@@ -112,9 +112,9 @@ const
# should not be translated.
proc OpenFile(f: var TFile, filename: string,
mode: TFileMode = fmRead,
bufSize: int = -1): Bool =
proc Open(f: var TFile, filename: string,
mode: TFileMode = fmRead,
bufSize: int = -1): Bool =
var
p: pointer
p = fopen(filename, FormatOpen[mode])
@@ -129,10 +129,18 @@ proc OpenFile(f: var TFile, filename: string,
proc fdopen(filehandle: TFileHandle, mode: cstring): TFile {.
importc: pccHack & "fdopen", header: "<stdio.h>".}
proc openFile(f: var TFile, filehandle: TFileHandle, mode: TFileMode): bool =
proc open(f: var TFile, filehandle: TFileHandle, mode: TFileMode): bool =
f = fdopen(filehandle, FormatOpen[mode])
result = f != nil
proc OpenFile(f: var TFile, filename: string,
mode: TFileMode = fmRead,
bufSize: int = -1): Bool =
result = open(f, filename, mode, bufSize)
proc openFile(f: var TFile, filehandle: TFileHandle, mode: TFileMode): bool =
result = open(f, filehandle, mode)
# C routine that is used here:
proc fread(buf: Pointer, size, n: int, f: TFile): int {.
importc: "fread", noDecl.}

View File

@@ -786,7 +786,7 @@ type
mem_root*: MEM_ROOT # root allocations
mysql*: PMYSQL # connection handle
params*: PMYSQL_BIND # input parameters
bind*: PMYSQL_BIND # input parameters
`bind`*: PMYSQL_BIND # input parameters
fields*: PMYSQL_FIELD # result set metadata
result*: MYSQL_DATA # cached result set
data_cursor*: PMYSQL_ROWS # current row in cached result
@@ -1042,7 +1042,7 @@ proc mysql_stmt_execute*(stmt: PMYSQL_STMT): cint{.stdcall, dynlib: mysqllib,
importc: "mysql_stmt_execute".}
proc mysql_stmt_fetch*(stmt: PMYSQL_STMT): cint{.stdcall, dynlib: mysqllib,
importc: "mysql_stmt_fetch".}
proc mysql_stmt_fetch_column*(stmt: PMYSQL_STMT, bind: PMYSQL_BIND,
proc mysql_stmt_fetch_column*(stmt: PMYSQL_STMT, `bind`: PMYSQL_BIND,
column: cuint, offset: int): cint{.stdcall,
dynlib: mysqllib, importc: "mysql_stmt_fetch_column".}
proc mysql_stmt_store_result*(stmt: PMYSQL_STMT): cint{.stdcall,

View File

@@ -78,27 +78,27 @@ type
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, nkCommentStmt,
nkStmtListExpr, nkBlockExpr, nkStmtListType, nkBlockType,
nkVm, nkTypeOfExpr, nkObjectTy, nkTupleTy,
nkRecList, nkRecCase, nkRecWhen, nkRefTy,
nkPtrTy, nkVarTy, nkAbstractTy, nkProcTy,
nkEnumTy, nkEnumFieldDef, nkReturnToken);
nkAccQuoted, nkTableConstr, nkQualified, nkBind,
nkSymChoice, 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,
nkCommentStmt, nkStmtListExpr, nkBlockExpr, nkStmtListType,
nkBlockType, nkVm, nkTypeOfExpr, nkObjectTy,
nkTupleTy, nkRecList, nkRecCase, nkRecWhen,
nkRefTy, nkPtrTy, nkVarTy, nkAbstractTy,
nkProcTy, nkEnumTy, nkEnumFieldDef, nkReturnToken);
TNodeKinds = set of TNodeKind;
const
NodeKindToStr: array [TNodeKind] of string = (
@@ -113,48 +113,48 @@ const
'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', 'nkCommentStmt',
'nkStmtListExpr', 'nkBlockExpr', 'nkStmtListType', 'nkBlockType',
'nkVm', 'nkTypeOfExpr', 'nkObjectTy', 'nkTupleTy',
'nkRecList', 'nkRecCase', 'nkRecWhen', 'nkRefTy',
'nkPtrTy', 'nkVarTy', 'nkAbstractTy', 'nkProcTy',
'nkEnumTy', 'nkEnumFieldDef', 'nkReturnToken');
'nkAccQuoted', 'nkTableConstr', 'nkQualified', 'nkBind',
'nkSymChoice', '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',
'nkCommentStmt', 'nkStmtListExpr', 'nkBlockExpr', 'nkStmtListType',
'nkBlockType', 'nkVm', 'nkTypeOfExpr', 'nkObjectTy',
'nkTupleTy', 'nkRecList', 'nkRecCase', 'nkRecWhen',
'nkRefTy', 'nkPtrTy', 'nkVarTy', 'nkAbstractTy',
'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,
sfBorrow);
sfResult, sfNoSideEffect, sfSideEffect, sfMainModule,
sfSystemModule, sfNoReturn, sfAddrTaken, sfCompilerProc,
sfCppMethod, sfDiscriminant, sfDeprecated, sfInClosure,
sfTypeCheck, sfCompileTime, sfThreadVar, sfMerge,
sfDeadCodeElim, sfBorrow);
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',
'sfBorrow');
'sfResult', 'sfNoSideEffect', 'sfSideEffect', 'sfMainModule',
'sfSystemModule', 'sfNoReturn', 'sfAddrTaken', 'sfCompilerProc',
'sfCppMethod', 'sfDiscriminant', 'sfDeprecated', 'sfInClosure',
'sfTypeCheck', 'sfCompileTime', 'sfThreadVar', 'sfMerge',
'sfDeadCodeElim', 'sfBorrow');
type
TTypeKind = (
tyNone, tyBool, tyChar, tyEmpty,
@@ -189,11 +189,13 @@ const
'nfAllConst', 'nfTransf', 'nfSem');
type
TTypeFlag = (
tfVarargs, tfFinal, tfAcyclic, tfEnumHasWholes);
tfVarargs, tfNoSideEffect, tfFinal, tfAcyclic,
tfEnumHasWholes);
TTypeFlags = set of TTypeFlag;
const
TypeFlagToStr: array [TTypeFlag] of string = (
'tfVarargs', 'tfFinal', 'tfAcyclic', 'tfEnumHasWholes');
'tfVarargs', 'tfNoSideEffect', 'tfFinal', 'tfAcyclic',
'tfEnumHasWholes');
type
TSymKind = (
skUnknownSym, skConditional, skDynLib, skParam,

View File

@@ -220,8 +220,7 @@ end;
function addrLoc(const a: TLoc): PRope;
begin
result := a.r;
if not (lfIndirect in a.flags) then
result := con('&'+'', result)
if not (lfIndirect in a.flags) then result := con('&'+'', result)
end;
function rdCharLoc(const a: TLoc): PRope;
@@ -2257,32 +2256,6 @@ begin
end;
// ---------------------- generation of complex constants ---------------------
(*
function transformRecordExpr(n: PNode): PNode;
var
i: int;
t: PType;
field: PSym;
begin
result := copyNode(n);
newSons(result, sonsLen(n));
t := getUniqueType(skipTypes(n.Typ, abstractVarRange));
if t.n = nil then
InternalError(n.info, 'transformRecordExpr: invalid type');
for i := 0 to sonsLen(n)-1 do begin
assert(n.sons[i].kind = nkExprColonExpr);
assert(n.sons[i].sons[0].kind = nkSym);
field := n.sons[i].sons[0].sym;
field := lookupInRecord(t.n, field.name);
if field = nil then
InternalError(n.sons[i].info, 'transformRecordExpr: unknown field');
if result.sons[field.position] <> nil then begin
InternalError(n.sons[i].info, 'transformRecordExpr: value twice: ' +
renderTree(n.sons[i]));
end;
result.sons[field.position] := copyTree(n.sons[i].sons[1]);
end;
end; *)
function genNamedConstExpr(p: BProc; n: PNode): PRope;
begin

View File

@@ -139,16 +139,22 @@ function ropeFormatNamedVars(const frmt: TFormatStr;
const varnames: array of string;
const varvalues: array of PRope): PRope;
var
i, j, L, start, idx: int;
i, j, L, start, idx, num: int;
id: string;
begin
i := strStart;
L := length(frmt);
result := nil;
num := 0;
while i <= L + StrStart - 1 do begin
if frmt[i] = '$' then begin
inc(i); // skip '$'
case frmt[i] of
'#': begin
app(result, varvalues[num]);
inc(num);
inc(i);
end;
'$': begin
app(result, '$'+'');
inc(i)
@@ -162,6 +168,7 @@ begin
end;
if j > high(varvalues) + 1 then
internalError('ropeFormatNamedVars');
num := j;
app(result, varvalues[j - 1])
end;
'A'..'Z', 'a'..'z', #128..#255: begin
@@ -515,17 +522,17 @@ begin
result := renderRstSons(d, n);
L := ropeLen(result);
result := ropef('$n$1$2$n$1$3', [ind, result,
toRope(repeatChar(L, lvlToChar[n.level]))]);
toRope(repeatChar(L, lvlToChar[n.level]))]);
end;
rnOverline: begin
result := renderRstSons(d, n);
L := ropeLen(result);
result := ropef('$n$1$3$n$1$2$n$1$3', [ind, result,
toRope(repeatChar(L, lvlToChar[n.level]))]);
toRope(repeatChar(L, lvlToChar[n.level]))]);
end;
rnTransition:
result := ropef('$n$n$1$2$n$n',
[ind, toRope(repeatChar(78-d.indent, '-'))]);
[ind, toRope(repeatChar(78-d.indent, '-'))]);
rnParagraph: begin
result := renderRstSons(d, n);
result := ropef('$n$n$1$2', [ind, result]);
@@ -1003,7 +1010,4 @@ begin
generateIndex(d);
end;
// #FFD700
// #9f9b75
end.

View File

@@ -35,8 +35,9 @@ type
TEvalContext = object(passes.TPassContext)
module: PSym;
tos: PStackFrame; // top of a tos tos
tos: PStackFrame; // top of stack
lastException: PNode;
optEval: bool; // evaluation done for optimization purposes
end;
PEvalContext = ^TEvalContext;
@@ -44,12 +45,15 @@ function newStackFrame(): PStackFrame;
procedure pushStackFrame(c: PEvalContext; t: PStackFrame);
procedure popStackFrame(c: PEvalContext);
function newEvalContext(module: PSym; const filename: string): PEvalContext;
function newEvalContext(module: PSym; const filename: string;
optEval: bool): PEvalContext;
function eval(c: PEvalContext; n: PNode): PNode;
// eval never returns nil! This simplifies the code a lot and
// makes it faster too.
function evalConstExpr(module: PSym; e: PNode): PNode;
function evalPass(): TPass;
implementation
@@ -71,13 +75,15 @@ begin
{@emit result.params := @[];}
end;
function newEvalContext(module: PSym; const filename: string): PEvalContext;
function newEvalContext(module: PSym; const filename: string;
optEval: bool): PEvalContext;
begin
new(result);
{@ignore}
fillChar(result^, sizeof(result^), 0);
{@emit}
result.module := module;
result.optEval := optEval;
end;
procedure pushStackFrame(c: PEvalContext; t: PStackFrame);
@@ -228,32 +234,35 @@ begin
case result.kind of
nkBreakStmt, nkReturnToken: begin end;
nkExceptBranch: begin
// exception token!
exc := result;
i := 1;
len := sonsLen(n);
while (i < len) and (n.sons[i].kind = nkExceptBranch) do begin
blen := sonsLen(n.sons[i]);
if blen = 1 then begin
// general except section:
result := evalAux(c, n.sons[i].sons[0]);
exc := result;
break
end
else begin
for j := 0 to blen-2 do begin
assert(n.sons[i].sons[j].kind = nkType);
if exc.typ.id = n.sons[i].sons[j].typ.id then begin
result := evalAux(c, n.sons[i].sons[blen-1]);
exc := result;
break
end
if sonsLen(result) >= 1 then begin
// creating a nkExceptBranch without sons means that it could not be
// evaluated
exc := result;
i := 1;
len := sonsLen(n);
while (i < len) and (n.sons[i].kind = nkExceptBranch) do begin
blen := sonsLen(n.sons[i]);
if blen = 1 then begin
// general except section:
result := evalAux(c, n.sons[i].sons[0]);
exc := result;
break
end
else begin
for j := 0 to blen-2 do begin
assert(n.sons[i].sons[j].kind = nkType);
if exc.typ.id = n.sons[i].sons[j].typ.id then begin
result := evalAux(c, n.sons[i].sons[blen-1]);
exc := result;
break
end
end
end;
inc(i);
end;
inc(i);
end;
result := evalFinally(c, n, exc);
end;
result := evalFinally(c, n, exc);
end
end
else
result := evalFinally(c, n, emptyNode);
end
@@ -339,6 +348,7 @@ begin
if n.typ <> nil then d.params[0] := getNullValue(n.typ, n.info);
pushStackFrame(c, d);
result := evalAux(c, prc);
if result.kind = nkExceptBranch then exit;
if n.typ <> nil then result := d.params[0];
popStackFrame(c);
end;
@@ -572,13 +582,24 @@ begin
if result.intVal <> 0 then result := evalAux(c, n.sons[2])
end;
function evalNoOpt(c: PEvalContext; n: PNode): PNode;
begin
result := newNodeI(nkExceptBranch, n.info);
// creating a nkExceptBranch without sons means that it could not be
// evaluated
end;
function evalNew(c: PEvalContext; n: PNode): PNode;
var
t: PType;
begin
t := skipTypes(n.sons[1].typ, abstractVar);
result := newNodeIT(nkRefTy, n.info, t);
addSon(result, getNullValue(t.sons[0], n.info));
if c.optEval then
result := evalNoOpt(c, n)
else begin
t := skipTypes(n.sons[1].typ, abstractVar);
result := newNodeIT(nkRefTy, n.info, t);
addSon(result, getNullValue(t.sons[0], n.info));
end
end;
function evalDeref(c: PEvalContext; n: PNode): PNode;
@@ -740,6 +761,7 @@ end;
function evalSetLengthStr(c: PEvalContext; n: PNode): PNode;
var
a, b: PNode;
oldLen, newLen: int;
begin
result := evalAux(c, n.sons[1]);
if result.kind = nkExceptBranch then exit;
@@ -748,7 +770,16 @@ begin
if result.kind = nkExceptBranch then exit;
b := result;
case a.kind of
nkStrLit..nkTripleStrLit: setLength(a.strVal, int(getOrdValue(b)));
nkStrLit..nkTripleStrLit: begin
{@ignore}
oldLen := length(a.strVal);
{@emit}
newLen := int(getOrdValue(b));
setLength(a.strVal, newLen);
{@ignore}
FillChar(a.strVal[oldLen+1], newLen-oldLen, 0);
{@emit}
end
else InternalError(n.info, 'evalSetLengthStr')
end;
result := emptyNode
@@ -1241,6 +1272,7 @@ end;
function evalAux(c: PEvalContext; n: PNode): PNode;
var
i: int;
a: PNode;
begin
result := emptyNode;
dec(gNestedEvals);
@@ -1254,13 +1286,22 @@ begin
nkCall, nkHiddenCallConv, nkMacroStmt, nkCommand:
result := evalMagicOrCall(c, n);
nkCurly, nkBracket, nkRange: begin
result := copyNode(n);
for i := 0 to sonsLen(n)-1 do addSon(result, evalAux(c, n.sons[i]));
a := copyNode(n);
for i := 0 to sonsLen(n)-1 do begin
result := evalAux(c, n.sons[i]);
if result.kind = nkExceptBranch then exit;
addSon(a, result);
end;
result := a
end;
nkPar: begin
result := copyTree(n);
for i := 0 to sonsLen(n)-1 do
result.sons[i].sons[1] := evalAux(c, n.sons[i].sons[1]);
a := copyTree(n);
for i := 0 to sonsLen(n)-1 do begin
result := evalAux(c, n.sons[i].sons[1]);
if result.kind = nkExceptBranch then exit;
a.sons[i].sons[1] := result;
end;
result := a
end;
nkBracketExpr: result := evalArrayAccess(c, n);
nkDotExpr: result := evalFieldAccess(c, n);
@@ -1313,15 +1354,30 @@ begin
gWhileCounter := evalMaxIterations;
gNestedEvals := evalMaxRecDepth;
result := evalAux(c, n);
if result.kind = nkExceptBranch then
if (result.kind = nkExceptBranch) and (sonsLen(result) >= 1) then
stackTrace(c, n, errUnhandledExceptionX, typeToString(result.typ));
end;
function evalConstExpr(module: PSym; e: PNode): PNode;
var
p: PEvalContext;
s: PStackFrame;
begin
p := newEvalContext(module, '', true);
s := newStackFrame();
s.call := e;
pushStackFrame(p, s);
result := eval(p, e);
if (result <> nil) and (result.kind = nkExceptBranch) then
result := nil;
popStackFrame(p);
end;
function myOpen(module: PSym; const filename: string): PPassContext;
var
c: PEvalContext;
begin
c := newEvalContext(module, filename);
c := newEvalContext(module, filename, false);
pushStackFrame(c, newStackFrame());
result := c;
end;

View File

@@ -68,8 +68,8 @@ begin
if (check <> nil) and (check.id <> copy.id) then begin
if not (s.kind in OverloadableSyms) then begin
// s and check need to be qualified:
IntSetIncl(c.AmbigiousSymbols, copy.id);
IntSetIncl(c.AmbigiousSymbols, check.id);
IntSetIncl(c.AmbiguousSymbols, copy.id);
IntSetIncl(c.AmbiguousSymbols, check.id);
end
end;
StrTableAdd(c.tab.stack[importTablePos], copy);

View File

@@ -1,7 +1,7 @@
//
//
// The Nimrod Compiler
// (c) Copyright 2008 Andreas Rumpf
// (c) Copyright 2009 Andreas Rumpf
//
// See the file "copying.txt", included in this
// distribution, for details about the copyright.
@@ -19,7 +19,8 @@ uses
{$include 'config.inc'}
type
TOverloadIterMode = (oimNoQualifier, oimSelfModule, oimOtherModule);
TOverloadIterMode = (oimDone, oimNoQualifier, oimSelfModule, oimOtherModule,
oimSymChoice);
TOverloadIter = record
stackPtr: int;
it: TIdentIter;
@@ -43,7 +44,7 @@ procedure addInterfaceOverloadableSymAt(c: PContext; sym: PSym; at: int);
function lookUp(c: PContext; n: PNode): PSym;
// Looks up a symbol. Generates an error in case of nil.
function QualifiedLookUp(c: PContext; n: PNode; ambigiousCheck: bool): PSym;
function QualifiedLookUp(c: PContext; n: PNode; ambiguousCheck: bool): PSym;
function InitOverloadIter(out o: TOverloadIter; c: PContext; n: PNode): PSym;
function nextOverloadIter(var o: TOverloadIter; c: PContext; n: PNode): PSym;
@@ -139,22 +140,22 @@ begin
result := SymtabGet(c.Tab, n.sym.name);
if result = nil then
liMessage(n.info, errUndeclaredIdentifier, n.sym.name.s);
include(result.flags, sfUsed);
//include(result.flags, sfUsed);
end;
nkIdent: begin
result := SymtabGet(c.Tab, n.ident);
if result = nil then
liMessage(n.info, errUndeclaredIdentifier, n.ident.s);
include(result.flags, sfUsed);
//include(result.flags, sfUsed);
end
else InternalError(n.info, 'lookUp');
end;
if IntSetContains(c.AmbigiousSymbols, result.id) then
if IntSetContains(c.AmbiguousSymbols, result.id) then
liMessage(n.info, errUseQualifier, result.name.s);
if result.kind = skStub then loadStub(result);
end;
function QualifiedLookUp(c: PContext; n: PNode; ambigiousCheck: bool): PSym;
function QualifiedLookUp(c: PContext; n: PNode; ambiguousCheck: bool): PSym;
var
m: PSym;
ident: PIdent;
@@ -164,16 +165,16 @@ begin
result := SymtabGet(c.Tab, n.ident);
if result = nil then
liMessage(n.info, errUndeclaredIdentifier, n.ident.s)
else if ambigiousCheck
and IntSetContains(c.AmbigiousSymbols, result.id) then
else if ambiguousCheck
and IntSetContains(c.AmbiguousSymbols, result.id) then
liMessage(n.info, errUseQualifier, n.ident.s)
end;
nkSym: begin
result := SymtabGet(c.Tab, n.sym.name);
if result = nil then
liMessage(n.info, errUndeclaredIdentifier, n.sym.name.s)
else if ambigiousCheck
and IntSetContains(c.AmbigiousSymbols, result.id) then
else if ambiguousCheck
and IntSetContains(c.AmbiguousSymbols, result.id) then
liMessage(n.info, errUseQualifier, n.sym.name.s)
end;
nkDotExpr, nkQualified: begin
@@ -200,7 +201,7 @@ begin
renderTree(n.sons[1]));
end
end;
nkAccQuoted: result := QualifiedLookup(c, n.sons[0], ambigiousCheck);
nkAccQuoted: result := QualifiedLookup(c, n.sons[0], ambiguousCheck);
else begin
result := nil;
//liMessage(n.info, errIdentifierExpected, '')
@@ -224,15 +225,18 @@ begin
result := InitIdentIter(o.it, c.tab.stack[o.stackPtr], n.ident);
end;
end;
nkSym: begin
nkSym: begin
result := n.sym;
o.mode := oimDone;
(*
o.stackPtr := c.tab.tos;
o.mode := oimNoQualifier;
while (result = nil) do begin
dec(o.stackPtr);
if o.stackPtr < 0 then break;
result := InitIdentIter(o.it, c.tab.stack[o.stackPtr], n.sym.name);
end;
end;
end; *)
end;
nkDotExpr, nkQualified: begin
o.mode := oimOtherModule;
o.m := qualifiedLookUp(c, n.sons[0], false);
@@ -258,6 +262,11 @@ begin
end
end;
nkAccQuoted: result := InitOverloadIter(o, c, n.sons[0]);
nkSymChoice: begin
o.mode := oimSymChoice;
result := n.sons[0].sym;
o.stackPtr := 1
end;
else begin end
end;
if (result <> nil) and (result.kind = skStub) then loadStub(result);
@@ -266,6 +275,7 @@ end;
function nextOverloadIter(var o: TOverloadIter; c: PContext; n: PNode): PSym;
begin
case o.mode of
oimDone: result := nil;
oimNoQualifier: begin
if n.kind = nkAccQuoted then
result := nextOverloadIter(o, c, n.sons[0]) // BUGFIX
@@ -282,6 +292,14 @@ begin
end;
oimSelfModule: result := nextIdentIter(o.it, c.tab.stack[ModuleTablePos]);
oimOtherModule: result := nextIdentIter(o.it, o.m.tab);
oimSymChoice: begin
if o.stackPtr < sonsLen(n) then begin
result := n.sons[o.stackPtr].sym;
inc(o.stackPtr);
end
else
result := nil
end;
end;
if (result <> nil) and (result.kind = skStub) then loadStub(result);
end;

View File

@@ -1,7 +1,7 @@
//
//
// The Nimrod Compiler
// (c) Copyright 2008 Andreas Rumpf
// (c) Copyright 2009 Andreas Rumpf
//
// See the file "copying.txt", included in this
// distribution, for details about the copyright.
@@ -79,19 +79,15 @@ type
errNoneSpeedOrSizeExpected,
errInvalidPragma,
errUnknownPragma,
errPragmaXHereNotAllowed,
errUnknownDirective,
errInvalidDirective,
errAtPopWithoutPush,
errEmptyAsm,
errAsgnInvalidInExpr,
errInvalidIndentation,
errExceptionExpected,
errExceptionAlreadyHandled,
errReturnNotAllowedHere,
errYieldNotAllowedHere,
errInvalidNumberOfYieldExpr,
errReturnInvalidInIterator,
errCannotReturnExpr,
errAttemptToRedefine,
errStmtInvalidAfterReturn,
@@ -116,7 +112,6 @@ type
errExprExpected,
errUndeclaredIdentifier,
errUseQualifier,
errTwiceForwarded,
errTypeExpected,
errSystemNeeds,
errExecutionOfProgramFailed,
@@ -126,8 +121,7 @@ type
errXExpectsTypeOrValue,
errXExpectsArrayType,
errIteratorCannotBeInstantiated,
errExprWithNoTypeCannotBeConverted,
errExprWithNoTypeCannotBeCasted,
errExprXAmbiguous,
errConstantDivisionByZero,
errOrdinalTypeExpected,
errOrdinalOrFloatTypeExpected,
@@ -145,21 +139,17 @@ type
errValueOutOfSetBounds,
errFieldInitTwice,
errFieldNotInit,
errExprCannotBeCalled,
errExprXCannotBeCalled,
errExprHasNoType,
errExprXHasNoType,
errCastNotInSafeMode,
errExprCannotBeCastedToX,
errUndefinedPrefixOpr,
errCommaOrParRiExpected,
errCurlyLeOrParLeExpected,
errSectionExpected,
errImplemenationExpected,
errRangeExpected,
errInvalidTypeDescription,
errAttemptToRedefineX,
errMagicOnlyInSystem,
errUnknownOperatorX,
errPowerOfTwoExpected,
errStringMayNotBeEmpty,
errCallConvExpected,
@@ -193,9 +183,8 @@ type
errTypeMismatch,
errButExpected,
errButExpectedX,
errAmbigiousCallXYZ,
errAmbiguousCallXYZ,
errWrongNumberOfTypeParams,
errOutParamNoDefaultValue,
errInlineProcHasNoAddress,
errXCannotBeInParamDecl,
errPragmaOnlyInHeaderOfProc,
@@ -204,21 +193,15 @@ type
errNoSymbolToBorrowFromFound,
errDiscardValue,
errInvalidDiscard,
errUnknownPrecedence,
errIllegalConvFromXtoY,
errTypeMismatchExpectedXGotY,
errCannotBindXTwice,
errInvalidOrderInEnumX,
errEnumXHasWholes,
errExceptExpected,
errInvalidTry,
errEofExpectedButXFound,
errOptionExpected,
errCannotEvaluateForwardConst,
errXisNoLabel,
errXNeedsConcreteType,
errNotAllCasesCovered,
errStringRange,
errUnkownSubstitionVar,
errComplexStmtRequiresInd,
errXisNotCallable,
@@ -279,6 +262,7 @@ type
errUnhandledExceptionX,
errCyclicTree,
errXisNoMacroOrTemplate,
errXhasSideEffects,
errUser,
warnCannotOpenFile,
warnOctalEscape,
@@ -338,19 +322,15 @@ const
'''none'', ''speed'' or ''size'' expected',
'invalid pragma',
'unknown pragma: ''$1''',
'pragma ''$1'' here not allowed',
'unknown directive: ''$1''',
'invalid directive',
'''pop'' without a ''push'' pragma',
'empty asm statement makes no sense',
'''='' invalid in an expression; probably ''=='' meant',
'invalid indentation',
'exception expected',
'exception already handled',
'''return'' only allowed in routine',
'''yield'' only allowed in a loop of an iterator',
'invalid number of ''yield'' expresions',
'''return'' not allowed in iterator',
'current routine cannot return an expression',
'attempt to redefine ''$1''',
'statement not allowed after ''return'', ''break'' or ''raise''',
@@ -374,19 +354,17 @@ const
''':'' or ''='' expected, but found ''$1''',
'expression expected, but found ''$1''',
'undeclared identifier: ''$1''',
'ambigious identifier: ''$1'' -- use a qualifier',
'''$1'' is forwarded twice',
'ambiguous identifier: ''$1'' -- use a qualifier',
'type expected',
'system module needs ''$1''',
'execution of an external program failed',
'overloaded ''$1'' leads to ambigious calls',
'overloaded ''$1'' leads to ambiguous calls',
'invalid argument for ''$1''',
'statement has no effect',
'''$1'' expects a type or value',
'''$1'' expects an array type',
'''$1'' cannot be instantiated because its body has not been compiled yet',
'expression with no type cannot be converted',
'expression with no type cannot be casted',
'expression ''$1'' ambiguous in this context',
'constant division by zero',
'ordinal type expected',
'ordinal or float type expected',
@@ -404,21 +382,17 @@ const
'value out of set bounds',
'field initialized twice: ''$1''',
'field ''$1'' not initialized',
'expression cannot be called',
'expression ''$1'' cannot be called',
'expression has no type',
'expression ''$1'' has no type',
'expression ''$1'' has no type (or is ambiguous)',
'''cast'' not allowed in safe mode',
'expression cannot be casted to $1',
'undefined prefix operator: $1',
''','' or '')'' expected',
'''{'' or ''('' expected',
'section (''type'', ''proc'', etc.) expected',
'''implementation'' or end of file expected',
'range expected',
'invalid type description',
'attempt to redefine ''$1''',
'''magic'' only allowed in system module',
'unkown operator: ''$1''',
'power of two expected',
'string literal may not be empty',
'calling convention expected',
@@ -452,9 +426,8 @@ const
'type mismatch: got (',
'but expected one of: ',
'but expected ''$1''',
'ambigious call; both $1 and $2 match for: $3',
'ambiguous call; both $1 and $2 match for: $3',
'wrong number of type parameters',
'out parameters cannot have default values',
'an inline proc has no address',
'$1 cannot be declared in parameter declaration',
'pragmas are only in the header of a proc allowed',
@@ -463,21 +436,15 @@ const
'no symbol to borrow from found',
'value returned by statement has to be discarded',
'statement returns no value that can be discarded',
'unknown precedence for operator; use ''infix: prec'' pragma',
'conversion from $1 to $2 is invalid',
'type mismatch: expected ''$1'', but got ''$2''',
'cannot bind parameter ''$1'' twice',
'invalid order in enum ''$1''',
'enum ''$1'' has wholes',
'''except'' or ''finally'' expected',
'after catch all ''except'' or ''finally'' no section may follow',
'end of file expected, but found token ''$1''',
'option expected, but found ''$1''',
'cannot evaluate forwarded constant',
'''$1'' is not a label',
'''$1'' needs to be of a non-generic type',
'not all cases are covered',
'string range in case statement not allowed',
'unknown substitution variable: ''$1''',
'complex statement requires indentation',
'''$1'' is not callable',
@@ -489,7 +456,7 @@ const
'no return type for $1 allowed',
'a type conversion needs exactly one argument',
'invalid pragma: $1',
'$1 here not allowed',
'$1 not allowed here',
'invalid control flow: $1',
'a type has no value',
'invalid type: ''$1''',
@@ -499,11 +466,11 @@ const
'invalid expression: ''$1''',
'enum has no value ''$1''',
'named expression expected',
'named expression here not allowed',
'named expression not allowed here',
'''$1'' expects one type parameter',
'array expects two type parameters',
'invalid invisibility: ''$1''',
'initialization here not allowed',
'initialization not allowed here',
'''$1'' cannot be assigned to',
'iterators can only be defined at the module''s top level',
'iterator needs an implementation',
@@ -538,6 +505,7 @@ const
'unhandled exception: $1',
'macro returned a cyclic abstract syntax tree',
'''$1'' is no macro or template',
'''$1'' can have side effects',
'$1',
'cannot open ''$1'' [CannotOpenFile]',
'octal escape sequences do not exist; leading zero is ignored [OctalEscape]',

View File

@@ -1,15 +1,14 @@
//
//
// The Nimrod Compiler
// (c) Copyright 2008 Andreas Rumpf
// (c) Copyright 2009 Andreas Rumpf
//
// See the file "copying.txt", included in this
// distribution, for details about the copyright.
//
unit nimsets;
// this unit handles Morpork sets; it implements symbolic sets
// the code here should be reused in the Morpork standard library
// this unit handles Nimrod sets; it implements symbolic sets
interface

View File

@@ -40,12 +40,11 @@ const
ImportBlackList: array [1..3] of string = (
'nsystem', 'sysutils', 'charsets'
);
stdReplacements: array [1..20] of TReplaceTuple = (
stdReplacements: array [1..19] of TReplaceTuple = (
('include', 'incl'),
('exclude', 'excl'),
('pchar', 'cstring'),
('close', 'closeFile'),
('assignfile', 'openFile'),
('assignfile', 'open'),
('integer', 'int'),
('longword', 'int32'),
('cardinal', 'int'),
@@ -62,10 +61,12 @@ const
('len', 'length'),
('setlength', 'setlen')
);
nimReplacements: array [1..30] of TReplaceTuple = (
nimReplacements: array [1..32] of TReplaceTuple = (
('nimread', 'read'),
('nimwrite', 'write'),
('nimclosefile', 'closeFile'),
('nimclosefile', 'close'),
('closefile', 'close'),
('openfile', 'open'),
('nsystem', 'system'),
('ntime', 'times'),
('nos', 'os'),
@@ -1972,7 +1973,7 @@ begin
if isHandledDirective(p) then
addSon(result, parseDirective(p))
else
parMessage(p, errPragmaXHereNotAllowed, p.tok.ident.s)
parMessage(p, errXNotAllowedHere, p.tok.ident.s)
end
else addSon(result, parseStmt(p))
end;

View File

@@ -313,9 +313,8 @@ end;
function accExpr(var p: TParser): PNode;
var
x, y: PNode;
info: TLineInfo;
begin
info := parLineInfo(p);
result := newNodeP(nkAccQuoted, p);
getTok(p); // skip `
x := nil;
y := nil;
@@ -343,16 +342,7 @@ begin
end
end;
end;
if (p.tok.tokType = tkParLe) or (p.tok.tokType = tkColon) then begin
result := newNodeP(nkHeaderQuoted, p);
addSon(result, x);
addSon(result, parseParamList(p));
end
else begin
result := newNodeP(nkAccQuoted, p);
addSon(result, x);
end;
result.info := info;
addSon(result, x);
eat(p, tkAccent);
end;
@@ -665,6 +655,13 @@ begin
optInd(p, a);
addSon(result, primary(p));
exit
end
else if p.tok.tokType = tkBind then begin
result := newNodeP(nkBind, p);
getTok(p);
optInd(p, result);
addSon(result, primary(p));
exit
end;
result := identOrLiteral(p);
while true do begin
@@ -798,7 +795,7 @@ end;
function isExprStart(const p: TParser): bool;
begin
case p.tok.tokType of
tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkLambda,
tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkLambda, tkBind,
tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit: result := true;
else result := false;
end;

View File

@@ -499,7 +499,11 @@ begin
// otherwise header would not make sense
if sym.loc.r = nil then sym.loc.r := toRope(sym.name.s)
end;
wNosideeffect: begin noVal(it); Include(sym.flags, sfNoSideEffect); end;
wNosideeffect: begin
noVal(it); Include(sym.flags, sfNoSideEffect);
if sym.typ <> nil then include(sym.typ.flags, tfNoSideEffect);
end;
wSideEffect: begin noVal(it); Include(sym.flags, sfSideEffect); end;
wNoReturn: begin noVal(it); Include(sym.flags, sfNoReturn); end;
wDynLib: processDynLib(c, it, sym);
wCompilerProc: begin
@@ -597,7 +601,7 @@ end;
procedure pragmaProc(c: PContext; s: PSym; n: PNode);
begin
pragma(c, s, n, {@set}[FirstCallConv..LastCallConv,
wImportc, wExportc, wNodecl, wMagic, wNosideEffect,
wImportc, wExportc, wNodecl, wMagic, wNosideEffect, wSideEffect,
wNoreturn, wDynLib, wHeader, wCompilerProc, wPure,
wCppMethod, wDeprecated, wVarargs, wCompileTime, wMerge,
wBorrow]);
@@ -612,7 +616,8 @@ end;
procedure pragmaIterator(c: PContext; s: PSym; n: PNode);
begin
pragma(c, s, n, {@set}[FirstCallConv..LastCallConv,
pragma(c, s, n, {@set}[FirstCallConv..LastCallConv,
wNosideEffect, wSideEffect,
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow]);
end;
@@ -630,7 +635,7 @@ end;
procedure pragmaLambda(c: PContext; s: PSym; n: PNode);
begin
pragma(c, s, n, {@set}[FirstCallConv..LastCallConv,
wImportc, wExportc, wNodecl, wNosideEffect,
wImportc, wExportc, wNodecl, wNosideEffect, wSideEffect,
wNoreturn, wDynLib, wHeader, wPure, wDeprecated]);
end;

View File

@@ -1,7 +1,7 @@
//
//
// The Nimrod Compiler
// (c) Copyright 2008 Andreas Rumpf
// (c) Copyright 2009 Andreas Rumpf
//
// See the file "copying.txt", included in this
// distribution, for details about the copyright.
@@ -498,8 +498,10 @@ begin
nkCommand: result := lsub(n.sons[0])+lcomma(n, 1)+1;
nkExprEqExpr, nkDefaultTypeParam, nkAsgn, nkFastAsgn: result := lsons(n)+3;
nkPar, nkCurly, nkBracket: result := lcomma(n)+2;
nkSymChoice: result := lsons(n) + length('()') + sonsLen(n)-1;
nkTupleTy: result := lcomma(n)+length('tuple[]');
nkQualified, nkDotExpr: result := lsons(n)+1;
nkBind: result := lsons(n)+length('bind_');
nkCheckedFieldExpr: result := lsub(n.sons[0]);
nkLambda: result := lsons(n)+length('lambda__=_');
nkConstDef, nkIdentDefs: begin
@@ -531,7 +533,6 @@ begin
nkDerefExpr: result := lsub(n.sons[0])+2;
nkImportAs: result := lsons(n) + length('_as_');
nkAccQuoted: result := lsub(n.sons[0]) + 2;
nkHeaderQuoted: result := lsub(n.sons[0]) + lsub(n.sons[1]) + 2;
nkIfExpr: result := lsub(n.sons[0].sons[0])+lsub(n.sons[0].sons[1])
+ lsons(n, 1) + length('if_:_');
@@ -1023,6 +1024,14 @@ begin
gcomma(g, n, 1);
put(g, tkParRi, ')'+'');
end;
nkSymChoice: begin
put(g, tkParLe, '('+'');
for i := 0 to sonsLen(n)-1 do begin
if i > 0 then put(g, tkOpr, '|'+'');
gsub(g, n.sons[i], c);
end;
put(g, tkParRi, ')'+'');
end;
nkPar: begin
put(g, tkParLe, '('+'');
gcomma(g, n, c);
@@ -1043,6 +1052,10 @@ begin
put(g, tkDot, '.'+'');
gsub(g, n.sons[1]);
end;
nkBind: begin
putWithSpace(g, tkBind, 'bind');
gsub(g, n.sons[0]);
end;
nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref: gsub(g, n.sons[0]);
nkLambda: begin
assert(n.sons[genericParamsPos] = nil);
@@ -1119,12 +1132,6 @@ begin
gsub(g, n.sons[0]);
put(g, tkAccent, '`'+'');
end;
nkHeaderQuoted: begin
put(g, tkAccent, '`'+'');
gsub(g, n.sons[0]);
gsub(g, n.sons[1]);
put(g, tkAccent, '`'+'');
end;
nkIfExpr: begin
putWithSpace(g, tkIf, 'if');
gsub(g, n.sons[0].sons[0]);

View File

@@ -488,22 +488,25 @@ end;
function ropef(const frmt: TFormatStr; const args: array of PRope): PRope;
var
i, j, len, start: int;
i, j, len, start, num: int;
begin
i := strStart;
len := length(frmt);
result := nil;
num := 0;
while i <= len + StrStart - 1 do begin
if frmt[i] = '$' then begin
inc(i); // skip '$'
case frmt[i] of
'$': begin app(result, '$'+''); inc(i); end;
'#': begin inc(i); app(result, args[num]); inc(num); end;
'0'..'9': begin
j := 0;
repeat
j := (j*10) + Ord(frmt[i]) - ord('0');
inc(i);
until (i > len + StrStart - 1) or not (frmt[i] in ['0'..'9']);
num := j;
if j > high(args)+1 then
internalError('ropes: invalid format string $' + toString(j));
app(result, args[j-1]);

View File

@@ -53,10 +53,10 @@ type
//cog.out(idents)
//]]]
tkAbstract, tkAddr, tkAnd, tkAs,
tkAsm, tkBlock, tkBreak, tkCase,
tkCast, tkConst, tkContinue, tkConverter,
tkDiscard, tkDiv, tkElif, tkElse,
tkEnd, tkEnum, tkExcept, tkException,
tkAsm, tkBind, tkBlock, tkBreak,
tkCase, tkCast, tkConst, tkContinue,
tkConverter, tkDiscard, tkDiv, tkElif,
tkElse, tkEnd, tkEnum, tkExcept,
tkFinally, tkFor, tkFrom, tkGeneric,
tkIf, tkImplies, tkImport, tkIn,
tkInclude, tkIs, tkIsnot, tkIterator,
@@ -97,10 +97,10 @@ const
//cog.out(strings)
//]]]
'abstract', 'addr', 'and', 'as',
'asm', 'block', 'break', 'case',
'cast', 'const', 'continue', 'converter',
'discard', 'div', 'elif', 'else',
'end', 'enum', 'except', 'exception',
'asm', 'bind', 'block', 'break',
'case', 'cast', 'const', 'continue',
'converter', 'discard', 'div', 'elif',
'else', 'end', 'enum', 'except',
'finally', 'for', 'from', 'generic',
'if', 'implies', 'import', 'in',
'include', 'is', 'isnot', 'iterator',

View File

@@ -90,8 +90,6 @@ end;
function semAndEvalConstExpr(c: PContext; n: PNode): PNode;
var
e: PNode;
p: PEvalContext;
s: PStackFrame;
begin
e := semExprWithType(c, n);
if e = nil then begin
@@ -101,12 +99,7 @@ begin
result := getConstExpr(c.module, e);
if result = nil then begin
//writeln(output, renderTree(n));
p := newEvalContext(c.module, '');
s := newStackFrame();
s.call := e;
pushStackFrame(p, s);
result := eval(p, e);
popStackFrame(p);
result := evalConstExpr(c.module, e);
if (result = nil) or (result.kind = nkEmpty) then
liMessage(n.info, errConstExprExpected);
end
@@ -135,7 +128,7 @@ var
s: PStackFrame;
begin
include(sym.flags, sfUsed);
p := newEvalContext(c.module, '');
p := newEvalContext(c.module, '', false);
s := newStackFrame();
s.call := n;
setLength(s.params, 2);

View File

@@ -45,7 +45,7 @@ type
module: PSym; // the module sym belonging to the context
filename: string; // the module's filename
tab: TSymTab; // each module has its own symbol table
AmbigiousSymbols: TIntSet; // contains ids of all ambigious symbols (cannot
AmbiguousSymbols: TIntSet; // contains ids of all ambiguous symbols (cannot
// store this info in the syms themselves!)
generics: PNode; // a list of the things to compile; list of
// nkExprEqExpr nodes which contain the generic
@@ -156,7 +156,7 @@ begin
fillChar(result^, sizeof(result^), 0);
{@emit}
InitSymTab(result.tab);
IntSetInit(result.AmbigiousSymbols);
IntSetInit(result.AmbiguousSymbols);
initLinkedList(result.optionStack);
initLinkedList(result.libs);
append(result.optionStack, newOptionEntry());

View File

@@ -1,6 +1,6 @@
//
//
// The Ethexor Morpork Compiler
// The Nimrod Compiler
// (c) Copyright 2009 Andreas Rumpf
//
// See the file "copying.txt", included in this
@@ -110,18 +110,33 @@ begin
end;
function semConv(c: PContext; n: PNode; s: PSym): PNode;
var
op: PNode;
i: int;
begin
if sonsLen(n) <> 2 then liMessage(n.info, errConvNeedsOneArg);
result := newNodeI(nkConv, n.info);
result.typ := semTypeNode(c, n.sons[0], nil);
addSon(result, copyTree(n.sons[0]));
addSon(result, semExprWithType(c, n.sons[1]));
checkConvertible(result.info, result.typ, result.sons[1].typ);
op := result.sons[1];
if op.kind <> nkSymChoice then
checkConvertible(result.info, result.typ, op.typ)
else begin
for i := 0 to sonsLen(op)-1 do begin
if sameType(result.typ, op.sons[i].typ) then begin
include(op.sons[i].sym.flags, sfUsed);
result := op.sons[i]; exit
end
end;
liMessage(n.info, errUseQualifier, op.sons[0].sym.name.s);
end
end;
function semCast(c: PContext; n: PNode): PNode;
begin
if optSafeCode in gGlobalOptions then liMessage(n.info, errCastNotInSafeMode);
include(c.p.owner.flags, sfSideEffect);
checkSonsLen(n, 2);
result := newNodeI(nkCast, n.info);
result.typ := semTypeNode(c, n.sons[0], nil);
@@ -354,7 +369,7 @@ function isAssignable(n: PNode): bool;
begin
result := false;
case n.kind of
nkSym: result := n.sym.kind in [skVar, skTemp];
nkSym: result := (n.sym.kind in [skVar, skTemp]);
nkDotExpr, nkQualified, nkBracketExpr: begin
checkMinSonsLen(n, 1);
if skipTypes(n.sons[0].typ, abstractInst).kind in [tyVar, tyPtr, tyRef] then
@@ -373,7 +388,7 @@ begin
nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
result := isAssignable(n.sons[0]);
else begin end
end
end;
end;
function newHiddenAddrTaken(c: PContext; n: PNode): PNode;
@@ -442,13 +457,31 @@ begin
n.sons[i] := analyseIfAddressTaken(c, n.sons[i]);
end;
function semDirectCallAnalyseEffects(c: PContext; n: PNode): PNode;
var
callee: PSym;
begin
result := semDirectCall(c, n);
if result <> nil then begin
if result.sons[0].kind <> nkSym then
InternalError('semDirectCallAnalyseEffects');
callee := result.sons[0].sym;
if not (sfNoSideEffect in callee.flags) then
if (sfForward in callee.flags)
or ([sfImportc, sfSideEffect] * callee.flags <> []) then
include(c.p.owner.flags, sfSideEffect);
end
end;
function semIndirectOp(c: PContext; n: PNode): PNode;
var
m: TCandidate;
msg: string;
i: int;
prc: PNode;
begin
result := nil;
prc := n.sons[0];
checkMinSonsLen(n, 1);
case n.sons[0].kind of
nkDotExpr, nkQualified: begin
@@ -457,8 +490,7 @@ begin
if n.sons[0].kind = nkDotCall then begin // it is a static call!
result := n.sons[0];
result.kind := nkCall;
for i := 1 to sonsLen(n)-1 do
addSon(result, n.sons[i]);
for i := 1 to sonsLen(n)-1 do addSon(result, n.sons[i]);
result := semExpr(c, result);
exit
end
@@ -475,8 +507,8 @@ begin
if m.state <> csMatch then begin
msg := msgKindToString(errTypeMismatch);
for i := 1 to sonsLen(n)-1 do begin
if i > 1 then add(msg, ', ');
add(msg, typeToString(n.sons[i].typ));
if i <> sonsLen(n)-1 then add(msg, ', ');
end;
add(msg, ')' +{&} nl +{&} msgKindToString(errButExpected) +{&}
nl +{&} typeToString(n.sons[0].typ));
@@ -485,11 +517,21 @@ begin
end
else
result := m.call;
// we assume that a procedure that calls something indirectly
// has side-effects:
include(c.p.owner.flags, sfSideEffect);
end
else begin
result := overloadedCallOpr(c, n);
if result = nil then result := semDirectCall(c, n);
if result = nil then liMessage(n.info, errExprCannotBeCalled);
// Now that nkSym does not imply an iteration over the proc/iterator space,
// the old ``prc`` (which is likely an nkIdent) has to be restored:
if result = nil then begin
n.sons[0] := prc;
result := semDirectCallAnalyseEffects(c, n);
end;
if result = nil then
liMessage(n.info, errExprXCannotBeCalled,
renderTree(n, {@set}[renderNoComments]));
end;
fixAbstractType(c, result);
analyseIfAddressTakenInCall(c, result);
@@ -499,7 +541,7 @@ function semDirectOp(c: PContext; n: PNode): PNode;
begin
// this seems to be a hotspot in the compiler!
semOpAux(c, n);
result := semDirectCall(c, n);
result := semDirectCallAnalyseEffects(c, n);
if result = nil then begin
result := overloadedCallOpr(c, n);
if result = nil then
@@ -508,45 +550,6 @@ begin
fixAbstractType(c, result);
analyseIfAddressTakenInCall(c, result);
end;
(*
function semIncSucc(c: PContext; n: PNode; const opr: string): PNode;
// handles Inc, Dec, Succ and Pred
var
a: PNode;
typ: PType;
begin
checkMinSonsLen(n, 2);
n.sons[1] := semExprWithType(c, n.sons[1]);
typ := skipTypes(n.sons[1].Typ, {@set}[tyGenericInst, tyVar]);
if not isOrdinalType(typ) or enumHasWholes(typ) then
liMessage(n.sons[1].Info, errOrdinalTypeExpected);
if sonsLen(n) = 3 then begin
n.sons[2] := semExprWithType(c, n.sons[2]);
a := IndexTypesMatch(c, getSysType(tyInt), n.sons[2].typ, n.sons[2]);
if a = nil then
typeMismatch(n.sons[2], getSysType(tyInt), n.sons[2].typ);
n.sons[2] := a;
end
else if sonsLen(n) = 2 then begin // default value of 1
a := newIntNode(nkIntLit, 1);
a.info := n.info;
a.typ := getSysType(tyInt);
addSon(n, a)
end
else
liMessage(n.info, errInvalidArgForX, opr);
result := n;
end;
function semOrd(c: PContext; n: PNode): PNode;
begin
checkSonsLen(n, 2);
n.sons[1] := semExprWithType(c, n.sons[1]);
if not isOrdinalType(skipTypes(n.sons[1].Typ, {@set}[tyGenericInst, tyVar])) then
liMessage(n.Info, errOrdinalTypeExpected);
n.typ := getSysType(tyInt);
result := n
end; *)
function semEcho(c: PContext; n: PNode): PNode;
var
@@ -632,18 +635,6 @@ begin
mSizeOf: result := semSizeof(c, setMs(n, s));
mIs: result := semIs(c, setMs(n, s));
mEcho: result := semEcho(c, setMs(n, s));
(*
mSucc: begin
result := semIncSucc(c, setMs(n, s), 'succ');
result.typ := n.sons[1].typ;
end;
mPred: begin
result := semIncSucc(c, setMs(n, s), 'pred');
result.typ := n.sons[1].typ;
end;
mInc: result := semIncSucc(c, setMs(n, s), 'inc');
ast.mDec: result := semIncSucc(c, setMs(n, s), 'dec');
mOrd: result := semOrd(c, setMs(n, s)); *)
else result := semDirectOp(c, n);
end;
end;
@@ -655,16 +646,14 @@ end;
function semSym(c: PContext; n: PNode; s: PSym; flags: TExprFlags): PNode;
begin
result := newSymNode(s);
result.info := n.info;
result.typ := s.typ;
include(s.flags, sfUsed);
if (s.kind = skType) and not (efAllowType in flags) then
liMessage(n.info, errATypeHasNoValue);
case s.kind of
skProc, skIterator, skConverter:
skProc, skIterator, skConverter: begin
if (s.magic <> mNone) then
liMessage(n.info, errInvalidContextForBuiltinX, s.name.s);
result := symChoice(c, n, s);
end;
skConst: begin
(*
Consider::
@@ -678,20 +667,40 @@ begin
copy `x`'s AST into each context, so that the type fixup phase can
deal with two different ``[]``.
*)
include(s.flags, sfUsed);
if s.typ.kind in ConstAbstractTypes then begin
result := copyTree(s.ast);
result.info := n.info;
result.typ := s.typ;
end
else begin
result := newSymNode(s);
result.info := n.info;
end
end;
skMacro: begin
include(s.flags, sfUsed);
result := semMacroExpr(c, n, s);
end;
skMacro: result := semMacroExpr(c, n, s);
skTemplate: begin
include(s.flags, sfUsed);
// Templates and macros can be invoked without ``()``
pushInfoContext(n.info);
result := evalTemplate(c, n, s);
popInfoContext();
end;
else begin end
skVar: begin
include(s.flags, sfUsed);
// if a proc accesses a global variable, it is not side effect free
if sfGlobal in s.flags then include(c.p.owner.flags, sfSideEffect);
result := newSymNode(s);
result.info := n.info;
end;
else begin
include(s.flags, sfUsed);
result := newSymNode(s);
result.info := n.info;
end
end;
checkDeprecated(n, s);
end;
@@ -1266,6 +1275,7 @@ begin
result := semExpr(c, result, flags)
end;
end;
nkBind: result := semExpr(c, n.sons[0], flags);
nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand: begin
// check if it is an expression macro:
checkMinSonsLen(n, 1);
@@ -1326,11 +1336,7 @@ begin
end;
nkCurly: result := semSetConstr(c, n);
nkBracket: result := semArrayConstr(c, n);
nkLambda: result := semLambda(c, n); // handled in semstmts
nkExprColonExpr: begin
internalError(n.info, 'semExpr() to implement');
// XXX: to implement for array constructors!
end;
nkLambda: result := semLambda(c, n);
nkDerefExpr: begin
checkSonsLen(n, 1);
n.sons[0] := semExprWithType(c, n.sons[0]);
@@ -1357,11 +1363,6 @@ begin
checkSonsLen(n, 1);
result := semExpr(c, n.sons[0]);
end;
nkHeaderQuoted: begin
// look up the proc:
internalError(n.info, 'semExpr() to implement');
// XXX: to implement
end;
nkIfExpr: result := semIfExpr(c, n);
nkStmtListExpr: result := semStmtListExpr(c, n);
nkBlockExpr: result := semBlockExpr(c, n);
@@ -1374,6 +1375,11 @@ begin
checkSonsLen(n, 3);
nkCheckedFieldExpr:
checkMinSonsLen(n, 2);
nkSymChoice: begin
liMessage(n.info, errExprXAmbiguous,
renderTree(n, {@set}[renderNoComments]));
result := nil
end
else begin
//InternalError(n.info, nodeKindToStr[n.kind]);
liMessage(n.info, errInvalidExpressionX,

View File

@@ -257,7 +257,7 @@ begin
addSon(result, newIdentNode(getIdent(id.s+'='), n.info));
addSon(result, semExpr(c, a.sons[0]));
addSon(result, semExpr(c, n.sons[1]));
result := semDirectCall(c, result);
result := semDirectCallAnalyseEffects(c, result);
if result <> nil then begin
fixAbstractType(c, result);
analyseIfAddressTakenInCall(c, result);
@@ -277,7 +277,7 @@ begin
addSonIfNotNil(result, semExpr(c, a.sons[1].sons[0]));
addSonIfNotNil(result, semExpr(c, a.sons[1].sons[1]));
addSon(result, semExpr(c, n.sons[1]));
result := semDirectCall(c, result);
result := semDirectCallAnalyseEffects(c, result);
if result <> nil then begin
fixAbstractType(c, result);
analyseIfAddressTakenInCall(c, result);
@@ -289,7 +289,7 @@ begin
addSon(result, semExpr(c, a.sons[0]));
addSon(result, semExpr(c, a.sons[1]));
addSon(result, semExpr(c, n.sons[1]));
result := semDirectCall(c, result);
result := semDirectCallAnalyseEffects(c, result);
if result <> nil then begin
fixAbstractType(c, result);
analyseIfAddressTakenInCall(c, result);
@@ -322,7 +322,7 @@ begin
result := n;
checkSonsLen(n, 1);
if not (c.p.owner.kind in [skConverter, skProc, skMacro]) then
liMessage(n.info, errReturnNotAllowedHere);
liMessage(n.info, errXNotAllowedHere, '''return''');
if (n.sons[0] <> nil) then begin
n.sons[0] := SemExprWithType(c, n.sons[0]);
// check for type compatibility:
@@ -624,9 +624,28 @@ begin
end
end;
function resolveGenericParams(c: PContext; n: PNode): PNode;
function resolveGenericParams(c: PContext; n: PNode;
withinBind: bool = false): PNode;
var
i: int;
s: PSym;
begin
result := n;
if n = nil then begin result := nil; exit end;
case n.kind of
nkIdent: begin
if not withinBind then
result := n
else
result := symChoice(c, n, lookup(c, n))
end;
nkSym..nkNilLit: result := n;
nkBind: result := resolveGenericParams(c, n.sons[0], true);
else begin
result := n;
for i := 0 to sonsLen(n)-1 do
result.sons[i] := resolveGenericParams(c, n.sons[i], withinBind);
end
end
end;
function SemTypeSection(c: PContext; n: PNode): PNode;
@@ -682,7 +701,7 @@ begin
addSon(s.typ, nil);
// process the type body for symbol lookup of generic params
// we can use the same algorithm as for template parameters:
a.sons[2] := resolveTemplateParams(c, a.sons[2]);
a.sons[2] := resolveTemplateParams(c, a.sons[2], false);
s.ast := a;
if s.typ.containerID <> 0 then
InternalError(a.info, 'semTypeSection: containerID');
@@ -754,6 +773,13 @@ begin
n.sons[codePos] := newSymNode(b);
end;
procedure sideEffectsCheck(c: PContext; s: PSym);
begin
if [sfNoSideEffect, sfSideEffect] * s.flags =
[sfNoSideEffect, sfSideEffect] then
liMessage(s.info, errXhasSideEffects, s.name.s);
end;
function semIterator(c: PContext; n: PNode): PNode;
var
s: PSym;
@@ -972,6 +998,7 @@ begin
else if sfBorrow in s.flags then
semBorrow(c, n, s);
end;
sideEffectsCheck(c, s);
closeScope(c.tab); // close scope for parameters
popOwner();
c.p := oldP; // restore

View File

@@ -1,7 +1,7 @@
//
//
// The Nimrod Compiler
// (c) Copyright 2008 Andreas Rumpf
// (c) Copyright 2009 Andreas Rumpf
//
// See the file "copying.txt", included in this
// distribution, for details about the copyright.
@@ -90,7 +90,37 @@ begin
dec(evalTemplateCounter);
end;
function resolveTemplateParams(c: PContext; n: PNode): PNode;
function symChoice(c: PContext; n: PNode; s: PSym): PNode;
var
a: PSym;
o: TOverloadIter;
i: int;
begin
i := 0;
a := initOverloadIter(o, c, n);
while a <> nil do begin
a := nextOverloadIter(o, c, n);
inc(i);
end;
if i <= 1 then begin
result := newSymNode(s);
result.info := n.info;
include(s.flags, sfUsed);
end
else begin
// semantic checking requires a type; ``fitNode`` deal with it
// appropriately
result := newNodeIT(nkSymChoice, n.info, newTypeS(tyNone, c));
a := initOverloadIter(o, c, n);
while a <> nil do begin
addSon(result, newSymNode(a));
a := nextOverloadIter(o, c, n);
end
end
end;
function resolveTemplateParams(c: PContext; n: PNode;
withinBind: bool): PNode;
var
i: int;
s: PSym;
@@ -98,20 +128,27 @@ begin
if n = nil then begin result := nil; exit end;
case n.kind of
nkIdent: begin
s := SymTabLocalGet(c.Tab, n.ident);
if (s <> nil) then begin
result := newSymNode(s);
result.info := n.info
if not withinBind then begin
s := SymTabLocalGet(c.Tab, n.ident);
if (s <> nil) then begin
result := newSymNode(s);
result.info := n.info
end
else
result := n
end
else begin
result := symChoice(c, n, lookup(c, n))
end
else
result := n
end;
nkSym..nkNilLit: // atom
result := n;
nkBind:
result := resolveTemplateParams(c, n.sons[0], true);
else begin
result := n;
for i := 0 to sonsLen(n)-1 do
result.sons[i] := resolveTemplateParams(c, n.sons[i]);
result.sons[i] := resolveTemplateParams(c, n.sons[i], withinBind);
end
end
end;
@@ -200,7 +237,7 @@ begin
if n.sons[genericParamsPos] <> nil then
liMessage(n.info, errNoGenericParamsAllowedForX, 'template');
// resolve parameters:
n.sons[codePos] := resolveTemplateParams(c, n.sons[codePos]);
n.sons[codePos] := resolveTemplateParams(c, n.sons[codePos], false);
if params.sons[0].ident.id = ord(wExpr) then
n.sons[codePos] := transformToExpr(n.sons[codePos]);

View File

@@ -46,6 +46,21 @@ begin
assert(c.callee <> nil);
end;
procedure copyCandidate(var a: TCandidate; const b: TCandidate);
begin
a.exactMatches := b.exactMatches;
a.subtypeMatches := b.subtypeMatches;
a.convMatches := b.convMatches;
a.intConvMatches := b.intConvMatches;
a.genericMatches := b.genericMatches;
a.state := b.state;
a.callee := b.callee;
a.calleeSym := b.calleeSym;
a.call := copyTree(b.call);
a.baseTypeMatch := b.baseTypeMatch;
copyIdTable(a.bindings, b.bindings);
end;
function cmpCandidates(const a, b: TCandidate): int;
begin
result := a.exactMatches - b.exactMatches;
@@ -552,8 +567,8 @@ begin
end
end;
function ParamTypesMatch(c: PContext; var m: TCandidate; f, a: PType;
arg: PNode): PNode;
function ParamTypesMatchAux(c: PContext; var m: TCandidate; f, a: PType;
arg: PNode): PNode;
var
r: TTypeRelation;
begin
@@ -608,6 +623,57 @@ begin
end
end;
function ParamTypesMatch(c: PContext; var m: TCandidate; f, a: PType;
arg: PNode): PNode;
var
i, cmp, best: int;
x, y, z: TCandidate;
r: TTypeRelation;
begin
if (arg = nil) or (arg.kind <> nkSymChoice) then
result := ParamTypesMatchAux(c, m, f, a, arg)
else begin
// CAUTION: The order depends on the used hashing scheme. Thus it is
// incorrect to simply use the first fitting match. However, to implement
// this correctly is inefficient. We have to copy `m` here to be able to
// roll back the side effects of the unification algorithm.
initCandidate(x, m.callee);
initCandidate(y, m.callee);
initCandidate(z, m.callee);
x.calleeSym := m.calleeSym;
y.calleeSym := m.calleeSym;
z.calleeSym := m.calleeSym;
best := -1;
for i := 0 to sonsLen(arg)-1 do begin
copyCandidate(z, m);
r := typeRel(z.bindings, f, arg.sons[i].typ);
if r <> isNone then begin
case x.state of
csEmpty, csNoMatch: begin x := z; best := i; x.state := csMatch; end;
csMatch: begin
cmp := cmpCandidates(x, z);
if cmp < 0 then begin best := i; x := z end // z is better than x
else if cmp = 0 then y := z // z is as good as x
else begin end // z is worse than x
end
end
end
end;
if x.state = csEmpty then
result := nil
else if (y.state = csMatch) and (cmpCandidates(x, y) = 0) then begin
if x.state <> csMatch then InternalError(arg.info, 'x.state is not csMatch');
// ambiguous: more than one symbol fits
result := nil
end
else begin
// only one valid interpretation found:
include(arg.sons[best].sym.flags, sfUsed);
result := ParamTypesMatchAux(c, m, f, arg.sons[best].typ, arg.sons[best]);
end
end
end;
function IndexTypesMatch(c: PContext; f, a: PType; arg: PNode): PNode;
var
m: TCandidate;
@@ -796,7 +862,7 @@ begin
//writeMatches(x);
//writeMatches(y);
liMessage(n.Info, errGenerated,
format(msgKindToString(errAmbigiousCallXYZ),
format(msgKindToString(errAmbiguousCallXYZ),
[getProcHeader(x.calleeSym),
getProcHeader(y.calleeSym), x.calleeSym.Name.s]))
end

View File

@@ -502,18 +502,25 @@ procedure addf(var result: string; const f: string; args: array of string);
const
PatternChars = ['a'..'z', 'A'..'Z', '0'..'9', '_', #128..#255];
var
i, j, x: int;
i, j, x, num: int;
begin
i := 1;
num := 0;
while i <= length(f) do
if f[i] = '$' then begin
case f[i+1] of
'#': begin
inc(i, 2);
add(result, args[num]);
inc(num);
end;
'$': begin
addChar(result, '$');
inc(i, 2);
end;
'1'..'9': begin
add(result, args[ord(f[i+1]) - ord('0') - 1]);
num := ord(f[i+1]) - ord('0');
add(result, args[num - 1]);
inc(i, 2);
end;
'{': begin

View File

@@ -15,6 +15,7 @@ unit transf;
// * inlines constants
// * performes contant folding
// * introduces nkHiddenDeref, nkHiddenSubConv, etc.
// * aggressive compile-time evaluation based on the side-effect analysis
interface
@@ -22,7 +23,7 @@ interface
uses
sysutils, nsystem, charsets, strutils,
lists, options, ast, astalgo, trees, treetab,
lists, options, ast, astalgo, trees, treetab, evals,
msgs, nos, idents, rnimsyn, types, passes, semfold, magicsys;
const
@@ -822,7 +823,24 @@ begin
end;
if sonsLen(result) = 2 then
result := result.sons[1];
end;
end
(*
else if result.sons[0].kind = nkSym then begin
// optimization still too aggressive
op := result.sons[0].sym;
if (op.magic = mNone) and (op.kind = skProc)
and ([sfSideEffect, sfForward, sfNoReturn, sfImportc] * op.flags = [])
then begin
for i := 1 to sonsLen(result)-1 do
if not isConstExpr(result.sons[i]) then exit;
// compile-time evaluation:
a := evalConstExpr(c.module, result);
if (a <> nil) and (a.kind <> nkEmpty) then begin
messageout('evaluated at compile time: ' + rendertree(result));
result := a
end
end
end *)
end;
function transform(c: PTransf; n: PNode): PNode;

View File

@@ -65,16 +65,6 @@ function equalParams(a, b: PNode): TParamsEquality;
function isOrdinalType(t: PType): Boolean;
function enumHasWholes(t: PType): Boolean;
(*
function skipRange(t: PType): PType;
function skipGeneric(t: PType): PType;
function skipGenericRange(t: PType): PType;
function skipVar(t: PType): PType;
function skipVarGeneric(t: PType): PType;
function skipVarGenericRange(t: PType): PType;
function skipPtrsGeneric(t: PType): PType;
*)
const
abstractPtrs = {@set}[tyVar, tyPtr, tyRef, tyGenericInst, tyAbstract, tyOrdinal];
abstractVar = {@set}[tyVar, tyGenericInst, tyAbstract, tyOrdinal];

View File

@@ -40,10 +40,10 @@ type
//cog.out(idents)
//]]]
wAbstract, wAddr, wAnd, wAs,
wAsm, wBlock, wBreak, wCase,
wCast, wConst, wContinue, wConverter,
wDiscard, wDiv, wElif, wElse,
wEnd, wEnum, wExcept, wException,
wAsm, wBind, wBlock, wBreak,
wCase, wCast, wConst, wContinue,
wConverter, wDiscard, wDiv, wElif,
wElse, wEnd, wEnum, wExcept,
wFinally, wFor, wFrom, wGeneric,
wIf, wImplies, wImport, wIn,
wInclude, wIs, wIsnot, wIterator,
@@ -62,7 +62,7 @@ type
// pragmas and command line options:
wMagic, wTypeCheck, wFinal, wProfiler,
wObjChecks, wImportc, wExportc, wAlign, wNodecl, wPure,
wVolatile, wRegister, wNostatic, wHeader, wNosideeffect, wNoreturn,
wVolatile, wRegister, wSideeffect, wHeader, wNosideeffect, wNoreturn,
wMerge, wLib, wDynlib, wCompilerproc, wCppmethod, wFatal,
wError, wWarning, wHint, wLine, wPush, wPop,
wDefine, wUndef, wLinedir, wStacktrace, wLinetrace, wPragma,
@@ -114,10 +114,10 @@ const
//cog.out(strings)
//]]]
'abstract', 'addr', 'and', 'as',
'asm', 'block', 'break', 'case',
'cast', 'const', 'continue', 'converter',
'discard', 'div', 'elif', 'else',
'end', 'enum', 'except', 'exception',
'asm', 'bind', 'block', 'break',
'case', 'cast', 'const', 'continue',
'converter', 'discard', 'div', 'elif',
'else', 'end', 'enum', 'except',
'finally', 'for', 'from', 'generic',
'if', 'implies', 'import', 'in',
'include', 'is', 'isnot', 'iterator',
@@ -136,7 +136,7 @@ const
// pragmas and command line options:
'magic', 'typecheck', 'final', 'profiler',
'objchecks', 'importc', 'exportc', 'align', 'nodecl', 'pure',
'volatile', 'register', 'nostatic', 'header', 'nosideeffect', 'noreturn',
'volatile', 'register', 'sideeffect', 'header', 'nosideeffect', 'noreturn',
'merge', 'lib', 'dynlib', 'compilerproc', 'cppmethod', 'fatal',
'error', 'warning', 'hint', 'line', 'push', 'pop',
'define', 'undef', 'linedir', 'stacktrace', 'linetrace', 'pragma',

View File

@@ -68,11 +68,16 @@ def Subs(frmt, *args, **substitution):
a = args
result = []
i = 0
num = 0
L = len(frmt)
while i < L:
if frmt[i] == '$':
i = i+1
if frmt[i] == '$':
if frmt[i] == '#':
result.append(a[num])
num = num+1
i = i+1
elif frmt[i] == '$':
result.append('$')
i = i+1
elif frmt[i] == '{':
@@ -91,7 +96,8 @@ def Subs(frmt, *args, **substitution):
while i < len(frmt) and frmt[i] in chars: i = i + 1
x = frmt[j:i]
if x[0] in DIGITS:
result.append(str(a[int(x)-1]))
num = int(x)
result.append(str(a[num-1]))
else:
result.append(str(d[x]))
else:

View File

@@ -1,8 +1,8 @@
# Test ambigious symbols
# Test ambiguous symbols
import mambsym1, mambsym2
var
v: TExport #ERROR_MSG ambigious identifier
v: TExport #ERROR_MSG ambiguous identifier
v = y

View File

@@ -1,8 +1,8 @@
# Test ambigious symbols
# Test ambiguous symbols
import mambsym1, times
var
v = mDec #ERROR_MSG ambigious identifier
v = mDec #ERROR_MSG ambiguous identifier
writeln(stdout, ord(v))

View File

@@ -1,4 +1,4 @@
# Test ambigious symbols
# Test ambiguous symbols
import mambsys1, mambsys2

View File

@@ -1,25 +1,26 @@
# Test the closure implementation
proc map(n: var openarray[int], fn: proc (x: int): int {.closure}) =
for i in 0..n.len-1:
n[i] = fn(n[i])
for i in 0..n.len-1: n[i] = fn(n[i])
proc foldr(n: openarray[int], fn: proc (x, y: int): int {.closure}): int =
result = 0
for i in 0..n.len-1:
result = fn(result, n[i])
var
myData: array[0..9, int] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
myData: array[0..4, int] = [0, 1, 2, 3, 4]
proc testA() =
var p = 0
map(myData, lambda (x: int): int =
result = x + 1 shl (lambda (y: int): int =
return y + 1
return y + p
)(0)
inc(p), 88)
inc(p))
testA()
for x in items(myData):
echo x
write(stout, x)
#OUT 2 4 6 8 10

View File

@@ -3,7 +3,7 @@
import
unicode, cgi, terminal, libcurl, web,
parsexml, parseopt, parsecfg,
osproc, zipfiles,
osproc,
sdl, smpeg, sdl_gfx, sdl_net, sdl_mixer, sdl_ttf,
sdl_image, sdl_mixer_nosmpeg,
cursorfont, xatom, xf86vmode, xkb, xrandr, xshm, xvlib, keysym, xcms, xi,
@@ -12,6 +12,10 @@ import
cairowin32, cairoxlib,
odbcsql,
gl, glut, glu, glx, glext, wingl,
zlib, lua, lualib, lauxlib, mysql, sqlite3, python, tcl
lua, lualib, lauxlib, mysql, sqlite3, python, tcl
when defined(linux):
import
zlib, zipfiles
writeln(stdout, "test compilation of binding modules")

View File

@@ -3,4 +3,4 @@
var
a: int
a() #ERROR_MSG expression cannot be called
a() #ERROR_MSG expression 'a()' cannot be called

View File

@@ -281,9 +281,9 @@ proc buildDir(os, cpu: int): string =
proc writeFile(filename, content: string) =
var f: TFile
if openFile(f, filename, fmWrite):
if open(f, filename, fmWrite):
writeln(f, content)
closeFile(f)
close(f)
else:
quit("Cannot open for writing: " & filename)
@@ -296,8 +296,8 @@ proc srcdist(c: var TConfigData) =
createDir(dir)
var cmd = ("nimrod compile -f --symbolfiles:off --compileonly " &
"--gen_mapping " &
" --os:$2 --cpu:$3 $1 $4") %
[c.nimrodArgs, c.oses[osA-1], c.cpus[cpuA-1],
" --os:$# --cpu:$# $# $#") %
[c.oses[osA-1], c.cpus[cpuA-1], c.nimrodArgs,
changeFileExt(c.infile, "nim")]
echo("Executing: " & cmd)
if executeShellCommand(cmd) != 0:
@@ -327,14 +327,13 @@ proc srcdist(c: var TConfigData) =
# --------------------- generate inno setup -----------------------------------
proc setupDist(c: var TConfigData) =
var scrpt = GenerateInnoSetup(c)
var n = "build" / "install_$1_$2.iss" % [toLower(c.name), c.version]
var n = "build" / "install_$#_$#.iss" % [toLower(c.name), c.version]
writeFile(n, scrpt)
when defined(windows):
if c.innoSetup.path.len == 0:
c.innoSetup.path = "iscc.exe"
var outcmd = if c.outdir.len == 0: "build" else: c.outdir
var cmd = "$1 $2 /O$3 $4" % [c.innoSetup.path, c.innoSetup.flags,
outcmd, n]
var cmd = "$# $# /O$# $#" % [c.innoSetup.path, c.innoSetup.flags, outcmd, n]
Echo("Executing: " & cmd)
if executeShellCommand(cmd) == 0:
removeFile(n)
@@ -350,7 +349,7 @@ when haveZipLib:
writeFile(deinstallShFile, GenerateDeinstallScript(c))
var proj = toLower(c.name)
var n = "$1_$2.zip" % [proj, c.version]
var n = "$#_$#.zip" % [proj, c.version]
if c.outdir.len == 0: n = "build" / n
else: n = c.outdir / n
var z: TZipArchive

View File

@@ -156,11 +156,11 @@ proc Exec(cmd: string) =
proc buildDoc(c: var TConfigData, destPath: string) =
# call nim for the documentation:
for d in items(c.doc):
Exec("nimrod rst2html $1 -o:$2 --index=$3/theindex $4" %
Exec("nimrod rst2html $# -o:$# --index=$#/theindex $#" %
[c.nimrodArgs, destPath / changeFileExt(extractFileTrunk(d), "html"),
destpath, d])
for d in items(c.srcdoc):
Exec("nimrod doc $1 -o:$2 --index=$3/theindex $4" %
Exec("nimrod doc $# -o:$# --index=$#/theindex $#" %
[c.nimrodArgs, destPath / changeFileExt(extractFileTrunk(d), "html"),
destpath, d])
Exec("nimrod rst2html $1 -o:$2/theindex.html $2/theindex" %
@@ -169,7 +169,7 @@ proc buildDoc(c: var TConfigData, destPath: string) =
proc buildAddDoc(c: var TConfigData, destPath: string) =
# build additional documentation (without the index):
for d in items(c.webdoc):
Exec("nimrod doc $1 -o:$2 $3" %
Exec("nimrod doc $# -o:$# $#" %
[c.nimrodArgs, destPath / changeFileExt(extractFileTrunk(d), "html"), d])
proc main(c: var TConfigData) =
@@ -188,10 +188,10 @@ proc main(c: var TConfigData) =
var content = readFile(temp)
if isNil(content): quit("[Error] cannot open: " & temp)
var f: TFile
var outfile = "web/upload/$1.html" % file
if openFile(f, outfile, fmWrite):
var outfile = "web/upload/$#.html" % file
if open(f, outfile, fmWrite):
writeln(f, generateHTMLPage(c, file, content))
closeFile(f)
close(f)
else:
quit("[Error] cannot write file: " & outfile)
removeFile(temp)