templates can access hidden fields

This commit is contained in:
Araq 2013-12-25 14:53:00 +01:00
commit 9e92455a53
6 changed files with 61 additions and 42 deletions

View file

@ -146,29 +146,18 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym allowed: TSymFlags): PSym
proc semStmtScope(c: PContext, n: PNode): PNode proc semStmtScope(c: PContext, n: PNode): PNode
proc ParamsTypeCheck(c: PContext, typ: PType) {.inline.} = proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
if not typeAllowed(typ, skConst): if not typeAllowed(typ, skConst):
LocalError(typ.n.info, errXisNoType, typeToString(typ)) localError(typ.n.info, errXisNoType, typeToString(typ))
proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
proc semWhen(c: PContext, n: PNode, semCheck: bool = true): PNode proc semWhen(c: PContext, n: PNode, semCheck: bool = true): PNode
proc IsOpImpl(c: PContext, n: PNode): PNode proc isOpImpl(c: PContext, n: PNode): PNode
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
semCheck: bool = true): PNode semCheck: bool = true): PNode
when false:
proc symFromType(t: PType, info: TLineInfo): PSym =
if t.sym != nil: return t.sym
result = newSym(skType, getIdent"AnonType", t.owner, info)
result.flags.incl sfAnon
result.typ = t
proc symNodeFromType(c: PContext, t: PType, info: TLineInfo): PNode =
result = newSymNode(symFromType(t, info), info)
result.typ = makeTypeDesc(c, t)
when false: when false:
proc createEvalContext(c: PContext, mode: TEvalMode): PEvalContext = proc createEvalContext(c: PContext, mode: TEvalMode): PEvalContext =
result = newEvalContext(c.module, mode) result = newEvalContext(c.module, mode)
@ -184,12 +173,6 @@ when false:
result.handleIsOperator = proc (n: PNode): PNode = result.handleIsOperator = proc (n: PNode): PNode =
result = IsOpImpl(c, n) result = IsOpImpl(c, n)
proc evalConstExpr(c: PContext, module: PSym, e: PNode): PNode =
result = evalConstExprAux(c.createEvalContext(emConst), module, nil, e)
proc evalStaticExpr(c: PContext, module: PSym, e: PNode, prc: PSym): PNode =
result = evalConstExprAux(c.createEvalContext(emStatic), module, prc, e)
proc semConstExpr(c: PContext, n: PNode): PNode = proc semConstExpr(c: PContext, n: PNode): PNode =
var e = semExprWithType(c, n) var e = semExprWithType(c, n)
if e == nil: if e == nil:
@ -226,7 +209,9 @@ include hlo, seminst, semcall
proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode = proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode =
inc(evalTemplateCounter) inc(evalTemplateCounter)
if evalTemplateCounter > 100: if evalTemplateCounter > 100:
GlobalError(s.info, errTemplateInstantiationTooNested) globalError(s.info, errTemplateInstantiationTooNested)
let oldFriend = c.friendModule
c.friendModule = s.owner.getModule
result = n result = n
if s.typ.sons[0] == nil: if s.typ.sons[0] == nil:
@ -250,6 +235,7 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode =
result = fitNode(c, s.typ.sons[0], result) result = fitNode(c, s.typ.sons[0], result)
#GlobalError(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0])) #GlobalError(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0]))
dec(evalTemplateCounter) dec(evalTemplateCounter)
c.friendModule = oldFriend
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
semCheck: bool = true): PNode = semCheck: bool = true): PNode =
@ -316,7 +302,7 @@ proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
result = myOpen(module) result = myOpen(module)
for m in items(rd.methods): methodDef(m, true) for m in items(rd.methods): methodDef(m, true)
proc SemStmtAndGenerateGenerics(c: PContext, n: PNode): PNode = proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
result = semStmt(c, n) result = semStmt(c, n)
# BUGFIX: process newly generated generics here, not at the end! # BUGFIX: process newly generated generics here, not at the end!
if c.lastGenericIdx < c.generics.len: if c.lastGenericIdx < c.generics.len:
@ -331,7 +317,7 @@ proc SemStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
result = buildEchoStmt(c, result) result = buildEchoStmt(c, result)
result = transformStmt(c.module, result) result = transformStmt(c.module, result)
proc RecoverContext(c: PContext) = proc recoverContext(c: PContext) =
# clean up in case of a semantic error: We clean up the stacks, etc. This is # clean up in case of a semantic error: We clean up the stacks, etc. This is
# faster than wrapping every stack operation in a 'try finally' block and # faster than wrapping every stack operation in a 'try finally' block and
# requires far less code. # requires far less code.

View file

@ -1268,12 +1268,13 @@ exclude ``nil`` as a valid value with the `not nil`:idx: annotation:
# compiler catches this: # compiler catches this:
p(nil) p(nil)
# but not this: # and also this:
var x: PObject var x: PObject
p(x) p(x)
As shown in the example this is merely an annotation for documentation purposes; The compiler ensures that every code path initializes variables which contain
for now the compiler can only catch the most trivial type violations. not nilable pointers. The details of this analysis are still to be specified
here.
Procedural type Procedural type
@ -1504,8 +1505,8 @@ The ``void`` type is particularly useful for generic code:
else: else:
p(x) p(x)
proc intProc(x: int) = nil proc intProc(x: int) = discard
proc emptyProc() = nil proc emptyProc() = discard
callProc[int](intProc, 12) callProc[int](intProc, 12)
callProc[void](emptyProc) callProc[void](emptyProc)
@ -1767,6 +1768,15 @@ been declared with the `discardable`:idx: pragma:
p(3, 4) # now valid p(3, 4) # now valid
An empty ``discard`` statement is often used as a null statement:
.. code-block:: nimrod
proc classify(s: string) =
case s[0]
of SymChars, '_': echo "an identifier"
of '0'..'9': echo "a number"
else: discard
Var statement Var statement
------------- -------------
@ -1816,7 +1826,7 @@ If a proc is annotated with the ``noinit`` pragma this refers to its implicit
``result`` variable: ``result`` variable:
.. code-block:: nimrod .. code-block:: nimrod
proc returnUndefinedValue: int {.noinit.} = nil proc returnUndefinedValue: int {.noinit.} = discard
The implicit initialization can be also prevented by the `requiresInit`:idx: The implicit initialization can be also prevented by the `requiresInit`:idx:
@ -3207,7 +3217,7 @@ Nimrod also allows for type classes and regular types to be specified
as `type constraints`:idx: of the generic type parameter: as `type constraints`:idx: of the generic type parameter:
.. code-block:: nimrod .. code-block:: nimrod
proc onlyIntOrString[T: int|string](x, y: T) = nil proc onlyIntOrString[T: int|string](x, y: T) = discard
onlyIntOrString(450, 616) # valid onlyIntOrString(450, 616) # valid
onlyIntOrString(5.0, 0.0) # type mismatch onlyIntOrString(5.0, 0.0) # type mismatch
@ -3782,7 +3792,7 @@ regular expressions:
macro case_token(n: stmt): stmt = macro case_token(n: stmt): stmt =
# creates a lexical analyzer from regular expressions # creates a lexical analyzer from regular expressions
# ... (implementation is an exercise for the reader :-) # ... (implementation is an exercise for the reader :-)
nil discard
case_token: # this colon tells the parser it is a macro statement case_token: # this colon tells the parser it is a macro statement
of r"[A-Za-z_]+[A-Za-z_0-9]*": of r"[A-Za-z_]+[A-Za-z_0-9]*":
@ -3811,17 +3821,17 @@ Whole routines (procs, iterators etc.) can also be passed to a template or
a macro via the pragma notation: a macro via the pragma notation:
.. code-block:: nimrod .. code-block:: nimrod
template m(s: stmt) = nil template m(s: stmt) = discard
proc p() {.m.} = nil proc p() {.m.} = discard
This is a simple syntactic transformation into: This is a simple syntactic transformation into:
.. code-block:: nimrod .. code-block:: nimrod
template m(s: stmt) = nil template m(s: stmt) = discard
m: m:
proc p() = nil proc p() = discard
Special Types Special Types
@ -4142,9 +4152,9 @@ all the arguments, but also the matched operators in reverse polish notation:
TMatrix = object TMatrix = object
dummy: int dummy: int
proc `*`(a, b: TMatrix): TMatrix = nil proc `*`(a, b: TMatrix): TMatrix = discard
proc `+`(a, b: TMatrix): TMatrix = nil proc `+`(a, b: TMatrix): TMatrix = discard
proc `-`(a, b: TMatrix): TMatrix = nil proc `-`(a, b: TMatrix): TMatrix = discard
proc `$`(a: TMatrix): string = result = $a.dummy proc `$`(a: TMatrix): string = result = $a.dummy
proc mat21(): TMatrix = proc mat21(): TMatrix =
result.dummy = 21 result.dummy = 21

View file

@ -106,7 +106,7 @@ proc write(f: TFile, b: bool) =
proc write(f: TFile, r: float32) = fprintf(f, "%g", r) proc write(f: TFile, r: float32) = fprintf(f, "%g", r)
proc write(f: TFile, r: biggestFloat) = fprintf(f, "%g", r) proc write(f: TFile, r: biggestFloat) = fprintf(f, "%g", r)
proc write(f: TFile, c: Char) = putc(c, f) proc write(f: TFile, c: char) = putc(c, f)
proc write(f: TFile, a: varargs[string, `$`]) = proc write(f: TFile, a: varargs[string, `$`]) =
for x in items(a): write(f, x) for x in items(a): write(f, x)
@ -184,7 +184,7 @@ when defined(windows) and not defined(useWinAnsi):
proc wfreopen(filename, mode: widecstring, stream: TFile): TFile {. proc wfreopen(filename, mode: widecstring, stream: TFile): TFile {.
importc: "_wfreopen", nodecl.} importc: "_wfreopen", nodecl.}
proc fopen(filename, mode: CString): pointer = proc fopen(filename, mode: cstring): pointer =
var f = newWideCString(filename) var f = newWideCString(filename)
var m = newWideCString(mode) var m = newWideCString(mode)
result = wfopen(f, m) result = wfopen(f, m)
@ -195,7 +195,7 @@ when defined(windows) and not defined(useWinAnsi):
result = wfreopen(f, m, stream) result = wfreopen(f, m, stream)
else: else:
proc fopen(filename, mode: CString): pointer {.importc: "fopen", noDecl.} proc fopen(filename, mode: cstring): pointer {.importc: "fopen", noDecl.}
proc freopen(filename, mode: cstring, stream: TFile): TFile {. proc freopen(filename, mode: cstring, stream: TFile): TFile {.
importc: "freopen", nodecl.} importc: "freopen", nodecl.}
@ -229,7 +229,7 @@ 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 fwrite(buf: Pointer, size, n: int, f: TFile): int {. proc fwrite(buf: pointer, size, n: int, f: TFile): int {.
importc: "fwrite", noDecl.} importc: "fwrite", noDecl.}
proc readBuffer(f: TFile, buffer: pointer, len: int): int = proc readBuffer(f: TFile, buffer: pointer, len: int): int =

View file

@ -0,0 +1,9 @@
type
Foo* = object
fooa, foob: int
proc createFoo*(a, b: int): Foo = Foo(fooa: a, foob: b)
template geta*(f: Foo): expr = f.fooa

View file

@ -0,0 +1,9 @@
discard """
output: 33
"""
import mcan_access_hidden_field
var myfoo = createFoo(33, 44)
echo myfoo.geta

View file

@ -30,6 +30,10 @@ Changes affecting backwards compatibility
- ``os.parentDir`` now returns "" if there is no parent dir. - ``os.parentDir`` now returns "" if there is no parent dir.
- In CGI scripts stacktraces are shown user only if cgi.setStackTraceStdout - In CGI scripts stacktraces are shown user only if cgi.setStackTraceStdout
is used. is used.
- The symbol binding rules for clean templates changed: ``bind`` for any
symbol that's not a parameter is now the default. ``mixin`` can be used
to require instantiation scope for a symbol.
Compiler Additions Compiler Additions
------------------ ------------------
@ -60,6 +64,7 @@ Language Additions
- Added ``delegator pragma`` for handling calls to missing procs and fields at - Added ``delegator pragma`` for handling calls to missing procs and fields at
compile-time. compile-time.
- Support for user-defined type classes has been added. - Support for user-defined type classes has been added.
- Exported templates are allowed to access hidden fields.
Tools improvements Tools improvements