summary refs log tree commit diff stats
path: root/rod/semgnrc.nim
diff options
context:
space:
mode:
Diffstat (limited to 'rod/semgnrc.nim')
-rwxr-xr-xrod/semgnrc.nim232
1 files changed, 232 insertions, 0 deletions
diff --git a/rod/semgnrc.nim b/rod/semgnrc.nim
new file mode 100755
index 000000000..fbc9f18bd
--- /dev/null
+++ b/rod/semgnrc.nim
@@ -0,0 +1,232 @@
+#
+#
+#           The Nimrod Compiler
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+# This implements the first pass over the generic body; it resolves some
+# symbols. Thus for generics there is a two-phase symbol lookup just like
+# in C++.
+# A problem is that it cannot be detected if the symbol is introduced
+# as in ``var x = ...`` or used because macros/templates can hide this!
+# So we have to eval templates/macros right here so that symbol
+# lookup can be accurate.
+
+type 
+  TSemGenericFlag = enum 
+    withinBind, withinTypeDesc
+  TSemGenericFlags = set[TSemGenericFlag]
+
+proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode
+proc semGenericStmtScope(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode = 
+  openScope(c.tab)
+  result = semGenericStmt(c, n, flags)
+  closeScope(c.tab)
+
+proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode = 
+  case s.kind
+  of skUnknown: 
+    # Introduced in this pass! Leave it as an identifier.
+    result = n
+  of skProc, skMethod, skIterator, skConverter: 
+    result = symChoice(c, n, s)
+  of skTemplate: 
+    result = semTemplateExpr(c, n, s, false)
+  of skMacro: 
+    result = semMacroExpr(c, n, s, false)
+  of skGenericParam: 
+    result = newSymNode(s)
+  of skParam: 
+    result = n
+  of skType: 
+    if (s.typ != nil) and (s.typ.kind != tyGenericParam): result = newSymNode(s)
+    else: result = n
+  else: result = newSymNode(s)
+  
+proc getIdentNode(n: PNode): PNode = 
+  case n.kind
+  of nkPostfix: result = getIdentNode(n.sons[1])
+  of nkPragmaExpr, nkAccQuoted: result = getIdentNode(n.sons[0])
+  of nkIdent: result = n
+  else: 
+    illFormedAst(n)
+    result = nil
+
+proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode = 
+  var 
+    L: int
+    a: PNode
+    s: PSym
+  result = n
+  if n == nil: return 
+  case n.kind
+  of nkIdent, nkAccQuoted: 
+    s = lookUp(c, n)
+    if withinBind in flags: result = symChoice(c, n, s)
+    else: result = semGenericStmtSymbol(c, n, s)
+  of nkDotExpr: 
+    s = QualifiedLookUp(c, n, true)
+    if s != nil: result = semGenericStmtSymbol(c, n, s)
+  of nkSym..nkNilLit: 
+    nil
+  of nkBind: 
+    result = semGenericStmt(c, n.sons[0], {withinBind})
+  of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit: 
+    # check if it is an expression macro:
+    checkMinSonsLen(n, 1)
+    s = qualifiedLookup(c, n.sons[0], false)
+    if (s != nil): 
+      case s.kind
+      of skMacro: 
+        return semMacroExpr(c, n, s, false)
+      of skTemplate: 
+        return semTemplateExpr(c, n, s, false)
+      of skUnknown, skParam: 
+        # Leave it as an identifier.
+      of skProc, skMethod, skIterator, skConverter: 
+        n.sons[0] = symChoice(c, n.sons[0], s)
+      of skGenericParam: 
+        n.sons[0] = newSymNode(s)
+      of skType: 
+        # bad hack for generics:
+        if (s.typ != nil) and (s.typ.kind != tyGenericParam): 
+          n.sons[0] = newSymNode(s)
+      else: n.sons[0] = newSymNode(s)
+    for i in countup(1, sonsLen(n) - 1): 
+      n.sons[i] = semGenericStmt(c, n.sons[i], flags)
+  of nkMacroStmt: 
+    result = semMacroStmt(c, n, false)
+  of nkIfStmt: 
+    for i in countup(0, sonsLen(n) - 1): 
+      n.sons[i] = semGenericStmtScope(c, n.sons[i])
+  of nkWhileStmt: 
+    openScope(c.tab)
+    for i in countup(0, sonsLen(n) - 1): n.sons[i] = semGenericStmt(c, n.sons[i])
+    closeScope(c.tab)
+  of nkCaseStmt: 
+    openScope(c.tab)
+    n.sons[0] = semGenericStmt(c, n.sons[0])
+    for i in countup(1, sonsLen(n) - 1): 
+      a = n.sons[i]
+      checkMinSonsLen(a, 1)
+      L = sonsLen(a)
+      for j in countup(0, L - 2): a.sons[j] = semGenericStmt(c, a.sons[j])
+      a.sons[L - 1] = semGenericStmtScope(c, a.sons[L - 1])
+    closeScope(c.tab)
+  of nkForStmt: 
+    L = sonsLen(n)
+    openScope(c.tab)
+    n.sons[L - 2] = semGenericStmt(c, n.sons[L - 2])
+    for i in countup(0, L - 3): addDecl(c, newSymS(skUnknown, n.sons[i], c))
+    n.sons[L - 1] = semGenericStmt(c, n.sons[L - 1])
+    closeScope(c.tab)
+  of nkBlockStmt, nkBlockExpr, nkBlockType: 
+    checkSonsLen(n, 2)
+    openScope(c.tab)
+    if n.sons[0] != nil: addDecl(c, newSymS(skUnknown, n.sons[0], c))
+    n.sons[1] = semGenericStmt(c, n.sons[1])
+    closeScope(c.tab)
+  of nkTryStmt: 
+    checkMinSonsLen(n, 2)
+    n.sons[0] = semGenericStmtScope(c, n.sons[0])
+    for i in countup(1, sonsLen(n) - 1): 
+      a = n.sons[i]
+      checkMinSonsLen(a, 1)
+      L = sonsLen(a)
+      for j in countup(0, L - 2): 
+        a.sons[j] = semGenericStmt(c, a.sons[j], {withinTypeDesc})
+      a.sons[L - 1] = semGenericStmtScope(c, a.sons[L - 1])
+  of nkVarSection: 
+    for i in countup(0, sonsLen(n) - 1): 
+      a = n.sons[i]
+      if a.kind == nkCommentStmt: continue 
+      if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): IllFormedAst(a)
+      checkMinSonsLen(a, 3)
+      L = sonsLen(a)
+      a.sons[L - 2] = semGenericStmt(c, a.sons[L - 2], {withinTypeDesc})
+      a.sons[L - 1] = semGenericStmt(c, a.sons[L - 1])
+      for j in countup(0, L - 3): 
+        addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
+  of nkGenericParams: 
+    for i in countup(0, sonsLen(n) - 1): 
+      a = n.sons[i]
+      if (a.kind != nkIdentDefs): IllFormedAst(a)
+      checkMinSonsLen(a, 3)
+      L = sonsLen(a)
+      a.sons[L - 2] = semGenericStmt(c, a.sons[L - 2], {withinTypeDesc}) # do not perform symbol lookup for default 
+                                                                         # expressions 
+      for j in countup(0, L - 3): 
+        addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
+  of nkConstSection: 
+    for i in countup(0, sonsLen(n) - 1): 
+      a = n.sons[i]
+      if a.kind == nkCommentStmt: continue 
+      if (a.kind != nkConstDef): IllFormedAst(a)
+      checkSonsLen(a, 3)
+      addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c))
+      a.sons[1] = semGenericStmt(c, a.sons[1], {withinTypeDesc})
+      a.sons[2] = semGenericStmt(c, a.sons[2])
+  of nkTypeSection: 
+    for i in countup(0, sonsLen(n) - 1): 
+      a = n.sons[i]
+      if a.kind == nkCommentStmt: continue 
+      if (a.kind != nkTypeDef): IllFormedAst(a)
+      checkSonsLen(a, 3)
+      addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c))
+    for i in countup(0, sonsLen(n) - 1): 
+      a = n.sons[i]
+      if a.kind == nkCommentStmt: continue 
+      if (a.kind != nkTypeDef): IllFormedAst(a)
+      checkSonsLen(a, 3)
+      if a.sons[1] != nil: 
+        openScope(c.tab)
+        a.sons[1] = semGenericStmt(c, a.sons[1])
+        a.sons[2] = semGenericStmt(c, a.sons[2], {withinTypeDesc})
+        closeScope(c.tab)
+      else: 
+        a.sons[2] = semGenericStmt(c, a.sons[2], {withinTypeDesc})
+  of nkEnumTy: 
+    checkMinSonsLen(n, 1)
+    if n.sons[0] != nil: 
+      n.sons[0] = semGenericStmt(c, n.sons[0], {withinTypeDesc})
+    for i in countup(1, sonsLen(n) - 1): 
+      case n.sons[i].kind
+      of nkEnumFieldDef: a = n.sons[i].sons[0]
+      of nkIdent: a = n.sons[i]
+      else: illFormedAst(n)
+      addDeclAt(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c), c.tab.tos -
+          1)
+  of nkObjectTy, nkTupleTy: 
+    nil
+  of nkFormalParams: 
+    checkMinSonsLen(n, 1)
+    if n.sons[0] != nil: 
+      n.sons[0] = semGenericStmt(c, n.sons[0], {withinTypeDesc})
+    for i in countup(1, sonsLen(n) - 1): 
+      a = n.sons[i]
+      if (a.kind != nkIdentDefs): IllFormedAst(a)
+      checkMinSonsLen(a, 3)
+      L = sonsLen(a)
+      a.sons[L - 1] = semGenericStmt(c, a.sons[L - 2], {withinTypeDesc})
+      a.sons[L - 1] = semGenericStmt(c, a.sons[L - 1])
+      for j in countup(0, L - 3): 
+        addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
+  of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, 
+     nkIteratorDef, nkLambda: 
+    checkSonsLen(n, codePos + 1)
+    addDecl(c, newSymS(skUnknown, getIdentNode(n.sons[0]), c))
+    openScope(c.tab)
+    n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos])
+    if n.sons[paramsPos] != nil: 
+      if n.sons[paramsPos].sons[0] != nil: 
+        addDecl(c, newSym(skUnknown, getIdent("result"), nil))
+      n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos])
+    n.sons[pragmasPos] = semGenericStmt(c, n.sons[pragmasPos])
+    n.sons[codePos] = semGenericStmtScope(c, n.sons[codePos])
+    closeScope(c.tab)
+  else: 
+    for i in countup(0, sonsLen(n) - 1): 
+      result.sons[i] = semGenericStmt(c, n.sons[i], flags)
+  
\ No newline at end of file