<?php

// $Date: 2004/03/01 01:44:25 $
// $Revision: 1.16 $
// $Author: jcrocholl $

$adofilename $argv[1];
$dont_clear_head true;

if (
$adofilename and !$argv[2]) $input file($adofilename);
else die(
"usage: $0 <input.ado>\n");

if (
preg_match('/^(.*?)([^\/]+)\.ado$/'$adofilename$m)) {
    
$filepath $m[1];
    
$filestem $m[2];
} else die(
"error: accept only .ado files");

// if ($adofilehandle = fopen($adofilename, 'r')) {
//     fclose($adofilehandle);
// } else die("Cannot open file $outfilename\n");

$indent_level 2;
require(
'plain.php');
require(
'formats.php');
require(
'heads.php');

function 
nametolower($input) {
    
$output strtolower($input);
    
$output preg_replace('/_/'' '$output);;
    return 
$output;
}

function 
accessors($object$package$name$type$initial$access) {
    global 
$create_head$create_body$create_args;
    global 
$ads_methods$adb_methods;

    if (
preg_match('/^(.+_(List|Hash_Table))_Access$/'$type$m)) {
        if (
$create_body$create_body .= "\n";
        
$create_body .= "      Result.$name := $m[1]s.Create;";
    }

    foreach (
preg_split('/\s+/'$access) as $a) {
        if (
$a == 'Create') {
            
add_variable($create_head$name'in'$type''$initial
                         
"The initial " nametolower($name) . ".");

            if (
$create_body$create_body .= "\n";
            if (
$type == 'String')
                
$create_body .= "      To_String_Access($name, Result.$name);";
            else 
$create_body .= "      Result.$name := $name;";

            if (
$create_args$create_args .= ', ';
            
$create_args .= $name;
            
// print "create args: $create_args\n";
        
} elseif ($a == 'Get') {
            
$head = array();
            
$head['type'] = 'function';
            
$head['name'] = "Get_$name";
            
add_variable($head'This''access'$object''''
                         
"The " nametolower($object) . " to read from.");
            
add_variable($head'''return'$type'''',
                         
"The " nametolower($name) . " of that " nametolower($object) . ".");
            
$head['comments'][] = "   -- Accessor to read the " nametolower($name) . 
                
" of a " nametolower($object).".\n";
            
            if (
$ads_methods$ads_methods .= "\n";
            if (
$adb_methods$adb_methods .= "\n";
            
$ads_methods .= format_head($head';');
            
$adb_methods .= format_head($head'is');
            
$adb_methods .= "   begin\n";
            if (
$type == 'String')
                
$adb_methods .= "      return To_String(This.$name);\n";
            else 
$adb_methods .= "      return This.$name;\n";
            
$adb_methods .= "   end Get_$name;\n";
        } elseif (
$a == 'Set') {
            
$head = array();
            
$head['type'] = 'procedure';
            
$head['name'] = "Set_$name";
            
add_variable($head'This''access'$object''''
                         
"The " nametolower($object) . " to be updated.");
            
add_variable($head$name'in'$type''$initial,
                         
"The new " nametolower($name) . " of that " nametolower($object) . ".");
            
$head['comments'][] = "   -- Mutator to update the " nametolower($name) . 
                
" of a " nametolower($object).".\n";

            if (
$ads_methods$ads_methods .= "\n";
            if (
$adb_methods$adb_methods .= "\n" ;
            
$ads_methods .= format_head($head';');
            
$adb_methods .= format_head($head'is');
            
$adb_methods .= "   begin\n";
            if (
$type == 'String')
                
$adb_methods .= "      To_String_Access($name, This.$name);\n";
            else 
$adb_methods .= "      This.$name := $name;\n";
            
$adb_methods .= "   end Set_$name;\n";
        }
    }
}

function 
add_this(&$head$object) {
    
add_variable($head'This''access'$object''''
                 
'The ' nametolower($object) . ' object instance.');
}

function 
method($type$name$abstract$is) {
    global 
$object$input;
    global 
$ads_methods$adb_methods;
    
$head['type'] = $type;
    
$head['name'] = $name;
    
$first_variable true;
    
$begin false;
    while (
$input) {
        
$line trim(array_shift($input));
        if (
$is) break;
        if (
preg_match('/^\(*(.+?)\s*:\s*(in|access)*\s*(out)*\s*(\S+?)' 
                       
'(|\s*:=\s*(\S.+?))' 
                       
'(\s*\)\s*is|\s*\)\s*;|\s*;|\s*\)|)' 
                       
'\s*(|--\s+(.+))$/x'$line$m)) {
            if (!
$m[9]) die("error: method $name parameter $m[1] has no comment\n");
            if (
$first_variable and $m[1] != 'This'add_this($head$object);
            
$first_variable false;
            
add_variable($head$m[1], "$m[2]$m[3]"$m[4], ''$m[6], $m[9]);
        } else {
            break; 
// outta here!
        
}
    }

    if (
$first_variableadd_this($head$object);
    
    if (
$type == 'function') {
        
// die("$line\n");
        
if (preg_match('/^return\s*(\S+?)(|\s*;|\s+is)\s*(|--\s+(.+))$/x'$line$m)) {
            if (!
$m[3]) die("error: return type of function $name has no comment\n");
            
add_variable($head'''return'$m[1], ''''$m[4]);
            
$line trim(array_shift($input));
        } else {
            print 
"found: $line\n";
            die(
"error: function $name has no return type\n");
        }
    }

    if (
$line == 'begin') {
        
$is true;
        
$begin true;
    } elseif (
$line == 'is') {
        
$is true;
        
$line trim(array_shift($input));
    }

    if (
$is and !$begin) {
        while (
$input) {
            if (
preg_match('/^--/'$line)) break; // outta here!
            
if ($line == 'begin') break; // outta here!
            
if ($line$line "      $line";
            
$declarations .= "$line\n";
            
$line trim(array_shift($input));
        }
    }

    while (
preg_match('/^--\s/'$line)) {
        
$comment .= "   $line\n";
        
$line trim(array_shift($input));
    }
    
$head['comments'][] = $comment;

    if (
$is) {
        if (
$line != 'begin') die("error in $name: expected 'begin', found '$line'\n");
        
$begin true;
        
$line array_shift($input);
    }

    while (
true) {
        if (!
trim($line) and !$begin) break;
        if (
trim($line) == 'end;') break;
        
$line '   ' $line;
        if (!
$begin$line '   ' $line;
        
$line rtrim($line);
        
$body .= "$line\n";
        if (!
$input) break;
        
$line array_shift($input);
    }

    if (
$abstract) {
        if (
$ads_methods$ads_methods .= "\n";
        
$ads_methods .= format_head($head'');
        
$ads_methods .= "     is abstract;\n";
    } else {
        if (
$ads_methods$ads_methods .= "\n";
        
$ads_methods .= format_head($head';');

        if (
$adb_methods$adb_methods .= "\n" ;
        if (
$declarations) {
            
$adb_methods .= format_head($head'');
            
$adb_methods .= "   is\n";
            
$adb_methods .= $declarations;
        } else {
            
$adb_methods .= format_head($head'is');
        }
        
$adb_methods .= "   begin\n";
        
$adb_methods .= $body;
        
$adb_methods .= "   end $name;\n";
    }
}

function 
read_attributes(&$input$object) {
    global 
$strings;
    global 
$attr_head;

    while (
$input) {
        
$line trim(array_shift($input));
        if (
preg_match('/^\s*$/'$line)) break;
        if (
preg_match('/^\s*end\s+record\s*;\s*$/'$line)) break;
        
        
preg_match('/^(\S+)\s*\:\s*([^\s\:;]+?)(|\s*:=\s*(\S.*?))\s*;' 
                   
'\s*(|[^\s-][^-]*[^\s-])\s*(|--\s+(.+))$/'$line$m);
        
$name $m[1]; $type $m[2]; $initial $m[4];
        
$access $m[5]; $comment $m[7];
        
// print "$name, $type, $initial, $access, $comment\n";
        
accessors($object$package$name$type$initial$access);
        
        if (
$type == 'String') {
            
$type 'String_Access';
            
$strings 1;
        }
        
add_variable($attr_head$name''$type''$initial$comment);
    }
}

function 
package_name($object) {
    
$package $object;
    if (
preg_match('/^(.+)_Data$/'$package$m2)) $package $m2[1];
    if (
preg_match('/^(.+)_Collector$/'$package$m2)) return $m2[1];
    if (
preg_match('/^(.+)_Printer$/'$package$m2)) return $m2[1];
    if (
preg_match('/^(.+)_Box$/'$package$m2)) $package $m2[1];
    if (
preg_match('/tch$/'$package)) $package .= 'e';
    if (
preg_match('/x$/'$package)) $package .= 'e';
    if (
$package != 'Music' 
        
and $package != 'Simple' 
        
and !preg_match('/s$/'$package)) 
        
$package .= 's';
    return 
$package;
}

function 
read_parent_attr($object$extends) {
    global 
$filepath;
    global 
$attr_head;
    global 
$create_args$create_head$create_body;
    global 
$ads_methods$adb_methods;
    
$package package_name($extends);
    
$filestem strtolower($package);
    
$filename "$filepath$filestem.ado";
    if (!
file_exists($filename)) 
        die(
"parent file $filename not found\n");
    
$input file($filename);
    while (
$input) {
        
$line trim(array_shift($input));
        if (
preg_match('/^(attributes)\s*$/'$line$m) or 
            
preg_match("/type\s+$extends\s+is(|\s+.+)\s+record\s*\$/"$line$m)) {
            
read_attributes($input$object); 
            if (
$create_args$create_args "($create_args)";
            
$object_access $object '_Access';
            
// $create_body = "      Result := $object($package.Create$create_args.All)'Access;";
            // die("create head " . $create_head['types'][0] . "\n");
            
$attr_head = array();
            
$ads_methods '';
            
$adb_methods '';
            break;
        }
    }
}

$state '';
while (
$input) {
    
$line rtrim(array_shift($input));
    
    
// Convert legacy object declarations to new style.
    
$line2 '';
    if (
preg_match('/^\s*(|abstract\s+)(|tagged\s+)object\s+(\S+)' 
                   
'(|\s+extends\s+(\S+))\s*$/'$line$m)) {
        if (
$m[1]) $line2 .= 'abstract ';
        
$line2 .= "type $m[3]";
        
$line2 .= ' is';
        if (
$m[5]) $line2 .= " new $m[5] with";
        if (
$m[2]) $line2 .= ' tagged';
        
$line2 .= ' record';
        
// print("old: $line\n");
        // print("new: $line2\n");
        // die("converted\n");
        
$line $line2;
    }

    if (
preg_match('/^\s*(|abstract\s+)type\s+(\S+)\s+is\s+' 
                   
'(|new\s+(\S+)\s+with\s+)(|tagged\s+)(|null\s+)record\s*;*$/'$line$m)) {

        
$abstract $m[1];
        if (
$abstract$abstract ' abstract';
        
        
$tagged $m[5];
        if (
$tagged$tagged ' tagged';

        
$null $m[6];

        
$object $m[2];
        
// $create_body = "      Result := new $object;";

        
$extends $m[4];
        if (
$extendsread_parent_attr($object$extends);

        
$object_access $object '_Access';
        
$object_lower nametolower($object);
        
$object_hyphen str_replace(' ''-'$object_lower);
        
// print "$object_lower\n";

        
$package package_name($object);
        if (
$extends$package package_name($extends) . '.' $package;

        
// read attributes, unless legacy style
        
if (!$line2 and !$nullread_attributes($input$object); 
    }

    if (
preg_match('/^(|body-)with\s+(\S.+\S)\s*$/'$line$m)) {
        foreach (
preg_split('/\s+/'$m[2]) as $pkg) {
            if (
preg_match('/\+(.+)/'$pkg$m2)) 
                
$pkg "$m2[1]; use $m2[1]";
            if (!
$m[1]) $with .= "with $pkg;\n";
            else 
$body_with .= "with $pkg;\n";
        }
    }

    if (
preg_match('/^(|abstract\s+)(procedure|function)\s+' 
                   
'([^\s;]+)(\s+(is)|\s*;|)\s*$/'$line$m)) {
        
method($m[2], $m[3], $m[1], $m[5]);
    }

    if (
trim($line) == 'end;'$state '';
    elseif (
trim($line) == 'attributes'read_attributes($input$object); 
    elseif (
trim($line) == 'pre-public'$state trim($line);
    elseif (
trim($line) == 'post-public'$state trim($line);
    elseif (
trim($line) == 'pre-private'$state trim($line);
    else {
        if (
preg_match('/^(--.+\S)/'$line$m)) $head_comment .= "$m[1]\n";
        else {
            if (
preg_match('/\S/'$line)) $line '   ' $line;
            if (
$state == 'pre-public') { $pre_public .= "$line\n"; }
            elseif (
$state == 'post-public') { $post_public .= "$line\n"; }
            elseif (
$state == 'pre-private') { $pre_private .= "$line\n"; }
        }
    }

}

$object_access $object '_Access';

if (
$pre_public$pre_public .= "\n";
if (
$post_public$post_public .= "\n";
if (
$pre_private$pre_private .= "\n";
if (
$body_with$body_with .= "\n";
if (
$create_body$create_body .= "\n";
if (
$with$with .= "\n";
if (
$strings) {
    
$with .= "with Strings; use Strings;\n\n";
}

add_variable($create_head'''return'$object_access''''
             
"The newly created " nametolower($object) . ".");
$create_head['comments'][] = "   -- Constructor for instances.\n";
$create_head['type'] = 'function';
$create_head['name'] = 'Create';
// add_variable($create_var, 'Result', '', $object_access, '', '', '');
// if ($extends) {
//     add_variable($create_var, 'Result', '', $object_access, '', 
//                  "$extends.Create($parent_create_args)", '');
// } else {
add_variable($create_var'Result'''$object_access''"new $object"'');
// }


if (!$abstract) {
    if (
$ads_methods$ads_methods "\n" $ads_methods;
    
$ads_methods format_head($create_head';') . $ads_methods;

    if (
$adb_methods$adb_methods "\n" $adb_methods;
    
$adb_methods 
        
format_head($create_head'') . 
        
"   is\n" .
        
format_head($create_var'') . 
        
"   begin
$create_body      return Result;
   end Create;
$adb_methods;
}

if (
$extends$indent_level++;
$attributes format_head($attr_head'');

$auto_header '
-- This file was automatically created with ado.php.
-- Manual changes will be lost when it is updated.
"\n";

?>