[comp.lang.clu] Compiler error message about missing tags

jokinen@tucos.UUCP (Matti Jokinen) (05/17/88)

Description:  If one or more tags are missing in a tagcase statement and
there is no others-arm, the compiler reports the error but does not list
the missing tags.  It is often rather tedious to find out which tags are
missing.

Repeat-by:  Run the following shell script:

cat > main.clu << 'EOF'
start_up = proc()
  t = oneof[a,b: null]
  x: t := t$make_a(nil)
  tagcase x
    tag a:
  end
end start_up
EOF
clu main

Fix:  The error message comes from the procedure c_tagcase in the
file ~CLU/cmp/cstmt2.clu.  Replace it with the following code:

c_tagcase = proc (e: c_env, ts: tagstmt)
    at: typespec := c_expr(e, ts.obj)
    specs: fieldspeclist := c_oneof_specs(e, at)
       except when abstract: c_tag_sugar(e, at, ts)
			     return
	      end
    used: flaglist := c_tagarms(e, ts.arms, specs)
    tagcase ts.others_
       tag body (mb: body):
	   all_used: bool
	   for all_used in flaglist$elements(used) do
	       if ~all_used then break end
	       end
	   if all_used cand  ~fieldspeclist$empty(specs)
	      then c_env$err1(e, "others arm not allowed - all selectors present")
	      end
	   c_body(e, mb)
       tag none:
	   miss: as := as$new()
	   for i: int in fieldspeclist$indexes(specs) do
	       if ~ used[i]
		  then as$addh(miss, specs[i].sel) end
       end
	   count: int := as$size(miss)
	   if count > 0
	      then message: as := as$["others arm required - ",
				      int$unparse(count),
				      " ",
				      "selectors",
				      " missing: "]
		   if count = 1
		      then message[4] := "selector" end
		   for i: int in as$indexes(miss) do
		       if i > 1
			  then as$addh(message, ", ") end
		       as$addh(message,miss[i]) end
		   c_env$err(e, qs$a2s(message))
	      end
       end
    end c_tagcase

If you want long lists to be folded on more than one line, replace the
procedure cenv$output in ~CLU/cmp/cenv.clu with the following routine pair:

output = proc (e: rep, msg: qs)
	st: stream := e.errst
	l: int := e.line
	begin
	if l > 0
	   then	stream$puts(st, int$unparse(e.line))
		stream$putc(st, ':')
	   end
	for s: str in lines(msg) do
		stream$putc(st, '\t')
		stream$putl(st, s)
		end
	end except others: end
	end output

lines = iter(msg: qs) yields(str)
	maxlength = 72
	s: str := ""
	for t: str in qs$elements(msg) do
	    s := s || t
	    while str$size(s) > maxlength do
		i: int := maxlength
		while true do
		    if s[i+1] = ' '
			then yield(str$substr(s,1,i))
			      s := str$rest(s,i+2)
			      break
		      elseif s[i] = ','
			then yield(str$substr(s,1,i))
			     s := str$rest(s,i+1)
			     break
		      else i := i - 1 end
		    end except when bounds:
			    yield(string$substr(s,1,maxlength))
			    s := string$rest(s,maxlength+1)
			    end
		end
	    end
	yield(s)
	end lines