about summary refs log tree commit diff
path: root/docs/doctool/Modules/NaturalDocs/Languages/ActionScript.pm
diff options
context:
space:
mode:
Diffstat (limited to 'docs/doctool/Modules/NaturalDocs/Languages/ActionScript.pm')
-rw-r--r--docs/doctool/Modules/NaturalDocs/Languages/ActionScript.pm885
1 files changed, 885 insertions, 0 deletions
diff --git a/docs/doctool/Modules/NaturalDocs/Languages/ActionScript.pm b/docs/doctool/Modules/NaturalDocs/Languages/ActionScript.pm
new file mode 100644
index 00000000..33f3b73d
--- /dev/null
+++ b/docs/doctool/Modules/NaturalDocs/Languages/ActionScript.pm
@@ -0,0 +1,885 @@
+###############################################################################
+#
+#   Class: NaturalDocs::Languages::ActionScript
+#
+###############################################################################
+#
+#   A subclass to handle the language variations of Flash ActionScript.
+#
+#
+#   Topic: Language Support
+#
+#       Supported:
+#
+#       Not supported yet:
+#
+###############################################################################
+
+# This file is part of Natural Docs, which is Copyright (C) 2003-2005 Greg Valure
+# Natural Docs is licensed under the GPL
+
+use strict;
+use integer;
+
+package NaturalDocs::Languages::ActionScript;
+
+use base 'NaturalDocs::Languages::Advanced';
+
+
+################################################################################
+# Group: Package Variables
+
+#
+#   hash: classModifiers
+#   An existence hash of all the acceptable class modifiers.  The keys are in all lowercase.
+#
+my %classModifiers = ( 'dynamic' => 1,
+                                   'intrinsic' => 1 );
+
+#
+#   hash: memberModifiers
+#   An existence hash of all the acceptable class member modifiers.  The keys are in all lowercase.
+#
+my %memberModifiers = ( 'public' => 1,
+                                        'private' => 1,
+                                        'static' => 1 );
+
+
+#
+#   hash: declarationEnders
+#   An existence hash of all the tokens that can end a declaration.  This is important because statements don't require a semicolon
+#   to end.  The keys are in all lowercase.
+#
+my %declarationEnders = ( ';' => 1,
+                                        '}' => 1,
+                                        '{' => 1,
+                                        'public' => 1,
+                                        'private' => 1,
+                                        'static' => 1,
+                                        'class' => 1,
+                                        'interface' => 1,
+                                        'var' => 1,
+                                        'function' => 1,
+                                        'import' => 1 );
+
+
+
+################################################################################
+# Group: Interface Functions
+
+
+#
+#   Function: PackageSeparator
+#   Returns the package separator symbol.
+#
+sub PackageSeparator
+    {  return '.';  };
+
+
+#
+#   Function: EnumValues
+#   Returns the <EnumValuesType> that describes how the language handles enums.
+#
+sub EnumValues
+    {  return ::ENUM_GLOBAL();  };
+
+
+#
+#   Function: ParseParameterLine
+#   Parses a prototype parameter line and returns it as a <NaturalDocs::Languages::Prototype::Parameter> object.
+#
+sub ParseParameterLine #(line)
+    {
+    my ($self, $line) = @_;
+    return $self->ParsePascalParameterLine($line);
+    };
+
+
+#
+#   Function: TypeBeforeParameter
+#   Returns whether the type appears before the parameter in prototypes.
+#
+sub TypeBeforeParameter
+    {  return 0;  };
+
+
+#
+#   Function: ParseFile
+#
+#   Parses the passed source file, sending comments acceptable for documentation to <NaturalDocs::Parser->OnComment()>.
+#
+#   Parameters:
+#
+#       sourceFile - The <FileName> to parse.
+#       topicList - A reference to the list of <NaturalDocs::Parser::ParsedTopics> being built by the file.
+#
+#   Returns:
+#
+#       The array ( autoTopics, scopeRecord ).
+#
+#       autoTopics - An arrayref of automatically generated topics from the file, or undef if none.
+#       scopeRecord - An arrayref of <NaturalDocs::Languages::Advanced::ScopeChanges>, or undef if none.
+#
+sub ParseFile #(sourceFile, topicsList)
+    {
+    my ($self, $sourceFile, $topicsList) = @_;
+
+    $self->ParseForCommentsAndTokens($sourceFile, [ '//' ], [ '/*', '*/' ] );
+
+    my $tokens = $self->Tokens();
+    my $index = 0;
+    my $lineNumber = 1;
+
+    while ($index < scalar @$tokens)
+        {
+        if ($self->TryToSkipWhitespace(\$index, \$lineNumber) ||
+            $self->TryToGetImport(\$index, \$lineNumber) ||
+            $self->TryToGetClass(\$index, \$lineNumber) ||
+            $self->TryToGetFunction(\$index, \$lineNumber) ||
+            $self->TryToGetVariable(\$index, \$lineNumber) )
+            {
+            # The functions above will handle everything.
+            }
+
+        elsif ($tokens->[$index] eq '{')
+            {
+            $self->StartScope('}', $lineNumber, undef, undef, undef);
+            $index++;
+            }
+
+        elsif ($tokens->[$index] eq '}')
+            {
+            if ($self->ClosingScopeSymbol() eq '}')
+                {  $self->EndScope($lineNumber);  };
+
+            $index++;
+            }
+
+        else
+            {
+            $self->SkipToNextStatement(\$index, \$lineNumber);
+            };
+        };
+
+
+    # Don't need to keep these around.
+    $self->ClearTokens();
+
+
+    my $autoTopics = $self->AutoTopics();
+
+    my $scopeRecord = $self->ScopeRecord();
+    if (defined $scopeRecord && !scalar @$scopeRecord)
+        {  $scopeRecord = undef;  };
+
+    return ( $autoTopics, $scopeRecord );
+    };
+
+
+
+################################################################################
+# Group: Statement Parsing Functions
+# All functions here assume that the current position is at the beginning of a statement.
+#
+# Note for developers: I am well aware that the code in these functions do not check if we're past the end of the tokens as
+# often as it should.  We're making use of the fact that Perl will always return undef in these cases to keep the code simpler.
+
+
+#
+#   Function: TryToGetIdentifier
+#
+#   Determines whether the position is at an identifier, and if so, skips it and returns the complete identifier as a string.  Returns
+#   undef otherwise.
+#
+#   Parameters:
+#
+#       indexRef - A reference to the current token index.
+#       lineNumberRef - A reference to the current line number.
+#       allowStar - If set, allows the last identifier to be a star.
+#
+sub TryToGetIdentifier #(indexRef, lineNumberRef, allowStar)
+    {
+    my ($self, $indexRef, $lineNumberRef, $allowStar) = @_;
+    my $tokens = $self->Tokens();
+
+    my $index = $$indexRef;
+
+    use constant MODE_IDENTIFIER_START => 1;
+    use constant MODE_IN_IDENTIFIER => 2;
+    use constant MODE_AFTER_STAR => 3;
+
+    my $identifier;
+    my $mode = MODE_IDENTIFIER_START;
+
+    while ($index < scalar @$tokens)
+        {
+        if ($mode == MODE_IDENTIFIER_START)
+            {
+            if ($tokens->[$index] =~ /^[a-z\$\_]/i)
+                {
+                $identifier .= $tokens->[$index];
+                $index++;
+
+                $mode = MODE_IN_IDENTIFIER;
+                }
+            elsif ($allowStar && $tokens->[$index] eq '*')
+                {
+                $identifier .= '*';
+                $index++;
+
+                $mode = MODE_AFTER_STAR;
+                }
+            else
+                {  return undef;  };
+            }
+
+        elsif ($mode == MODE_IN_IDENTIFIER)
+            {
+            if ($tokens->[$index] eq '.')
+                {
+                $identifier .= '.';
+                $index++;
+
+                $mode = MODE_IDENTIFIER_START;
+                }
+            elsif ($tokens->[$index] =~ /^[a-z0-9\$\_]/i)
+                {
+                $identifier .= $tokens->[$index];
+                $index++;
+                }
+            else
+                {  last;  };
+            }
+
+        else #($mode == MODE_AFTER_STAR)
+            {
+            if ($tokens->[$index] =~ /^[a-z0-9\$\_\.]/i)
+                {  return undef;  }
+            else
+                {  last;  };
+            };
+        };
+
+    # We need to check again because we may have run out of tokens after a dot.
+    if ($mode != MODE_IDENTIFIER_START)
+        {
+        $$indexRef = $index;
+        return $identifier;
+        }
+    else
+        {  return undef;  };
+    };
+
+
+#
+#   Function: TryToGetImport
+#
+#   Determines whether the position is at a import statement, and if so, adds it as a Using statement to the current scope, skips
+#   it, and returns true.
+#
+sub TryToGetImport #(indexRef, lineNumberRef)
+    {
+    my ($self, $indexRef, $lineNumberRef) = @_;
+    my $tokens = $self->Tokens();
+
+    my $index = $$indexRef;
+    my $lineNumber = $$lineNumberRef;
+
+    if ($tokens->[$index] ne 'import')
+        {  return undef;  };
+
+    $index++;
+    $self->TryToSkipWhitespace(\$index, \$lineNumber);
+
+    my $identifier = $self->TryToGetIdentifier(\$index, \$lineNumber, 1);
+    if (!$identifier)
+        {  return undef;  };
+
+
+    # Currently we implement importing by stripping the last package level and treating it as a using.  So "import p1.p2.p3" makes
+    # p1.p2 the using path, which is over-tolerant but that's okay.  "import p1.p2.*" is treated the same way, but in this case it's
+    # not over-tolerant.  If there's no dot, there's no point to including it.
+
+    if (index($identifier, '.') != -1)
+        {
+        $identifier =~ s/\.[^\.]+$//;
+        $self->AddUsing( NaturalDocs::SymbolString->FromText($identifier) );
+        };
+
+    $$indexRef = $index;
+    $$lineNumberRef = $lineNumber;
+
+    return 1;
+    };
+
+
+#
+#   Function: TryToGetClass
+#
+#   Determines whether the position is at a class declaration statement, and if so, generates a topic for it, skips it, and
+#   returns true.
+#
+#   Supported Syntaxes:
+#
+#       - Classes
+#       - Interfaces
+#       - Classes and interfaces with _global
+#
+sub TryToGetClass #(indexRef, lineNumberRef)
+    {
+    my ($self, $indexRef, $lineNumberRef) = @_;
+    my $tokens = $self->Tokens();
+
+    my $index = $$indexRef;
+    my $lineNumber = $$lineNumberRef;
+
+    my @modifiers;
+
+    while ($tokens->[$index] =~ /^[a-z]/i &&
+              exists $classModifiers{lc($tokens->[$index])} )
+        {
+        push @modifiers, lc($tokens->[$index]);
+        $index++;
+
+        $self->TryToSkipWhitespace(\$index, \$lineNumber);
+        };
+
+    my $type;
+
+    if ($tokens->[$index] eq 'class' || $tokens->[$index] eq 'interface')
+        {
+        $type = $tokens->[$index];
+
+        $index++;
+        $self->TryToSkipWhitespace(\$index, \$lineNumber);
+        }
+    else
+        {  return undef;  };
+
+    my $className = $self->TryToGetIdentifier(\$index, \$lineNumber);
+
+    if (!$className)
+        {  return undef;  };
+
+    $self->TryToSkipWhitespace(\$index, \$lineNumber);
+
+    my @parents;
+
+    if ($tokens->[$index] eq 'extends')
+        {
+        $index++;
+        $self->TryToSkipWhitespace(\$index, \$lineNumber);
+
+        my $parent = $self->TryToGetIdentifier(\$index, \$lineNumber);
+        if (!$parent)
+            {  return undef;  };
+
+        push @parents, $parent;
+
+        $self->TryToSkipWhitespace(\$index, \$lineNumber);
+        };
+
+    if ($type eq 'class' && $tokens->[$index] eq 'implements')
+        {
+        $index++;
+        $self->TryToSkipWhitespace(\$index, \$lineNumber);
+
+        for (;;)
+            {
+            my $parent = $self->TryToGetIdentifier(\$index, \$lineNumber);
+            if (!$parent)
+                {  return undef;  };
+
+            push @parents, $parent;
+
+            $self->TryToSkipWhitespace(\$index, \$lineNumber);
+
+            if ($tokens->[$index] ne ',')
+                {  last;  }
+            else
+                {
+                $index++;
+                $self->TryToSkipWhitespace(\$index, \$lineNumber);
+                };
+            };
+        };
+
+    if ($tokens->[$index] ne '{')
+        {  return undef;  };
+
+    $index++;
+
+
+    # If we made it this far, we have a valid class declaration.
+
+    my $topicType;
+
+    if ($type eq 'interface')
+        {  $topicType = ::TOPIC_INTERFACE();  }
+    else
+        {  $topicType = ::TOPIC_CLASS();  };
+
+    $className =~ s/^_global.//;
+
+    my $autoTopic = NaturalDocs::Parser::ParsedTopic->New($topicType, $className,
+                                                                                         undef, $self->CurrentUsing(),
+                                                                                         undef,
+                                                                                         undef, undef, $$lineNumberRef);
+
+    $self->AddAutoTopic($autoTopic);
+    NaturalDocs::Parser->OnClass($autoTopic->Package());
+
+    foreach my $parent (@parents)
+        {
+        NaturalDocs::Parser->OnClassParent($autoTopic->Package(), NaturalDocs::SymbolString->FromText($parent),
+                                                               undef, $self->CurrentUsing(), ::RESOLVE_ABSOLUTE());
+        };
+
+    $self->StartScope('}', $lineNumber, $autoTopic->Package());
+
+    $$indexRef = $index;
+    $$lineNumberRef = $lineNumber;
+
+    return 1;
+    };
+
+
+#
+#   Function: TryToGetFunction
+#
+#   Determines if the position is on a function declaration, and if so, generates a topic for it, skips it, and returns true.
+#
+#   Supported Syntaxes:
+#
+#       - Functions
+#       - Constructors
+#       - Properties
+#       - Functions with _global
+#
+sub TryToGetFunction #(indexRef, lineNumberRef)
+    {
+    my ($self, $indexRef, $lineNumberRef) = @_;
+    my $tokens = $self->Tokens();
+
+    my $index = $$indexRef;
+    my $lineNumber = $$lineNumberRef;
+
+    my $startIndex = $index;
+    my $startLine = $lineNumber;
+
+    my @modifiers;
+
+    while ($tokens->[$index] =~ /^[a-z]/i &&
+              exists $memberModifiers{lc($tokens->[$index])} )
+        {
+        push @modifiers, lc($tokens->[$index]);
+        $index++;
+
+        $self->TryToSkipWhitespace(\$index, \$lineNumber);
+        };
+
+    if ($tokens->[$index] ne 'function')
+        {  return undef;  };
+    $index++;
+
+    $self->TryToSkipWhitespace(\$index, \$lineNumber);
+
+    my $type;
+
+    if ($tokens->[$index] eq 'get' || $tokens->[$index] eq 'set')
+        {
+        # This can either be a property ("function get Something()") or a function name ("function get()").
+
+        my $nextIndex = $index;
+        my $nextLineNumber = $lineNumber;
+
+        $nextIndex++;
+        $self->TryToSkipWhitespace(\$nextIndex, \$nextLineNumber);
+
+        if ($tokens->[$nextIndex] eq '(')
+            {
+            $type = ::TOPIC_FUNCTION();
+            # Ignore the movement and let the code ahead pick it up as the name.
+            }
+        else
+            {
+            $type = ::TOPIC_PROPERTY();
+            $index = $nextIndex;
+            $lineNumber = $nextLineNumber;
+            };
+        }
+    else
+        {  $type = ::TOPIC_FUNCTION();  };
+
+    my $name = $self->TryToGetIdentifier(\$index, \$lineNumber);
+    if (!$name)
+        {  return undef;  };
+
+    $self->TryToSkipWhitespace(\$index, \$lineNumber);
+
+    if ($tokens->[$index] ne '(')
+        {  return undef;  };
+
+    $index++;
+    $self->GenericSkipUntilAfter(\$index, \$lineNumber, ')');
+
+    $self->TryToSkipWhitespace(\$index, \$lineNumber);
+
+    if ($tokens->[$index] eq ':')
+        {
+        $index++;
+
+        $self->TryToSkipWhitespace(\$index, \$lineNumber);
+
+        $self->TryToGetIdentifier(\$index, \$lineNumber);
+
+        $self->TryToSkipWhitespace(\$index, \$lineNumber);
+        };
+
+
+    my $prototype = $self->NormalizePrototype( $self->CreateString($startIndex, $index) );
+
+    if ($tokens->[$index] eq '{')
+        {  $self->GenericSkip(\$index, \$lineNumber);  }
+    elsif (!exists $declarationEnders{$tokens->[$index]})
+        {  return undef;  };
+
+
+    my $scope = $self->CurrentScope();
+
+    if ($name =~ s/^_global.//)
+        {  $scope = undef;  };
+
+    $self->AddAutoTopic(NaturalDocs::Parser::ParsedTopic->New($type, $name,
+                                                                                              $scope, $self->CurrentUsing(),
+                                                                                              $prototype,
+                                                                                              undef, undef, $startLine));
+
+
+    # We succeeded if we got this far.
+
+    $$indexRef = $index;
+    $$lineNumberRef = $lineNumber;
+
+    return 1;
+    };
+
+
+#
+#   Function: TryToGetVariable
+#
+#   Determines if the position is on a variable declaration statement, and if so, generates a topic for each variable, skips the
+#   statement, and returns true.
+#
+#   Supported Syntaxes:
+#
+#       - Variables
+#       - Variables with _global
+#
+sub TryToGetVariable #(indexRef, lineNumberRef)
+    {
+    my ($self, $indexRef, $lineNumberRef) = @_;
+    my $tokens = $self->Tokens();
+
+    my $index = $$indexRef;
+    my $lineNumber = $$lineNumberRef;
+
+    my $startIndex = $index;
+    my $startLine = $lineNumber;
+
+    my @modifiers;
+
+    while ($tokens->[$index] =~ /^[a-z]/i &&
+              exists $memberModifiers{lc($tokens->[$index])} )
+        {
+        push @modifiers, lc($tokens->[$index]);
+        $index++;
+
+        $self->TryToSkipWhitespace(\$index, \$lineNumber);
+        };
+
+    if ($tokens->[$index] ne 'var')
+        {  return undef;  };
+    $index++;
+
+    $self->TryToSkipWhitespace(\$index, \$lineNumber);
+
+    my $endTypeIndex = $index;
+    my @names;
+    my @types;
+
+    for (;;)
+        {
+        my $name = $self->TryToGetIdentifier(\$index, \$lineNumber);
+        if (!$name)
+            {  return undef;  };
+
+        $self->TryToSkipWhitespace(\$index, \$lineNumber);
+
+        my $type;
+
+        if ($tokens->[$index] eq ':')
+            {
+            $index++;
+            $self->TryToSkipWhitespace(\$index, \$lineNumber);
+
+            $type = ': ' . $self->TryToGetIdentifier(\$index, \$lineNumber);
+
+            $self->TryToSkipWhitespace(\$index, \$lineNumber);
+            };
+
+        if ($tokens->[$index] eq '=')
+            {
+            do
+                {
+                $self->GenericSkip(\$index, \$lineNumber);
+                }
+            while ($tokens->[$index] ne ',' && !exists $declarationEnders{$tokens->[$index]} && $index < scalar @$tokens);
+            };
+
+        push @names, $name;
+        push @types, $type;
+
+        if ($tokens->[$index] eq ',')
+            {
+            $index++;
+            $self->TryToSkipWhitespace(\$index, \$lineNumber);
+            }
+        elsif (exists $declarationEnders{$tokens->[$index]})
+            {  last;  }
+        else
+            {  return undef;  };
+        };
+
+
+    # We succeeded if we got this far.
+
+    my $prototypePrefix = $self->CreateString($startIndex, $endTypeIndex);
+
+    for (my $i = 0; $i < scalar @names; $i++)
+        {
+        my $prototype = $self->NormalizePrototype( $prototypePrefix . ' ' . $names[$i] . $types[$i]);
+        my $scope = $self->CurrentScope();
+
+        if ($names[$i] =~ s/^_global.//)
+            {  $scope = undef;  };
+
+        $self->AddAutoTopic(NaturalDocs::Parser::ParsedTopic->New(::TOPIC_VARIABLE(), $names[$i],
+                                                                                                  $scope, $self->CurrentUsing(),
+                                                                                                  $prototype,
+                                                                                                  undef, undef, $startLine));
+        };
+
+    $$indexRef = $index;
+    $$lineNumberRef = $lineNumber;
+
+    return 1;
+    };
+
+
+
+################################################################################
+# Group: Low Level Parsing Functions
+
+
+#
+#   Function: GenericSkip
+#
+#   Advances the position one place through general code.
+#
+#   - If the position is on a string, it will skip it completely.
+#   - If the position is on an opening symbol, it will skip until the past the closing symbol.
+#   - If the position is on whitespace (including comments), it will skip it completely.
+#   - Otherwise it skips one token.
+#
+#   Parameters:
+#
+#       indexRef - A reference to the current index.
+#       lineNumberRef - A reference to the current line number.
+#
+sub GenericSkip #(indexRef, lineNumberRef)
+    {
+    my ($self, $indexRef, $lineNumberRef) = @_;
+    my $tokens = $self->Tokens();
+
+    # We can ignore the scope stack because we're just skipping everything without parsing, and we need recursion anyway.
+    if ($tokens->[$$indexRef] eq '{')
+        {
+        $$indexRef++;
+        $self->GenericSkipUntilAfter($indexRef, $lineNumberRef, '}');
+        }
+    elsif ($tokens->[$$indexRef] eq '(')
+        {
+        $$indexRef++;
+        $self->GenericSkipUntilAfter($indexRef, $lineNumberRef, ')');
+        }
+    elsif ($tokens->[$$indexRef] eq '[')
+        {
+        $$indexRef++;
+        $self->GenericSkipUntilAfter($indexRef, $lineNumberRef, ']');
+        }
+
+    elsif ($self->TryToSkipWhitespace($indexRef, $lineNumberRef) ||
+            $self->TryToSkipString($indexRef, $lineNumberRef))
+        {
+        }
+
+    else
+        {  $$indexRef++;  };
+    };
+
+
+#
+#   Function: GenericSkipUntilAfter
+#
+#   Advances the position via <GenericSkip()> until a specific token is reached and passed.
+#
+sub GenericSkipUntilAfter #(indexRef, lineNumberRef, token)
+    {
+    my ($self, $indexRef, $lineNumberRef, $token) = @_;
+    my $tokens = $self->Tokens();
+
+    while ($$indexRef < scalar @$tokens && $tokens->[$$indexRef] ne $token)
+        {  $self->GenericSkip($indexRef, $lineNumberRef);  };
+
+    if ($tokens->[$$indexRef] eq "\n")
+        {  $$lineNumberRef++;  };
+    $$indexRef++;
+    };
+
+
+#
+#   Function: SkipToNextStatement
+#
+#   Advances the position via <GenericSkip()> until the next statement, which is defined as anything in <declarationEnders> not
+#   appearing in brackets or strings.  It will always advance at least one token.
+#
+sub SkipToNextStatement #(indexRef, lineNumberRef)
+    {
+    my ($self, $indexRef, $lineNumberRef) = @_;
+    my $tokens = $self->Tokens();
+
+    do
+        {
+        $self->GenericSkip($indexRef, $lineNumberRef);
+        }
+    while ( $$indexRef < scalar @$tokens &&
+              !exists $declarationEnders{$tokens->[$$indexRef]} );
+    };
+
+
+#
+#   Function: TryToSkipString
+#   If the current position is on a string delimiter, skip past the string and return true.
+#
+#   Parameters:
+#
+#       indexRef - A reference to the index of the position to start at.
+#       lineNumberRef - A reference to the line number of the position.
+#
+#   Returns:
+#
+#       Whether the position was at a string.
+#
+#   Syntax Support:
+#
+#       - Supports quotes, apostrophes, and at-quotes.
+#
+sub TryToSkipString #(indexRef, lineNumberRef)
+    {
+    my ($self, $indexRef, $lineNumberRef) = @_;
+
+    return ($self->SUPER::TryToSkipString($indexRef, $lineNumberRef, '\'') ||
+               $self->SUPER::TryToSkipString($indexRef, $lineNumberRef, '"') );
+    };
+
+
+#
+#   Function: TryToSkipWhitespace
+#   If the current position is on a whitespace token, a line break token, or a comment, it skips them and returns true.  If there are
+#   a number of these in a row, it skips them all.
+#
+sub TryToSkipWhitespace #(indexRef, lineNumberRef)
+    {
+    my ($self, $indexRef, $lineNumberRef) = @_;
+    my $tokens = $self->Tokens();
+
+    my $result;
+
+    while ($$indexRef < scalar @$tokens)
+        {
+        if ($tokens->[$$indexRef] =~ /^[ \t]/)
+            {
+            $$indexRef++;
+            $result = 1;
+            }
+        elsif ($tokens->[$$indexRef] eq "\n")
+            {
+            $$indexRef++;
+            $$lineNumberRef++;
+            $result = 1;
+            }
+        elsif ($self->TryToSkipComment($indexRef, $lineNumberRef))
+            {
+            $result = 1;
+            }
+        else
+            {  last;  };
+        };
+
+    return $result;
+    };
+
+
+#
+#   Function: TryToSkipComment
+#   If the current position is on a comment, skip past it and return true.
+#
+sub TryToSkipComment #(indexRef, lineNumberRef)
+    {
+    my ($self, $indexRef, $lineNumberRef) = @_;
+
+    return ( $self->TryToSkipLineComment($indexRef, $lineNumberRef) ||
+                $self->TryToSkipMultilineComment($indexRef, $lineNumberRef) );
+    };
+
+
+#
+#   Function: TryToSkipLineComment
+#   If the current position is on a line comment symbol, skip past it and return true.
+#
+sub TryToSkipLineComment #(indexRef, lineNumberRef)
+    {
+    my ($self, $indexRef, $lineNumberRef) = @_;
+    my $tokens = $self->Tokens();
+
+    if ($tokens->[$$indexRef] eq '/' && $tokens->[$$indexRef+1] eq '/')
+        {
+        $self->SkipRestOfLine($indexRef, $lineNumberRef);
+        return 1;
+        }
+    else
+        {  return undef;  };
+    };
+
+
+#
+#   Function: TryToSkipMultilineComment
+#   If the current position is on an opening comment symbol, skip past it and return true.
+#
+sub TryToSkipMultilineComment #(indexRef, lineNumberRef)
+    {
+    my ($self, $indexRef, $lineNumberRef) = @_;
+    my $tokens = $self->Tokens();
+
+    if ($tokens->[$$indexRef] eq '/' && $tokens->[$$indexRef+1] eq '*')
+        {
+        $self->SkipUntilAfter($indexRef, $lineNumberRef, '*', '/');
+        return 1;
+        }
+    else
+        {  return undef;  };
+    };
+
+
+1;