fndecls: ref Decl;labstack: array of ref Node;maxlabdep: int;inexcept: ref Node;nexc: int;fndec: ref Decl; increfs(id: ref Decl){ for( ; id != nil; id = id.link) id.refs++;} fninline(d: ref Decl): int{ left, right: ref Node; n := d.init; if(dontinline || d.inline == byte -1 || d.locals != nil || ispoly(d) || n.ty.tof.kind == Tnone || nodes(n) >= 100) return 0; n = n.right; if(n.op == Oseq && n.right == nil) n = n.left; # # inline # (a) return e; # (b) if(c) return e1; else return e2; # (c) if(c) return e1; return e2; # case(n.op){ Oret => break; Oif => right = n.right; if(right.right == nil || right.left.op != Oret || right.right.op != Oret || !tequal(right.left.left.ty, right.right.left.ty)) return 0; break; Oseq => left = n.left; right = n.right; if(left.op != Oif || left.right.right != nil || left.right.left.op != Oret || right.op != Oseq || right.right != nil || right.left.op != Oret || !tequal(left.right.left.left.ty, right.left.left.ty)) return 0; break; * => return 0; } if(occurs(d, n) || hasasgns(n)) return 0; if(n.op == Oseq){ left.right.right = right.left; n = left; right = n.right; d.init.right.right = nil; } if(n.op == Oif){ n.ty = right.ty = right.left.left.ty; right.left = right.left.left; right.right = right.right.left; d.init.right.left = mkunary(Oret, n); } return 1;} rewind(n: ref Node){ r, nn: ref Node; r = n; nn = n.left; for(n = n.right; n != nil; n = n.right){ if(n.right == nil){ r.left = nn; r.right = n.left; } else nn = mkbin(Oindex, nn, n.left); }} ckmod(n: ref Node, id: ref Decl){ t: ref Type; d, idc: ref Decl; mod: ref Node; if(id == nil) fatal("can't find function: " + nodeconv(n)); idc = nil; mod = nil; if(n.op == Oname){ idc = id; mod = id.eimport; } else if(n.op == Omdot) mod = n.left; else if(n.op == Odot){ idc = id.dot; t = n.left.ty; if(t.kind == Tref) t = t.tof; if(t.kind == Tadtpick) t = t.decl.dot.ty; d = t.decl; while(d != nil && d.link != nil) d = d.link; if(d != nil && d.timport != nil) mod = d.timport.eimport; n.right.left = mod; } if(mod != nil && mod.ty.kind != Tmodule){ nerror(n, "cannot use " + expconv(n) + " as a function reference"); return; } if(mod != nil){ if(valistype(mod)){ nerror(n, "cannot use " + expconv(n) + " as a function reference because " + expconv(mod) + " is a module interface"); return; } }else if(idc != nil && idc.dot != nil && !isimpmod(idc.dot.sym)){ nerror(n, "cannot use " + expconv(n) + " without importing " + idc.sym.name + " from a variable"); return; } if(mod != nil) modrefable(n.ty);} addref(n: ref Node){ nn: ref Node; nn = mkn(0, nil, nil); *nn = *n; n.op = Oref; n.left = nn; n.right = nil; n.decl = nil; n.ty = usetype(mktype(n.src.start, n.src.stop, Tref, nn.ty, nil));} fnref(n: ref Node, id: ref Decl){ id.inline = byte -1; ckmod(n, id); addref(n); while(id.link != nil) id = id.link; if(ispoly(id) && encpolys(id) != nil) nerror(n, "cannot have a polymorphic adt function reference " + id.sym.name);} typecheck(checkimp: int): ref Decl{ entry, d, m: ref Decl; if(errors) return nil; # # generate the set of all functions # compile one function at a time # gdecl(tree); gbind(tree); fns = array[nfns] of ref Decl; i := gcheck(tree, fns, 0); if(i != nfns) fatal("wrong number of functions found in gcheck"); maxlabdep = 0; for(i = 0; i < nfns; i++){ d = fns[i]; if(d != nil) fndec = d; if(d != nil) fncheck(d); fndec = nil; } if(errors) return nil; entry = nil; if(checkimp){ im: ref Decl; dm: ref Dlist; if(impmods == nil){ yyerror("no implementation module"); return nil; } for(im = impmods; im != nil; im = im.next){ for(dm = impdecls; dm != nil; dm = dm.next) if(dm.d.sym == im.sym) break; if(dm == nil || dm.d.ty == nil){ yyerror("no definition for implementation module "+im.sym.name); return nil; } } # # can't check the module spec until all types and imports are determined, # which happens in scheck # for(dm = impdecls; dm != nil; dm = dm.next){ im = dm.d; im.refs++; im.ty = usetype(im.ty); if(im.store != Dtype || im.ty.kind != Tmodule){ error(im.src.start, "cannot implement "+declconv(im)); return nil; } } # now check any multiple implementations impdecl = modimp(impdecls, impmods); s := enter("init", 0); for(dm = impdecls; dm != nil; dm = dm.next){ im = dm.d; for(m = im.ty.ids; m != nil; m = m.next){ m.ty = usetype(m.ty); m.refs++; if(m.sym == s && m.ty.kind == Tfn && entry == nil) entry = m; if(m.store == Dglobal || m.store == Dfn) modrefable(m.ty); if(m.store == Dtype && m.ty.kind == Tadt){ for(d = m.ty.ids; d != nil; d = d.next){ d.ty = usetype(d.ty); modrefable(d.ty); d.refs++; } } } checkrefs(im.ty.ids); } } if(errors) return nil; gsort(tree); tree = nil; return entry;}## introduce all global declarations# also adds all fields to adts and modules# note the complications due to nested Odas expressions#gdecl(n: ref Node){ for(;;){ if(n == nil) return; if(n.op != Oseq) break; gdecl(n.left); n = n.right; } case n.op{ Oimport => importdecled(n); gdasdecl(n.right); Oadtdecl => adtdecled(n); Ocondecl => condecled(n); gdasdecl(n.right); Oexdecl => exdecled(n); Omoddecl => moddecled(n); Otypedecl => typedecled(n); Ovardecl => vardecled(n); Ovardecli => vardecled(n.left); gdasdecl(n.right); Ofunc => fndecled(n); Oas or Odas or Onothing => gdasdecl(n); * => fatal("can't deal with "+opconv(n.op)+" in gdecl"); }} ## bind all global type ids,# including those nested inside modules# this needs to be done, since we may use such# a type later in a nested scope, so if we bound# the type ids then, the type could get bound# to a nested declaration#gbind(n: ref Node){ ids: ref Decl; for(;;){ if(n == nil) return; if(n.op != Oseq) break; gbind(n.left); n = n.right; } case n.op{ Oas or Ocondecl or Odas or Oexdecl or Ofunc or Oimport or Onothing or Ovardecl or Ovardecli => break; Ofielddecl => bindtypes(n.decl.ty); Otypedecl => bindtypes(n.decl.ty); if(n.left != nil) gbind(n.left); Opickdecl => gbind(n.left); d := n.right.left.decl; bindtypes(d.ty); repushids(d.ty.ids); gbind(n.right.right); # get new ids for undefined types; propagate outwards ids = popids(d.ty.ids); if(ids != nil) installids(Dundef, ids); Oadtdecl or Omoddecl => bindtypes(n.ty); if(n.ty.polys != nil) repushids(n.ty.polys); repushids(n.ty.ids); gbind(n.left); # get new ids for undefined types; propagate outwards ids = popids(n.ty.ids); if(ids != nil) installids(Dundef, ids); if(n.ty.polys != nil) popids(n.ty.polys); * => fatal("can't deal with "+opconv(n.op)+" in gbind"); }} ## check all of the global declarations# bind all type ids referred to within types at the global level# record decls for defined functions#gcheck(n: ref Node, fns: array of ref Decl, nfns: int): int{ ok, allok: int; for(;;){ if(n == nil) return nfns; if(n.op != Oseq) break; nfns = gcheck(n.left, fns, nfns); n = n.right; } case n.op{ Ofielddecl => if(n.decl.ty.eraises != nil) raisescheck(n.decl.ty); Onothing or Opickdecl => break; Otypedecl => tcycle(n.ty); Oadtdecl or Omoddecl => if(n.ty.polys != nil) repushids(n.ty.polys); repushids(n.ty.ids); if(gcheck(n.left, nil, 0)) fatal("gcheck fn decls nested in modules or adts"); if(popids(n.ty.ids) != nil) fatal("gcheck installs new ids in a module or adt"); if(n.ty.polys != nil) popids(n.ty.polys); Ovardecl => varcheck(n, 1); Ocondecl => concheck(n, 1); Oexdecl => excheck(n, 1); Oimport => importcheck(n, 1); Ovardecli => varcheck(n.left, 1); (ok, allok) = echeck(n.right, 0, 1, nil); if(ok){ if(allok) n.right = fold(n.right); globalas(n.right.left, n.right.right, allok); } Oas or Odas => (ok, allok) = echeck(n, 0, 1, nil); if(ok){ if(allok) n = fold(n); globalas(n.left, n.right, allok); } Ofunc => (ok, allok) = echeck(n.left, 0, 1, n); if(ok && n.ty.eraises != nil) raisescheck(n.ty); d : ref Decl = nil; if(ok) d = fnchk(n); fns[nfns++] = d; * => fatal("can't deal with "+opconv(n.op)+" in gcheck"); } return nfns;} ## check for unused expression results# make sure the any calculated expression has# a destination#checkused(n: ref Node): ref Node{ # # only nil; and nil = nil; should have type tany # if(n.ty == tany){ if(n.op == Oname) return n; if(n.op == Oas) return checkused(n.right); fatal("line "+lineconv(n.src.start)+" checkused "+nodeconv(n)); } if(n.op == Ocall && n.left.ty.kind == Tfn && n.left.ty.tof != tnone){ n = mkunary(Oused, n); n.ty = n.left.ty; return n; } if(n.op == Ocall && isfnrefty(n.left.ty)){ if(n.left.ty.tof.tof != tnone){ n = mkunary(Oused, n); n.ty = n.left.ty; } return n; } if(isused[n.op] && (n.op != Ocall || n.left.ty.kind == Tfn)) return n; t := n.ty; if(t.kind == Tfn) nerror(n, "function "+expconv(n)+" not called"); else if(t.kind == Tadt && t.tags != nil || t.kind == Tadtpick) nerror(n, "expressions cannot have type "+typeconv(t)); else if(n.op == Otuple){ for(nn := n.left; nn != nil; nn = nn.right) checkused(nn.left); } else nwarn(n, "result of expression "+expconv(n)+" not used"); n = mkunary(Oused, n); n.ty = n.left.ty; return n;} fncheck(d: ref Decl){ n := d.init; if(debug['t']) print("typecheck tree: %s\n", nodeconv(n)); fndecls = nil; adtp := outerpolys(n.left); if(n.left.op == Odot) repushids(adtp); if(d.ty.polys != nil) repushids(d.ty.polys); repushids(d.ty.ids); labdep = 0; labstack = array[maxlabdep] of ref Node; n.right = scheck(n.right, d.ty.tof, Sother); if(labdep != 0)Lines 1–500 of 3225. Load more
fndecls: ref Decl; labstack: array of ref Node; maxlabdep: int; inexcept: ref Node; nexc: int; fndec: ref Decl; increfs(id: ref Decl) { for( ; id != nil; id = id.link) id.refs++; } fninline(d: ref Decl): int { left, right: ref Node; n := d.init; if(dontinline || d.inline == byte -1 || d.locals != nil || ispoly(d) || n.ty.tof.kind == Tnone || nodes(n) >= 100) return 0; n = n.right; if(n.op == Oseq && n.right == nil) n = n.left; # # inline # (a) return e; # (b) if(c) return e1; else return e2; # (c) if(c) return e1; return e2; # case(n.op){ Oret => break; Oif => right = n.right; if(right.right == nil || right.left.op != Oret || right.right.op != Oret || !tequal(right.left.left.ty, right.right.left.ty)) return 0; break; Oseq => left = n.left; right = n.right; if(left.op != Oif || left.right.right != nil || left.right.left.op != Oret || right.op != Oseq || right.right != nil || right.left.op != Oret || !tequal(left.right.left.left.ty, right.left.left.ty)) return 0; break; * => return 0; } if(occurs(d, n) || hasasgns(n)) return 0; if(n.op == Oseq){ left.right.right = right.left; n = left; right = n.right; d.init.right.right = nil; } if(n.op == Oif){ n.ty = right.ty = right.left.left.ty; right.left = right.left.left; right.right = right.right.left; d.init.right.left = mkunary(Oret, n); } return 1; } rewind(n: ref Node) { r, nn: ref Node; r = n; nn = n.left; for(n = n.right; n != nil; n = n.right){ if(n.right == nil){ r.left = nn; r.right = n.left; } else nn = mkbin(Oindex, nn, n.left); } } ckmod(n: ref Node, id: ref Decl) { t: ref Type; d, idc: ref Decl; mod: ref Node; if(id == nil) fatal("can't find function: " + nodeconv(n)); idc = nil; mod = nil; if(n.op == Oname){ idc = id; mod = id.eimport; } else if(n.op == Omdot) mod = n.left; else if(n.op == Odot){ idc = id.dot; t = n.left.ty; if(t.kind == Tref) t = t.tof; if(t.kind == Tadtpick) t = t.decl.dot.ty; d = t.decl; while(d != nil && d.link != nil) d = d.link; if(d != nil && d.timport != nil) mod = d.timport.eimport; n.right.left = mod; } if(mod != nil && mod.ty.kind != Tmodule){ nerror(n, "cannot use " + expconv(n) + " as a function reference"); return; } if(mod != nil){ if(valistype(mod)){ nerror(n, "cannot use " + expconv(n) + " as a function reference because " + expconv(mod) + " is a module interface"); return; } }else if(idc != nil && idc.dot != nil && !isimpmod(idc.dot.sym)){ nerror(n, "cannot use " + expconv(n) + " without importing " + idc.sym.name + " from a variable"); return; } if(mod != nil) modrefable(n.ty); } addref(n: ref Node) { nn: ref Node; nn = mkn(0, nil, nil); *nn = *n; n.op = Oref; n.left = nn; n.right = nil; n.decl = nil; n.ty = usetype(mktype(n.src.start, n.src.stop, Tref, nn.ty, nil)); } fnref(n: ref Node, id: ref Decl) { id.inline = byte -1; ckmod(n, id); addref(n); while(id.link != nil) id = id.link; if(ispoly(id) && encpolys(id) != nil) nerror(n, "cannot have a polymorphic adt function reference " + id.sym.name); } typecheck(checkimp: int): ref Decl { entry, d, m: ref Decl; if(errors) return nil; # # generate the set of all functions # compile one function at a time # gdecl(tree); gbind(tree); fns = array[nfns] of ref Decl; i := gcheck(tree, fns, 0); if(i != nfns) fatal("wrong number of functions found in gcheck"); maxlabdep = 0; for(i = 0; i < nfns; i++){ d = fns[i]; if(d != nil) fndec = d; if(d != nil) fncheck(d); fndec = nil; } if(errors) return nil; entry = nil; if(checkimp){ im: ref Decl; dm: ref Dlist; if(impmods == nil){ yyerror("no implementation module"); return nil; } for(im = impmods; im != nil; im = im.next){ for(dm = impdecls; dm != nil; dm = dm.next) if(dm.d.sym == im.sym) break; if(dm == nil || dm.d.ty == nil){ yyerror("no definition for implementation module "+im.sym.name); return nil; } } # # can't check the module spec until all types and imports are determined, # which happens in scheck # for(dm = impdecls; dm != nil; dm = dm.next){ im = dm.d; im.refs++; im.ty = usetype(im.ty); if(im.store != Dtype || im.ty.kind != Tmodule){ error(im.src.start, "cannot implement "+declconv(im)); return nil; } } # now check any multiple implementations impdecl = modimp(impdecls, impmods); s := enter("init", 0); for(dm = impdecls; dm != nil; dm = dm.next){ im = dm.d; for(m = im.ty.ids; m != nil; m = m.next){ m.ty = usetype(m.ty); m.refs++; if(m.sym == s && m.ty.kind == Tfn && entry == nil) entry = m; if(m.store == Dglobal || m.store == Dfn) modrefable(m.ty); if(m.store == Dtype && m.ty.kind == Tadt){ for(d = m.ty.ids; d != nil; d = d.next){ d.ty = usetype(d.ty); modrefable(d.ty); d.refs++; } } } checkrefs(im.ty.ids); } } if(errors) return nil; gsort(tree); tree = nil; return entry; } # # introduce all global declarations # also adds all fields to adts and modules # note the complications due to nested Odas expressions # gdecl(n: ref Node) { for(;;){ if(n == nil) return; if(n.op != Oseq) break; gdecl(n.left); n = n.right; } case n.op{ Oimport => importdecled(n); gdasdecl(n.right); Oadtdecl => adtdecled(n); Ocondecl => condecled(n); gdasdecl(n.right); Oexdecl => exdecled(n); Omoddecl => moddecled(n); Otypedecl => typedecled(n); Ovardecl => vardecled(n); Ovardecli => vardecled(n.left); gdasdecl(n.right); Ofunc => fndecled(n); Oas or Odas or Onothing => gdasdecl(n); * => fatal("can't deal with "+opconv(n.op)+" in gdecl"); } } # # bind all global type ids, # including those nested inside modules # this needs to be done, since we may use such # a type later in a nested scope, so if we bound # the type ids then, the type could get bound # to a nested declaration # gbind(n: ref Node) { ids: ref Decl; for(;;){ if(n == nil) return; if(n.op != Oseq) break; gbind(n.left); n = n.right; } case n.op{ Oas or Ocondecl or Odas or Oexdecl or Ofunc or Oimport or Onothing or Ovardecl or Ovardecli => break; Ofielddecl => bindtypes(n.decl.ty); Otypedecl => bindtypes(n.decl.ty); if(n.left != nil) gbind(n.left); Opickdecl => gbind(n.left); d := n.right.left.decl; bindtypes(d.ty); repushids(d.ty.ids); gbind(n.right.right); # get new ids for undefined types; propagate outwards ids = popids(d.ty.ids); if(ids != nil) installids(Dundef, ids); Oadtdecl or Omoddecl => bindtypes(n.ty); if(n.ty.polys != nil) repushids(n.ty.polys); repushids(n.ty.ids); gbind(n.left); # get new ids for undefined types; propagate outwards ids = popids(n.ty.ids); if(ids != nil) installids(Dundef, ids); if(n.ty.polys != nil) popids(n.ty.polys); * => fatal("can't deal with "+opconv(n.op)+" in gbind"); } } # # check all of the global declarations # bind all type ids referred to within types at the global level # record decls for defined functions # gcheck(n: ref Node, fns: array of ref Decl, nfns: int): int { ok, allok: int; for(;;){ if(n == nil) return nfns; if(n.op != Oseq) break; nfns = gcheck(n.left, fns, nfns); n = n.right; } case n.op{ Ofielddecl => if(n.decl.ty.eraises != nil) raisescheck(n.decl.ty); Onothing or Opickdecl => break; Otypedecl => tcycle(n.ty); Oadtdecl or Omoddecl => if(n.ty.polys != nil) repushids(n.ty.polys); repushids(n.ty.ids); if(gcheck(n.left, nil, 0)) fatal("gcheck fn decls nested in modules or adts"); if(popids(n.ty.ids) != nil) fatal("gcheck installs new ids in a module or adt"); if(n.ty.polys != nil) popids(n.ty.polys); Ovardecl => varcheck(n, 1); Ocondecl => concheck(n, 1); Oexdecl => excheck(n, 1); Oimport => importcheck(n, 1); Ovardecli => varcheck(n.left, 1); (ok, allok) = echeck(n.right, 0, 1, nil); if(ok){ if(allok) n.right = fold(n.right); globalas(n.right.left, n.right.right, allok); } Oas or Odas => (ok, allok) = echeck(n, 0, 1, nil); if(ok){ if(allok) n = fold(n); globalas(n.left, n.right, allok); } Ofunc => (ok, allok) = echeck(n.left, 0, 1, n); if(ok && n.ty.eraises != nil) raisescheck(n.ty); d : ref Decl = nil; if(ok) d = fnchk(n); fns[nfns++] = d; * => fatal("can't deal with "+opconv(n.op)+" in gcheck"); } return nfns; } # # check for unused expression results # make sure the any calculated expression has # a destination # checkused(n: ref Node): ref Node { # # only nil; and nil = nil; should have type tany # if(n.ty == tany){ if(n.op == Oname) return n; if(n.op == Oas) return checkused(n.right); fatal("line "+lineconv(n.src.start)+" checkused "+nodeconv(n)); } if(n.op == Ocall && n.left.ty.kind == Tfn && n.left.ty.tof != tnone){ n = mkunary(Oused, n); n.ty = n.left.ty; return n; } if(n.op == Ocall && isfnrefty(n.left.ty)){ if(n.left.ty.tof.tof != tnone){ n = mkunary(Oused, n); n.ty = n.left.ty; } return n; } if(isused[n.op] && (n.op != Ocall || n.left.ty.kind == Tfn)) return n; t := n.ty; if(t.kind == Tfn) nerror(n, "function "+expconv(n)+" not called"); else if(t.kind == Tadt && t.tags != nil || t.kind == Tadtpick) nerror(n, "expressions cannot have type "+typeconv(t)); else if(n.op == Otuple){ for(nn := n.left; nn != nil; nn = nn.right) checkused(nn.left); } else nwarn(n, "result of expression "+expconv(n)+" not used"); n = mkunary(Oused, n); n.ty = n.left.ty; return n; } fncheck(d: ref Decl) { n := d.init; if(debug['t']) print("typecheck tree: %s\n", nodeconv(n)); fndecls = nil; adtp := outerpolys(n.left); if(n.left.op == Odot) repushids(adtp); if(d.ty.polys != nil) repushids(d.ty.polys); repushids(d.ty.ids); labdep = 0; labstack = array[maxlabdep] of ref Node; n.right = scheck(n.right, d.ty.tof, Sother); if(labdep != 0)