overload resolution for proc vars

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

View file

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

View file

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

View file

@ -29,8 +29,8 @@ addrExpr ::= 'addr' '(' optInd expr ')'
symbol ::= '`' (KEYWORD | IDENT | operator | '(' ')' symbol ::= '`' (KEYWORD | IDENT | operator | '(' ')'
| '[' ']' | '=' | literal)+ '`' | '[' ']' | '=' | literal)+ '`'
| IDENT | IDENT
primary ::= (prefixOperator optInd)* (symbol | constructor | primary ::= ((prefixOperator | 'bind') optInd)* (symbol | constructor |
castExpr | addrExpr) ( castExpr | addrExpr) (
'.' optInd symbol '.' optInd symbol
| '(' optInd namedExprList [SAD] ')' | '(' optInd namedExprList [SAD] ')'
| '[' optInd | '[' optInd
@ -42,7 +42,7 @@ primary ::= (prefixOperator optInd)* (symbol | constructor |
literal ::= INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT literal ::= INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
| FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
| STR_LIT | RSTR_LIT | TRIPLESTR_LIT | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
| CHAR_LIT | RCHAR_LIT | CHAR_LIT
| NIL | NIL
constructor ::= literal 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 The grammar's start symbol is ``module``. The grammar is LL(1) and therefore
not ambigious. not ambiguous.
.. include:: grammar.txt .. include:: grammar.txt
:literal: :literal:
@ -920,6 +920,95 @@ each other:
Most calling conventions exist only for the Windows 32-bit platform. 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 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. produce a value in contrast to expressions. Call expressions are statements.
If the called procedure returns a value, it is not a valid statement If the called procedure returns a value, it is not a valid statement
as statements do not produce values. To evaluate an expression for as statements do not produce values. To evaluate an expression for
side-effects and throwing its value away, one can use the ``discard`` side-effects and throw its value away, one can use the ``discard`` statement.
statement.
Statements are separated into `simple statements`:idx: and Statements are separated into `simple statements`:idx: and
`complex statements`:idx:. `complex statements`:idx:.
@ -1917,11 +2005,11 @@ iterator in which case the overloading resolution takes place:
# Module C # Module C
import A, B import A, B
write(stdout, x) # error: x is ambigious write(stdout, x) # error: x is ambiguous
write(stdout, A.x) # no error: qualifier used write(stdout, A.x) # no error: qualifier used
var x = 4 var x = 4
write(stdout, x) # not ambigious: uses the module C's x write(stdout, x) # not ambiguous: uses the module C's x
Messages Messages

View file

@ -154,6 +154,9 @@ Index
* `system.html#313 <system.html#313>`_ * `system.html#313 <system.html#313>`_
* `system.html#314 <system.html#314>`_ * `system.html#314 <system.html#314>`_
`<=`:idx:
`times.html#115 <times.html#115>`_
`<=`:idx: `<=`:idx:
* `system.html#253 <system.html#253>`_ * `system.html#253 <system.html#253>`_
* `system.html#254 <system.html#254>`_ * `system.html#254 <system.html#254>`_
@ -169,9 +172,6 @@ Index
* `system.html#345 <system.html#345>`_ * `system.html#345 <system.html#345>`_
* `system.html#346 <system.html#346>`_ * `system.html#346 <system.html#346>`_
`<=`:idx:
`times.html#115 <times.html#115>`_
`<=%`:idx: `<=%`:idx:
* `system.html#305 <system.html#305>`_ * `system.html#305 <system.html#305>`_
* `system.html#306 <system.html#306>`_ * `system.html#306 <system.html#306>`_
@ -201,7 +201,7 @@ Index
* `macros.html#117 <macros.html#117>`_ * `macros.html#117 <macros.html#117>`_
`=~`:idx: `=~`:idx:
`regexprs.html#111 <regexprs.html#111>`_ `regexprs.html#108 <regexprs.html#108>`_
`>`:idx: `>`:idx:
`system.html#357 <system.html#357>`_ `system.html#357 <system.html#357>`_
@ -218,18 +218,18 @@ Index
`@`:idx: `@`:idx:
`system.html#365 <system.html#365>`_ `system.html#365 <system.html#365>`_
`[]`:idx:
`strtabs.html#107 <strtabs.html#107>`_
`[]`:idx: `[]`:idx:
`macros.html#113 <macros.html#113>`_ `macros.html#113 <macros.html#113>`_
`[]=`:idx: `[]`:idx:
`macros.html#114 <macros.html#114>`_ `strtabs.html#107 <strtabs.html#107>`_
`[]=`:idx: `[]=`:idx:
`strtabs.html#106 <strtabs.html#106>`_ `strtabs.html#106 <strtabs.html#106>`_
`[]=`:idx:
`macros.html#114 <macros.html#114>`_
`[ESC]`:idx: `[ESC]`:idx:
`manual.html#134 <manual.html#134>`_ `manual.html#134 <manual.html#134>`_
@ -366,8 +366,7 @@ Index
`xmlgen.html#111 <xmlgen.html#111>`_ `xmlgen.html#111 <xmlgen.html#111>`_
`backslash`:idx: `backslash`:idx:
* `manual.html#127 <manual.html#127>`_ `manual.html#127 <manual.html#127>`_
* `regexprs.html#101 <regexprs.html#101>`_
`backspace`:idx: `backspace`:idx:
`manual.html#132 <manual.html#132>`_ `manual.html#132 <manual.html#132>`_
@ -1228,7 +1227,7 @@ Index
`system.html#156 <system.html#156>`_ `system.html#156 <system.html#156>`_
`EInvalidRegEx`:idx: `EInvalidRegEx`:idx:
`regexprs.html#104 <regexprs.html#104>`_ `regexprs.html#101 <regexprs.html#101>`_
`EInvalidValue`:idx: `EInvalidValue`:idx:
`system.html#148 <system.html#148>`_ `system.html#148 <system.html#148>`_
@ -1265,12 +1264,12 @@ Index
`enum_cursor_type`:idx: `enum_cursor_type`:idx:
`mysql.html#237 <mysql.html#237>`_ `mysql.html#237 <mysql.html#237>`_
`Enumeration`:idx:
`manual.html#148 <manual.html#148>`_
`enumeration`:idx: `enumeration`:idx:
`tut1.html#113 <tut1.html#113>`_ `tut1.html#113 <tut1.html#113>`_
`Enumeration`:idx:
`manual.html#148 <manual.html#148>`_
`enum_field_types`:idx: `enum_field_types`:idx:
`mysql.html#202 <mysql.html#202>`_ `mysql.html#202 <mysql.html#202>`_
@ -1546,8 +1545,8 @@ Index
* `strutils.html#124 <strutils.html#124>`_ * `strutils.html#124 <strutils.html#124>`_
* `strutils.html#125 <strutils.html#125>`_ * `strutils.html#125 <strutils.html#125>`_
* `strutils.html#126 <strutils.html#126>`_ * `strutils.html#126 <strutils.html#126>`_
* `regexprs.html#109 <regexprs.html#109>`_ * `regexprs.html#106 <regexprs.html#106>`_
* `regexprs.html#110 <regexprs.html#110>`_ * `regexprs.html#107 <regexprs.html#107>`_
`findChars`:idx: `findChars`:idx:
`strutils.html#123 <strutils.html#123>`_ `strutils.html#123 <strutils.html#123>`_
@ -1631,9 +1630,6 @@ Index
* `system.html#478 <system.html#478>`_ * `system.html#478 <system.html#478>`_
* `system.html#479 <system.html#479>`_ * `system.html#479 <system.html#479>`_
`generic character types`:idx:
`regexprs.html#102 <regexprs.html#102>`_
`Generics`:idx: `Generics`:idx:
* `manual.html#207 <manual.html#207>`_ * `manual.html#207 <manual.html#207>`_
* `tut2.html#108 <tut2.html#108>`_ * `tut2.html#108 <tut2.html#108>`_
@ -2258,11 +2254,11 @@ Index
`xmlgen.html#150 <xmlgen.html#150>`_ `xmlgen.html#150 <xmlgen.html#150>`_
`match`:idx: `match`:idx:
* `regexprs.html#106 <regexprs.html#106>`_ * `regexprs.html#103 <regexprs.html#103>`_
* `regexprs.html#107 <regexprs.html#107>`_ * `regexprs.html#104 <regexprs.html#104>`_
`matchLen`:idx: `matchLen`:idx:
`regexprs.html#108 <regexprs.html#108>`_ `regexprs.html#105 <regexprs.html#105>`_
`math`:idx: `math`:idx:
`nimrodc.html#118 <nimrodc.html#118>`_ `nimrodc.html#118 <nimrodc.html#118>`_
@ -2301,7 +2297,7 @@ Index
`mysql.html#191 <mysql.html#191>`_ `mysql.html#191 <mysql.html#191>`_
`MaxSubpatterns`:idx: `MaxSubpatterns`:idx:
`regexprs.html#105 <regexprs.html#105>`_ `regexprs.html#102 <regexprs.html#102>`_
`MAX_TINYINT_WIDTH`:idx: `MAX_TINYINT_WIDTH`:idx:
`mysql.html#190 <mysql.html#190>`_ `mysql.html#190 <mysql.html#190>`_
@ -3095,12 +3091,12 @@ Index
`ord`:idx: `ord`:idx:
`system.html#172 <system.html#172>`_ `system.html#172 <system.html#172>`_
`ordinal`:idx:
`tut1.html#114 <tut1.html#114>`_
`Ordinal`:idx: `Ordinal`:idx:
`system.html#114 <system.html#114>`_ `system.html#114 <system.html#114>`_
`ordinal`:idx:
`tut1.html#114 <tut1.html#114>`_
`Ordinal types`:idx: `Ordinal types`:idx:
`manual.html#141 <manual.html#141>`_ `manual.html#141 <manual.html#141>`_
@ -3623,16 +3619,16 @@ Index
`system.html#419 <system.html#419>`_ `system.html#419 <system.html#419>`_
`reBinary`:idx: `reBinary`:idx:
`regexprs.html#116 <regexprs.html#116>`_ `regexprs.html#113 <regexprs.html#113>`_
`Recursive module dependancies`:idx: `Recursive module dependancies`:idx:
`manual.html#216 <manual.html#216>`_ `manual.html#216 <manual.html#216>`_
`reEmail`:idx: `reEmail`:idx:
`regexprs.html#119 <regexprs.html#119>`_ `regexprs.html#116 <regexprs.html#116>`_
`reFloat`:idx: `reFloat`:idx:
`regexprs.html#118 <regexprs.html#118>`_ `regexprs.html#115 <regexprs.html#115>`_
`REFRESH_DES_KEY_FILE`:idx: `REFRESH_DES_KEY_FILE`:idx:
`mysql.html#154 <mysql.html#154>`_ `mysql.html#154 <mysql.html#154>`_
@ -3680,13 +3676,13 @@ Index
`nimrodc.html#112 <nimrodc.html#112>`_ `nimrodc.html#112 <nimrodc.html#112>`_
`reHex`:idx: `reHex`:idx:
`regexprs.html#115 <regexprs.html#115>`_
`reIdentifier`:idx:
`regexprs.html#112 <regexprs.html#112>`_ `regexprs.html#112 <regexprs.html#112>`_
`reIdentifier`:idx:
`regexprs.html#109 <regexprs.html#109>`_
`reInteger`:idx: `reInteger`:idx:
`regexprs.html#114 <regexprs.html#114>`_ `regexprs.html#111 <regexprs.html#111>`_
`removeDir`:idx: `removeDir`:idx:
`os.html#150 <os.html#150>`_ `os.html#150 <os.html#150>`_
@ -3695,10 +3691,10 @@ Index
`os.html#141 <os.html#141>`_ `os.html#141 <os.html#141>`_
`reNatural`:idx: `reNatural`:idx:
`regexprs.html#113 <regexprs.html#113>`_ `regexprs.html#110 <regexprs.html#110>`_
`reOctal`:idx: `reOctal`:idx:
`regexprs.html#117 <regexprs.html#117>`_ `regexprs.html#114 <regexprs.html#114>`_
`repeatChar`:idx: `repeatChar`:idx:
`strutils.html#148 <strutils.html#148>`_ `strutils.html#148 <strutils.html#148>`_
@ -3724,7 +3720,7 @@ Index
`manual.html#189 <manual.html#189>`_ `manual.html#189 <manual.html#189>`_
`reURL`:idx: `reURL`:idx:
`regexprs.html#120 <regexprs.html#120>`_ `regexprs.html#117 <regexprs.html#117>`_
`round`:idx: `round`:idx:
`math.html#121 <math.html#121>`_ `math.html#121 <math.html#121>`_
@ -3889,9 +3885,6 @@ Index
* `system.html#226 <system.html#226>`_ * `system.html#226 <system.html#226>`_
* `system.html#227 <system.html#227>`_ * `system.html#227 <system.html#227>`_
`simple assertions`:idx:
`regexprs.html#103 <regexprs.html#103>`_
`simple statements`:idx: `simple statements`:idx:
`manual.html#174 <manual.html#174>`_ `manual.html#174 <manual.html#174>`_
@ -5154,6 +5147,9 @@ Index
* `manual.html#156 <manual.html#156>`_ * `manual.html#156 <manual.html#156>`_
* `tut2.html#103 <tut2.html#103>`_ * `tut2.html#103 <tut2.html#103>`_
`verbose`:idx:
`regexprs.html#118 <regexprs.html#118>`_
`vertical tabulator`:idx: `vertical tabulator`:idx:
`manual.html#126 <manual.html#126>`_ `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 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 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 ``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: the compiler that for every other value nothing should be done:
.. code-block:: nimrod .. code-block:: nimrod
@ -624,7 +624,8 @@ Nimrod provides the ability to overload procedures similar to C++:
.. code-block:: nimrod .. code-block:: nimrod
proc toString(x: int): string = ... proc toString(x: int): string = ...
proc toString(x: bool): 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(13)) # calls the toString(x: int) proc
Echo(toString(true)) # calls the toString(x: bool) 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 this overloading resolution algorithm works exactly is not discussed here
(it will be specified in the manual soon). (it will be specified in the manual soon).
However, it does not lead to nasty suprises and is based on a quite simple 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 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 each operator like ``+`` is a just an overloaded proc. The parser lets you
use operators in `infix notation` (``a + b``) or `prefix notation` (``+ a``). use operators in `infix notation` (``a + b``) or `prefix notation` (``+ a``).
An infix operator always receives two arguments, a prefix operator always one. 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`` mean ``(a) @ (@b)`` or ``(a@) @ (b)``? It always means
``(a) @ (@b)``, because there are no postfix operators in Nimrod. ``(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 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 if it is defined in two (or more) different modules and both modules are
imported by a third one: imported by a third one:
@ -1344,11 +1345,11 @@ imported by a third one:
# Module C # Module C
import A, B 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 write(stdout, A.x) # no error: qualifier used
var x = 4 var x = 4
write(stdout, x) # not ambigious: uses the module C's x write(stdout, x) # not ambiguous: uses the module C's x
But this rule does not apply to procedures or iterators. Here the overloading 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 write(stdout, x("")) # no error: B.x is called
proc x*(a: int): string = nil 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 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 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 program, not *the only* way. Often a procedural approach leads to simpler
and more efficient code. In particular, prefering aggregation over inheritance and more efficient code. In particular, prefering aggregation over inheritance
often results in a better design. is often the better design.
Objects Objects
@ -446,8 +446,7 @@ containers:
# this uses an explicit stack (which is more efficient anyway): # this uses an explicit stack (which is more efficient anyway):
var stack: seq[PBinaryTree[T]] = @[root] var stack: seq[PBinaryTree[T]] = @[root]
while stack.len > 0: while stack.len > 0:
var n = stack[stack.len-1] var n = stack.pop()
setLen(stack, stack.len-1) # pop `n` of the stack
while n != nil: while n != nil:
yield n yield n
add(stack, n.ri) # push right subtree onto the stack add(stack, n.ri) # push right subtree onto the stack
@ -562,11 +561,11 @@ via a special ``:`` syntax:
block: block:
var fn = filename var fn = filename
var f: TFile var f: TFile
if openFile(f, fn, mode): if open(f, fn, mode):
try: try:
actions actions
finally: finally:
closeFile(f) close(f)
else: else:
quit("cannot open: " & fn) 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 cannot change Nimrod's syntax. However, this is no real restriction because
Nimrod's syntax is flexible enough anyway. Nimrod's syntax is flexible enough anyway.
`Macros`:idx: can be used to implement `domain specific languages`:idx:. To write a macro, one needs to know how the Nimrod concrete syntax is converted
To write macros, one needs to know how the Nimrod concrete syntax is converted
to an abstract syntax tree (AST). The AST is documented in the to an abstract syntax tree (AST). The AST is documented in the
`macros <macros.html>`_ module. `macros <macros.html>`_ module.

View file

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

View file

@ -253,8 +253,8 @@ class Changed:
c = Changed("unique_name", "file1.pas file2.pas file3.pas") c = Changed("unique_name", "file1.pas file2.pas file3.pas")
if c.check(): if c.check():
Exec("fpc file1.pas") Exec("fpc file1.pas")
# Exec raises an exception if it fails, thus if we get to here, it was # Exec raises an exception if it fails, thus if we reach the
# a success: # next statement, it was a success:
c.success() c.success()
""" """
def __init__(self, id, files, explain=false, 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, nnkCurly, nnkBracket, nnkBracketExpr, nnkPragmaExpr,
nnkRange, nnkDotExpr, nnkCheckedFieldExpr, nnkDerefExpr, nnkRange, nnkDotExpr, nnkCheckedFieldExpr, nnkDerefExpr,
nnkIfExpr, nnkElifExpr, nnkElseExpr, nnkLambda, nnkIfExpr, nnkElifExpr, nnkElseExpr, nnkLambda,
nnkAccQuoted, nnkHeaderQuoted, nnkTableConstr, nnkQualified, nnkAccQuoted, nnkTableConstr, nnkQualified, nnkBind,
nnkHiddenStdConv, nnkHiddenSubConv, nnkHiddenCallConv, nnkConv, nnkSymChoice, nnkHiddenStdConv, nnkHiddenSubConv, nnkHiddenCallConv,
nnkCast, nnkAddr, nnkHiddenAddr, nnkHiddenDeref, nnkConv, nnkCast, nnkAddr, nnkHiddenAddr,
nnkObjDownConv, nnkObjUpConv, nnkChckRangeF, nnkChckRange64, nnkHiddenDeref, nnkObjDownConv, nnkObjUpConv, nnkChckRangeF,
nnkChckRange, nnkStringToCString, nnkCStringToString, nnkPassAsOpenArray, nnkChckRange64, nnkChckRange, nnkStringToCString, nnkCStringToString,
nnkAsgn, nnkFastAsgn, nnkDefaultTypeParam, nnkGenericParams, nnkPassAsOpenArray, nnkAsgn, nnkFastAsgn, nnkDefaultTypeParam,
nnkFormalParams, nnkOfInherit, nnkModule, nnkProcDef, nnkGenericParams, nnkFormalParams, nnkOfInherit, nnkModule,
nnkConverterDef, nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkProcDef, nnkConverterDef, nnkMacroDef, nnkTemplateDef,
nnkOfBranch, nnkElifBranch, nnkExceptBranch, nnkElse, nnkIteratorDef, nnkOfBranch, nnkElifBranch, nnkExceptBranch,
nnkMacroStmt, nnkAsmStmt, nnkPragma, nnkIfStmt, nnkElse, nnkMacroStmt, nnkAsmStmt, nnkPragma,
nnkWhenStmt, nnkForStmt, nnkWhileStmt, nnkCaseStmt, nnkIfStmt, nnkWhenStmt, nnkForStmt, nnkWhileStmt,
nnkVarSection, nnkConstSection, nnkConstDef, nnkTypeSection, nnkCaseStmt, nnkVarSection, nnkConstSection, nnkConstDef,
nnkTypeDef, nnkYieldStmt, nnkTryStmt, nnkFinally, nnkTypeSection, nnkTypeDef, nnkYieldStmt, nnkTryStmt,
nnkRaiseStmt, nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkFinally, nnkRaiseStmt, nnkReturnStmt, nnkBreakStmt,
nnkBlockStmt, nnkDiscardStmt, nnkStmtList, nnkImportStmt, nnkContinueStmt, nnkBlockStmt, nnkDiscardStmt, nnkStmtList,
nnkFromStmt, nnkImportAs, nnkIncludeStmt, nnkCommentStmt, nnkImportStmt, nnkFromStmt, nnkImportAs, nnkIncludeStmt,
nnkStmtListExpr, nnkBlockExpr, nnkStmtListType, nnkBlockType, nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr, nnkStmtListType,
nnkVm, nnkTypeOfExpr, nnkObjectTy, nnkTupleTy, nnkBlockType, nnkVm, nnkTypeOfExpr, nnkObjectTy,
nnkRecList, nnkRecCase, nnkRecWhen, nnkRefTy, nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen,
nnkPtrTy, nnkVarTy, nnkAbstractTy, nnkProcTy, nnkRefTy, nnkPtrTy, nnkVarTy, nnkAbstractTy,
nnkEnumTy, nnkEnumFieldDef, nnkReturnToken nnkProcTy, nnkEnumTy, nnkEnumFieldDef, nnkReturnToken
TNimNodeKinds* = set[TNimrodNodeKind] TNimNodeKinds* = set[TNimrodNodeKind]
TNimrodTypeKind* = enum TNimrodTypeKind* = enum
ntyNone, ntyBool, ntyChar, ntyEmpty, ntyNone, ntyBool, ntyChar, ntyEmpty,

View file

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

View file

@ -405,17 +405,17 @@ else:
proc inputStream(p: PProcess): PStream = proc inputStream(p: PProcess): PStream =
var f: TFile var f: TFile
if not openFile(f, p.inputHandle, fmWrite): OSError() if not open(f, p.inputHandle, fmWrite): OSError()
result = newFileStream(f) result = newFileStream(f)
proc outputStream(p: PProcess): PStream = proc outputStream(p: PProcess): PStream =
var f: TFile var f: TFile
if not openFile(f, p.outputHandle, fmRead): OSError() if not open(f, p.outputHandle, fmRead): OSError()
result = newFileStream(f) result = newFileStream(f)
proc errorStream(p: PProcess): PStream = proc errorStream(p: PProcess): PStream =
var f: TFile var f: TFile
if not openFile(f, p.errorHandle, fmRead): OSError() if not open(f, p.errorHandle, fmRead): OSError()
result = newFileStream(f) result = newFileStream(f)
proc csystem(cmd: cstring): cint {.nodecl, importc: "system".} 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):" & reURL* = r"\b(http(s)?|ftp|gopher|telnet|file|notes|ms\-help):" &
r"((//)|(\\\\))+[\w\d:#@%/;$()~_?\+\-\=\\\.\&]*\b" r"((//)|(\\\\))+[\w\d:#@%/;$()~_?\+\-\=\\\.\&]*\b"
## describes an URL ## 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 TFileStream* = object of TStream
f: TFile 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 fsAtEnd(s: PFileStream): bool = return EndOfFile(s.f)
proc fsSetPosition(s: PFileStream, pos: int) = setFilePos(s.f, pos) proc fsSetPosition(s: PFileStream, pos: int) = setFilePos(s.f, pos)
proc fsGetPosition(s: PFileStream): int = return int(getFilePos(s.f)) 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`. ## creates a new stream from the file named `filename` with the mode `mode`.
## If the file cannot be opened, nil is returned. ## If the file cannot be opened, nil is returned.
var f: TFile var f: TFile
if OpenFile(f, filename, mode): result = newFileStream(f) if Open(f, filename, mode): result = newFileStream(f)
when true: 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 ## Searches for `chars` in `s` starting at position `start`. If `s` contains
## none of the characters in `chars`, -1 is returned. ## 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`. ## 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. ## 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 ## Deletes in `s` the characters at position `first`..`last`. This modifies
## `s` itself, it does not return a copy. ## `s` itself, it does not return a copy.
## **Deprecated since version 0.8.0**: Use `delete` instead.
proc toOctal*(c: char): string proc toOctal*(c: char): string
## Converts a character `c` to its octal representation. The resulting ## 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;;;", {';'}): ## for word in split(";;this;is;an;;example;;;", {';'}):
## writeln(stdout, word) ## writeln(stdout, word)
## ##
## produces in the same output. ## produces the same output.
var var
first: int = 0 first: int = 0
last: int = 0 last: int = 0
@ -315,17 +318,15 @@ proc intToStr*(x: int, minchars: int = 1): string
proc ParseInt*(s: string): int {.noSideEffect.} proc ParseInt*(s: string): int {.noSideEffect.}
## Parses a decimal integer value contained in `s`. If `s` is not ## Parses a decimal integer value contained in `s`. If `s` is not
## a valid integer, `EInvalidValue` is raised. ## a valid integer, `EInvalidValue` is raised.
# XXX: make this biggestint!
proc ParseBiggestInt*(s: string): biggestInt {.noSideEffect.} proc ParseBiggestInt*(s: string): biggestInt {.noSideEffect.}
## Parses a decimal integer value contained in `s`. If `s` is not ## Parses a decimal integer value contained in `s`. If `s` is not
## a valid integer, `EInvalidValue` is raised. ## 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 ## Parses a decimal floating point value contained in `s`. If `s` is not
## a valid floating point number, `EInvalidValue` is raised. ``NAN``, ## a valid floating point number, `EInvalidValue` is raised. ``NAN``,
## ``INF``, ``-INF`` are also supported (case insensitive comparison). ## ``INF``, ``-INF`` are also supported (case insensitive comparison).
# XXX: make this biggestfloat.
# the stringify and format operators: # the stringify and format operators:
proc toString*[Ty](x: Ty): string 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]) = proc addf(s: var string, formatstr: string, a: openarray[string]) =
const PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\128'..'\255', '_'} const PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\128'..'\255', '_'}
var i = 0 var i = 0
var num = 0
while i < len(formatstr): while i < len(formatstr):
if formatstr[i] == '$': if formatstr[i] == '$':
case formatstr[i+1] # again we use the fact that strings case formatstr[i+1] # again we use the fact that strings
# are zero-terminated here # are zero-terminated here
of '#':
add s, a[num]
inc i, 2
inc num
of '$': of '$':
add s, '$' add s, '$'
inc(i, 2) inc(i, 2)
@ -452,6 +458,7 @@ proc addf(s: var string, formatstr: string, a: openarray[string]) =
while formatstr[i] in {'0'..'9'}: while formatstr[i] in {'0'..'9'}:
j = j * 10 + ord(formatstr[i]) - ord('0') j = j * 10 + ord(formatstr[i]) - ord('0')
inc(i) inc(i)
num = j
add s, a[j - 1] add s, a[j - 1]
of '{': of '{':
var j = i+1 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 = proc strip(s: string, leading = true, trailing = true): string =
const const
chars: set[Char] = Whitespace chars: set[Char] = Whitespace
@ -638,7 +670,8 @@ proc contains(s: string, c: char): bool =
proc contains(s, sub: string): bool = proc contains(s, sub: string): bool =
return find(s, sub) >= 0 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 var a: TSkipTable
result = "" result = ""
preprocessSub(sub, a) preprocessSub(sub, a)
@ -652,7 +685,8 @@ proc replaceStr(s, sub, by: string): string =
# copy the rest: # copy the rest:
add result, copy(s, i) 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) result = newString(s.len)
var i = 0 var i = 0
while i < s.len: while i < s.len:
@ -660,17 +694,23 @@ proc replaceStr(s: string, sub, by: char): string =
else: result[i] = s[i] else: result[i] = s[i]
inc(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) # example: "abc___uvwxyz\0" (___ is to be deleted)
# --> first == 3, last == 5 # --> first == 3, last == 5
# s[first..] = s[last+1..] # s[first..] = s[last+1..]
var
i = first
while last+i+1 < len(s): while last+i+1 < len(s):
s[i] = s[last+i+1] s[i] = s[last+i+1]
inc(i) inc(i)
setlen(s, len(s)-(last-first+1)) 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: # parsing numbers:
proc toHex(x: BiggestInt, len: int): string = proc toHex(x: BiggestInt, len: int): string =
@ -734,11 +774,11 @@ proc ParseBiggestInt(s: string): biggestInt =
if index == -1: if index == -1:
raise newException(EInvalidValue, "invalid integer: " & s) raise newException(EInvalidValue, "invalid integer: " & s)
proc ParseFloat(s: string, start = 0): float = proc ParseFloat(s: string): float =
var var
esign = 1.0 esign = 1.0
sign = 1.0 sign = 1.0
i = start i = 0
exponent: int exponent: int
flags: int flags: int
result = 0.0 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.} proc `xor`*(x, y: bool): bool {.magic: "Xor", noSideEffect.}
## Boolean `exclusive or`; returns true iff ``x != y``. ## 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) ## creates a new object of type ``T`` and returns a safe (traced)
## reference to it in ``a``. ## 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) ## creates a new object of type ``T`` and returns a safe (traced)
## reference to it in ``a``. When the garbage collector frees the object, ## reference to it in ``a``. When the garbage collector frees the object,
## `finalizer` is called. The `finalizer` may not keep a reference to the ## `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 ## an ordinal type. If such a value does not exist, ``EOutOfRange`` is raised
## or a compile time error occurs. ## 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 ## 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 ## exist, ``EOutOfRange`` is raised or a compile time error occurs. This is a
## short notation for: ``x = succ(x, y)``. ## 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 ## 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 ## exist, ``EOutOfRange`` is raised or a compile time error occurs. This is a
## short notation for: ``x = pred(x, y)``. ## 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``. ## creates a new sequence of type ``seq[T]`` with length ``len``.
## This is equivalent to ``s = []; setlen(s, len)``, but more ## This is equivalent to ``s = []; setlen(s, len)``, but more
## efficient since no relocation is needed. ## efficient since no relocation is needed.
@ -255,11 +256,11 @@ proc len*[T](x: seq[T]): int {.magic: "LengthSeq", noSideEffect.}
## always an int. ## always an int.
# set routines: # 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 ## includes element ``y`` to the set ``x``. This is the same as
## ``x = x + {y}``, but it might be more efficient. ## ``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 ## excludes element ``y`` to the set ``x``. This is the same as
## ``x = x - {y}``, but it might be more efficient. ## ``x = x - {y}``, but it might be more efficient.
@ -641,8 +642,8 @@ proc `&` * (x: char, y: string): string {.
magic: "ConStrStr", noSideEffect, merge.} magic: "ConStrStr", noSideEffect, merge.}
## is the `concatenation operator`. It concatenates `x` and `y`. ## is the `concatenation operator`. It concatenates `x` and `y`.
proc add*(x: var string, y: char) {.magic: "AppendStrCh".} proc add*(x: var string, y: char) {.magic: "AppendStrCh", noSideEffect.}
proc add*(x: var string, y: string) {.magic: "AppendStrStr".} proc add*(x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.}
when not defined(ECMAScript): when not defined(ECMAScript):
{.push overflow_checks:off} {.push overflow_checks:off}
@ -663,8 +664,8 @@ else:
`x`[0][len] = 0 `x`[0][len] = 0
""" """
proc add *[T](x: var seq[T], y: T) {.magic: "AppendSeqElem".} proc add *[T](x: var seq[T], y: T) {.magic: "AppendSeqElem", noSideEffect.}
proc add *[T](x: var seq[T], y: seq[T]) {.magic: "AppendSeqSeq".} 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`. ## Generic proc for adding a data item `y` to a container `x`.
## For containers that have an order, `add` means *append*. New generic ## For containers that have an order, `add` means *append*. New generic
## containers should also call their adding proc `add` for consistency. ## 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`` ## the first and last characters that shall be copied. If ``last``
## is omitted, it is treated as ``high(s)``. ## 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`. ## sets the length of `s` to `newlen`.
## If the current length is greater than the new length, ## If the current length is greater than the new length,
## ``s`` will be truncated. ## ``s`` will be truncated.
@ -873,20 +875,21 @@ proc dealloc*(p: Pointer) {.noconv.}
## or other memory may be corrupted. So this procedure is really ## or other memory may be corrupted. So this procedure is really
## *unsafe*. ## *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`. ## sets the length of `s` to `newlen`.
## ``T`` may be any sequence type. ## ``T`` may be any sequence type.
## If the current length is greater than the new length, ## If the current length is greater than the new length,
## ``s`` will be truncated. ## ``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. ## provides a means to implement `programming by contracts` in Nimrod.
## ``assert`` evaluates expression ``cond`` and if ``cond`` is false, it ## ``assert`` evaluates expression ``cond`` and if ``cond`` is false, it
## raises an ``EAssertionFailure`` exception. However, the compiler may ## raises an ``EAssertionFailure`` exception. However, the compiler may
## not generate any code at all for ``assert`` if it is advised to do so. ## not generate any code at all for ``assert`` if it is advised to do so.
## Thus one should use ``assert`` for debugging purposes only. ## 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 ## swaps the values `a` and `b`. This is often more efficient than
## ``tmp = a; a = b; b = tmp``. Particularly useful for sorting algorithms. ## ``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.) ## used instead. (In other words: *Overwriting* is possible.)
# undocumented: # undocumented:
proc getRefcount*[T](x: ref T): int {.importc: "getRefcount".} proc getRefcount*[T](x: ref T): int {.importc: "getRefcount", noSideEffect.}
## retrieves the reference count of an heap-allocated object. The ## retrieves the reference count of an heap-allocated object. The
## value is implementation-dependant. ## value is implementation-dependant.
@ -1107,18 +1110,19 @@ proc find*[T, S](a: T, item: S): int {.inline.} =
inc(result) inc(result)
result = -1 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 ## returns the last item of `s` and decreases ``s.len`` by one. This treats
## `s` as a stack and implements the common *pop* operation. ## `s` as a stack and implements the common *pop* operation.
var L = s.len-1 var L = s.len-1
result = s[L] result = s[L]
setLen(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 ## The well-known ``map`` operation from functional programming. Applies
## `op` to every item in `data` and returns the result as a sequence. ## `op` to every item in `data` and returns the result as a sequence.
result = @[] newSeq(result, data.len)
for d in items(data): add(result, op(d)) for i in 0..data.len-1: result[i] = op(data[i])
# ----------------- FPU ------------------------------------------------------ # ----------------- FPU ------------------------------------------------------
@ -1293,7 +1297,16 @@ when not defined(EcmaScript) and not defined(NimrodVM):
## does not work because the program writes to ``stderr``. ## does not work because the program writes to ``stderr``.
proc OpenFile*(f: var TFile, filename: string, 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`. ## Opens a file named `filename` with given `mode`.
## ##
## Default mode is readonly. Returns true iff the file could be opened. ## 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 ## that the programmer needs to provide an appropriate error message anyway
## (yes, even in scripts). ## (yes, even in scripts).
proc OpenFile*(f: var TFile, filehandle: TFileHandle, proc Open*(f: var TFile, filehandle: TFileHandle,
mode: TFileMode = fmRead): Bool mode: TFileMode = fmRead): Bool
## Creates a ``TFile`` from a `filehandle` with given `mode`. ## Creates a ``TFile`` from a `filehandle` with given `mode`.
## ##
## Default mode is readonly. Returns true iff the file could be opened. ## 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. ## 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 proc EndOfFile*(f: TFile): Bool
## Returns true iff `f` is at the end. ## Returns true iff `f` is at the end.
proc readChar*(f: TFile): char {.importc: "fgetc", nodecl.} 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. ## If the file does not exist `EIO` is raised.
var var
f: TFile f: TFile
if not openFile(f, filename): if not open(f, filename):
raise newException(EIO, "cannot open: " & filename) raise newException(EIO, "cannot open: " & filename)
var res = "" var res = ""
while not endOfFile(f): while not endOfFile(f):
rawReadLine(f, res) rawReadLine(f, res)
yield res yield res
CloseFile(f) Close(f)
proc fileHandle*(f: TFile): TFileHandle {.importc: "fileno", proc fileHandle*(f: TFile): TFileHandle {.importc: "fileno",
header: "<stdio.h>"} header: "<stdio.h>"}

View file

@ -13,10 +13,11 @@
{.push hints:off} {.push hints:off}
proc c_strcmp(a, b: CString): cint {.nodecl, importc: "strcmp".} proc c_strcmp(a, b: CString): cint {.nodecl, noSideEffect, importc: "strcmp".}
proc c_memcmp(a, b: CString, size: cint): cint {.nodecl, importc: "memcmp".} 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_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".} proc c_memset(p: pointer, value: cint, size: int) {.nodecl, importc: "memset".}
type type

View file

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

View file

@ -81,7 +81,7 @@ proc ListBreakPoints() =
write(stdout, "***\n") write(stdout, "***\n")
proc openAppend(filename: string): TFile = proc openAppend(filename: string): TFile =
if openFile(result, filename, fmAppend): if open(result, filename, fmAppend):
write(result, "----------------------------------------\n") write(result, "----------------------------------------\n")
proc dbgRepr(p: pointer, typ: PNimType): string = 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 ") debugOut("[Warning] could not open or create file ")
return return
dbgEvaluate(stream, s, i, currFrame) dbgEvaluate(stream, s, i, currFrame)
closeFile(stream) close(stream)
proc dbgStackFrame(s: string, start: int, currFrame: PExtendedFrame) = proc dbgStackFrame(s: string, start: int, currFrame: PExtendedFrame) =
var dbgTemp: string var dbgTemp: string
@ -343,7 +343,7 @@ proc dbgStackFrame(s: string, start: int, currFrame: PExtendedFrame) =
debugOut("[Warning] could not open or create file ") debugOut("[Warning] could not open or create file ")
return return
ListFrame(stream, currFrame) ListFrame(stream, currFrame)
closeFile(stream) close(stream)
proc CommandPrompt() = proc CommandPrompt() =
# if we return from this routine, user code executes again # 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 = proc readFile(filename: string): string =
var f: TFile var f: TFile
try: try:
if openFile(f, filename): if open(f, filename):
var len = getFileSize(f) var len = getFileSize(f)
if len < high(int): if len < high(int):
result = newString(int(len)) result = newString(int(len))
if readBuffer(f, addr(result[0]), int(len)) != len: if readBuffer(f, addr(result[0]), int(len)) != len:
result = nil result = nil
closeFile(f) close(f)
else: else:
result = nil result = nil
except EIO: except EIO:
@ -112,9 +112,9 @@ const
# should not be translated. # should not be translated.
proc OpenFile(f: var TFile, filename: string, proc Open(f: var TFile, filename: string,
mode: TFileMode = fmRead, mode: TFileMode = fmRead,
bufSize: int = -1): Bool = bufSize: int = -1): Bool =
var var
p: pointer p: pointer
p = fopen(filename, FormatOpen[mode]) p = fopen(filename, FormatOpen[mode])
@ -129,10 +129,18 @@ proc OpenFile(f: var TFile, filename: string,
proc fdopen(filehandle: TFileHandle, mode: cstring): TFile {. proc fdopen(filehandle: TFileHandle, mode: cstring): TFile {.
importc: pccHack & "fdopen", header: "<stdio.h>".} 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]) f = fdopen(filehandle, FormatOpen[mode])
result = f != nil 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: # C routine that is used here:
proc fread(buf: Pointer, size, n: int, f: TFile): int {. proc fread(buf: Pointer, size, n: int, f: TFile): int {.
importc: "fread", noDecl.} importc: "fread", noDecl.}

View file

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

View file

@ -78,27 +78,27 @@ type
nkCurly, nkBracket, nkBracketExpr, nkPragmaExpr, nkCurly, nkBracket, nkBracketExpr, nkPragmaExpr,
nkRange, nkDotExpr, nkCheckedFieldExpr, nkDerefExpr, nkRange, nkDotExpr, nkCheckedFieldExpr, nkDerefExpr,
nkIfExpr, nkElifExpr, nkElseExpr, nkLambda, nkIfExpr, nkElifExpr, nkElseExpr, nkLambda,
nkAccQuoted, nkHeaderQuoted, nkTableConstr, nkQualified, nkAccQuoted, nkTableConstr, nkQualified, nkBind,
nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv, nkConv, nkSymChoice, nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv,
nkCast, nkAddr, nkHiddenAddr, nkHiddenDeref, nkConv, nkCast, nkAddr, nkHiddenAddr,
nkObjDownConv, nkObjUpConv, nkChckRangeF, nkChckRange64, nkHiddenDeref, nkObjDownConv, nkObjUpConv, nkChckRangeF,
nkChckRange, nkStringToCString, nkCStringToString, nkPassAsOpenArray, nkChckRange64, nkChckRange, nkStringToCString, nkCStringToString,
nkAsgn, nkFastAsgn, nkDefaultTypeParam, nkGenericParams, nkPassAsOpenArray, nkAsgn, nkFastAsgn, nkDefaultTypeParam,
nkFormalParams, nkOfInherit, nkModule, nkProcDef, nkGenericParams, nkFormalParams, nkOfInherit, nkModule,
nkConverterDef, nkMacroDef, nkTemplateDef, nkIteratorDef, nkProcDef, nkConverterDef, nkMacroDef, nkTemplateDef,
nkOfBranch, nkElifBranch, nkExceptBranch, nkElse, nkIteratorDef, nkOfBranch, nkElifBranch, nkExceptBranch,
nkMacroStmt, nkAsmStmt, nkPragma, nkIfStmt, nkElse, nkMacroStmt, nkAsmStmt, nkPragma,
nkWhenStmt, nkForStmt, nkWhileStmt, nkCaseStmt, nkIfStmt, nkWhenStmt, nkForStmt, nkWhileStmt,
nkVarSection, nkConstSection, nkConstDef, nkTypeSection, nkCaseStmt, nkVarSection, nkConstSection, nkConstDef,
nkTypeDef, nkYieldStmt, nkTryStmt, nkFinally, nkTypeSection, nkTypeDef, nkYieldStmt, nkTryStmt,
nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt, nkFinally, nkRaiseStmt, nkReturnStmt, nkBreakStmt,
nkBlockStmt, nkDiscardStmt, nkStmtList, nkImportStmt, nkContinueStmt, nkBlockStmt, nkDiscardStmt, nkStmtList,
nkFromStmt, nkImportAs, nkIncludeStmt, nkCommentStmt, nkImportStmt, nkFromStmt, nkImportAs, nkIncludeStmt,
nkStmtListExpr, nkBlockExpr, nkStmtListType, nkBlockType, nkCommentStmt, nkStmtListExpr, nkBlockExpr, nkStmtListType,
nkVm, nkTypeOfExpr, nkObjectTy, nkTupleTy, nkBlockType, nkVm, nkTypeOfExpr, nkObjectTy,
nkRecList, nkRecCase, nkRecWhen, nkRefTy, nkTupleTy, nkRecList, nkRecCase, nkRecWhen,
nkPtrTy, nkVarTy, nkAbstractTy, nkProcTy, nkRefTy, nkPtrTy, nkVarTy, nkAbstractTy,
nkEnumTy, nkEnumFieldDef, nkReturnToken); nkProcTy, nkEnumTy, nkEnumFieldDef, nkReturnToken);
TNodeKinds = set of TNodeKind; TNodeKinds = set of TNodeKind;
const const
NodeKindToStr: array [TNodeKind] of string = ( NodeKindToStr: array [TNodeKind] of string = (
@ -113,48 +113,48 @@ const
'nkCurly', 'nkBracket', 'nkBracketExpr', 'nkPragmaExpr', 'nkCurly', 'nkBracket', 'nkBracketExpr', 'nkPragmaExpr',
'nkRange', 'nkDotExpr', 'nkCheckedFieldExpr', 'nkDerefExpr', 'nkRange', 'nkDotExpr', 'nkCheckedFieldExpr', 'nkDerefExpr',
'nkIfExpr', 'nkElifExpr', 'nkElseExpr', 'nkLambda', 'nkIfExpr', 'nkElifExpr', 'nkElseExpr', 'nkLambda',
'nkAccQuoted', 'nkHeaderQuoted', 'nkTableConstr', 'nkQualified', 'nkAccQuoted', 'nkTableConstr', 'nkQualified', 'nkBind',
'nkHiddenStdConv', 'nkHiddenSubConv', 'nkHiddenCallConv', 'nkConv', 'nkSymChoice', 'nkHiddenStdConv', 'nkHiddenSubConv', 'nkHiddenCallConv',
'nkCast', 'nkAddr', 'nkHiddenAddr', 'nkHiddenDeref', 'nkConv', 'nkCast', 'nkAddr', 'nkHiddenAddr',
'nkObjDownConv', 'nkObjUpConv', 'nkChckRangeF', 'nkChckRange64', 'nkHiddenDeref', 'nkObjDownConv', 'nkObjUpConv', 'nkChckRangeF',
'nkChckRange', 'nkStringToCString', 'nkCStringToString', 'nkPassAsOpenArray', 'nkChckRange64', 'nkChckRange', 'nkStringToCString', 'nkCStringToString',
'nkAsgn', 'nkFastAsgn', 'nkDefaultTypeParam', 'nkGenericParams', 'nkPassAsOpenArray', 'nkAsgn', 'nkFastAsgn', 'nkDefaultTypeParam',
'nkFormalParams', 'nkOfInherit', 'nkModule', 'nkProcDef', 'nkGenericParams', 'nkFormalParams', 'nkOfInherit', 'nkModule',
'nkConverterDef', 'nkMacroDef', 'nkTemplateDef', 'nkIteratorDef', 'nkProcDef', 'nkConverterDef', 'nkMacroDef', 'nkTemplateDef',
'nkOfBranch', 'nkElifBranch', 'nkExceptBranch', 'nkElse', 'nkIteratorDef', 'nkOfBranch', 'nkElifBranch', 'nkExceptBranch',
'nkMacroStmt', 'nkAsmStmt', 'nkPragma', 'nkIfStmt', 'nkElse', 'nkMacroStmt', 'nkAsmStmt', 'nkPragma',
'nkWhenStmt', 'nkForStmt', 'nkWhileStmt', 'nkCaseStmt', 'nkIfStmt', 'nkWhenStmt', 'nkForStmt', 'nkWhileStmt',
'nkVarSection', 'nkConstSection', 'nkConstDef', 'nkTypeSection', 'nkCaseStmt', 'nkVarSection', 'nkConstSection', 'nkConstDef',
'nkTypeDef', 'nkYieldStmt', 'nkTryStmt', 'nkFinally', 'nkTypeSection', 'nkTypeDef', 'nkYieldStmt', 'nkTryStmt',
'nkRaiseStmt', 'nkReturnStmt', 'nkBreakStmt', 'nkContinueStmt', 'nkFinally', 'nkRaiseStmt', 'nkReturnStmt', 'nkBreakStmt',
'nkBlockStmt', 'nkDiscardStmt', 'nkStmtList', 'nkImportStmt', 'nkContinueStmt', 'nkBlockStmt', 'nkDiscardStmt', 'nkStmtList',
'nkFromStmt', 'nkImportAs', 'nkIncludeStmt', 'nkCommentStmt', 'nkImportStmt', 'nkFromStmt', 'nkImportAs', 'nkIncludeStmt',
'nkStmtListExpr', 'nkBlockExpr', 'nkStmtListType', 'nkBlockType', 'nkCommentStmt', 'nkStmtListExpr', 'nkBlockExpr', 'nkStmtListType',
'nkVm', 'nkTypeOfExpr', 'nkObjectTy', 'nkTupleTy', 'nkBlockType', 'nkVm', 'nkTypeOfExpr', 'nkObjectTy',
'nkRecList', 'nkRecCase', 'nkRecWhen', 'nkRefTy', 'nkTupleTy', 'nkRecList', 'nkRecCase', 'nkRecWhen',
'nkPtrTy', 'nkVarTy', 'nkAbstractTy', 'nkProcTy', 'nkRefTy', 'nkPtrTy', 'nkVarTy', 'nkAbstractTy',
'nkEnumTy', 'nkEnumFieldDef', 'nkReturnToken'); 'nkProcTy', 'nkEnumTy', 'nkEnumFieldDef', 'nkReturnToken');
type type
TSymFlag = ( TSymFlag = (
sfUsed, sfStar, sfMinus, sfInInterface, sfUsed, sfStar, sfMinus, sfInInterface,
sfFromGeneric, sfGlobal, sfForward, sfImportc, sfFromGeneric, sfGlobal, sfForward, sfImportc,
sfExportc, sfVolatile, sfRegister, sfPure, sfExportc, sfVolatile, sfRegister, sfPure,
sfResult, sfNoSideEffect, sfMainModule, sfSystemModule, sfResult, sfNoSideEffect, sfSideEffect, sfMainModule,
sfNoReturn, sfAddrTaken, sfCompilerProc, sfCppMethod, sfSystemModule, sfNoReturn, sfAddrTaken, sfCompilerProc,
sfDiscriminant, sfDeprecated, sfInClosure, sfTypeCheck, sfCppMethod, sfDiscriminant, sfDeprecated, sfInClosure,
sfCompileTime, sfThreadVar, sfMerge, sfDeadCodeElim, sfTypeCheck, sfCompileTime, sfThreadVar, sfMerge,
sfBorrow); sfDeadCodeElim, sfBorrow);
TSymFlags = set of TSymFlag; TSymFlags = set of TSymFlag;
const const
SymFlagToStr: array [TSymFlag] of string = ( SymFlagToStr: array [TSymFlag] of string = (
'sfUsed', 'sfStar', 'sfMinus', 'sfInInterface', 'sfUsed', 'sfStar', 'sfMinus', 'sfInInterface',
'sfFromGeneric', 'sfGlobal', 'sfForward', 'sfImportc', 'sfFromGeneric', 'sfGlobal', 'sfForward', 'sfImportc',
'sfExportc', 'sfVolatile', 'sfRegister', 'sfPure', 'sfExportc', 'sfVolatile', 'sfRegister', 'sfPure',
'sfResult', 'sfNoSideEffect', 'sfMainModule', 'sfSystemModule', 'sfResult', 'sfNoSideEffect', 'sfSideEffect', 'sfMainModule',
'sfNoReturn', 'sfAddrTaken', 'sfCompilerProc', 'sfCppMethod', 'sfSystemModule', 'sfNoReturn', 'sfAddrTaken', 'sfCompilerProc',
'sfDiscriminant', 'sfDeprecated', 'sfInClosure', 'sfTypeCheck', 'sfCppMethod', 'sfDiscriminant', 'sfDeprecated', 'sfInClosure',
'sfCompileTime', 'sfThreadVar', 'sfMerge', 'sfDeadCodeElim', 'sfTypeCheck', 'sfCompileTime', 'sfThreadVar', 'sfMerge',
'sfBorrow'); 'sfDeadCodeElim', 'sfBorrow');
type type
TTypeKind = ( TTypeKind = (
tyNone, tyBool, tyChar, tyEmpty, tyNone, tyBool, tyChar, tyEmpty,
@ -189,11 +189,13 @@ const
'nfAllConst', 'nfTransf', 'nfSem'); 'nfAllConst', 'nfTransf', 'nfSem');
type type
TTypeFlag = ( TTypeFlag = (
tfVarargs, tfFinal, tfAcyclic, tfEnumHasWholes); tfVarargs, tfNoSideEffect, tfFinal, tfAcyclic,
tfEnumHasWholes);
TTypeFlags = set of TTypeFlag; TTypeFlags = set of TTypeFlag;
const const
TypeFlagToStr: array [TTypeFlag] of string = ( TypeFlagToStr: array [TTypeFlag] of string = (
'tfVarargs', 'tfFinal', 'tfAcyclic', 'tfEnumHasWholes'); 'tfVarargs', 'tfNoSideEffect', 'tfFinal', 'tfAcyclic',
'tfEnumHasWholes');
type type
TSymKind = ( TSymKind = (
skUnknownSym, skConditional, skDynLib, skParam, skUnknownSym, skConditional, skDynLib, skParam,

View file

@ -220,8 +220,7 @@ end;
function addrLoc(const a: TLoc): PRope; function addrLoc(const a: TLoc): PRope;
begin begin
result := a.r; result := a.r;
if not (lfIndirect in a.flags) then if not (lfIndirect in a.flags) then result := con('&'+'', result)
result := con('&'+'', result)
end; end;
function rdCharLoc(const a: TLoc): PRope; function rdCharLoc(const a: TLoc): PRope;
@ -2257,32 +2256,6 @@ begin
end; end;
// ---------------------- generation of complex constants --------------------- // ---------------------- 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; function genNamedConstExpr(p: BProc; n: PNode): PRope;
begin begin

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,7 +1,7 @@
// //
// //
// The Nimrod Compiler // The Nimrod Compiler
// (c) Copyright 2008 Andreas Rumpf // (c) Copyright 2009 Andreas Rumpf
// //
// See the file "copying.txt", included in this // See the file "copying.txt", included in this
// distribution, for details about the copyright. // distribution, for details about the copyright.
@ -498,8 +498,10 @@ begin
nkCommand: result := lsub(n.sons[0])+lcomma(n, 1)+1; nkCommand: result := lsub(n.sons[0])+lcomma(n, 1)+1;
nkExprEqExpr, nkDefaultTypeParam, nkAsgn, nkFastAsgn: result := lsons(n)+3; nkExprEqExpr, nkDefaultTypeParam, nkAsgn, nkFastAsgn: result := lsons(n)+3;
nkPar, nkCurly, nkBracket: result := lcomma(n)+2; nkPar, nkCurly, nkBracket: result := lcomma(n)+2;
nkSymChoice: result := lsons(n) + length('()') + sonsLen(n)-1;
nkTupleTy: result := lcomma(n)+length('tuple[]'); nkTupleTy: result := lcomma(n)+length('tuple[]');
nkQualified, nkDotExpr: result := lsons(n)+1; nkQualified, nkDotExpr: result := lsons(n)+1;
nkBind: result := lsons(n)+length('bind_');
nkCheckedFieldExpr: result := lsub(n.sons[0]); nkCheckedFieldExpr: result := lsub(n.sons[0]);
nkLambda: result := lsons(n)+length('lambda__=_'); nkLambda: result := lsons(n)+length('lambda__=_');
nkConstDef, nkIdentDefs: begin nkConstDef, nkIdentDefs: begin
@ -531,7 +533,6 @@ begin
nkDerefExpr: result := lsub(n.sons[0])+2; nkDerefExpr: result := lsub(n.sons[0])+2;
nkImportAs: result := lsons(n) + length('_as_'); nkImportAs: result := lsons(n) + length('_as_');
nkAccQuoted: result := lsub(n.sons[0]) + 2; 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]) nkIfExpr: result := lsub(n.sons[0].sons[0])+lsub(n.sons[0].sons[1])
+ lsons(n, 1) + length('if_:_'); + lsons(n, 1) + length('if_:_');
@ -1023,6 +1024,14 @@ begin
gcomma(g, n, 1); gcomma(g, n, 1);
put(g, tkParRi, ')'+''); put(g, tkParRi, ')'+'');
end; 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 nkPar: begin
put(g, tkParLe, '('+''); put(g, tkParLe, '('+'');
gcomma(g, n, c); gcomma(g, n, c);
@ -1043,6 +1052,10 @@ begin
put(g, tkDot, '.'+''); put(g, tkDot, '.'+'');
gsub(g, n.sons[1]); gsub(g, n.sons[1]);
end; end;
nkBind: begin
putWithSpace(g, tkBind, 'bind');
gsub(g, n.sons[0]);
end;
nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref: gsub(g, n.sons[0]); nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref: gsub(g, n.sons[0]);
nkLambda: begin nkLambda: begin
assert(n.sons[genericParamsPos] = nil); assert(n.sons[genericParamsPos] = nil);
@ -1119,12 +1132,6 @@ begin
gsub(g, n.sons[0]); gsub(g, n.sons[0]);
put(g, tkAccent, '`'+''); put(g, tkAccent, '`'+'');
end; end;
nkHeaderQuoted: begin
put(g, tkAccent, '`'+'');
gsub(g, n.sons[0]);
gsub(g, n.sons[1]);
put(g, tkAccent, '`'+'');
end;
nkIfExpr: begin nkIfExpr: begin
putWithSpace(g, tkIf, 'if'); putWithSpace(g, tkIf, 'if');
gsub(g, n.sons[0].sons[0]); 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; function ropef(const frmt: TFormatStr; const args: array of PRope): PRope;
var var
i, j, len, start: int; i, j, len, start, num: int;
begin begin
i := strStart; i := strStart;
len := length(frmt); len := length(frmt);
result := nil; result := nil;
num := 0;
while i <= len + StrStart - 1 do begin while i <= len + StrStart - 1 do begin
if frmt[i] = '$' then begin if frmt[i] = '$' then begin
inc(i); // skip '$' inc(i); // skip '$'
case frmt[i] of case frmt[i] of
'$': begin app(result, '$'+''); inc(i); end; '$': begin app(result, '$'+''); inc(i); end;
'#': begin inc(i); app(result, args[num]); inc(num); end;
'0'..'9': begin '0'..'9': begin
j := 0; j := 0;
repeat repeat
j := (j*10) + Ord(frmt[i]) - ord('0'); j := (j*10) + Ord(frmt[i]) - ord('0');
inc(i); inc(i);
until (i > len + StrStart - 1) or not (frmt[i] in ['0'..'9']); until (i > len + StrStart - 1) or not (frmt[i] in ['0'..'9']);
num := j;
if j > high(args)+1 then if j > high(args)+1 then
internalError('ropes: invalid format string $' + toString(j)); internalError('ropes: invalid format string $' + toString(j));
app(result, args[j-1]); app(result, args[j-1]);

View file

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

View file

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

View file

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

View file

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

View file

@ -257,7 +257,7 @@ begin
addSon(result, newIdentNode(getIdent(id.s+'='), n.info)); addSon(result, newIdentNode(getIdent(id.s+'='), n.info));
addSon(result, semExpr(c, a.sons[0])); addSon(result, semExpr(c, a.sons[0]));
addSon(result, semExpr(c, n.sons[1])); addSon(result, semExpr(c, n.sons[1]));
result := semDirectCall(c, result); result := semDirectCallAnalyseEffects(c, result);
if result <> nil then begin if result <> nil then begin
fixAbstractType(c, result); fixAbstractType(c, result);
analyseIfAddressTakenInCall(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[0]));
addSonIfNotNil(result, semExpr(c, a.sons[1].sons[1])); addSonIfNotNil(result, semExpr(c, a.sons[1].sons[1]));
addSon(result, semExpr(c, n.sons[1])); addSon(result, semExpr(c, n.sons[1]));
result := semDirectCall(c, result); result := semDirectCallAnalyseEffects(c, result);
if result <> nil then begin if result <> nil then begin
fixAbstractType(c, result); fixAbstractType(c, result);
analyseIfAddressTakenInCall(c, result); analyseIfAddressTakenInCall(c, result);
@ -289,7 +289,7 @@ begin
addSon(result, semExpr(c, a.sons[0])); addSon(result, semExpr(c, a.sons[0]));
addSon(result, semExpr(c, a.sons[1])); addSon(result, semExpr(c, a.sons[1]));
addSon(result, semExpr(c, n.sons[1])); addSon(result, semExpr(c, n.sons[1]));
result := semDirectCall(c, result); result := semDirectCallAnalyseEffects(c, result);
if result <> nil then begin if result <> nil then begin
fixAbstractType(c, result); fixAbstractType(c, result);
analyseIfAddressTakenInCall(c, result); analyseIfAddressTakenInCall(c, result);
@ -322,7 +322,7 @@ begin
result := n; result := n;
checkSonsLen(n, 1); checkSonsLen(n, 1);
if not (c.p.owner.kind in [skConverter, skProc, skMacro]) then 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 if (n.sons[0] <> nil) then begin
n.sons[0] := SemExprWithType(c, n.sons[0]); n.sons[0] := SemExprWithType(c, n.sons[0]);
// check for type compatibility: // check for type compatibility:
@ -624,9 +624,28 @@ begin
end end
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 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; end;
function SemTypeSection(c: PContext; n: PNode): PNode; function SemTypeSection(c: PContext; n: PNode): PNode;
@ -682,7 +701,7 @@ begin
addSon(s.typ, nil); addSon(s.typ, nil);
// process the type body for symbol lookup of generic params // process the type body for symbol lookup of generic params
// we can use the same algorithm as for template parameters: // 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; s.ast := a;
if s.typ.containerID <> 0 then if s.typ.containerID <> 0 then
InternalError(a.info, 'semTypeSection: containerID'); InternalError(a.info, 'semTypeSection: containerID');
@ -754,6 +773,13 @@ begin
n.sons[codePos] := newSymNode(b); n.sons[codePos] := newSymNode(b);
end; 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; function semIterator(c: PContext; n: PNode): PNode;
var var
s: PSym; s: PSym;
@ -972,6 +998,7 @@ begin
else if sfBorrow in s.flags then else if sfBorrow in s.flags then
semBorrow(c, n, s); semBorrow(c, n, s);
end; end;
sideEffectsCheck(c, s);
closeScope(c.tab); // close scope for parameters closeScope(c.tab); // close scope for parameters
popOwner(); popOwner();
c.p := oldP; // restore c.p := oldP; // restore

View file

@ -1,7 +1,7 @@
// //
// //
// The Nimrod Compiler // The Nimrod Compiler
// (c) Copyright 2008 Andreas Rumpf // (c) Copyright 2009 Andreas Rumpf
// //
// See the file "copying.txt", included in this // See the file "copying.txt", included in this
// distribution, for details about the copyright. // distribution, for details about the copyright.
@ -90,7 +90,37 @@ begin
dec(evalTemplateCounter); dec(evalTemplateCounter);
end; 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 var
i: int; i: int;
s: PSym; s: PSym;
@ -98,20 +128,27 @@ begin
if n = nil then begin result := nil; exit end; if n = nil then begin result := nil; exit end;
case n.kind of case n.kind of
nkIdent: begin nkIdent: begin
s := SymTabLocalGet(c.Tab, n.ident); if not withinBind then begin
if (s <> nil) then begin s := SymTabLocalGet(c.Tab, n.ident);
result := newSymNode(s); if (s <> nil) then begin
result.info := n.info result := newSymNode(s);
result.info := n.info
end
else
result := n
end
else begin
result := symChoice(c, n, lookup(c, n))
end end
else
result := n
end; end;
nkSym..nkNilLit: // atom nkSym..nkNilLit: // atom
result := n; result := n;
nkBind:
result := resolveTemplateParams(c, n.sons[0], true);
else begin else begin
result := n; result := n;
for i := 0 to sonsLen(n)-1 do 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 end
end; end;
@ -200,7 +237,7 @@ begin
if n.sons[genericParamsPos] <> nil then if n.sons[genericParamsPos] <> nil then
liMessage(n.info, errNoGenericParamsAllowedForX, 'template'); liMessage(n.info, errNoGenericParamsAllowedForX, 'template');
// resolve parameters: // 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 if params.sons[0].ident.id = ord(wExpr) then
n.sons[codePos] := transformToExpr(n.sons[codePos]); n.sons[codePos] := transformToExpr(n.sons[codePos]);

View file

@ -46,6 +46,21 @@ begin
assert(c.callee <> nil); assert(c.callee <> nil);
end; 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; function cmpCandidates(const a, b: TCandidate): int;
begin begin
result := a.exactMatches - b.exactMatches; result := a.exactMatches - b.exactMatches;
@ -552,8 +567,8 @@ begin
end end
end; end;
function ParamTypesMatch(c: PContext; var m: TCandidate; f, a: PType; function ParamTypesMatchAux(c: PContext; var m: TCandidate; f, a: PType;
arg: PNode): PNode; arg: PNode): PNode;
var var
r: TTypeRelation; r: TTypeRelation;
begin begin
@ -608,6 +623,57 @@ begin
end end
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; function IndexTypesMatch(c: PContext; f, a: PType; arg: PNode): PNode;
var var
m: TCandidate; m: TCandidate;
@ -796,7 +862,7 @@ begin
//writeMatches(x); //writeMatches(x);
//writeMatches(y); //writeMatches(y);
liMessage(n.Info, errGenerated, liMessage(n.Info, errGenerated,
format(msgKindToString(errAmbigiousCallXYZ), format(msgKindToString(errAmbiguousCallXYZ),
[getProcHeader(x.calleeSym), [getProcHeader(x.calleeSym),
getProcHeader(y.calleeSym), x.calleeSym.Name.s])) getProcHeader(y.calleeSym), x.calleeSym.Name.s]))
end end

View file

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

View file

@ -15,6 +15,7 @@ unit transf;
// * inlines constants // * inlines constants
// * performes contant folding // * performes contant folding
// * introduces nkHiddenDeref, nkHiddenSubConv, etc. // * introduces nkHiddenDeref, nkHiddenSubConv, etc.
// * aggressive compile-time evaluation based on the side-effect analysis
interface interface
@ -22,7 +23,7 @@ interface
uses uses
sysutils, nsystem, charsets, strutils, 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; msgs, nos, idents, rnimsyn, types, passes, semfold, magicsys;
const const
@ -822,7 +823,24 @@ begin
end; end;
if sonsLen(result) = 2 then if sonsLen(result) = 2 then
result := result.sons[1]; 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; end;
function transform(c: PTransf; n: PNode): PNode; 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 isOrdinalType(t: PType): Boolean;
function enumHasWholes(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 const
abstractPtrs = {@set}[tyVar, tyPtr, tyRef, tyGenericInst, tyAbstract, tyOrdinal]; abstractPtrs = {@set}[tyVar, tyPtr, tyRef, tyGenericInst, tyAbstract, tyOrdinal];
abstractVar = {@set}[tyVar, tyGenericInst, tyAbstract, tyOrdinal]; abstractVar = {@set}[tyVar, tyGenericInst, tyAbstract, tyOrdinal];

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -3,7 +3,7 @@
import import
unicode, cgi, terminal, libcurl, web, unicode, cgi, terminal, libcurl, web,
parsexml, parseopt, parsecfg, parsexml, parseopt, parsecfg,
osproc, zipfiles, osproc,
sdl, smpeg, sdl_gfx, sdl_net, sdl_mixer, sdl_ttf, sdl, smpeg, sdl_gfx, sdl_net, sdl_mixer, sdl_ttf,
sdl_image, sdl_mixer_nosmpeg, sdl_image, sdl_mixer_nosmpeg,
cursorfont, xatom, xf86vmode, xkb, xrandr, xshm, xvlib, keysym, xcms, xi, cursorfont, xatom, xf86vmode, xkb, xrandr, xshm, xvlib, keysym, xcms, xi,
@ -12,6 +12,10 @@ import
cairowin32, cairoxlib, cairowin32, cairoxlib,
odbcsql, odbcsql,
gl, glut, glu, glx, glext, wingl, 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") writeln(stdout, "test compilation of binding modules")

View file

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

View file

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