<?php

// $Date: 2004/01/13 03:30:01 $
// $Revision: 1.9 $
// $Author: jcrocholl $

// $head is supposed to be an array consisting of
// - the following properties:
//   - with: '' or 'with' for generic methods
//   - type: 'function' or 'procedure' or
//           '' for just a block of variables
//   - name: name of the function or procedure
//   - return: return type of the function
// - and the following arrays:
//   - names, modes, types, bounds, initials, comments
//   - one entry for each parameter
//   - and possibly a function return value
//   - if comments has one extra, that's for above the head

// add another row of parameters to the head
function add_variable(&$head, $name, $mode, $type, $bound, $initial, $comment) {
    
$head['names'][] = $name;
    
$head['modes'][] = $mode;
    
$head['types'][] = $type;
    
$head['bounds'][] = $bound;
    
$head['initials'][] = $initial;
    
$head['comments'][] = $comment;
}

// signature of a function or procedure
function signature($head) {
    
$count = count($head['names']);
    for (
$i = 0; $i < $count; $i++) {
        if (
$result) $result .= '; ';
        
$result .= $head['names'][$i] . ' : ';
        if (
$head['modes'][$i]) $result .= $head['modes'][$i] . ' ';
        
$result .= $head['types'][$i];
        
$result .= $head['bounds'][$i] . ' ';
        if (
$head['initials'][$i])
            
$result .= ':= ' . $head['initials'][$i];
    }
    if (
$head['type'] == 'procedure') {
        return
"procedure $head[name]($result)";
    } elseif (
$head['type'] == 'function') {
        return
"function $head[name]($result) return $head[return]";
    } else {
        print
"error: signature($head[type])\n";
        if (
$result) $result .= ';';
        return
$result;
    }
}

function
format_name($name) {
    
$parts = explode(',', $name);
    
$result = trim(array_shift($parts));
    while (
$parts) $result .= ', ' . trim(array_shift($parts));
    return
$result;
}

function
format_type($type) {
    return
type($type);
}

function
format_mode($mode, $type = '') {
    if (
$mode == 'in') return keyword('in ');
    if (
$mode == 'out') return keyword('out ');
    if (
$mode == 'inout') return keyword('in ') . keyword('out ');
    if (
$mode == 'return') return keyword('return ');
    if (
$mode == 'constant') return keyword('constant ');
    if (
$mode == 'access') return keyword('access ');
    if (
$mode == '') {
        if (
$type == 'function' or $type == 'procedure')
            return
keyword('in ');
        else return
'';
    }
    exit(
"unknown mode: $mode\n");
}

function
format_bound($bound) {
    if (
$bound == '') return '';
    return
'(' . bounds($bound) . ')';
}

function
format_initial($initial) {
    if (
$initial == '') return '';
    return
' := ' . term($initial);
}

function
format_comment($comment) {
    if (!
$comment) return '';
    return
comment("-- $comment");
}

// Pretty print a head. Second parameter tail can be
// '' or ';' or 'is' if we have a function or procedure.
function format_head(&$head, $tail = '') {
    
$type = $head['type'];
    
$count = count($head['names']);
    
$result = ''; // 'start' . newline();

    // extra comment is for above the head
    
if (count($head['comments']) > $count)
        
$result .= $head['comments'][$count];

    
// format all parameter entries
    
if ($tail == 'is') $tail = keyword(' is');
    for (
$i = 0; $i < $count; $i++) {
        
$head['names'][$i] = format_name($head['names'][$i]);
        
$head['modes'][$i] = format_mode($head['modes'][$i], $type);
        
$head['types'][$i] = format_type($head['types'][$i]);
        
$head['bounds'][$i] = format_bound($head['bounds'][$i]);
        
$head['initials'][$i] = format_initial($head['initials'][$i]);
        
$head['comments'][$i] = format_comment($head['comments'][$i]);
    }
    
    if (
$type) {
        global
$indent_level;
        
$indent_level--;
        
$result .= indent();
        
$indent_level++;
    }

    if (
$type == 'procedure') {
        if (
$head['with']) $result .= keyword('with ');
        
$result .= keyword('procedure ') . name($head['name']);
        if (
$type == 'procedure' and $tail and !$count) $result .= $tail;
        
$result .= newline();
    } elseif (
$type == 'function') {
        if (
$head['with']) $result .= keyword('with ');
        
$result .= keyword('function ') . name($head['name']) . newline();
        
// tail comes after the function return value
        
$return_tail = $tail; $tail = '';
        
// don't use function return value as parameter
        
$count--;
    } elseif (
$head['with']) {
        exit(
"error: 'with' can only appear with a function or procedure\n");
    }

    
// calculate maximum width of parameter names and specs
    
for ($i = 0; $i < $count; $i++) {
        
$l  = length($head['names'][$i]);
        
$max_names = max($max_names, $l);
        
$l  = 3 + length($head['modes'][$i]); // ' : in '
        
$l += length($head['types'][$i]);     // 'Integer_Array'
        
$l += length($head['bounds'][$i]);    // '(1 .. Size)'
        
$l += length($head['initials'][$i]);  // ' := Integers(3)'
        
$l += 1; // semicolon or final closing bracket
        
if ($i == $count - 1) $l += length($tail);
        if (
$head['comments'][$i]) $max_specs = max($max_specs, $l);
    }

    
// calculate maximum width of function return value
    
if ($type == 'function') {
        
$l  = 6;                                  // 'return'
        
$l += 1 + length($head['types'][$count]); // ' Integer_Array'
        
$l += length($head['bounds'][$count]);    // '(1 .. Size)'
        
$l += length($return_tail);               // ' is'
        
$l -= $max_names; // overlaps
        
$l -= 1; // return is shifted left by one
        
if ($head['comments'][$count])
            
$max_specs = max($max_specs, $l);
    }

    
// collect the parameters
    
for ($i = 0; $i < $count; $i++) {
        if (
$i == 0 and ($type == 'function' or $type == 'procedure'))
            
$result .= indent(-1) . '(';
        else
$result .= indent();
        
$result .= fill($head['names'][$i], $max_names);

        
$spec  = ' : ';
        
$spec .= $head['modes'][$i];
        
$spec .= $head['types'][$i];
        
$spec .= $head['bounds'][$i];
        
$spec .= $head['initials'][$i];
        if (
$i == $count - 1) {
            if (
$type == 'function' or
                
$type == 'procedure') $spec .= ')' . $tail;
            else
$spec .= ';';
        } else
$spec .= ';';

        if (
$head['comments'][$i]) {
            
$result .= fill($spec, $max_specs + 1);
            
$result .= $head['comments'][$i];
        } else
$result .= $spec;
        
$result .= newline();
    }

    
// collect the function return value
    
if ($type == 'function') {
        
$spec  = keyword('return ');
        
$spec .= $head['types'][$count];
        
$spec .= $head['bounds'][$count];
        
$spec .= $return_tail;
        
        
$result .= indent(-1);
        if (
$head['comments'][$count]) {
            
$result .= fill($spec, $max_names + $max_specs + 2);
            
$result .= $head['comments'][$count];
        } else
$result .= $spec;
        
$result .= newline();
    }

    
$head = array();
    
// And that's all folks!
    
return $result; // . 'end' . newline();
}

?>