gt.clu 10 KB

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