// // // 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 = (withinBind, withinTypeDesc); TSemGenericFlags = set of TSemGenericFlag; function semGenericStmt(c: PContext; n: PNode; flags: TSemGenericFlags = {@set}[]): PNode; forward; function semGenericStmtScope(c: PContext; n: PNode; flags: TSemGenericFlags = {@set}[]): PNode; begin openScope(c.tab); result := semGenericStmt(c, n, flags); closeScope(c.tab); end; function semGenericStmtSymbol(c: PContext; n: PNode; s: PSym): PNode; begin case s.kind of skUnknown: begin // Introduced in this pass! Leave it as an identifier. result := n; end; skProc, skMethod, skIterator, skConverter: result := symChoice(c, n, s); skTemplate: result := semTemplateExpr(c, n, s, false); skMacro: result := semMacroExpr(c, n, s, false); skGenericParam: result := newSymNode(s); skParam: result := n; skType: begin if (s.typ <> nil) and (s.typ.kind <> tyGenericParam) then result := newSymNode(s) else result := n end else result := newSymNode(s) end end; function getIdentNode(n: PNode): PNode; begin case n.kind of nkPostfix: result := getIdentNode(n.sons[1]); nkPragmaExpr, nkAccQuoted: result := getIdentNode(n.sons[0]); nkIdent: result := n; else begin illFormedAst(n); result := nil end end end; function semGenericStmt(c: PContext; n: PNode; flags: TSemGenericFlags = {@set}[]): PNode; var i, j, L: int; a: PNode; s: PSym; begin result := n; if n = nil then exit; case n.kind of nkIdent, nkAccQuoted: begin s := lookUp(c, n); if withinBind in flags then result := symChoice(c, n, s) else result := semGenericStmtSymbol(c, n, s); end; nkDotExpr: begin s := QualifiedLookUp(c, n, true); if s <> nil then result := semGenericStmtSymbol(c, n, s); end; nkSym..nkNilLit: begin end; nkBind: result := semGenericStmt(c, n.sons[0], {@set}[withinBind]); nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit: begin // check if it is an expression macro: checkMinSonsLen(n, 1); s := qualifiedLookup(c, n.sons[0], false); if (s <> nil) then begin case s.kind of skMacro: begin result := semMacroExpr(c, n, s, false); exit end; skTemplate: begin result := semTemplateExpr(c, n, s, false); exit end; skUnknown, skParam: begin // Leave it as an identifier. end; skProc, skMethod, skIterator, skConverter: begin n.sons[0] := symChoice(c, n.sons[0], s); end; skGenericParam: n.sons[0] := newSymNode(s); skType: begin // bad hack for generics: if (s.typ <> nil) and (s.typ.kind <> tyGenericParam) then begin n.sons[0] := newSymNode(s); end end; else n.sons[0] := newSymNode(s) end end; for i := 1 to sonsLen(n)-1 do n.sons[i] := semGenericStmt(c, n.sons[i], flags); end; nkMacroStmt: begin result := semMacroStmt(c, n, false); end; nkIfStmt: begin for i := 0 to sonsLen(n)-1 do n.sons[i] := semGenericStmtScope(c, n.sons[i]); end; nkWhileStmt: begin openScope(c.tab); for i := 0 to sonsLen(n)-1 do n.sons[i] := semGenericStmt(c, n.sons[i]); closeScope(c.tab); end; nkCaseStmt: begin openScope(c.tab); n.sons[0] := semGenericStmt(c, n.sons[0]); for i := 1 to sonsLen(n)-1 do begin a := n.sons[i]; checkMinSonsLen(a, 1); L := sonsLen(a); for j := 0 to L-2 do a.sons[j] := semGenericStmt(c, a.sons[j]); a.sons[L-1] := semGenericStmtScope(c, a.sons[L-1]); end; closeScope(c.tab); end; nkForStmt: begin L := sonsLen(n); openScope(c.tab); n.sons[L-2] := semGenericStmt(c, n.sons[L-2]); for i := 0 to L-3 do addDecl(c, newSymS(skUnknown, n.sons[i], c)); n.sons[L-1] := semGenericStmt(c, n.sons[L-1]); closeScope(c.tab); end; nkBlockStmt, nkBlockExpr, nkBlockType: begin checkSonsLen(n, 2); openScope(c.tab); if n.sons[0] <> nil then addDecl(c, newSymS(skUnknown, n.sons[0], c)); n.sons[1] := semGenericStmt(c, n.sons[1]); closeScope(c.tab); end; nkTryStmt: begin checkMinSonsLen(n, 2); n.sons[0] := semGenericStmtScope(c, n.sons[0]); for i := 1 to sonsLen(n)-1 do begin a := n.sons[i]; checkMinSonsLen(a, 1); L := sonsLen(a); for j := 0 to L-2 do a.sons[j] := semGenericStmt(c, a.sons[j], {@set}[withinTypeDesc]); a.sons[L-1] := semGenericStmtScope(c, a.sons[L-1]); end; end; nkVarSection: begin for i := 0 to sonsLen(n)-1 do begin a := n.sons[i]; if a.kind = nkCommentStmt then continue; if (a.kind <> nkIdentDefs) and (a.kind <> nkVarTuple) then IllFormedAst(a); checkMinSonsLen(a, 3); L := sonsLen(a); a.sons[L-2] := semGenericStmt(c, a.sons[L-2], {@set}[withinTypeDesc]); a.sons[L-1] := semGenericStmt(c, a.sons[L-1]); for j := 0 to L-3 do addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c)); end end; nkGenericParams: begin for i := 0 to sonsLen(n)-1 do begin a := n.sons[i]; if (a.kind <> nkIdentDefs) then IllFormedAst(a); checkMinSonsLen(a, 3); L := sonsLen(a); a.sons[L-2] := semGenericStmt(c, a.sons[L-2], {@set}[withinTypeDesc]); // do not perform symbol lookup for default expressions for j := 0 to L-3 do addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c)); end end; nkConstSection: begin for i := 0 to sonsLen(n)-1 do begin a := n.sons[i]; if a.kind = nkCommentStmt then continue; if (a.kind <> nkConstDef) then IllFormedAst(a); checkSonsLen(a, 3); addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c)); a.sons[1] := semGenericStmt(c, a.sons[1], {@set}[withinTypeDesc]); a.sons[2] := semGenericStmt(c, a.sons[2]); end end; nkTypeSection: begin for i := 0 to sonsLen(n)-1 do begin a := n.sons[i]; if a.kind = nkCommentStmt then continue; if (a.kind <> nkTypeDef) then IllFormedAst(a); checkSonsLen(a, 3); addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c)); end; for i := 0 to sonsLen(n)-1 do begin a := n.sons[i]; if a.kind = nkCommentStmt then continue; if (a.kind <> nkTypeDef) then IllFormedAst(a); checkSonsLen(a, 3); if a.sons[1] <> nil then begin openScope(c.tab); a.sons[1] := semGenericStmt(c, a.sons[1]); a.sons[2] := semGenericStmt(c, a.sons[2], {@set}[withinTypeDesc]); closeScope(c.tab); end else a.sons[2] := semGenericStmt(c, a.sons[2], {@set}[withinTypeDesc]); end end; nkEnumTy: begin checkMinSonsLen(n, 1); if n.sons[0] <> nil then n.sons[0] := semGenericStmt(c, n.sons[0], {@set}[withinTypeDesc]); for i := 1 to sonsLen(n)-1 do begin case n.sons[i].kind of nkEnumFieldDef: a := n.sons[i].sons[0]; nkIdent: a := n.sons[i]; else illFormedAst(n); end; addDeclAt(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c), c.tab.tos-1); end end; nkObjectTy, nkTupleTy: begin end; nkFormalParams: begin checkMinSonsLen(n, 1); if n.sons[0] <> nil then n.sons[0] := semGenericStmt(c, n.sons[0], {@set}[withinTypeDesc]); for i := 1 to sonsLen(n)-1 do begin a := n.sons[i]; if (a.kind <> nkIdentDefs) then IllFormedAst(a); checkMinSonsLen(a, 3); L := sonsLen(a); a.sons[L-1] := semGenericStmt(c, a.sons[L-2], {@set}[withinTypeDesc]); a.sons[L-1] := semGenericStmt(c, a.sons[L-1]); for j := 0 to L-3 do begin addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c)); end end end; nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, nkIteratorDef, nkLambda: begin 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 then begin if n.sons[paramsPos].sons[0] <> nil then addDecl(c, newSym(skUnknown, getIdent('result'), nil)); n.sons[paramsPos] := semGenericStmt(c, n.sons[paramsPos]); end; n.sons[pragmasPos] := semGenericStmt(c, n.sons[pragmasPos]); n.sons[codePos] := semGenericStmtScope(c, n.sons[codePos]); closeScope(c.tab); end else begin for i := 0 to sonsLen(n)-1 do result.sons[i] := semGenericStmt(c, n.sons[i], flags); end end end;