// Licensed under the terms of the GNU GPL
//
// (C) 2001, 2002 Ximian, Inc (http://www.ximian.com)
+// (C) 2004 Novell, Inc
//
/*
bool handle_remove_add = false;
bool handle_assembly = false;
+ //
+ // XML documentation buffer. The save point is used to divide
+ // comments on types and comments on members.
+ //
+ StringBuilder xml_comment_buffer;
+
+ //
+ // See comment on XmlCommentState enumeration.
+ //
+ XmlCommentState xmlDocState = XmlCommentState.Allowed;
+
//
// Whether tokens have been seen on this line
//
// after a token has been seen.
//
bool any_token_seen = false;
+
static Hashtable tokenValues;
private static Hashtable TokenValueName
handle_remove_add = value;
}
}
+
+ public XmlCommentState doc_state {
+ get { return xmlDocState; }
+ set {
+ if (value == XmlCommentState.Allowed) {
+ check_incorrect_doc_comment ();
+ consume_doc_comment ();
+ }
+ xmlDocState = value;
+ }
+ }
+
//
// Class variables
define (def);
}
+ xml_comment_buffer = new StringBuilder ();
+
//
// FIXME: This could be `Location.Push' but we have to
// find out why the MS compiler allows this
case '}':
return Token.CLOSE_BRACE;
case '[':
+ // To block doccomment inside attribute declaration.
+ if (doc_state == XmlCommentState.Allowed)
+ doc_state = XmlCommentState.NotAllowed;
return Token.OPEN_BRACKET;
case ']':
return Token.CLOSE_BRACKET;
//
Report.Warning (78, Location, "The 'l' suffix is easily confused with the digit '1' (use 'L' for clarity)");
}
- goto case 'L';
-
+ //
+ // This goto statement causes the MS CLR 2.0 beta 1 csc to report an error, so
+ // work around that.
+ //
+ //goto case 'L';
+ if (is_long)
+ scanning = false;
+ is_long = true;
+ getChar ();
+ break;
+
case 'L':
if (is_long)
scanning = false;
val = 0ul;
return Token.LITERAL_INTEGER;
}
+ catch (FormatException) {
+ Report.Error (1013, Location, "Invalid number");
+ val = 0ul;
+ return Token.LITERAL_INTEGER;
+ }
return integer_type_suffix (ul, peekChar ());
}
}
}
+ /// <summary>
+ /// Handles #pragma directive
+ /// </summary>
+ void PreProcessPragma (string arg)
+ {
+ const string disable = "warning disable";
+ const string restore = "warning restore";
+
+ if (arg == disable) {
+ Report.RegisterWarningRegion (Location).WarningDisable (line);
+ return;
+ }
+
+ if (arg == restore) {
+ Report.RegisterWarningRegion (Location).WarningEnable (line);
+ return;
+ }
+
+ if (arg.StartsWith (disable)) {
+ int[] codes = ParseNumbers (arg.Substring (disable.Length));
+ foreach (int code in codes) {
+ if (code != 0)
+ Report.RegisterWarningRegion (Location).WarningDisable (Location, code);
+ }
+ return;
+ }
+
+ if (arg.StartsWith (restore)) {
+ int[] codes = ParseNumbers (arg.Substring (restore.Length));
+ foreach (int code in codes) {
+ Report.RegisterWarningRegion (Location).WarningEnable (Location, code);
+ }
+ return;
+ }
+
+ return;
+ }
+
+ int[] ParseNumbers (string text)
+ {
+ string[] string_array = text.Split (',');
+ int[] values = new int [string_array.Length];
+ int index = 0;
+ foreach (string string_code in string_array) {
+ try {
+ values[index++] = int.Parse (string_code, System.Globalization.CultureInfo.InvariantCulture);
+ }
+ catch (FormatException) {
+ Report.Warning (1692, Location, "Invalid number");
+ }
+ }
+ return values;
+ }
+
bool eval_val (string s)
{
if (s == "true")
if (s [0] == '&'){
if (len > 2 && s [1] == '&'){
s = s.Substring (2);
- return (va & pp_eq (ref s));
+ return (va & pp_and (ref s));
} else {
Error_InvalidDirective ();
return false;
//
switch (cmd){
case "pragma":
- if (RootContext.V2)
+ if (RootContext.Version == LanguageVersion.ISO_1) {
+ Report.FeatureIsNotStandardized (Location, "#pragma");
return caller_is_taking;
- break;
-
+ }
+
+ PreProcessPragma (arg);
+ return caller_is_taking;
+
case "line":
if (!PreProcessLine (arg))
Report.Error (
{
int res = consume_identifier (s, false);
+ if (doc_state == XmlCommentState.Allowed)
+ doc_state = XmlCommentState.NotAllowed;
+ switch (res) {
+ case Token.USING:
+ case Token.NAMESPACE:
+ check_incorrect_doc_comment ();
+ break;
+ }
+
if (res == Token.PARTIAL) {
// Save current position and parse next token.
int old = reader.Position;
bool doread = false;
int c;
+ // Whether we have seen comments on the current line
+ bool comments_seen = false;
+
val = null;
// optimization: eliminate col and implement #directive semantic correctly.
for (;(c = getChar ()) != -1; col++) {
col = 0;
any_token_seen |= tokens_seen;
tokens_seen = false;
+ comments_seen = false;
continue;
}
if (d == '/'){
getChar ();
+ if (RootContext.Documentation != null && peekChar () == '/') {
+ getChar ();
+ // Don't allow ////.
+ if ((d = peekChar ()) != '/') {
+ if (doc_state == XmlCommentState.Allowed)
+ handle_one_line_xml_comment ();
+ else if (doc_state == XmlCommentState.NotAllowed)
+ warn_incorrect_doc_comment ();
+ }
+ }
while ((d = getChar ()) != -1 && (d != '\n') && d != '\r')
col++;
if (d == '\n'){
}
any_token_seen |= tokens_seen;
tokens_seen = false;
+ comments_seen = false;
continue;
} else if (d == '*'){
getChar ();
+ bool docAppend = false;
+ if (RootContext.Documentation != null && peekChar () == '*') {
+ getChar ();
+ // But when it is /**/, just do nothing.
+ if (peekChar () == '/') {
+ getChar ();
+ continue;
+ }
+ if (doc_state == XmlCommentState.Allowed)
+ docAppend = true;
+ else if (doc_state == XmlCommentState.NotAllowed)
+ warn_incorrect_doc_comment ();
+ }
+
+ int current_comment_start = 0;
+ if (docAppend) {
+ current_comment_start = xml_comment_buffer.Length;
+ xml_comment_buffer.Append (Environment.NewLine);
+ }
while ((d = getChar ()) != -1){
if (d == '*' && peekChar () == '/'){
getChar ();
col++;
+ comments_seen = true;
break;
}
+ if (docAppend)
+ xml_comment_buffer.Append ((char) d);
+
if (d == '\n'){
line++;
ref_line++;
col = 0;
any_token_seen |= tokens_seen;
tokens_seen = false;
+ //
+ // Reset 'comments_seen' just to be consistent.
+ // It doesn't matter either way, here.
+ //
+ comments_seen = false;
}
}
+ if (docAppend)
+ update_formatted_doc_comment (current_comment_start);
continue;
}
goto is_punct_label;
col = 0;
any_token_seen |= tokens_seen;
tokens_seen = false;
+ comments_seen = false;
continue;
}
/* For now, ignore pre-processor commands */
// FIXME: In C# the '#' is not limited to appear
// on the first column.
- if (c == '#' && !tokens_seen){
+ if (c == '#') {
bool cont = true;
+ if (tokens_seen || comments_seen) {
+ error_details = "Preprocessor directives must appear as the first non-whitespace " +
+ "character on a line.";
+
+ Report.Error (1040, Location, error_details);
+
+ return Token.ERROR;
+ }
+
start_again:
cont = handle_preprocessing_directive (cont);
}
}
- if (c == '#') {
- error_details = "Preprocessor directives must appear as the first non-whitespace " +
- "character on a line.";
-
- Report.Error (1040, Location, error_details);
-
- return Token.ERROR;
- }
-
error_details = ((char)c).ToString ();
return Token.ERROR;
return Token.EOF;
}
+ //
+ // Handles one line xml comment
+ //
+ private void handle_one_line_xml_comment ()
+ {
+ int c;
+ while ((c = peekChar ()) == ' ')
+ getChar (); // skip heading whitespaces.
+ while ((c = peekChar ()) != -1 && c != '\n' && c != '\r') {
+ col++;
+ xml_comment_buffer.Append ((char) getChar ());
+ }
+ if (c == '\r' || c == '\n')
+ xml_comment_buffer.Append (Environment.NewLine);
+ }
+
+ //
+ // Remove heading "*" in Javadoc-like xml documentation.
+ //
+ private void update_formatted_doc_comment (int current_comment_start)
+ {
+ int length = xml_comment_buffer.Length - current_comment_start;
+ string [] lines = xml_comment_buffer.ToString (
+ current_comment_start,
+ length).Replace ("\r", "").Split ('\n');
+
+ // The first line starts with /**, thus it is not target
+ // for the format check.
+ for (int i = 1; i < lines.Length; i++) {
+ string s = lines [i];
+ int idx = s.IndexOf ('*');
+ string head = null;
+ if (idx < 0) {
+ if (i < lines.Length - 1)
+ return;
+ head = s;
+ } else
+ head = s.Substring (0, idx);
+ foreach (char c in head)
+ if (c != ' ')
+ return;
+ lines [i] = s.Substring (idx + 1);
+ }
+ xml_comment_buffer.Remove (current_comment_start, length);
+ xml_comment_buffer.Insert (current_comment_start, String.Join (Environment.NewLine, lines));
+ }
+
+ //
+ // Checks if there was incorrect doc comments and raise
+ // warnings.
+ //
+ public void check_incorrect_doc_comment ()
+ {
+ if (xml_comment_buffer.Length > 0)
+ warn_incorrect_doc_comment ();
+ }
+
+ //
+ // Raises a warning when tokenizer found incorrect doccomment
+ // markup.
+ //
+ private void warn_incorrect_doc_comment ()
+ {
+ doc_state = XmlCommentState.Error;
+ // in csc, it is 'XML comment is not placed on a valid
+ // language element'. But that does not make sense.
+ Report.Warning (1587, 2, Location, "XML comment is placed on an invalid language element which can not accept it.");
+ }
+
+ //
+ // Consumes the saved xml comment lines (if any)
+ // as for current target member or type.
+ //
+ public string consume_doc_comment ()
+ {
+ if (xml_comment_buffer.Length > 0) {
+ string ret = xml_comment_buffer.ToString ();
+ xml_comment_buffer.Length = 0;
+ return ret;
+ }
+ return null;
+ }
+
public void cleanup ()
{
if (ifstack != null && ifstack.Count >= 1) {
int state = (int) ifstack.Pop ();
if ((state & REGION) != 0)
- Report.Error (1038, "#endregion directive expected");
+ Report.Error (1038, Location, "#endregion directive expected");
else
Report.Error (1027, "#endif directive expected");
}
}
}
-}
+ //
+ // Indicates whether it accepts XML documentation or not.
+ //
+ public enum XmlCommentState {
+ // comment is allowed in this state.
+ Allowed,
+ // comment is not allowed in this state.
+ NotAllowed,
+ // once comments appeared when it is NotAllowed, then the
+ // state is changed to it, until the state is changed to
+ // .Allowed.
+ Error
+ }
+}