3709192002-03-20Martin Nilsson #pike __REAL_VERSION__
35eee72001-01-08David Norlin //======================================================================== // PARSING OF DOCUMENTATION COMMENTS //======================================================================== inherit .PikeObjects;
d47c322001-03-06David Norlin #include "./debug.h"
1e72ec2010-08-29Henrik Grubbström (Grubba) //! Metadata about a @[Documentation] object.
35eee72001-01-08David Norlin class MetaData {
1e72ec2010-08-29Henrik Grubbström (Grubba)  //! Type of documented entity.
35eee72001-01-08David Norlin  string type;
1e72ec2010-08-29Henrik Grubbström (Grubba)  //! If @[type] is one of @expr{"class"@}, @expr{"module"@}, //! @expr{"endmodule"@}, or @expr{"endclass"@}. string name; //! Set of declarations.
35eee72001-01-08David Norlin  array(PikeObject) decls = ({});
1e72ec2010-08-29Henrik Grubbström (Grubba)  //! Relocation information.
35eee72001-01-08David Norlin  string belongs = 0; string appears = 0;
1e72ec2010-08-29Henrik Grubbström (Grubba)  //! Set of inherits.
d5297c2004-03-02Martin Nilsson  array(PikeObject) inherits = ({});
35eee72001-01-08David Norlin }
1e72ec2010-08-29Henrik Grubbström (Grubba) //! End of file marker.
35eee72001-01-08David Norlin constant EOF = .PikeParser.EOF;
1e72ec2010-08-29Henrik Grubbström (Grubba) //! Enum of documentation token types. enum DocTokenType { METAKEYWORD = 1, //! eg @expr{@@decl@} BRACEKEYWORD = 2, //! eg @expr{@@i{@@}@} DELIMITERKEYWORD = 3, //! eg @expr{@@param@} CONTAINERKEYWORD = 4, //! eg @expr{@@mapping@}
0f5cea2012-03-05Henrik Grubbström (Grubba)  SINGLEKEYWORD = 5, //! None existant.
1e72ec2010-08-29Henrik Grubbström (Grubba)  ENDKEYWORD = 6, //! eg @expr{@@endmapping@} ERRORKEYWORD = 7, //! eg @expr{@@invalid@}
35eee72001-01-08David Norlin 
1e72ec2010-08-29Henrik Grubbström (Grubba)  TEXTTOKEN = 8, //! Documentation text. ENDTOKEN = 9, //! End of documentation marker. };
35eee72001-01-08David Norlin  // The following is the "DTD" of
1e72ec2010-08-29Henrik Grubbström (Grubba) // the documentation markup language. //! The @[DocTokenType]s for the documentation @@-keywords. mapping(string : DocTokenType) keywordtype =
35eee72001-01-08David Norlin ([ "appears" : METAKEYWORD, "belongs" : METAKEYWORD, "class" : METAKEYWORD,
ce8f3e2011-12-18Henrik Grubbström (Grubba)  "global" : METAKEYWORD,
35eee72001-01-08David Norlin  "endclass" : METAKEYWORD, "module" : METAKEYWORD, "endmodule" : METAKEYWORD,
9ba9e42002-12-11Henrik Grubbström (Grubba)  "namespace" : METAKEYWORD, "endnamespace" : METAKEYWORD,
35eee72001-01-08David Norlin  "decl" : METAKEYWORD,
2110692012-02-05Henrik Grubbström (Grubba)  "directive" : METAKEYWORD,
d5297c2004-03-02Martin Nilsson  "inherit" : METAKEYWORD,
7dc6982003-11-08Henrik Grubbström (Grubba)  "enum" : METAKEYWORD, "endenum" : METAKEYWORD,
35eee72001-01-08David Norlin 
ecba372001-05-15David Norlin  "b" : BRACEKEYWORD,
35eee72001-01-08David Norlin  "i" : BRACEKEYWORD,
90cb472001-05-15David Norlin  "u" : BRACEKEYWORD,
35eee72001-01-08David Norlin  "tt" : BRACEKEYWORD,
a380f82001-05-29David Norlin  "url" : BRACEKEYWORD,
cc33b12001-07-17Martin Nilsson  "pre" : BRACEKEYWORD,
8ee3df2004-03-02Martin Nilsson  "sub" : BRACEKEYWORD, "sup" : BRACEKEYWORD,
35eee72001-01-08David Norlin  "ref" : BRACEKEYWORD,
f995462015-08-21Henrik Grubbström (Grubba)  "rfc" : BRACEKEYWORD,
90cb472001-05-15David Norlin  "xml" : BRACEKEYWORD, // well, not really, but....
3821e52002-05-30Martin Nilsson  "expr" : BRACEKEYWORD,
7c14112001-05-09David Norlin  "image" : BRACEKEYWORD,
35eee72001-01-08David Norlin 
0f5cea2012-03-05Henrik Grubbström (Grubba)  "deprecated" : DELIMITERKEYWORD, "obsolete" : DELIMITERKEYWORD,
2e0d132001-02-05David Norlin 
5dc7ca2003-04-01Martin Nilsson  "bugs" : DELIMITERKEYWORD,
28d4fc2011-12-03Henrik Grubbström (Grubba)  "copyright" : DELIMITERKEYWORD,
35eee72001-01-08David Norlin  "example" : DELIMITERKEYWORD,
5dc7ca2003-04-01Martin Nilsson  "fixme" : DELIMITERKEYWORD,
35eee72001-01-08David Norlin  "note" : DELIMITERKEYWORD, "param" : DELIMITERKEYWORD,
5dc7ca2003-04-01Martin Nilsson  "returns" : DELIMITERKEYWORD,
46b75b2001-01-08Henrik Grubbström (Grubba)  "seealso" : DELIMITERKEYWORD,
28d4fc2011-12-03Henrik Grubbström (Grubba)  "thanks" : DELIMITERKEYWORD,
5dc7ca2003-04-01Martin Nilsson  "throws" : DELIMITERKEYWORD,
35eee72001-01-08David Norlin 
5dc7ca2003-04-01Martin Nilsson  "code" : CONTAINERKEYWORD,
fd033d2001-02-06David Norlin  "section" : CONTAINERKEYWORD,
3f97b32001-04-11David Norlin  "constant" : DELIMITERKEYWORD, // used inside @decl enum Foo
35eee72001-01-08David Norlin  "mapping" : CONTAINERKEYWORD, "member" : DELIMITERKEYWORD, "multiset" : CONTAINERKEYWORD, "index" : DELIMITERKEYWORD, "array" : CONTAINERKEYWORD, "elem" : DELIMITERKEYWORD,
141bba2001-02-06Henrik Grubbström (Grubba)  "int" : CONTAINERKEYWORD, "value" : DELIMITERKEYWORD,
57add72001-02-14Henrik Grubbström (Grubba)  "string" : CONTAINERKEYWORD,
141bba2001-02-06Henrik Grubbström (Grubba)  "mixed" : CONTAINERKEYWORD, "type" : DELIMITERKEYWORD,
35eee72001-01-08David Norlin  "dl" : CONTAINERKEYWORD, "item" : DELIMITERKEYWORD,
bbab332001-08-20Martin Nilsson  "ol" : CONTAINERKEYWORD, "ul" : CONTAINERKEYWORD,
35eee72001-01-08David Norlin ]); mapping(string : array(string)) attributenames = ([ "item" : ({ "name" }), "param" : ({ "name" }), "mapping" : ({ "name" }), "array" : ({ "name" }), "multiset" : ({ "name" }),
141bba2001-02-06Henrik Grubbström (Grubba)  "int" : ({ "name" }),
57add72001-02-14Henrik Grubbström (Grubba)  "string" : ({ "name" }),
141bba2001-02-06Henrik Grubbström (Grubba)  "mixed" : ({ "name" }),
3f97b32001-04-11David Norlin  "constant" : ({ "name" }),
9b77a92002-11-25Henrik Grubbström (Grubba)  "typedef" : ({ "name" }), "enum" : ({ "name" }),
35eee72001-01-08David Norlin ]);
5239232002-12-07Henrik Grubbström (Grubba) mapping(string:array(string)) required_attributes = ([ "param" : ({ "name" }),
3524712015-05-26Martin Nilsson ]);
5239232002-12-07Henrik Grubbström (Grubba) 
9eaf1d2008-06-28Martin Nilsson protected constant standard = (<
28d4fc2011-12-03Henrik Grubbström (Grubba)  "note", "bugs", "example", "seealso", "deprecated", "fixme", "code",
e931352012-01-24Henrik Grubbström (Grubba)  "copyright", "thanks", "obsolete",
0d10ab2001-04-26Henrik Grubbström (Grubba) >);
35eee72001-01-08David Norlin  mapping(string : multiset(string)) allowedChildren = (["_general" : standard,
0d10ab2001-04-26Henrik Grubbström (Grubba)  "_method" : (< "param", "returns", "throws" >) + standard,
8575a02001-02-06David Norlin  "_variable": standard, "_inherit" : standard,
3def6b2003-09-01Martin Nilsson  "_class" : (< "param" >) + standard,
ade4e12002-12-23Henrik Grubbström (Grubba)  "_namespace" : standard,
9b1ad32001-02-06David Norlin  "_module" : standard, "_constant" : standard,
3f97b32001-04-11David Norlin  "_enum" : (< "constant" >) + standard,
9b77a92002-11-25Henrik Grubbström (Grubba)  "_typedef" : standard,
fd567c2012-02-15Henrik Grubbström (Grubba)  "_directive" : standard,
35eee72001-01-08David Norlin  "mapping" : (< "member" >), "multiset": (< "index" >), "array" : (< "elem" >),
141bba2001-02-06Henrik Grubbström (Grubba)  "int" : (< "value" >),
57add72001-02-14Henrik Grubbström (Grubba)  "string" : (< "value" >),
141bba2001-02-06Henrik Grubbström (Grubba)  "mixed" : (< "type" >),
35eee72001-01-08David Norlin  "dl" : (< "item" >),
bbab332001-08-20Martin Nilsson  "ol" : (< "item" >), "ul" : (< "item" >),
35eee72001-01-08David Norlin ]);
2e0d132001-02-05David Norlin mapping(string : multiset(string)) allowGrouping = (["param" : (< "param" >),
d47c322001-03-06David Norlin  "index" : (< "index" >),
8a6cdd2001-02-06Henrik Grubbström (Grubba)  "member" : (< "member" >),
161f1d2001-02-09Henrik Grubbström (Grubba)  "type" : (< "type" >),
57add72001-02-14Henrik Grubbström (Grubba)  "value" : (< "value" >),
3f97b32001-04-11David Norlin  "constant" : (< "constant" >),
ecba372001-05-15David Norlin  "item" : (< "item" >),
2e0d132001-02-05David Norlin ]);
35eee72001-01-08David Norlin 
3f97b32001-04-11David Norlin multiset(string) allowOnlyOne = (< "seealso", "returns",
0d10ab2001-04-26Henrik Grubbström (Grubba)  "throws",
3f97b32001-04-11David Norlin  "deprecated", >);
9eaf1d2008-06-28Martin Nilsson protected int getKeywordType(string keyword) {
35eee72001-01-08David Norlin  if (keywordtype[keyword]) return keywordtype[keyword];
ead9722003-01-20Martin Nilsson  if (sizeof(keyword) > 3 && keyword[0..2] == "end")
35eee72001-01-08David Norlin  return ENDKEYWORD; return ERRORKEYWORD; }
9eaf1d2008-06-28Martin Nilsson protected int getTokenType(array(string) | string token) {
35eee72001-01-08David Norlin  if (arrayp(token)) return getKeywordType(token[0]); if (!token) return ENDTOKEN; return TEXTTOKEN; }
9eaf1d2008-06-28Martin Nilsson protected int isSpaceChar(int char) {
35eee72001-01-08David Norlin  return (< '\t', '\n', ' ' >) [char]; }
9eaf1d2008-06-28Martin Nilsson protected int isKeywordChar(int char) {
35eee72001-01-08David Norlin  return char >= 'a' && char <= 'z'; }
9eaf1d2008-06-28Martin Nilsson protected array(string) extractKeyword(string line) {
35eee72001-01-08David Norlin  line += "\0"; int i = 0;
ead9722003-01-20Martin Nilsson  while (i < sizeof(line) && isSpaceChar(line[i]))
35eee72001-01-08David Norlin  ++i; if (line[i++] != '@') return 0; int keywordstart = i; while (isKeywordChar(line[i])) ++i; if (i == keywordstart || line[i] && !isSpaceChar(line[i])) return 0; string keyword = line[keywordstart .. i - 1]; // if (getKeywordType(keyword) == METAKEYWORD)
ead9722003-01-20Martin Nilsson  return ({ keyword, line[i .. sizeof(line) - 2] }); // skippa "\0" ...
35eee72001-01-08David Norlin }
9eaf1d2008-06-28Martin Nilsson protected int allSpaces(string s) {
ead9722003-01-20Martin Nilsson  for (int i = sizeof(s) - 1; i >= 0; --i)
35eee72001-01-08David Norlin  if (s[i] != ' ' && s[i] != '\t') return 0; return 1; }
9eaf1d2008-06-28Martin Nilsson protected private class Token (
d47c322001-03-06David Norlin  int type, string keyword, string arg, // the rest of the line, after the keyword string text, SourcePosition position, ) {
4507e92002-11-29Martin Nilsson  string _sprintf(int t) { return t=='O' && sprintf("%O(%d, %O, %O, %O, %O)", this_program, type, keyword, arg, text, position);
d47c322001-03-06David Norlin  } }
9eaf1d2008-06-28Martin Nilsson protected array(Token) split(string s, SourcePosition pos) {
d47c322001-03-06David Norlin  s = s - "\r"; s = replace(s, "@\n", "@\r"); array(string) lines = s / "\n"; // array holding the number of src lines per line array(int) counts = allocate(sizeof(lines)); for(int i = 0; i < sizeof(lines); ++i) { array(string) a = lines[i] / "@\r"; counts[i] = sizeof(a); lines[i] = a * ""; } array(Token) res = ({ }); string filename = pos->filename; string text = 0; int textFirstLine; int textLastLine; int curLine = pos->firstline; for(int i = 0; i < sizeof(lines); ++i) { string line = lines[i]; array(string) extr = extractKeyword(line); if (extr) { if (text) res += ({ Token(TEXTTOKEN, 0, 0, text, SourcePosition(filename, textFirstLine, textLastLine)) }); text = 0; res += ({ Token(getKeywordType(extr[0]), extr[0], extr[1], 0, SourcePosition(filename, curLine, curLine + counts[i] - 1)) });
35eee72001-01-08David Norlin  } else { if (allSpaces(line))
d47c322001-03-06David Norlin  line = ""; if (!text) { text = ""; textFirstLine = curLine; } text += line + "\n"; textLastLine = curLine;
35eee72001-01-08David Norlin  }
d47c322001-03-06David Norlin  curLine += counts[i];
35eee72001-01-08David Norlin  }
d47c322001-03-06David Norlin  if (text) res += ({ Token(TEXTTOKEN, 0, 0, text, SourcePosition(filename, textFirstLine, textLastLine)) });
35eee72001-01-08David Norlin  return res; }
3524712015-05-26Martin Nilsson //! Internal class for parsing documentation markup.
9eaf1d2008-06-28Martin Nilsson protected class DocParserClass {
35eee72001-01-08David Norlin 
1e72ec2010-08-29Henrik Grubbström (Grubba)  //!
ca8e252002-10-01Martin Nilsson  SourcePosition currentPosition = 0;
d47c322001-03-06David Norlin 
40ae6f2011-12-04Henrik Grubbström (Grubba)  .Flags flags = .FLAG_NORMAL;
9eaf1d2008-06-28Martin Nilsson  protected void parseError(string s, mixed ... args) {
d47c322001-03-06David Norlin  s = sprintf(s, @args);
fe97f92011-11-18Henrik Grubbström (Grubba)  if (currentPosition->lastline) { werror("%s:%d..%d: DocParser error: %s\n", currentPosition->filename, currentPosition->firstline, currentPosition->lastline, s); } else { werror("%s:%d: DocParser error: %s\n", currentPosition->filename, currentPosition->firstline, s); }
1e22952011-12-19Henrik Grubbström (Grubba)  if (flags & .FLAG_KEEP_GOING) return;
d47c322001-03-06David Norlin  throw (AutoDocError(currentPosition, "DocParser", s)); }
9eaf1d2008-06-28Martin Nilsson  protected array(Token) tokenArr = 0; protected Token peekToken() {
d47c322001-03-06David Norlin  Token t = tokenArr[0]; currentPosition = t->position || currentPosition; return t; }
9eaf1d2008-06-28Martin Nilsson  protected Token readToken() {
d47c322001-03-06David Norlin  Token t = peekToken(); tokenArr = tokenArr[1..]; return t; }
1e72ec2010-08-29Henrik Grubbström (Grubba)  //! Contains functions that handle keywords with non-standard arg list //! syntax. The function for each keyword can return a mapping or a string: //! //! @mixed //! @type mapping(string:string) //! If a @expr{mapping(string:string)@} is returned, it is interpreted //! as the attributes to put in the tag. //! @type string //! If a string is returned, it is an XML fragment that gets inserted //! inside the tag. //! @endmixed
d47c322001-03-06David Norlin  mapping(string : function(string, string : string) | function(string, string : mapping(string : string))) argHandlers = ([ "member" : memberArgHandler, "elem" : elemArgHandler, "index" : indexArgHandler, "deprecated" : deprArgHandler,
e931352012-01-24Henrik Grubbström (Grubba)  "obsolete" : deprArgHandler,
d47c322001-03-06David Norlin  "section" : sectionArgHandler, "type" : typeArgHandler, "value" : valueArgHandler,
5ae2462011-03-07Martin Stjernholm  "item": itemArgHandler,
d47c322001-03-06David Norlin  ]);
9eaf1d2008-06-28Martin Nilsson  protected string memberArgHandler(string keyword, string arg) {
d47c322001-03-06David Norlin  // werror("This is the @member arg handler "); .PikeParser parser = .PikeParser(arg, currentPosition); // werror("&&& %O\n", arg); Type t = parser->parseOrType();
1e22952011-12-19Henrik Grubbström (Grubba)  if (!t) {
d47c322001-03-06David Norlin  parseError("@member: expected type, got %O", arg);
1e22952011-12-19Henrik Grubbström (Grubba)  t = MixedType(); }
d47c322001-03-06David Norlin  // werror("%%%%%% got type == %O\n", t->xml()); string s = parser->parseLiteral() || parser->parseIdents();
1e22952011-12-19Henrik Grubbström (Grubba)  if (!s) {
4eef662012-01-24Henrik Grubbström (Grubba)  parseError("@member: expected type followed by identifier or literal constant, got %O", arg);
1e22952011-12-19Henrik Grubbström (Grubba)  s = ""; }
d47c322001-03-06David Norlin  parser->eat(EOF); return xmltag("type", t->xml()) + xmltag("index", xmlquote(s)); }
9eaf1d2008-06-28Martin Nilsson  protected string elemArgHandler(string keyword, string arg) {
d47c322001-03-06David Norlin  // werror("This is the @elem arg handler\n"); .PikeParser parser = .PikeParser(arg, currentPosition); Type t = parser->parseOrType();
1e22952011-12-19Henrik Grubbström (Grubba)  if (!t) {
d47c322001-03-06David Norlin  parseError("@elem: expected type, got %O", arg);
1e22952011-12-19Henrik Grubbström (Grubba)  t = MixedType(); }
d47c322001-03-06David Norlin  if (parser->peekToken() == "...") { t = VarargsType(t); parser->eat("..."); } string s = parser->parseLiteral() || parser->parseIdents(); string s2 = 0; int dots = 0; if (parser->peekToken() == "..") { dots = 1; parser->readToken(); s2 = parser->parseLiteral() || parser->parseIdents(); } parser->eat(EOF);
a32a5f2001-06-14David Norlin  string type = xmltag("type", t->xml());
d47c322001-03-06David Norlin  if (s) if (s2)
a32a5f2001-06-14David Norlin  return type + xmltag("minindex", xmlquote(s))
d47c322001-03-06David Norlin  + xmltag("maxindex", xmlquote(s2)); else
a32a5f2001-06-14David Norlin  return type + xmltag(dots ? "minindex" : "index", xmlquote(s));
d47c322001-03-06David Norlin  else if (s2)
a32a5f2001-06-14David Norlin  return type + xmltag("maxindex", xmlquote(s2));
d47c322001-03-06David Norlin  else parseError("@elem: expected identifier or literal");
1e22952011-12-19Henrik Grubbström (Grubba)  return type;
d47c322001-03-06David Norlin  }
9eaf1d2008-06-28Martin Nilsson  protected string indexArgHandler(string keyword, string arg) {
d47c322001-03-06David Norlin  // werror("indexArgHandler\n"); .PikeParser parser = .PikeParser(arg, currentPosition); string s = parser->parseLiteral();
1e22952011-12-19Henrik Grubbström (Grubba)  if (!s) {
d47c322001-03-06David Norlin  parseError("@index: expected identifier, got %O", arg);
1e22952011-12-19Henrik Grubbström (Grubba)  s = ""; }
d47c322001-03-06David Norlin  parser->eat(EOF); return xmltag("value", xmlquote(s)); }
e931352012-01-24Henrik Grubbström (Grubba)  protected string deprArgHandler(string keyword, string arg) { if (keyword != "deprecated") { parseError("Illegal keyword: @%s, did you mean @deprecated?"); }
d47c322001-03-06David Norlin  .PikeParser parser = .PikeParser(arg, currentPosition); if (parser->peekToken() == EOF) return ""; string res = ""; for (;;) { string s = parser->parseIdents();
1e22952011-12-19Henrik Grubbström (Grubba)  if (!s) {
d47c322001-03-06David Norlin  parseError("@deprecated: expected list identifier, got %O", arg);
1e22952011-12-19Henrik Grubbström (Grubba)  if (parser->peekToken() != ",") return res; } else res += xmltag("name", xmltag("ref", s));
d47c322001-03-06David Norlin  if (parser->peekToken() == EOF) return res; parser->eat(","); } }
9eaf1d2008-06-28Martin Nilsson  protected mapping(string : string) sectionArgHandler(string keyword, string arg) {
8ff89d2016-07-04Martin Nilsson  return ([ "title" : String.trim (arg) ]);
d47c322001-03-06David Norlin  }
9eaf1d2008-06-28Martin Nilsson  protected string typeArgHandler(string keyword, string arg) {
d47c322001-03-06David Norlin  // werror("This is the @type arg handler "); .PikeParser parser = .PikeParser(arg, currentPosition); // werror("&&& %O\n", arg); Type t = parser->parseOrType();
1e22952011-12-19Henrik Grubbström (Grubba)  if (!t) {
d47c322001-03-06David Norlin  parseError("@member: expected type, got %O", arg);
1e22952011-12-19Henrik Grubbström (Grubba)  t = MixedType(); }
d47c322001-03-06David Norlin  // werror("%%%%%% got type == %O\n", t->xml()); parser->eat(EOF);
a20f852001-07-26David Norlin  return t->xml();
d47c322001-03-06David Norlin  }
9eaf1d2008-06-28Martin Nilsson  protected string valueArgHandler(string keyword, string arg) {
a20f852001-07-26David Norlin  // werror("This is the @value arg handler ");
d47c322001-03-06David Norlin  .PikeParser parser = .PikeParser(arg, currentPosition); // werror("&&& %O\n", arg); string s = parser->parseLiteral() || parser->parseIdents();
3d7c7c2001-04-26David Norlin  string s2 = 0; int dots = 0; if (parser->peekToken() == "..") { dots = 1; parser->readToken(); s2 = parser->parseLiteral() || parser->parseIdents(); }
d47c322001-03-06David Norlin  parser->eat(EOF);
3d7c7c2001-04-26David Norlin  if (s) if (s2) return xmltag("minvalue", xmlquote(s)) + xmltag("maxvalue", xmlquote(s2)); else
a20f852001-07-26David Norlin  return dots ? xmltag("minvalue", xmlquote(s)) : xmlquote(s);
3d7c7c2001-04-26David Norlin  else if (s2) return xmltag("maxvalue", xmlquote(s2)); else
4eef662012-01-24Henrik Grubbström (Grubba)  parseError("@value: expected identifier or literal constant, got %O", arg);
1e22952011-12-19Henrik Grubbström (Grubba)  return "";
d47c322001-03-06David Norlin  }
923b702014-04-02Henrik Grubbström (Grubba)  protected string|mapping(string:string) itemArgHandler(string keyword, string arg)
5ae2462011-03-07Martin Stjernholm  {
8ff89d2016-07-04Martin Nilsson  arg = String.trim(arg);
4e7de02014-04-02Henrik Grubbström (Grubba)  if (arg == "") return "";
923b702014-04-02Henrik Grubbström (Grubba)  if (!has_value(arg, "@")) return ([ "name":arg ]);
4e7de02014-04-02Henrik Grubbström (Grubba)  return xmlNode(arg);
5ae2462011-03-07Martin Stjernholm  }
9eaf1d2008-06-28Martin Nilsson  protected mapping(string : string) standardArgHandler(string keyword, string arg)
d47c322001-03-06David Norlin  { array(string) args = ({}); arg += "\0"; int i = 0; for (;;) { while (isSpaceChar(arg[i]))
35eee72001-01-08David Norlin  ++i;
d47c322001-03-06David Norlin  if (!arg[i]) break; if (arg[i] == '"' || arg[i] == '\'') { int quotechar = arg[i];
35eee72001-01-08David Norlin  ++i; int start = i;
d47c322001-03-06David Norlin  while(arg[i]) { if (arg[i] == quotechar) if (arg[i + 1] == quotechar) ++i; else break; // Or should we have \n style quoting?? //else if (arg[i] == '\\' && arg[i + 1]) // ++i; ++i; } if (!arg[i]) parseError("keyword parameter is unterminated string constant");
35eee72001-01-08David Norlin  else
d47c322001-03-06David Norlin  ++i; string s = arg[start .. i - 2]; array(string) replacefrom = ({ quotechar == '"' ? "\"\"" : "''" }); array(string) replaceto = ({ quotechar == '"' ? "\"" : "'" }); // Or should we have \n style quoting?? //array(string) replacefrom = ({ "\\n", "\\t", "\\r", "\\\"", "\\\\", // quotechar == '"' ? "\"\"" : "''" }); //array(string) replaceto = ({ "\n", "\t", "\r", "\"", "\\", // quotechar == '"' ? "\"" : "'" }); s = replace(s,replacefrom, replaceto); args += ({ s });
35eee72001-01-08David Norlin  }
d47c322001-03-06David Norlin  else {
a0238e2004-11-26Martin Nilsson  String.Buffer out = String.Buffer(); int quote = 0; while (arg[i] && (!isSpaceChar(arg[i]) || quote) ) { if(arg[i]=='@') { switch(arg[i+1]) { case '@': out->putchar( '@' ); break; case '{': quote++; break; case '}': quote--; if(quote<0) parseError(sprintf("@%s with too many @}.\n", keyword)); break; case 0: default: parseError("Illegal @ statement.\n"); } } else out->putchar(arg[i]);
35eee72001-01-08David Norlin  ++i;
a0238e2004-11-26Martin Nilsson  } args += ({ (string)out });
35eee72001-01-08David Norlin  } }
d47c322001-03-06David Norlin  mapping(string:string) res = ([]); array(string) attrnames = attributenames[keyword]; int attrcount = sizeof(attrnames || ({}) );
2e52c92012-02-15Henrik Grubbström (Grubba)  if (attrcount < sizeof(args)) {
d47c322001-03-06David Norlin  parseError(sprintf("@%s with too many parameters", keyword));
2e52c92012-02-15Henrik Grubbström (Grubba)  args = args[..attrcount-1]; }
d47c322001-03-06David Norlin  for (int i = 0; i < sizeof(args); ++i) res[attrnames[i]] = attributequote(args[i]);
b96f9a2002-12-07Henrik Grubbström (Grubba)  foreach(required_attributes[keyword]||({}), string attrname) {
5239232002-12-07Henrik Grubbström (Grubba)  if (!res[attrname]) { parseError(sprintf("@%s lacking required parameter %s", keyword, attrname)); } }
d47c322001-03-06David Norlin  return res; }
9eaf1d2008-06-28Martin Nilsson  protected string|mapping(string:string) getArgs(string keyword, string arg) {
d47c322001-03-06David Norlin  return (argHandlers[keyword] || standardArgHandler)(keyword, arg); }
9eaf1d2008-06-28Martin Nilsson  protected string xmlNode(string s) { /* now, @xml works like @i & @tt */
d47c322001-03-06David Norlin  s += "\0"; string res = ""; int i = 0; array(string) tagstack = ({ }); int inXML = 0; while (s[i] == '\n') // strip leading empty lines.
35eee72001-01-08David Norlin  ++i;
d47c322001-03-06David Norlin  while (s[i]) { if (s[i] == '@') { ++i; if (s[i] == '@') { res += "@"; ++i; } else if (s[i] == '[') { // @ref shortcut int j = ++i; multiset(int) forbidden = (<'@','\n'>); int level = 1; while (s[j] && level && !forbidden[s[j]] ) { if (s[j] == ']') { level--; } else if (s[j] == '[') { level++; } ++j; } if (level) { if (forbidden[s[j]]) { parseError("forbidden character inside @[...]: %O", s[i-2..j]);
1e22952011-12-19Henrik Grubbström (Grubba)  } else { parseError("@[ without matching ]"); j++; }
d47c322001-03-06David Norlin  } res += xmltag("ref", xmlquote(s[i .. j - 2])); i = j; } else if (s[i] == '}') { if (!sizeof(tagstack)) { werror("///\n%O\n///\n", s); parseError("closing @} without corresponding @keyword{");
1e22952011-12-19Henrik Grubbström (Grubba)  } else { if (tagstack[0] == "xml") --inXML; else res += closetag(tagstack[0]); tagstack = tagstack[1..]; }
d47c322001-03-06David Norlin  ++i; } else if (isKeywordChar(s[i])) { int start = i; while (isKeywordChar(s[++i])) ; string keyword = s[start .. i - 1];
1e22952011-12-19Henrik Grubbström (Grubba)  if (s[i] != '{') {
d47c322001-03-06David Norlin  parseError("expected @keyword{, got %O", s[start .. i]);
1e22952011-12-19Henrik Grubbström (Grubba)  i--; } if (getKeywordType(keyword) != BRACEKEYWORD) {
61c0812001-05-09David Norlin  parseError("@%s cannot be used like this: @%s{ ... @}", keyword, keyword);
1e22952011-12-19Henrik Grubbström (Grubba)  if (keyword == "code") { // Common mistake. parseError("Converted @code{ to @expr{."); keyword = "expr"; } }
d47c322001-03-06David Norlin  ++i; tagstack = ({ keyword }) + tagstack; if (keyword == "xml") ++inXML; else res += opentag(keyword); } else parseError("expected @keyword{ or @}, got \"" + s[i-1 .. i+4] + "\""); } else if (s[i] == '\n' && !sizeof(tagstack)) { if (s[++i] == '\n') { // at least two conseq. '\n' while (s[i] == '\n') ++i; if (s[i]) // no </p><p> if it was trailing stuff res += "</p>\n<p>"; } else res += "\n"; } else { string add = s[i..i]; if (inXML == 0) add = replace(add, ({ "<", ">", "&" }), // if inside @xml{...@}, escape it ({ "&lt;", "&gt;", "&amp;" }) ); res += add; ++i; }
35eee72001-01-08David Norlin  }
1e22952011-12-19Henrik Grubbström (Grubba)  while (sizeof(tagstack)) {
d47c322001-03-06David Norlin  parseError("@" + tagstack[0] + "{ without matching @}");
1e22952011-12-19Henrik Grubbström (Grubba)  if (tagstack[0] == "xml") --inXML; else res += closetag(tagstack[0]); tagstack = tagstack[1..]; }
8ff89d2016-07-04Martin Nilsson  res = String.trim(res-"<p></p>");
43037f2001-10-03Martin Nilsson  if(!sizeof(res)) return "\n"; return "<p>" + res + "</p>\n";
35eee72001-01-08David Norlin  } // Read until the next delimiter token on the same level, or to // the end.
9eaf1d2008-06-28Martin Nilsson  protected string xmlText() {
35eee72001-01-08David Norlin  string res = ""; for (;;) {
d47c322001-03-06David Norlin  Token token = peekToken(); switch (token->type) {
35eee72001-01-08David Norlin  case TEXTTOKEN:
d47c322001-03-06David Norlin  res += xmlNode(token->text); readToken();
35eee72001-01-08David Norlin  break; case CONTAINERKEYWORD:
d47c322001-03-06David Norlin  string keyword = token->keyword; string arg = token->arg;
35eee72001-01-08David Norlin  res += "<" + keyword; string|mapping(string:string) args = getArgs(keyword, arg); if (mappingp(args)) foreach(indices(args), string s)
61ee482009-04-07Henrik Grubbström (Grubba)  res += " " + s + "=\"" + Parser.encode_html_entities(args[s]) + "\"";
35eee72001-01-08David Norlin  res += ">"; if (stringp(args)) res += args;
d47c322001-03-06David Norlin  readToken();
35eee72001-01-08David Norlin  res += xmlContainerContents(keyword);
d47c322001-03-06David Norlin  if (!(peekToken()->type == ENDKEYWORD && peekToken()->keyword == "end" + keyword))
1cd4712001-02-06Henrik Grubbström (Grubba)  parseError(sprintf("@%s without matching @end%s", keyword, keyword));
35eee72001-01-08David Norlin  res += closetag(keyword);
d47c322001-03-06David Norlin  readToken();
35eee72001-01-08David Norlin  break; default: return res; } } }
9eaf1d2008-06-28Martin Nilsson  protected string xmlContainerContents(string container) {
35eee72001-01-08David Norlin  string res = "";
d47c322001-03-06David Norlin  Token token = peekToken(); switch(token->type) {
35eee72001-01-08David Norlin  case ENDTOKEN: return ""; case TEXTTOKEN: // SHOULD WE KILL EMPTY TEXT LIKE THIS ?? {
d47c322001-03-06David Norlin  string text = token->text;
35eee72001-01-08David Norlin  if (text - "\n" - "\t" - " " == "") {
d47c322001-03-06David Norlin  readToken();
35eee72001-01-08David Norlin  break; } else ; // fall through } case CONTAINERKEYWORD: res += opentag("text") + xmlText() + closetag("text"); break; case ERRORKEYWORD:
2e0d132001-02-05David Norlin  //werror("bosse larsson: %O\n", tokens);
d47c322001-03-06David Norlin  parseError("unknown keyword: @" + token->keyword);
1e22952011-12-19Henrik Grubbström (Grubba)  readToken(); return xmlContainerContents(container);
35eee72001-01-08David Norlin  } for (;;) {
d47c322001-03-06David Norlin  token = peekToken(); if (! (<SINGLEKEYWORD, DELIMITERKEYWORD>) [token->type] )
35eee72001-01-08David Norlin  return res;
2e0d132001-02-05David Norlin  string single = 0; array(string) keywords = ({});
35eee72001-01-08David Norlin  res += opentag("group");
1e22952011-12-19Henrik Grubbström (Grubba)  group:
d47c322001-03-06David Norlin  while ( (<SINGLEKEYWORD, DELIMITERKEYWORD>) [token->type] ) { string keyword = token->keyword; single = single || (token->type == SINGLEKEYWORD && keyword);
35eee72001-01-08David Norlin  multiset(string) allow = allowedChildren[container];
cdec892001-07-16David Norlin  if (!allow || !allow[keyword]) { string e = sprintf("@%s is not allowed inside @%s", keyword, container);
1e22952011-12-19Henrik Grubbström (Grubba)  if (allow) {
cdec892001-07-16David Norlin  e += sprintf(" (allowed children are:%{ @%s%})", indices(allow));
1e22952011-12-19Henrik Grubbström (Grubba)  } else
cdec892001-07-16David Norlin  e += " (no children are allowed)"; parseError(e);
1e22952011-12-19Henrik Grubbström (Grubba)  if (allow && sizeof(allow) == 1) { parseError("Rewriting @%s to @%s.", keyword, indices(allow)[0]); token->keyword = indices(allow)[0]; continue; } readToken(); token = peekToken(); break;
cdec892001-07-16David Norlin  }
35eee72001-01-08David Norlin 
2e0d132001-02-05David Norlin  multiset(string) allowGroup = allowGrouping[keyword] || ([]); foreach (keywords, string k)
1e22952011-12-19Henrik Grubbström (Grubba)  if (!allowGroup[k]) {
2e0d132001-02-05David Norlin  parseError("@" + keyword + " may not be grouped together with @" + k);
1e22952011-12-19Henrik Grubbström (Grubba)  break group; }
2e0d132001-02-05David Norlin  keywords += ({ keyword });
d47c322001-03-06David Norlin  string arg = token->arg;
35eee72001-01-08David Norlin  res += "<" + keyword; string|mapping(string:string) args = getArgs(keyword, arg); if (mappingp(args)) { foreach(indices(args), string s)
61ee482009-04-07Henrik Grubbström (Grubba)  res += " " + s + "=\"" + Parser.encode_html_entities(args[s]) + "\"";
35eee72001-01-08David Norlin  res += "/>"; } else if (stringp(args)) res += ">" + args + "</" + keyword + ">"; else res += "/>";
d47c322001-03-06David Norlin  readToken(); token = peekToken();
35eee72001-01-08David Norlin  }
d47c322001-03-06David Norlin  switch(token->type) {
35eee72001-01-08David Norlin  case TEXTTOKEN:
d47c322001-03-06David Norlin  // SHOULD WE KILL EMPTY TEXT LIKE THIS ??
35eee72001-01-08David Norlin  {
d47c322001-03-06David Norlin  string text = token->text;
35eee72001-01-08David Norlin  if (text - "\n" - "\t" - " " == "") {
d47c322001-03-06David Norlin  readToken();
35eee72001-01-08David Norlin  break; } else ; // fall through } case CONTAINERKEYWORD:
2e0d132001-02-05David Norlin  if (single) parseError("cannot have text after @" + single);
1e22952011-12-19Henrik Grubbström (Grubba)  else res += opentag("text") + xmlText() + closetag("text");
35eee72001-01-08David Norlin  } res += closetag("group"); } }
9eaf1d2008-06-28Martin Nilsson  protected void create(string | array(Token) s,
40ae6f2011-12-04Henrik Grubbström (Grubba)  SourcePosition|void position, .Flags|void flags)
d47c322001-03-06David Norlin  {
65340d2014-08-15Martin Nilsson  if (undefinedp(flags)) flags = .FLAG_NORMAL;
40ae6f2011-12-04Henrik Grubbström (Grubba) 
8e06a32014-09-30Martin Nilsson  this::flags = flags;
40ae6f2011-12-04Henrik Grubbström (Grubba) 
d47c322001-03-06David Norlin  if (arrayp(s)) { tokenArr = s; } else {
f671012014-08-12Per Hedbor  if (!position) error("position == 0");
d47c322001-03-06David Norlin  tokenArr = split(s, position); } tokenArr += ({ Token(ENDTOKEN, 0, 0, 0, 0) });
35eee72001-01-08David Norlin  }
1e72ec2010-08-29Henrik Grubbström (Grubba)  //! @returns //! Returns the @[MetaData] for the documentation string.
35eee72001-01-08David Norlin  MetaData getMetaData() { MetaData meta = MetaData();
f4c6ad2001-02-09David Norlin  string scopeModule = 0;
d47c322001-03-06David Norlin  while(peekToken()->type == METAKEYWORD) { Token token = readToken(); string keyword = token->keyword; string arg = token->arg; string endkeyword = 0;
35eee72001-01-08David Norlin  switch (keyword) {
9ba9e42002-12-11Henrik Grubbström (Grubba)  case "namespace":
46a28a2016-08-04Henrik Grubbström (Grubba)  case "enum":
9ba9e42002-12-11Henrik Grubbström (Grubba)  case "class": case "module": {
d47c322001-03-06David Norlin  if (endkeyword) parseError("@%s must stand alone", endkeyword);
35eee72001-01-08David Norlin  if (meta->appears) parseError("@appears before @%s", keyword); if (meta->belongs) parseError("@belongs before @%s", keyword); if (meta->type) parseError("@%s can not be combined with @%s", keyword, meta->type); meta->type = keyword;
d47c322001-03-06David Norlin  .PikeParser nameparser = .PikeParser(arg, currentPosition);
2e0d132001-02-05David Norlin  string s = nameparser->readToken();
9ba9e42002-12-11Henrik Grubbström (Grubba)  if (!isIdent(s)) {
ade4e12002-12-23Henrik Grubbström (Grubba)  if (keyword == "namespace") { if (s == "::") { s = ""; } else if (!isFloat(s)) { parseError("@%s: expected %s name, got %O", keyword, keyword, s); }
9ba9e42002-12-11Henrik Grubbström (Grubba)  } else { parseError("@%s: expected %s name, got %O", keyword, keyword, s); }
ade4e12002-12-23Henrik Grubbström (Grubba)  } if (nameparser->peekToken() == "::") {
9ba9e42002-12-11Henrik Grubbström (Grubba)  nameparser->readToken(); if (keyword != "namespace") parseError("@%s: '%s::' only allowed as @namespace name", keyword, s); }
ad66622001-02-08David Norlin  if (nameparser->peekToken() != EOF)
2a139d2001-02-15David Norlin  parseError("@%s: expected %s name, got %O", keyword, keyword, arg);
35eee72001-01-08David Norlin  meta->name = s;
9ba9e42002-12-11Henrik Grubbström (Grubba)  } break;
35eee72001-01-08David Norlin 
9ba9e42002-12-11Henrik Grubbström (Grubba)  case "endnamespace":
46a28a2016-08-04Henrik Grubbström (Grubba)  case "endenum":
9ba9e42002-12-11Henrik Grubbström (Grubba)  case "endclass": case "endmodule": { if (meta->type || meta->belongs || meta->appears || endkeyword) parseError("@%s must stand alone", keyword); meta->type = endkeyword = keyword; .PikeParser nameparser = .PikeParser(arg, currentPosition); while (nameparser->peekToken() != EOF) meta->name = (meta->name || "") + nameparser->readToken(); } break; case "decl": {
d47c322001-03-06David Norlin  if (endkeyword) parseError("@%s must stand alone", endkeyword);
f4c6ad2001-02-09David Norlin  int first = !meta->type;
35eee72001-01-08David Norlin  if (!meta->type) meta->type = "decl"; else if (meta->type != "decl") parseError("@decl can not be combined with @%s", meta->type); if (meta->appears) parseError("@appears before @decl"); if (meta->belongs) parseError("@belongs before @decl"); meta->type = "decl";
d47c322001-03-06David Norlin  .PikeParser declparser = .PikeParser(arg, currentPosition);
c748382001-01-11David Norlin  PikeObject p = declparser->parseDecl(
f4c6ad2001-02-09David Norlin  ([ "allowArgListLiterals" : 1, "allowScopePrefix" : 1 ]) ); // constants/literals + scope::
35eee72001-01-08David Norlin  string s = declparser->peekToken(); if (s != ";" && s != EOF)
2a139d2001-02-15David Norlin  parseError("@decl: expected end of line, got %O", s);
66f31b2003-11-11Henrik Grubbström (Grubba)  int i = search(p->name||"", "::");
f4c6ad2001-02-09David Norlin  if (i >= 0) { string scope = p->name[0 .. i + 1]; p->name = p->name[i + 2 ..]; if (!first && scopeModule != scope)
2a139d2001-02-15David Norlin  parseError("@decl's must have identical 'scope::' prefix");
f4c6ad2001-02-09David Norlin  scopeModule = scope; } else if (!first && scopeModule)
2a139d2001-02-15David Norlin  parseError("@decl's must have identical 'scope::' prefix");
35eee72001-01-08David Norlin  meta->decls += ({ p });
9ba9e42002-12-11Henrik Grubbström (Grubba)  } break;
35eee72001-01-08David Norlin 
d5297c2004-03-02Martin Nilsson  case "inherit": { if (endkeyword) parseError("@%s must stand alone", endkeyword); string s = .PikeParser(arg, currentPosition)->parseIdents(); if (!s) parseError("@inherits: expected identifier, got %O", arg); Inherit i = .PikeObjects.Inherit(); i->name = s; i->classname = s; meta->inherits += ({ i }); } break;
2110692012-02-05Henrik Grubbström (Grubba)  case "directive": { if (endkeyword) parseError("@%s must stand alone", endkeyword); int first = !meta->type; if (!meta->type) meta->type = "decl"; else if (meta->type != "decl") parseError("@directive can not be combined with @%s", meta->type); if (meta->appears) parseError("@appears before @directive"); if (meta->belongs) parseError("@belongs before @directive"); meta->type = "decl";
8ff89d2016-07-04Martin Nilsson  string s = String.trim(arg);
2110692012-02-05Henrik Grubbström (Grubba)  meta->decls += ({ .PikeObjects.CppDirective(s) }); } break;
9ba9e42002-12-11Henrik Grubbström (Grubba)  case "appears": {
d47c322001-03-06David Norlin  if (endkeyword) parseError("@%s must stand alone", endkeyword);
35eee72001-01-08David Norlin  if (meta->type == "class" || meta->type == "decl" || meta->type == "module" || !meta->type) { if (meta->appears) parseError("duplicate @appears"); if (meta->belongs) parseError("both @appears and @belongs");
f4c6ad2001-02-09David Norlin  if (scopeModule)
2a139d2001-02-15David Norlin  parseError("both 'scope::' and @appears");
d47c322001-03-06David Norlin  .PikeParser idparser = .PikeParser(arg, currentPosition);
35eee72001-01-08David Norlin  string s = idparser->parseIdents(); if (!s)
2a139d2001-02-15David Norlin  parseError("@appears: expected identifier, got %O", arg);
1e22952011-12-19Henrik Grubbström (Grubba)  else meta->appears = s;
35eee72001-01-08David Norlin  } else parseError("@appears not allowed here");
9ba9e42002-12-11Henrik Grubbström (Grubba)  } break;
35eee72001-01-08David Norlin 
ce8f3e2011-12-18Henrik Grubbström (Grubba)  case "global": { parseError("The @global keyword is obsolete. " "Use @belongs predef:: instead."); if (meta->type == "class" || meta->type == "decl" || meta->type == "module" || !meta->type) { if (meta->belongs) parseError("duplicate @belongs/@global"); if (meta->appears) parseError("both @appears and @belongs/@global"); if (scopeModule) parseError("both 'scope::' and @belongs/@global"); meta->belongs = "predef::"; } } break;
9ba9e42002-12-11Henrik Grubbström (Grubba)  case "belongs": {
d47c322001-03-06David Norlin  if (endkeyword) parseError("@%s must stand alone", endkeyword);
35eee72001-01-08David Norlin  if (meta->type == "class" || meta->type == "decl"
d47c322001-03-06David Norlin  || meta->type == "module" || !meta->type)
35eee72001-01-08David Norlin  { if (meta->belongs) parseError("duplicate @belongs"); if (meta->appears) parseError("both @appears and @belongs");
f4c6ad2001-02-09David Norlin  if (scopeModule)
2a139d2001-02-15David Norlin  parseError("both 'scope::' and @belongs");
d47c322001-03-06David Norlin  .PikeParser idparser = .PikeParser(arg, currentPosition);
35eee72001-01-08David Norlin  string s = idparser->parseIdents(); if (!s && idparser->peekToken() != EOF)
2a139d2001-02-15David Norlin  parseError("@belongs: expected identifier or blank, got %O", arg);
35eee72001-01-08David Norlin  meta->belongs = s || ""; // blank is allowed too, you know .. }
9ba9e42002-12-11Henrik Grubbström (Grubba)  } break;
35eee72001-01-08David Norlin 
9ba9e42002-12-11Henrik Grubbström (Grubba)  default: parseError("illegal keyword: @%s", keyword);
35eee72001-01-08David Norlin  }
d47c322001-03-06David Norlin  }
f4c6ad2001-02-09David Norlin  if (scopeModule) meta->belongs = scopeModule;
35eee72001-01-08David Norlin  return meta; }
1e72ec2010-08-29Henrik Grubbström (Grubba)  //! @returns //! Returns the documentation corresponding to the @[context] //! as an XML string. //! //! @note //! @[getMetaData()] must be called before this function.
35eee72001-01-08David Norlin  string getDoc(string context) { string xml = xmlContainerContents(context);
d47c322001-03-06David Norlin  switch (peekToken()->type) {
35eee72001-01-08David Norlin  case ENDTOKEN: break; case ERRORKEYWORD:
d47c322001-03-06David Norlin  parseError("illegal keyword: @"+ peekToken()->keyword);
35eee72001-01-08David Norlin  default: parseError("expected end of doc comment"); } return xml; } }
1e72ec2010-08-29Henrik Grubbström (Grubba) //! Split a @[block] of documentation text into segments of @[Token]s //! split on @[METAKEYWORD]s. //! //! @returns //! Each of the arrays in the returned array can be fed to //! @[Parse::create()]
d47c322001-03-06David Norlin array(array(Token)) splitDocBlock(string block, SourcePosition position) { array(Token) tokens = split(block, position); array(Token) current = ({ }); array(array(Token)) result = ({ });
9556392001-01-18David Norlin  int prevMeta = 0;
d47c322001-03-06David Norlin  foreach (tokens, Token token) { int meta = token->type == METAKEYWORD;
9556392001-01-18David Norlin  if (meta && !prevMeta && sizeof(current)) { result += ({ current }); current = ({ }); } prevMeta = meta; current += ({ token }); } result += ({ current }); return result; }
1e72ec2010-08-29Henrik Grubbström (Grubba) //! Documentation markup parser. //! //! This is a class, because you need to examine the meta lines //! @b{before@} you can determine which context to parse the //! actual doc lines in.
35eee72001-01-08David Norlin class Parse {
1e72ec2010-08-29Henrik Grubbström (Grubba)  //!
35eee72001-01-08David Norlin  inherit DocParserClass;
1e72ec2010-08-29Henrik Grubbström (Grubba) 
9eaf1d2008-06-28Martin Nilsson  protected int state; protected MetaData mMetaData = 0; protected string mDoc = 0; protected string mContext = 0;
1e72ec2010-08-29Henrik Grubbström (Grubba)  //! Parse a documentation string @[s].
40ae6f2011-12-04Henrik Grubbström (Grubba)  void create(string | array(Token) s, SourcePosition|void sp, .Flags|void flags) { ::create(s, sp, flags);
dd2d3b2001-01-09David Norlin  state = 0; }
35eee72001-01-08David Norlin 
1e72ec2010-08-29Henrik Grubbström (Grubba)  //! @returns //! Returns the @[MetaData] for the documentation string.
35eee72001-01-08David Norlin  MetaData metadata() {
d47c322001-03-06David Norlin  if (state == 0) { ++state; mMetaData = ::getMetaData(); } return mMetaData;
35eee72001-01-08David Norlin  }
1e72ec2010-08-29Henrik Grubbström (Grubba)  //! @returns //! Returns the documentation corresponding to the @[context] //! as an XML string. //! //! @note //! @[metadata()] must be called before this function.
35eee72001-01-08David Norlin  string doc(string context) {
d47c322001-03-06David Norlin  if (state == 1) { ++state; mContext == context; mDoc = ::getDoc(context); } else if (state == 0 || state > 1 && mContext != context) return 0; return mDoc;
35eee72001-01-08David Norlin  } }