view dmd/ddoc/DocComment.d @ 153:560eaedcb7a2

added lots of ddoc code, still needs much care added helpers functions in ddoc.Util
author trass3r
date Wed, 15 Sep 2010 04:18:46 +0200
parents 4092a614a9f3
children
line wrap: on
line source

module dmd.ddoc.DocComment;

import dmd.ddoc.Escape;
import dmd.ddoc.Macro;
import dmd.ddoc.Sections;
import dmd.ddoc.Util;

import dmd.Array;
import dmd.Scope;
import dmd.Dsymbol;
import dmd.OutBuffer;

//!
class DocComment
{
	Sections sections;		// Section*[]

	Section summary;
	Section copyright;
	Section macros;
	Macro** pmacrotable;
	Escape** pescapetable;

	this()
	{
		// TODO: memset(this, 0, sizeof(DocComment));
	}

	static DocComment parse(Scope sc, Dsymbol s, string comment)
	{
		uint idlen;

		// writef("parse(%s): '%s'\n", s.toChars(), comment);
		if (sc.lastdc && isDitto(comment))
		return null;

		DocComment dc = new DocComment();
		if (!comment)
		return dc;

		dc.parseSections(comment);

		foreach (Section s; dc.sections)
		{
			if (icmp("copyright", s.name, s.namelen) == 0)
			{
				dc.copyright = s;
			}
			if (icmp("macros", s.name, s.namelen) == 0)
			{
				dc.macros = s;
			}
		}

		sc.lastdc = dc;
		return dc;
	}
	
	/************************************************
	 * Parse macros out of Macros: section.
	 * Macros are of the form:
	 *	  name1 = value1
	 *
	 *	  name2 = value2
	 */
	static void parseMacros(Escape** pescapetable, Macro** pmacrotable, ubyte* m, uint mlen)
	{/+
		unsigned char *p = m;
		unsigned len = mlen;
		unsigned char *pend = p + len;

		unsigned char *tempstart;
		unsigned templen;

		unsigned char *namestart;
		unsigned namelen = 0;	   // !=0 if line continuation

		unsigned char *textstart;
		unsigned textlen;

		while (p < pend)
		{
			// Skip to start of macro
			while (1)
			{
				if (p >= pend)
					goto Ldone;
				switch (*p)
				{
					case ' ':
					case '\t':
						p++;
						continue;

					case '\n':
						p++;
						goto Lcont;

					default:
						if (isIdStart(p))
							break;
						if (namelen)
							goto Ltext;			 // continuation of prev macro
						goto Lskipline;
				}
				break;
			}
			tempstart = p;

			while (1)
			{
				if (p >= pend)
					goto Ldone;
				if (!isIdTail(p))
					break;
				p += utfStride(p);
			}
			templen = p - tempstart;

			while (1)
			{
				if (p >= pend)
					goto Ldone;
				if (!(*p == ' ' || *p == '\t'))
					break;
				p++;
			}

			if (*p != '=')
			{   if (namelen)
					goto Ltext;			 // continuation of prev macro
				goto Lskipline;
			}
			p++;
			if (p >= pend)
				goto Ldone;

			if (namelen)
			{   // Output existing macro
			L1:
				//printf("macro '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart);
				if (icmp("ESCAPES", namestart, namelen) == 0)
					parseEscapes(pescapetable, textstart, textlen);
				else
					Macro.define(pmacrotable, namestart, namelen, textstart, textlen);
				namelen = 0;
				if (p >= pend)
					break;
			}

			namestart = tempstart;
			namelen = templen;

			while (p < pend && (*p == ' ' || *p == '\t'))
				p++;
			textstart = p;

		  Ltext:
			while (p < pend && *p != '\n')
				p++;
			textlen = p - textstart;

			// Remove trailing \r if there is one
			if (p > m && p[-1] == '\r')
				textlen--;

			p++;
			//printf("p = %p, pend = %p\n", p, pend);

		 Lcont:
			continue;

		 Lskipline:
			// Ignore this line
			while (p < pend && *p++ != '\n') {}
		}
	Ldone:
		if (namelen)
			goto L1;				// write out last one
	+/}
	
	/**************************************
	 * Parse escapes of the form:
	 *	  /c/string/
	 * where c is a single character.
	 * Multiple escapes can be separated
	 * by whitespace and/or commas.
	 */
	static void parseEscapes(Escape** pescapetable, ubyte* textstart, uint textlen)
	{/+
		   Escape *escapetable = *pescapetable;

			if (!escapetable)
			{   escapetable = new Escape;
				*pescapetable = escapetable;
			}
			unsigned char *p = textstart;
			unsigned char *pend = p + textlen;

			while (1)
			{
				while (1)
				{
					if (p + 4 >= pend)
						return;
					if (!(*p == ' ' || *p == '\t' || *p == '\n' || *p == ','))
						break;
					p++;
				}
				if (p[0] != '/' || p[2] != '/')
					return;
				unsigned char c = p[1];
				p += 3;
				unsigned char *start = p;
				while (1)
				{
					if (p >= pend)
						return;
					if (*p == '/')
						break;
					p++;
				}
				size_t len = p - start;
				char *s = (char *)memcpy(mem.malloc(len + 1), start, len);
				s[len] = 0;
				escapetable.strings[c] = s;
				//printf("%c = '%s'\n", c, s);
				p++;
			}
	+/}

	/*****************************************
	 * Parse next paragraph out of *pcomment.
	 * Update *pcomment to point past paragraph.
	 * Returns null if no more paragraphs.
	 * If paragraph ends in 'identifier:',
	 * then (*pcomment)[0 .. idlen] is the identifier.
	 */
	void parseSections(string comment)
	{
		ubyte*p;
		ubyte*pstart;
		ubyte*pend;
		ubyte*idstart;
		uint idlen;

		ubyte*name = null;
		size_t namelen = 0;

		//printf("parseSections('%s')\n", comment);
		p = comment;
		while (*p)
		{
		p = skipwhitespace(p);
		pstart = p;

		/* Find end of section, which is ended by one of:
		 *	'identifier:' (but not inside a code section)
		 *	'\0'
		 */
		idlen = 0;
		int inCode = 0;
		while (1)
		{
			// Check for start/end of a code section
			if (*p == '-')
			{
			int numdash = 0;
			while (*p == '-')
			{
				++numdash;
				p++;
			}
			// BUG: handle UTF PS and LS too
			if (!*p || *p == '\r' || *p == '\n' && numdash >= 3)
				inCode ^= 1;
			}

			if (!inCode && isIdStart(p))
			{
				ubyte*q = p + utfStride(p);
				while (isIdTail(q))
					q += utfStride(q);
				if (*q == ':')	// identifier: ends it
				{
					idlen = q - p;
					idstart = p;
					for (pend = p; pend > pstart; pend--)
					{
						if (pend[-1] == '\n')
						break;
					}
					p = q + 1;
					break;
				}
			}
			while (1)
			{
			if (!*p)
			{   pend = p;
				goto L1;
			}
			if (*p == '\n')
			{   p++;
				if (*p == '\n' && !summary && !namelen)
				{
				pend = p;
				p++;
				goto L1;
				}
				break;
			}
			p++;
			}
			p = skipwhitespace(p);
		}
		  L1:

		if (namelen || pstart < pend)
		{
			Section *s;
			if (icmp("Params", name, namelen) == 0)
			s = new ParamSection();
			else if (icmp("Macros", name, namelen) == 0)
			s = new MacroSection();
			else
			s = new Section();
			s.name = name;
			s.namelen = namelen;
			s.body_ = pstart;
			s.bodylen = pend - pstart;
			s.nooutput = 0;

			//printf("Section: '%.*s' = '%.*s'\n", s.namelen, s.name, s.body_len, s.body);

			sections.push(s);

			if (!summary && !namelen)
			summary = s;
		}

		if (idlen)
		{   name = idstart;
			namelen = idlen;
		}
		else
		{   name = null;
			namelen = 0;
			if (!*p)
			break;
		}
		}
	}
	
	void writeSections(Scope sc, Dsymbol s, OutBuffer buf)
	{
		//printf("DocComment.writeSections()\n");
		if (sections.dim)
		{
			buf.writestring("$(DDOC_SECTIONS \n");
			for (int i = 0; i < sections.dim; i++)
			{
				Section sec = cast(Section)sections.data[i];
	
				if (sec.nooutput)
					continue;
				//printf("Section: '%.*s' = '%.*s'\n", sec.namelen, sec.name, sec.bodylen, sec.body);
				if (sec.namelen || i)
					sec.write(this, sc, s, buf);
				else
				{
					buf.writestring("$(DDOC_SUMMARY ");
					uint o = buf.offset;
					buf.write(sec.body_, sec.bodylen);
					highlightText(sc, s, buf, o);
					buf.writestring(")\n");
				}
			}
			buf.writestring(")\n");
		}
		else
		{
		buf.writestring("$(DDOC_BLANKLINE)\n");
		}
	}
}