1
###############################################################################
3
# Class: NaturalDocs::Languages::PLSQL
5
###############################################################################
7
# A subclass to handle the language variations of PL/SQL.
9
###############################################################################
11
# This file is part of Natural Docs, which is Copyright (C) 2003-2008 Greg Valure
12
# Natural Docs is licensed under the GPL
17
package NaturalDocs::Languages::PLSQL;
19
use base 'NaturalDocs::Languages::Simple';
23
# Function: OnPrototypeEnd
25
# Microsoft's SQL specifies parameters as shown below.
27
# > CREATE PROCEDURE Test @as int, @foo int AS ...
29
# Having a parameter @is or @as is perfectly valid even though those words are also used to end the prototype. We need to
30
# ignore text-based enders preceded by an at sign. Also note that it does not have parenthesis for parameter lists. We need to
31
# skip all commas if the prototype doesn't have parenthesis but does have @ characters.
33
# Identifiers such as function names may contain the characters $, #, and _, so if "as" or "is" appears directly after one of them
34
# we need to ignore the ender there as well.
36
# > FUNCTION Something_is_something ...
40
# type - The <TopicType> of the prototype.
41
# prototypeRef - A reference to the prototype so far, minus the ender in dispute.
42
# ender - The ender symbol.
46
# ENDER_ACCEPT - The ender is accepted and the prototype is finished.
47
# ENDER_IGNORE - The ender is rejected and parsing should continue. Note that the prototype will be rejected as a whole
48
# if all enders are ignored before reaching the end of the code.
49
# ENDER_ACCEPT_AND_CONTINUE - The ender is accepted so the prototype may stand as is. However, the prototype might
50
# also continue on so continue parsing. If there is no accepted ender between here and
51
# the end of the code this version will be accepted instead.
52
# ENDER_REVERT_TO_ACCEPTED - The expedition from ENDER_ACCEPT_AND_CONTINUE failed. Use the last accepted
53
# version and end parsing.
55
sub OnPrototypeEnd #(type, prototypeRef, ender)
57
my ($self, $type, $prototypeRef, $ender) = @_;
59
# _ should be handled already.
60
if ($ender =~ /^[a-z]+$/i && substr($$prototypeRef, -1) =~ /^[\@\$\#]$/)
61
{ return ::ENDER_IGNORE(); }
63
elsif ($type eq ::TOPIC_FUNCTION() && $ender eq ',')
65
if ($$prototypeRef =~ /^[^\(]*\@/)
66
{ return ::ENDER_IGNORE(); }
68
{ return ::ENDER_ACCEPT(); };
72
{ return ::ENDER_ACCEPT(); };
77
# Function: ParsePrototype
79
# Overridden to handle Microsoft's parenthesisless version. Otherwise just throws to the parent.
83
# type - The <TopicType>.
84
# prototype - The text prototype.
88
# A <NaturalDocs::Languages::Prototype> object.
90
sub ParsePrototype #(type, prototype)
92
my ($self, $type, $prototype) = @_;
94
my $noParenthesisParameters = ($type eq ::TOPIC_FUNCTION() && $prototype =~ /^[^\(]*\@/);
96
if ($prototype !~ /\(.*[^ ].*\)/ && !$noParenthesisParameters)
97
{ return $self->SUPER::ParsePrototype($type, $prototype); };
101
my ($beforeParameters, $afterParameters, $isAfterParameters);
103
if ($noParenthesisParameters)
105
($beforeParameters, $prototype) = split(/\@/, $prototype, 2);
106
$prototype = '@' . $prototype;
109
my @tokens = $prototype =~ /([^\(\)\[\]\{\}\<\>\'\"\,]+|.)/g;
116
foreach my $token (@tokens)
118
if ($isAfterParameters)
119
{ $afterParameters .= $token; }
121
elsif ($symbolStack[-1] eq '\'' || $symbolStack[-1] eq '"')
123
if ($noParenthesisParameters || $symbolStack[0] eq '(')
124
{ $parameter .= $token; }
126
{ $beforeParameters .= $token; };
128
if ($token eq $symbolStack[-1])
129
{ pop @symbolStack; };
132
elsif ($token =~ /^[\(\[\{\<\'\"]$/)
134
if ($noParenthesisParameters || $symbolStack[0] eq '(')
135
{ $parameter .= $token; }
137
{ $beforeParameters .= $token; };
139
push @symbolStack, $token;
142
elsif ( ($token eq ')' && $symbolStack[-1] eq '(') ||
143
($token eq ']' && $symbolStack[-1] eq '[') ||
144
($token eq '}' && $symbolStack[-1] eq '{') ||
145
($token eq '>' && $symbolStack[-1] eq '<') )
147
if (!$noParenthesisParameters && $token eq ')' && scalar @symbolStack == 1 && $symbolStack[0] eq '(')
149
$afterParameters .= $token;
150
$isAfterParameters = 1;
153
{ $parameter .= $token; };
158
elsif ($token eq ',')
160
if (!scalar @symbolStack)
162
if ($noParenthesisParameters)
164
push @parameterLines, $parameter . $token;
169
$beforeParameters .= $token;
174
if (scalar @symbolStack == 1 && $symbolStack[0] eq '(' && !$noParenthesisParameters)
176
push @parameterLines, $parameter . $token;
181
$parameter .= $token;
188
if ($noParenthesisParameters || $symbolStack[0] eq '(')
189
{ $parameter .= $token; }
191
{ $beforeParameters .= $token; };
195
push @parameterLines, $parameter;
197
foreach my $item (\$beforeParameters, \$afterParameters)
203
my $prototypeObject = NaturalDocs::Languages::Prototype->New($beforeParameters, $afterParameters);
206
# Parse the actual parameters.
208
foreach my $parameterLine (@parameterLines)
210
$prototypeObject->AddParameter( $self->ParseParameterLine($parameterLine) );
213
return $prototypeObject;
218
# Function: ParseParameterLine
220
# Parses a prototype parameter line and returns it as a <NaturalDocs::Languages::Prototype::Parameter> object.
222
sub ParseParameterLine #(line)
224
my ($self, $line) = @_;
229
my @tokens = $line =~ /([^\(\)\[\]\{\}\<\>\'\"\:\=\ ]+|\:\=|.)/g;
231
my ($name, $type, $defaultValue, $defaultValuePrefix, $inType, $inDefaultValue);
236
foreach my $token (@tokens)
239
{ $defaultValue .= $token; }
241
elsif ($symbolStack[-1] eq '\'' || $symbolStack[-1] eq '"')
246
{ $name .= $token; };
248
if ($token eq $symbolStack[-1])
249
{ pop @symbolStack; };
252
elsif ($token =~ /^[\(\[\{\<\'\"]$/)
257
{ $name .= $token; };
259
push @symbolStack, $token;
262
elsif ( ($token eq ')' && $symbolStack[-1] eq '(') ||
263
($token eq ']' && $symbolStack[-1] eq '[') ||
264
($token eq '}' && $symbolStack[-1] eq '{') ||
265
($token eq '>' && $symbolStack[-1] eq '<') )
270
{ $name .= $token; };
275
elsif ($token eq ' ')
279
elsif (!scalar @symbolStack)
282
{ $name .= $token; };
285
elsif ($token eq ':=' || $token eq '=')
287
if (!scalar @symbolStack)
289
$defaultValuePrefix = $token;
295
{ $name .= $token; };
303
{ $name .= $token; };
307
foreach my $part (\$type, \$defaultValue)
312
return NaturalDocs::Languages::Prototype::Parameter->New($type, undef, $name, undef, $defaultValue, $defaultValuePrefix);
316
sub TypeBeforeParameter