ngt.clu 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. % NGT CLU special for NCLU
  2. % These routines are the code generator's interface to the
  3. % typechecker. Until typechecking is complete, the types
  4. % determined by the typechecker cannot be used, as they
  5. % may contain BAD types resulting from undefined externals.
  6. % Thus, these routines must determine types on their own,
  7. % as best they can.
  8. BEGIN
  9. # include "clu/absyn2.clu"
  10. idntype = oneof [ var, parm, op: typespec,
  11. undec: null ];
  12. END
  13. gt_exprlist = proc (z: zen, el: exprlist) returns (typelist);
  14. a: typelist := typelist$predict (0, exprlist$size (el));
  15. for i: int := exprlist$low (el) to exprlist$high (el) do
  16. typelist$extendh (a, gt_expr (z, el[i]));
  17. return (a);
  18. end gt_exprlist;
  19. gt_expr = proc (z: zen, x: expr) returns (typespec);
  20. if (in_system ()) then return (expr$get_type (x));
  21. e: exprabs := expr$d (x);
  22. tagcase e in
  23. add,sub,mul,div,pow,mod,cat: return (gt_binexp(z,e.l,e.r));
  24. not,and,or,eq,gt,lt,ne,le,ge: return (typespec$make_bool ());
  25. assn: return (gt_expr(z,e.l));
  26. minus: return (gt_expr(z,e));
  27. condexp: return (gt_binexp(z,e.t,e.f));
  28. reccon: return (gt_reccon(z,e));
  29. arrcon: return (gt_arrcon(z,e));
  30. fill: return (typespec$make_array (gt_expr (z, e.val)));
  31. boolcon: return (typespec$make_bool ());
  32. intcon: return (typespec$make_int ());
  33. nilcon: return (typespec$make_null ());
  34. charcon: return (typespec$make_char ());
  35. stringcon: return (typespec$make_string ());
  36. typecon: return (typespec$make_type ());
  37. op: return (gt_op(z,e));
  38. invoke: return (gt_invoke(z,e));
  39. recref: return (gt_stringcall (z, gt_expr (z, e.r),
  40. "get_" || name$d (e.sel)));
  41. arrayref: return (gt_stringcall (z, gt_expr (z, e.l), "fetch"));
  42. idn: return (gt_idn(z,e));
  43. upop: return (zen$abstract_type (z));
  44. downop: return (zen$concrete_type (z));
  45. caste: return (e.typ);
  46. out: oops(z,"Illegal expression given to gt_expr");
  47. end;
  48. return (gt_empty());
  49. end gt_expr;
  50. % The type of a binary expression is generally that
  51. % that of its left operand. However, if we all we
  52. % have been able to find out is that it is the return
  53. % type of some procedure, then we use the type of the
  54. % right operand.
  55. gt_binexp = proc (z: zen, l, r: expr) returns (typespec);
  56. ty: typespec := gt_expr (z, l);
  57. if (typespec$is_atype (ty)) then begin;
  58. a: atype := typespec$get_atype (ty);
  59. if (gk_is_fake (z, a.name)) then return (gt_expr (z, r));
  60. end;
  61. return (ty);
  62. end gt_binexp;
  63. % Record constructor types must be built from the types
  64. % of the expressions in the constructor, then sorted according
  65. % to alphabetic order of the selectors.
  66. gt_reccon = proc (z: zen, x: reccon) returns (typespec);
  67. RT = recordtype;
  68. ORT = orecordtype;
  69. typ: typespec;
  70. r: ORT := ORT$new ();
  71. for i: int := reccon$low (x) to reccon$high (x) do
  72. ORT$extendh (r, {
  73. sels: x[i].sels,
  74. typ: gt_expr (z, x[i].val)});
  75. typ := typespec$u (typespecabs$make_orecordtype (r));
  76. typespec$nicefy (typ);
  77. return (typ);
  78. end gt_reccon;
  79. % Array constructors get typed by the first expression
  80. % in the list.
  81. gt_arrcon = proc (z: zen, x: arrcon) returns (typespec);
  82. return (typespec$make_array (gt_expr (z, exprlist$bottom (x.vals))));
  83. end gt_arrcon;
  84. % The type of an operation object (which is a procedure
  85. % object) is proctype, but we fudge it here since we only need
  86. % to know that much.
  87. gt_op = proc (z: zen, x: clustop) returns (typespec);
  88. tl: typelist := typelist$new();
  89. return (typespec$make_proc ({
  90. args, rtns: tl,
  91. sigs: errorlist$new ()}));
  92. end gt_op;
  93. % The type of an invocation can be known several ways.
  94. % It can be a call on an operation, a procedure, a procedure
  95. % variable, or a procedure object resulting from a record
  96. % fetch, an array fetch, or another invocation. So it should
  97. % be no surprise to find out that this procedure is little
  98. % more than a switch.
  99. gt_invoke = proc (z: zen, x: invoke) returns (typespec);
  100. e: exprabs := expr$d (x.p);
  101. tagcase e in
  102. idn: return (gt_idncall(z,e));
  103. op: return (gt_opcall(z,e));
  104. recref: return (gt_call(z,gt_sel(z,e)));
  105. arrayref: return (gt_call(z,gt_ref(z,e)));
  106. invoke: return (gt_dollar(z,gt_invoke(z,e)));
  107. end;
  108. oops(z,"Illegal procedure object given to gt_invoke");
  109. return (gt_empty());
  110. end gt_invoke;
  111. % If the type is known to be a procedure type, then we
  112. % get the return type quite easily.
  113. gt_call = proc (z: zen, t: typespec) returns (typespec);
  114. ty: typespecabs := typespec$dn (t);
  115. tagcase ty in
  116. proctype: return (typelist$bottom (ty.rtns));
  117. end;
  118. oops (z, "Type not a procedure type: gt_call");
  119. return (gt_empty());
  120. end;
  121. % To get the type of a record component, we must look for
  122. % the selector in the record type, then return the associated
  123. % type.
  124. gt_sel = proc (z: zen, x: recref) returns (typespec);
  125. return (gt_tag(z,gt_expr(z,x.r),x.sel));
  126. end gt_sel;
  127. % This routine is used to get a subtype from a
  128. % record or oneof type given a selector. Very useful.
  129. gt_tag = proc (z: zen, t: typespec, y: name) returns (typespec);
  130. rt = recordtype;
  131. x: typespecabs := typespec$dn (t);
  132. tagcase x in
  133. recordtype,oneoftype:
  134. for i:int := rt$low(x) to rt$high(x) do
  135. if y = x[i].sel then return (x[i].typ);
  136. end;
  137. oops (z, "Tag " || name$d(y) || " undefined");
  138. return (gt_empty());
  139. end gt_tag;
  140. % To get the type of an array element, just take a peek
  141. % inside the array type.
  142. gt_ref = proc (z: zen, x: binexp) returns (typespec);
  143. at: typespec := gt_expr (z, x.l);
  144. return (typespec$get_array (at));
  145. except not_array: end;
  146. oops (z, "Attempt to perform array fetch on non-array");
  147. return (typespec$make_bad ());
  148. end;
  149. % To get the type of an identifier, just ask the idn
  150. % cluster, unless it is 'marked', in which case look it up
  151. % in the current type array.
  152. gt_idn = proc (z: zen, id: idn) returns (typespec);
  153. idt: idntype := idn$get_type(id);
  154. if idn$is_marked(id) then return (zen$curtype (z, id));
  155. tagcase idt in
  156. undec: oops(z,"Type of externally declared identifier unknown: " ||
  157. idn$getstring(id) || "\n gt_idn");
  158. out: return (idt);
  159. end;
  160. return (gt_empty());
  161. end gt_idn;
  162. % When an identifier is invoked, it could be external, in
  163. % which case there is an external type object; or it could be
  164. % local, in which case we can get the type easily.
  165. gt_idncall = proc (z: zen, id: idn) returns (typespec);
  166. idt: idntype := idn$get_type(id);
  167. tagcase idt in
  168. undec: return (typespec$make_atype(
  169. {name: idn$fake(string$concat(
  170. idn$getstring(id),
  171. "$type")),
  172. args: exprlist$new() } ));
  173. var,parm,op: return (gt_call(z,idt));
  174. end;
  175. end gt_idncall;
  176. % When an operation returns a procedure object, we either
  177. % know the type, or it has been faked into an 'atype'. In the
  178. % case where we know the type, we just return the return type;
  179. % in the other case we fake one more level.
  180. gt_dollar = proc (z: zen, t: typespec) returns (typespec);
  181. x: typespecabs := typespec$dn (t);
  182. tagcase x in
  183. atype: return (typespec$make_atype(
  184. {name: idn$fake(string$concat(
  185. idn$getstring(x.name),
  186. "$type")),
  187. args: x.args } ) );
  188. end;
  189. return (gt_call(z,x));
  190. end gt_dollar;
  191. % The type resulting from an operation is known if the
  192. % operation belongs to a built-in type, or is one of the
  193. % generic functions (copy, equal, encode, decode). Otherwise
  194. % we fake it by making an 'atype' with a bogus id, which
  195. % contains the cluster name and the operation name.
  196. gt_opcall = proc (z: zen, x: clustop) returns (typespec);
  197. return (gt_stringcall(z,x.typ,name$d(x.op)));
  198. end gt_opcall;
  199. % This is essentially another entry to generate the type
  200. % of an operation call given the operation name as a string
  201. % and a typespec as the type specification.
  202. gt_stringcall = proc(z: zen, ty: typespec, s: string) returns (typespec);
  203. rt = recordtype;
  204. nty: typespecabs := typespec$dn (ty);
  205. % First, check for special operations...
  206. case s in
  207. "lt","le","ge","gt","equal","similar","similar1":
  208. return (typespec$make_bool ());
  209. "copy","decode","copy1":
  210. return (ty);
  211. "encode": begin;
  212. oops (z, "Encode operation returns nothing");
  213. return (typespec$make_null ());
  214. end;
  215. end;
  216. tagcase nty in
  217. stringtype: case s in
  218. "size", "indexs","indexc":
  219. return (typespec$make_int ());
  220. "rest", "substr", "concat", "ac2s","c2s","append":
  221. return (ty);
  222. "s2ac": return (typespec$make_array (
  223. typespec$make_char ()));
  224. "fetch":return (typespec$make_char ());
  225. end;
  226. chartype: case s in
  227. "i2c": return (ty);
  228. "c2i": return (typespec$make_int ());
  229. end;
  230. inttype: case s in
  231. "add","sub","mul","minus","div","power","mod":
  232. return (ty);
  233. end;
  234. booltype: case s in
  235. "and","or","not":
  236. return (ty);
  237. end;
  238. dutype: case s in % must be array
  239. "create", "fill", "new", "predict","fill_copy":
  240. return (ty);
  241. "size", "high", "low":
  242. return (typespec$make_int ());
  243. "fetch","bottom","top","remh","reml":
  244. return (gt_const (z, constlist$bottom (nty.args)));
  245. "set_low","trim","store","addh","addl":
  246. begin
  247. oops (z, s || " operation returns nothing");
  248. return (gt_empty());
  249. end;
  250. end;
  251. oneoftype: case string$cn(s, 0) in
  252. 'i': return (typespec$make_bool ());
  253. 'm': return (ty);
  254. 'v': return (gt_tag(z,ty,name$u(string$rest(s,6))));
  255. end;
  256. recordtype: case string$cn(s, 0) in
  257. 'g': return (nty[gk_recordop(z,nty,s)].typ);
  258. 'p': begin
  259. oops (z, s || " operations returns nothing");
  260. return (gt_empty ());
  261. end;
  262. end;
  263. atype: begin
  264. ns: string := idn$getstring(nty.name);
  265. return (typespec$make_atype (
  266. {name: idn$fake(ns || "$"
  267. || s || "$type"),
  268. args: nty.args} ) );
  269. end;
  270. end;
  271. oops(z,"Unrecognized operation '" || s || "' on type ");
  272. typespec$print(ty);
  273. return (gt_empty());
  274. end gt_stringcall;
  275. gt_empty = proc () returns (typespec);
  276. return (typespec$make_null ());
  277. end gt_empty;
  278. gt_const = proc (z: zen, c: const) returns (typespec);
  279. cc: constabs := const$d (c);
  280. tagcase cc in
  281. t: return (cc);
  282. p: return (typespec$make_parm (cc));
  283. out: ;
  284. end;
  285. oops (z, "Bad const to GT_CONST");
  286. return (typespec$make_bad ());
  287. end gt_const;