Here's the perl script (attached).  I tried to upload it to the Runtime_Differences page,
but it looks like I can only update .gif/.jpeg files.  Any advice about where to put it?

I think I got all the cases:

-   if the class name already has lz. , no change

-   if the class name is a class defined in the input, then add lz. (?)  [requires two passes]

-   if the class name is class for a LFC tagname, convert it to tagname and add lz.  (new LzView => lz.view)
        I coded my list from WEB-INF/lps/server/src/org/openlaszlo/compiler/ClassModel.java

-   if the class name is a known laszlo class, then add lz.
        I have a fixed list embedded in the script, generated via find WEB-INF/lps | xargs grep class

-   new global[*] is converted to new lz[*]

-   otherwise, no change (this includes Object, Array, ...).

Let me know if there are any changes, should be easy to modify.
Script includes a testcase to try all these situations.

- Don

#!/usr/bin/perl
# Copyright 2008 Laszlo Systems.  Use according to license terms.
#
# convert_instantiation.pl
# Helps to convert 4.1 lzs programs that use deprecated form
# of 'new'.  For example:
#
#    'new LzText' is converted to 'new lz.text'
# 
# See usage message.
#
# Warnings:
#
#   - PLEASE BACK UP your entire work directory before starting.
#
#   - Please compare the end result of each changed file with the
#     version before changing (filename.bak) and verify that the
#     changes make sense.
#
# Should work with Perl 5 or greater.
# tested on OSX 10.5.3 with perl v5.8.8
# Author: Don Anderson

# The only 'native' classes that you might say `new *` or `x instanceof *` about are:
#
# Object, Array, String, Number, or Boolean.
#
#So we should be able to add to the conversion script that if you see `new *` or `x instanceof *` and * does not start with lz. and is not one of the five native classes above, you should rewrite it to lz.*.
#
#We also need to cover the case `new global[*]` needs to become `new lz[*]`.
#
#Icing on the cake would be to replace instances of the LFC class names with their tagname, e.g., (LzView becomes lz.view).
#

# This list is derived from
#   WEB-INF/lps/server/src/org/openlaszlo/compiler/ClassModel.java
#
%lzxname = (
    LzNode => "node",
    LzView => "view",
    LzText => "text",
    LzInputText => "inputtext",
    LzCanvas => "canvas",
    LzScript => "script",
    LzAnimatorGroup => "animatorgroup",
    LzAnimator => "animator",
    LzLayout => "layout",
    LzState => "state",
    LzCommand => "command",
    LzSelectionManager => "selectionmanager",
    LzDataSelectionManager => "dataselectionmanager",
    LzDatapointer => "datapointer",
    LzDataProvider => "dataprovider",
    LzDatapath => "datapath",
    LzDataset => "dataset",
    LzDatasource => "datasource",
    LzHTTPDataProvider => "lzhttpdataprovider",
    LzLibrary => "import",
);

# This list of known classes in Laszlo
# TODO: we might want a better way to maintain this list.
# This list was generated via:
#  $ cd WEB-INF/lps
#  $ find . -type f -print | grep 'lzs$' | \
#      xargs grep '^[        ]*class[        ]' | \
#      sed -e 's/[        ][      ]*/ /' \
#          -e 's/.*:[       ]*class[        ]//' \
#          -e 's/ .*//' | sort  > /tmp/classes

%lzsclassname = (
    AnonDatasetGenerator => "",
    ColorUtilsClass => "",
    LzAlwaysExpr => "",
    LzAudioKernel => "",
    LzAudioService => "",
    LzBrowserKernel => "",
    LzBrowserKernel => "",
    LzBrowserKernel => "",
    LzBrowserService => "",
    LzCSSStyleClass => "",
    LzCSSStyleDeclaration => "",
    LzCSSStyleRule => "",
    LzCSSStyleSheet => "",
    LzCommand => "",
    LzConstraintExpr => "",
    LzContextMenu => "",
    LzContextMenuItem => "",
    LzContextMenuItemKernel => "",
    LzContextMenuItemKernel => "",
    LzContextMenuItemKernel => "",
    LzContextMenuKernel => "",
    LzContextMenuKernel => "",
    LzContextMenuKernel => "",
    LzDataAttrBind => "",
    LzDataElement => "",
    LzDataNode => "",
    LzDataProvider => "",
    LzDataRequest => "",
    LzDataSelectionManager => "",
    LzDataText => "",
    LzDatapointer => "",
    LzDictionary => "",
    LzEventable => "",
    LzFont => "",
    LzFontManagerClass => "",
    LzHTTPDataProvider => "",
    LzHTTPDataRequest => "",
    LzIdleService => "",
    LzInitExpr => "",
    LzLibrary => "",
    LzLibraryCleanup => "",
    LzLibraryLoader => "",
    LzLoader => "",
    LzMediaLoader => "",
    LzMessage => "",
    LzOnceExpr => "",
    LzParam => "",
    LzParsedPath => "",
    LzRefNode => "",
    LzSelectionManager => "",
    LzStyleAttr => "",
    LzStyleAttrBinder => "",
    LzStyleExpr => "",
    LzStyleIdent => "",
    LzStyleSheet => "",
    LzTimerService => "",
    LzTrackService => "",
    LzUtilsClass => "",
    LzValueExpr => "",
    LzViewLinkage => "",
    __LzHttpDatasetPoolClass => "",
    __LzLeak => "",
    __LzLeaks => "",
);

use File::Basename;
use File::Copy;
use Getopt::Std;

################
my $VERSION = "1.0.0";
my $PROG = basename($0);
my $USAGE = <<END;
Usage: perl convert_instantiation.pl [ options ] filename...

Options:

   -d debuglevel
           get debugging info for development

   -t
           create output for simple tests in /tmp/convtest

   -v
           show version number and exit

For each file, a backup file is made (filename.bak) and the file will
be converted, with the result put into filename.


Examples:

  # Convert all the lzx files in the directory, doing all conversions.
  \$ perl convert_instantiation.pl *.lzs

END
################

##
# Other global variables
##
$DEBUGLEVEL=0;         # set to non-zero to get successive amounts of debug out
$curfile = "unknown file";  # track current file for error messages

##
# debug(level, string);
# debugln(level, string);
# Show the string if the level is less or equal to
# the current debug level. debug(1, '...') is more likely
# to appear, and debug(9, '...') least likely.
##
sub debug {
    my $level = $_[0];
    my $str = $_[1];
    if ($level <= $DEBUGLEVEL) {
        print STDOUT $str;
    }
}
sub debugln {
    debug($_[0], $_[1] . "\n");
}

##
# debugentry(level, funcname, @_);
# Show the function entry with args if level is <= current debug level.
##
sub debugentry {
    my $n = $#_;
    my $argstr = "";
    my $i = 2;
    while ($i <= $n) {
        if ($i != 2) {
            $argstr .= ", ";
        }
        $argstr .= $_[$i];
        $i++;
    } 
    debugln($_[0], $_[1] . "(" . $argstr . ")");
}

##
# warning(string)
# Show a warning to user.
##
sub warning {
    print STDERR "$curfile: Warning: " . $_[0] . "\n";
}

##
# create_test(filename);
# Put a test file into place.
##
sub create_test {
    my $file = $_[0];

    unlink($file);
    open OUT, ">$file" || die("Cannot create $file");

    # basic tests, also with '' delimiter
    print OUT
        "// file to convert\n" .
        "new something\n" .
        "new LzView  // want lz.view\n" .
        "   y = new node\n" .
        " class myclass extends foo { }\n" .
        "do_not_convert = newsome\n\n" .
        "y = n instanceof z\n" .
        "already_converted = instanceof lz.xyz\n" .
        "y = n instanceof Boolean\n" .
        "y = n instanceof LzView // want lz.view\n" .
        "y = n instanceof view" .
        "y = n instanceof myclass // want lz.myclass\n" .
        "y = new myotherclass  // want lz.myotherclass\n" .
        "y = new global[*]  // want lz[*]\n" .
        "y = new somethingelse[*]\n" .
        "y = n instanceof LzParam  // want lz.LzParam\n" .
        "y = n instanceof LzView  // want lz.view\n" .
        "y = new LzView(new Integer(new LzNode(), new LzView))   // 3 subs\n" .
        "class myotherclass { }\n";

    close OUT;
    print STDOUT "Testing $file\n";
}

##
# file_cannot_exist(filename)
# Complain and die if the file exists.
##
sub file_cannot_exist {
    my $file = $_[0];
    if ( -f "$file" ) {
        print STDERR "$PROG: $file already exists, please rename/remove it and run again\n";
        exit(1);
    }
}

##
# add_lz_prefix(classnm)
# 
##
sub add_lz_prefix() {
    my $nm = $_[0];
    if (exists $lzxname{$nm}) {
        return 'lz.' . $lzxname{$nm};
    }
    if (exists $lzsclassname{$nm}) {
        return 'lz.' . $nm;
    }
    return $nm;                 # false
}

##
# track_class(nm)
# Do all conversions for the file.
##
sub track_class {
    my $line = $_[0];

    if ($line =~ /\s*class\s+(\w+)\b/) {
        # register that we know about this class
        $lzsclassname{$1} = "";
        debugln(1, "CLASS match: $1");
    }
}

##
# emit_content(HANDLE, string)
# Emits the content to the handle, applying some basic text transforms.
##
sub emit_content {
    my $save = $_;
    my $FH = $_[0];
    $_ = $_[1];

    while (/(.*)\b(new|instanceof)(\s+)(lz[.])?([_a-zA-Z0-9]+)\b(.*)/) {
        debugln(3, "Line: $_");
        debugln(3, "MATCH: $1, $2, $3, $4, $5, $6");
        my($first, $keyword, $space, $optlz, $classnm, $last) = ($1, $2, $3, $4, $5, $6);
        my $sub = "$optlz$classnm";
        # Special case - handle 'new global[*]' => 'new lz[*]'
        if ($keyword eq 'new' && $optlz eq '' && $classnm eq 'global') {
            debugln(4, "match new global: $last");
            if ($last =~ /^\s*\[\*\]/) {
                $sub = "lz";
            }
        }
        elsif ($optlz eq '') {
            $sub = &add_lz_prefix($classnm);
        }

        # We insert @ around the keyword so we won't match it again.
        # This allows us to successively match nested
        # (e.g. 'new class1(new class2())') or sequential
        # (e.g. 'new class1(), new class2()') items.
        # We remove the @ after we've applied substitutions to the whole line.
        $_ = "[EMAIL PROTECTED]@$space$sub$last";
        debugln(3, "Modified: $_");
    }
    s/[EMAIL PROTECTED]@/new/g;
    s/[EMAIL PROTECTED]@/instanceof/g;

    # After matching, the newline may be lost.
    # Add it again here so everything comes out even.
    if ($_ !~ "\n") {
        $_ .= "\n";
    }

    debugln(3, "   EMIT CONTENT: " . $_);
    print $FH $_ ;
    $_ = $save;
    return $inmethod;
}

##
# convert_file(filename)
# Do all conversions for the file.
##
sub convert_file {
    my $file = $_[0];
    my $inmethod=0;
    my $event;
    my $name;

    debugentry(1, "convert_file", @_);
    $curfile = $file;
    copy("$file", "$file.bak") || die("Cannot copy to $file.bak");

    # Two pass algorithm.
    # First take note of all 'class' declarations
    open(IN, "<$file") || die("Cannot open $file");
    while (<IN>) {
        track_class($_);
    }
    close(IN);

    # Second, convert the files
    open(IN, "<$file") || die("Cannot open $file");
    unlink("$file.tmp");
    open(OUT, ">$file.tmp") || die("Cannot create $file.tmp");
    while (<IN>) {
        emit_content(OUT, $_);
    }
    close(OUT);
    close(IN);
    move("$file.tmp", "$file") || die("Cannot create $file");
    print STDOUT "Converted $file\n";
}

##
# Main program
# parse arguments and dispatch work to convert_file.
##
my $file;
my %options;
$ok = getopts("d:tx:v", \%options);
if (!$ok) {
    print STDERR "$USAGE";
    exit(1);
}

$DEBUGLEVEL = $options{d} || '0';

if ($options{v}) {
    print STDOUT "$PROG: version $VERSION\n";
    exit(0);
}

if ($options{t}) {
    create_test("/tmp/convtest");
    convert_file("/tmp/convtest");
    exit(0);
}

if ($#ARGV < 0) {
    print STDERR "$USAGE";
    exit(1);
}

foreach $file (@ARGV) {
    if (! -f $file) {
    }
    file_cannot_exist("$file.bak");
}

foreach $file (@ARGV) {
    if (! -f $file ) {
        print STDERR "$PROG: $file does not exist, skipping\n";
    }
    else {
        convert_file($file);
    }
}

On Jun 30, 2008, at 3:01 PM, P T Withington wrote:

One flaw in thus idea:  many times the argument to new will be a parameter of the class, so you have to skip all the class attributes too. That may make searching for only the defined class names a better choice of algorithm.

On Jun 30, 2008, at 13:59, P T Withington <[EMAIL PROTECTED]> wrote:

The only 'native' classes that you might say `new *` or `x instanceof *` about are:

Object, Array, String, Number, or Boolean.

So we should be able to add to the conversion script that if you see `new *` or `x instanceof *` and * does not start with lz. and is not one of the five native classes above, you should rewrite it to lz.*.

We also need to cover the case `new global[*]` needs to become `new lz[*]`.

Icing on the cake would be to replace instances of the LFC class names with their tagname, e.g., (LzView becomes lz.view).



--

Don Anderson
Java/C/C++, Berkeley DB, systems consultant

voice: 617-547-7881
email: [EMAIL PROTECTED]
www: http://www.ddanderson.com



Reply via email to