diode.license

module diode.license;


//! This is the license for the diode.
enum license;

global licenseArray: string[];

fn __ctor() { }

diode.vdoc.as_code

//! Code to format vdoc objects as code.Hmm 
module diode.vdoc.as_code;


//! Formats a vdoc module into code.
class FormatAsCode : Value
{
public:
	this(d: Driver, e: Engine, root: VdocRoot, v: Value, type: string) { }
	fn toText(n: ir.Node, sink: scope (Sink)) { }
}

struct State
{
public:
	drv: Driver;
	mod: Parent;
	root: VdocRoot;
	engine: Engine;
	parent: Parent;
	tabs: string;
	tabsProt: string;
	lastKind: Kind;
	lastAccess: Access;
	hasProt: bool;


public:
	fn setup(drv: Driver, engine: Engine, root: VdocRoot, mod: Parent, parent: Parent) { }
	fn setup(oldState: State, parent: Parent) { }
}

fn flushaProtAndNewLine(s: State, access: Access, kind: Kind, spacing: string, sink: scope (Sink)) { }
fn drawName(s: State, named: Named, htmlClass: string, sink: scope (Sink)) { }
fn drawName(s: State, named: Named, name: string, htmlClass: string, sink: scope (Sink)) { }
fn drawModule(s: State, sink: scope (Sink)) { }
fn drawChildren(s: State, sink: scope (Sink)) { }
fn drawBrief(s: State, n: Named, sink: scope (Sink)) { }
fn drawParentList(sink: scope (Sink), parents: scope (scope (string)[])) { }
fn drawImports(s: State, access: Access, sink: scope (Sink)) { }
fn drawEnums(s: State, access: Access, sink: scope (Sink)) { }
fn drawEnum(s: State, c: Parent, sink: scope (Sink)) { }
fn drawAliases(s: State, access: Access, sink: scope (Sink)) { }
fn drawAlias(s: State, c: Alias, sink: scope (Sink)) { }
fn drawEnumDecls(s: State, access: Access, sink: scope (Sink)) { }
fn drawEnumDecl(s: State, c: EnumDecl, sink: scope (Sink)) { }
fn drawFields(s: State, access: Access, sink: scope (Sink)) { }
fn drawLocals(s: State, access: Access, sink: scope (Sink)) { }
fn drawGlobals(s: State, access: Access, sink: scope (Sink)) { }
fn drawVariables(s: State, access: Access, storage: Storage, sink: scope (Sink)) { }
fn drawFns(s: State, access: Access, sink: scope (Sink)) { }
fn drawCtors(s: State, access: Access, sink: scope (Sink)) { }
fn drawMembers(s: State, access: Access, sink: scope (Sink)) { }
fn drawCtor(s: State, f: Function, sink: scope (Sink)) { }
fn drawFn(s: State, f: Function, prefix: string, sink: scope (Sink)) { }
fn drawInterfaces(s: State, access: Access, sink: scope (Sink)) { }
fn drawInterface(s: State, c: Parent, sink: scope (Sink)) { }
fn drawClasses(s: State, access: Access, sink: scope (Sink)) { }
fn drawClass(s: State, c: Parent, sink: scope (Sink)) { }
fn drawUnions(s: State, access: Access, sink: scope (Sink)) { }
fn drawStructs(s: State, access: Access, sink: scope (Sink)) { }
fn drawAggrs(s: State, access: Access, kind: Kind, prefix: string, sink: scope (Sink)) { }
fn drawAggr(s: State, c: Parent, prefix: string, sink: scope (Sink)) { }

diode.vdoc.filter

//! Code handle vdoc filters.
module diode.vdoc.filter;


//! Helper class for Filters.
class FilterValue : Value
{
public:
	html: bool;
	named: Named;


public:
	this(named: Named, html: bool) { }
}

//! Filter for brief.
class FilterBrief : FilterValue
{
public:
	this(named: Named) { }
	fn toText(n: ir.Node, sink: scope (Sink)) { }
}

//! Filter for brief.
class FilterProto : FilterValue
{
public:
	this(named: Named) { }
	fn toText(n: ir.Node, sink: scope (Sink)) { }
}

//! Filter for formating of content of DocComments into HTML.
class FilterContent : FilterValue
{
public:
	this(named: Named, html: bool) { }
	fn toText(n: ir.Node, sink: scope (Sink)) { }
}

//! Filter for formating of full DocComments into HTML.
class FilterFull : FilterValue
{
public:
	this(named: Named) { }
	fn toText(n: ir.Node, sink: scope (Sink)) { }
}

fn handleDocCommentFilter(d: Driver, e: Engine, root: VdocRoot, v: Value, filter: string, type: string) Value { }
//! Print the brief as regular text.
fn drawBriefText(named: Named, sink: scope (Sink)) { }
//! Print the raw content as markdown.
fn drawContentMD(named: Named, sink: scope (Sink)) { }
//! Print the content as html as processed by markdown.
fn drawContentHTML(named: Named, sink: scope (Sink)) { }
//! Print the full content as HTML.
fn drawFullHTML(named: Named, sink: scope (Sink)) { }
//! Print extra function doccomments, like return and parameters.
fn drawFullFunctionHTML(func: Function, sink: scope (Sink)) { }
//! Print the content as html as processed by markdown.
fn drawProtoHTML(named: Named, sink: scope (Sink)) { }
fn drawProtoNameHTML(sink: scope (Sink), name: string) { }
fn drawProtoPrefixAndNameHTML(sink: scope (Sink), prefix: string, name: string) { }
fn drawProtoAggr(named: Named, sink: scope (Sink), prefix: string) { }
fn drawProtoVar(named: Named, sink: scope (Sink)) { }
fn drawProtoFunc(named: Named, sink: scope (Sink)) { }

diode.vdoc

module diode.vdoc;


//! Type of doc object.
enum Kind
{
	Invalid,
	Arg,
	Enum,
	EnumDecl,
	Alias,
	Class,
	Union,
	Group,
	Import,
	Return,
	Struct,
	Module,
	Member,
	Function,
	Variable,
	Interface,
	Destructor,
	Constructor,
}

//! Access of a symbool.
enum Access
{
	Public,
	Protected,
	Private,
}

//! Storage of a variable.
enum Storage
{
	Field,
	Global,
	Local,
}

//! The object that templates accesses the rest of the documentation nodes
//! from.
class VdocRoot : Value
{
public:
	//! Current thing that a vdoc template is rendering.
	current: Value;
	//! Set holding config data.
	set: Set;


public:
	this() { }
	fn modules() Parent[] { }
	fn groups() Parent[] { }
	fn ident(n: ir.Node, key: string) Value { }
	//! Return a named object of the given name.
	fn findNamed(name: string) Named { }
	//! Add a group, mostly used to create groups implicitly.
	fn addGroup(name: string, title: string, raw: string) Parent { }
	//! Sets the children and does any upfront processing needed.
	fn setChildren(children: Value[]) { }
}

//! Base class for all doc objects.
class Base : Value
{
public:
	kind: Kind;


public:
	this() { }
}

//! Base class for all doc objects that can have names.
class Named : Base
{
public:
	//! Printable name of this object.
	name: string;
	//! Ident for looking up this Named thing.
	search: string;
	//! Access of this named object.
	access: Access;
	//! Raw doccomment string.
	raw: string;
	//! Where to find the per thing documentation page, if any.
	url: string;
	//! A unique identifier for this object.
	tag: string;
	//! The content of the doccomment, in markdown form.
	content: string;
	//! The brief in text form.
	brief: string;
	//! The groups this named is in.
	ingroup: Value[];
	//! The sa commands for this Named thing.
	sa: string[];
	//! The throw commands for this Named thing.
	_throw: string[];
	//! The se commands for this Named thing.
	se: string[];
	//! The parsed name of parent class to the class.
	parentStr: string;
	//! The full name of parent class to the class.
	parentFullStr: string;
	//! The parsed name of the interface(s) to the class or interface.
	interfacesStr: string[];
	//! The full name of the interface(s) to the class or interface.
	interfacesFullStr: string[];


public:
	this() { }
	fn ident(n: ir.Node, key: string) Value { }
}

//! Regular imports and bound imports.
class Import : Named
{
public:
	//! Is this import bound to a name.
	bind: string;


public:
	this() { }
	fn ident(n: ir.Node, key: string) Value { }
}

//! A single freestanding enum or value part of a enum.
class EnumDecl : Named
{
public:
	//! Is this a enum
	isStandalone: bool;


public:
	this() { }
	fn ident(n: ir.Node, key: string) Value { }
}

//! Base class for things with children, like Module, Class, Structs.
class Parent : Named
{
public:
	//! The children of this Named thing.
	children: Value[];


public:
	this() { }
	fn ident(n: ir.Node, key: string) Value { }
}

//! Argument to a function.
class Arg : Base
{
public:
	name: string;
	type: string;
	typeFull: string;
	//! The doccomment content for this argument.
	content: string;


public:
	this() { }
	fn ident(n: ir.Node, key: string) Value { }
}

//! Return from a function.
class Return : Base
{
public:
	type: string;
	typeFull: string;
	//! The doccomment content for this return.
	content: string;


public:
	this() { }
	fn ident(n: ir.Node, key: string) Value { }
}

//! A variable or field on a aggregate.
class Variable : Named
{
public:
	type: string;
	typeFull: string;
	storage: Storage;


public:
	this() { }
	fn ident(n: ir.Node, key: string) Value { }
}

//! An alias declaration.
class Alias : Named
{
public:
	type: string;
	typeFull: string;


public:
	this() { }
	fn ident(n: ir.Node, key: string) Value { }
}

//! A function or constructor, destructor or method on a aggreegate.
class Function : Named
{
public:
	args: Value[];
	rets: Value[];
	linkage: string;
	hasBody: bool;
	forceLabel: bool;
	isFinal: bool;
	isScope: bool;
	isAbstract: bool;
	isProperty: bool;
	isOverride: bool;


public:
	this() { }
	fn ident(n: ir.Node, key: string) Value { }
}

//! A special array that you can access fields on to filter the members.
class Collection : Array
{
public:
	this(vals: Value[]) { }
	fn ident(n: ir.Node, key: string) Value { }


public:
	static fn make(vals: Value[], key: string) Value { }
}

fn accessToString(access: Access) string { }
//! Create a text Value, nil if string is empty.
fn makeNilOrText(text: string) Value { }
//! Create a array Value, nil if string is empty.
fn makeNilOrArray(array: Value[]) Value { }

diode.vdoc.parser

module diode.vdoc.parser;


//! Parser for getting defgroup name and title.
class DocCommentDefGroup : vdoc.DocSink
{
public:
	groupName: string;
	groupTitle: string;


public:
	this() { }
	fn parseRaw(raw: string, defgroup: string, title: string) { }
	fn defgroup(sink: scope (Sink), group: string, text: string) { }
	fn start(sink: scope (Sink)) { }
	fn end(sink: scope (Sink)) { }
	fn briefStart(sink: scope (Sink)) { }
	fn briefEnd(sink: scope (Sink)) { }
	fn sectionStart(sink: scope (Sink), sec: vdoc.DocSection) { }
	fn sectionEnd(sink: scope (Sink), sec: vdoc.DocSection) { }
	fn paramStart(sink: scope (Sink), direction: string, arg: string) { }
	fn paramEnd(sink: scope (Sink)) { }
	fn p(sink: scope (Sink), state: vdoc.DocState, d: string) { }
	fn link(sink: scope (Sink), state: vdoc.DocState, target: string, text: string) { }
	fn content(sink: scope (Sink), state: vdoc.DocState, cnt: string) { }
	fn ingroup(sink: scope (Sink), group: string) { }
}

//! Parse the given data and add the vdocRoot.
fn parse(vdocRoot: VdocRoot, data: string) { }

diode.vdoc.brief

//! Code to generate brief comments from full vdoc doccomments.
module diode.vdoc.brief;


//! A Markdown visitor that removes most of the special formating.
class PlainText : Visitor
{
public:
	this(lineLimit: size_t) { }
	fn visit(n: Text, sink: scope (Sink)) { }
	fn visit(n: Code, sink: scope (Sink)) { }
	fn visit(n: Softbreak, sink: scope (Sink)) { }
	fn visit(n: Linebreak, sink: scope (Sink)) { }
	fn enter(n: Link, sink: scope (Sink)) { }
	fn leave(n: Link, sink: scope (Sink)) { }
	fn enter(n: BlockQuote, sink: scope (Sink)) { }
	fn enter(n: Item, sink: scope (Sink)) { }
	fn enter(n: List, sink: scope (Sink)) { }
	fn enter(n: Heading, sink: scope (Sink)) { }
	fn leave(n: Paragraph, sink: scope (Sink)) { }
	fn enter(n: Document, sink: scope (Sink)) { }
	fn enter(n: Image, sink: scope (Sink)) { }
	fn enter(n: Paragraph, sink: scope (Sink)) { }
	fn enter(n: Strong, sink: scope (Sink)) { }
	fn enter(n: Emph, sink: scope (Sink)) { }
	fn leave(n: Document, sink: scope (Sink)) { }
	fn leave(n: Strong, sink: scope (Sink)) { }
	fn leave(n: Emph, sink: scope (Sink)) { }
	fn leave(n: Image, sink: scope (Sink)) { }
	fn leave(n: Heading, sink: scope (Sink)) { }
	fn leave(n: Item, sink: scope (Sink)) { }
	fn leave(n: List, sink: scope (Sink)) { }
	fn leave(n: BlockQuote, sink: scope (Sink)) { }
	fn visit(n: HtmlBlock, sink: scope (Sink)) { }
	fn visit(n: CodeBlock, sink: scope (Sink)) { }
	fn visit(n: ThematicBreak, sink: scope (Sink)) { }
	fn visit(n: HtmlInline, sink: scope (Sink)) { }


protected:
	//! Have we stopped processing text.
	mStopped: bool;
	//! Used to insert spaces between words and instead of softbreaks.
	mWriteSpace: bool;
	//! The current link that has not yet been flushed to the sink.
	mNewLink: Link;
	//! Link that has been flushed to the sink, and should be closed.
	mAppliedLink: Link;
	//! The current length of the line we are writing.
	mLineLength: size_t;
	//! Limit for the number of characters on a line.
	mLineLimit: size_t;


protected:
	//! Write a string to the sink, will compact whitespace and insert newlines
	//! when the line will break the mLineLimit.
	fn writeText(str: string, sink: scope (Sink)) { }
	//! Flushes spaces and links to the sink.
	fn flushThings(sink: scope (Sink)) { }
	//! Inserts a newline and resets link.
	fn insertNewLine(sink: scope (Sink)) { }
}

fn generateAutoBrief(str: string) string { }

diode.vdoc.processor

//! Code to process vdoc objects raw doccomments.
module diode.vdoc.processor;


//! Main class for processing vdoc objects.
class Processor : DocCommentParser
{
public:
	groups: Parent[string];


public:
	this(root: VdocRoot) { }
}

//! A single parameter result.
class DocCommentParam
{
public:
	arg: string;
	dir: string;
	doc: string;


public:
	this() { }
}

//! Helper class for DocComments.
class DocCommentParser : DocSink
{
public:
	//! For lookups.
	root: VdocRoot;
	//! The full comment content.
	full: StringSink;
	//! String sink for params, briefs and more.
	temp: StringSink;
	//! Current param.
	param: DocCommentParam;
	//! The result of the processing.
	results: DocCommentResult;
	//! ` directive been processed.
	hasBrief: bool;


public:
	this(root: VdocRoot) { }
	fn parseRaw(raw: string) { }
	fn ingroup(sink: scope (Sink), group: string) { }
	fn sectionStart(sink: scope (Sink), sec: DocSection) { }
	fn sectionEnd(sink: scope (Sink), sec: DocSection) { }
	fn paramStart(sink: scope (Sink), direction: string, arg: string) { }
	fn paramEnd(sink: scope (Sink)) { }
	fn briefStart(sink: scope (Sink)) { }
	fn briefEnd(sink: scope (Sink)) { }
	fn p(sink: scope (Sink), state: DocState, d: string) { }
	fn link(sink: scope (Sink), state: DocState, target: string, text: string) { }
	fn content(sink: scope (Sink), state: DocState, d: string) { }
	fn defgroup(sink: scope (Sink), group: string, text: string) { }
	fn start(sink: scope (Sink)) { }
	fn end(sink: scope (Sink)) { }
}

//! Results from a doccomment parsing.
struct DocCommentResult
{
public:
	//! The main content for this doccomment.
	content: string;
	//! Brief doccomment.
	brief: string;
	//! The groups this comment is in.
	ingroups: string[];
	//! Return documentation.
	ret: string;
	//! Params for functions.
	params: DocCommentParam[];
	//! See also sections.
	sa: string[];
	//! Throws sections.
	_throw: string[];
	//! Side-Effect sections.
	se: string[];
	//! The doccomment content form the return command.
	returnContent: string;
}

//! Processes the given VdocRoot.
fn process(vdocRoot: VdocRoot) { }

diode.tester

//! Small testing harness.
module diode.tester;


//! Single test files are split with this marker.
enum Split;

class Tester : Engine
{
public:
	this(env: Set) { }
	fn handleError(str: string) { }
}

fn runTest(args: string[]) i32 { }
fn runTest(srcFile: string) i32 { }
fn runTest(srcFile: string, cmpFile: string) i32 { }
fn compileAndCompare(srcText: string, cmpText: string, srcFile: string) i32 { }
fn getTestEnv() Set { }

diode.driver

module diode.driver;


//! Main focal point of Diode.
class DiodeDriver : Driver
{
public:
	this(settings: Settings) { }
	fn setConfig(source: string, filename: string) { }
	fn addBuiltins() { }
	fn processDoc() { }
	fn addLayout(source: string, filename: string) { }
	fn addInclude(source: string, filename: string) { }
	fn renderFile(source: string, filename: string, output: string) { }
	fn addDoc(source: string, filename: string) { }
	fn addDocTemplate(source: string, filename: string) { }
	fn verbose(fmt: string) { }
	fn info(fmt: string) { }
	fn warning(fmt: string) { }
	fn addInclude(file: File, filename: string) { }
	fn addLayout(file: File, filename: string) { }
	fn addDocTemplate(file: File, filename: string) { }
	fn renderFileTo(file: File, output: string) { }


protected:
	mLayouts: File[string];
	mRoot: Set;
	mSite: Set;
	mVdoc: VdocRoot;
	mModules: Array;
	mEngine: DriverEngine;
	mDocGroup: File;
	mDocModule: File;
	mDocModules: File;
	mVerbose: bool;
	mSiteSettings: json.Value;
	mPrintUndocumented: bool;


protected:
	fn tag(val: Value, parentWithUrl: Parent, prev: Value) { }
	fn setUrl(named: Named, parentWithUrl: Named) { }
	fn getTag(base: string) string { }
	fn getUrl(named: Named, parentWithUrl: Named) string { }
	fn getName(dir: string, base: string) string { }
	fn createFile(source: string, filename: string) File { }
	fn selectType(layout: File, contents: File) Contents { }
	fn getAndCheckExt(base: string) File.Ext { }
	fn getLayout(key: string) File { }
	fn getNeededLayout(file: File) File { }
	fn buildRootEnv() { }
}

class DriverEngine : Engine
{
public:
	file: File;


public:
	this(d: DiodeDriver, root: Set) { }
	fn addInclude(f: File, filename: string) { }
	fn renderFile(f: File, sink: scope (Sink)) { }
	fn handleFilter(n: ir.Node, ident: string, child: Value, args: Value[], sink: scope (Sink)) { }
	fn handleInclude(p: ir.Include, e: Set, sink: scope (Sink)) { }
}

//! A file to be rendered. Used for includes and layouts as well.
class File
{
public:
	enum Ext
	{
		HTML,
		Markdown,
	}


public:
	filename: string;
	fullName: string;
	layout: string;
	header: Header;
	file: ir.File;
	ext: Ext;


public:
	this() { }
	fn getOption(key: string, def: string) string { }
}

//! Special Value for the contents value.
class Contents : Value
{
public:
	engine: DriverEngine;
	file: File;
	env: Set;


public:
	this() { }
	fn toText(n: ir.Node, sink: scope (Sink)) { }
}

//! Special Value for Markdown to HTML contents.
class MarkdownContents : Contents
{
public:
	this() { }
	fn toText(n: ir.Node, sink: scope (Sink)) { }
}

//! Implementation of relative_url filter, appends baseurl.
fn filterRelativeUrl(drv: Driver, str: string) string { }
//! Implementation of absolute_url filter, appends url and baseurl.
fn filterAbsoluteUrl(drv: Driver, str: string) string { }

diode.errors

module diode.errors;


class DiodeException : Exception
{
public:
	this(msg: string) { }
}

class EvalException : DiodeException
{
public:
	n: ir.Node;


public:
	this(n: ir.Node, msg: string) { }
}

fn makeNoExtension(file: string) DiodeException { }
fn makeExtensionNotSupported(file: string) DiodeException { }
fn makeLayoutNotFound(file: string, layout: string) DiodeException { }
fn makeConversionNotSupported(layout: string, contents: string) DiodeException { }
fn makeNoField(n: ir.Node, key: string) EvalException { }
fn makeNotSet(n: ir.Node) EvalException { }
fn makeNotText(n: ir.Node) EvalException { }
fn makeNotArray(n: ir.Node) EvalException { }

diode.interfaces

module diode.interfaces;


//! Main class driving everything.
class Driver
{
public:
	settings: Settings;


public:
	this(settings: Settings) { }
	fn addBuiltins();
	fn processDoc();
	fn setConfig(source: string, filename: string);
	fn addLayout(source: string, filename: string);
	fn addInclude(source: string, filename: string);
	fn addDoc(source: string, filename: string);
	fn addDocTemplate(source: string, filename: string);
	fn renderFile(source: string, filename: string, output: string);
	fn verbose(fmt: string);
	fn info(fmt: string);
	fn warning(fmt: string);
}

//! Holds settings for Diode.
class Settings
{
public:
	enum vdocDirDefault;
	enum outputDirDefault;
	enum layoutDirDefault;
	enum includeDirDefault;


public:
	sourceDir: string;
	vdocDir: string;
	outputDir: string;
	layoutDir: string;
	includeDir: string;
	urlFromCommandLine: bool;
	url: string;
	baseurlFromCommandLine: bool;
	baseurl: string;
	//! Temporary hack for guru untill we add vdoc cross-reference code.
	guruHackSuffix: string;


public:
	this() { }
	fn fillInDefaults() { }
	fn processPath(val: string, def: string) { }
}

main

//! Holds the main function and some small test code.
module main;


enum ParseState
{
	Normal,
	Skip,
	OutputDir,
	SourceDir,
	Baseurl,
}

fn main(args: string[]) i32 { }
fn parseArgs(args: string[], s: Settings) string[] { }
fn splitUrl(str: string, server: string, address: string) bool { }
fn test(args: string[]) i32 { }
fn findConfig(d: DiodeDriver) { }
fn addFiles(d: DiodeDriver, files: string[]) { }
fn renderFiles(d: Driver) { }
fn addLayouts(d: Driver) { }
fn addIncludes(d: Driver) { }
fn addVdocTemplates(d: Driver) { }

diode.parser.frontmatter

module diode.parser.frontmatter;


class Header
{
public:
	map: string[string];


public:
	this() { }
}

fn parse(src: Source, err: ErrorDg) Header { }
//! Does not advance the source, just check if the next 3 chars are
//! dashes.
fn isTripleDash(src: Source) bool { }
//! Does what it says on the tin, yes I felt bad naming this function.
fn skipWhiteAndCheckIfEmptyLine(src: Source) bool { }
fn skipWhiteTillAfterColon(src: Source, err: ErrorDg) { }
fn getIdent(src: Source, err: ErrorDg) string { }
fn getRestOfLine(src: Source) string { }

diode.parser.errors

module diode.parser.errors;


alias ErrorDg = void delegate(string);

fn makeBadHeader(loc: Location, err: ErrorDg) { }

liquid.eval.engine

module liquid.eval.engine;


class Engine : ir.Visitor
{
public:
	env: Set;
	v: Value;


public:
	this(env: Set) { }
	fn handleFilter(n: ir.Node, ident: string, child: Value, args: Value[], sink: scope (Sink)) { }
	fn handleError(str: string) { }
	fn handleInclude(i: ir.Include, env: Set, sink: scope (Sink)) { }
	fn visit(t: ir.Text, sink: scope (Sink)) Status { }
	fn leave(p: ir.Print, sink: scope (Sink)) Status { }
	fn enter(i: ir.If, sink: scope (Sink)) Status { }
	fn enter(f: ir.For, sink: scope (Sink)) Status { }
	fn leave(a: ir.Assign, sink: scope (Sink)) Status { }
	fn visit(p: ir.Include, sink: scope (Sink)) Status { }
	fn enter(p: ir.BinOp, sink: scope (Sink)) Status { }
	fn leave(p: ir.BinOp, sink: scope (Sink)) Status { }
	fn enter(p: ir.Index, sink: scope (Sink)) Status { }
	fn leave(p: ir.Index, sink: scope (Sink)) Status { }
	fn leave(p: ir.Access, sink: scope (Sink)) Status { }
	fn enter(p: ir.Filter, sink: scope (Sink)) Status { }
	fn visit(p: ir.Ident, sink: scope (Sink)) Status { }
	fn visit(p: ir.StringLiteral, sink: scope (Sink)) Status { }
	fn visit(p: ir.BoolLiteral, sink: scope (Sink)) Status { }
	fn visit(p: ir.NumberLiteral, sink: scope (Sink)) Status { }
	fn enter(ir.Assign, scope (Sink)) Status { }
	fn enter(ir.File, scope (Sink)) Status { }
	fn leave(ir.File, scope (Sink)) Status { }
	fn enter(ir.Access, scope (Sink)) Status { }
	fn leave(ir.Filter, scope (Sink)) Status { }
	fn enter(ir.Print, scope (Sink)) Status { }
	fn leave(ir.If, scope (Sink)) Status { }
	fn leave(ir.For, scope (Sink)) Status { }
}

liquid.eval.json

//! This module holds code to parse json files into eval sets and values.
module liquid.eval.json;


fn toValue(v: json.Value) Value { }
fn toSet(v: json.Value) Set { }
fn toArray(v: json.Value) Array { }

liquid.eval.value

module liquid.eval.value;


//! Use the IR visitor Sink.
alias Sink = ir.Sink;

class Value
{
public:
	this() { }
	fn ident(n: ir.Node, key: string) Value { }
	fn toText(n: ir.Node, sink: scope (Sink)) { }
	fn toArray(n: ir.Node) Value[] { }
	fn toBool(n: ir.Node) bool { }
	fn toSize(n: ir.Node) Value { }
	fn opEquals(other: Value) bool { }
	fn opIndex(other: Value) Value { }
	fn contains(other: Value) bool { }
	fn opCmp(other: Value) i32 { }
}

class Nil : Value
{
public:
	this() { }
	fn toBool(n: ir.Node) bool { }
	fn opEquals(other: Value) bool { }
}

class Number : Value
{
public:
	value: f64;
	integer: bool;


public:
	this(value: f64, integer: bool) { }
	fn toText(n: ir.Node, sink: scope (Sink)) { }
	fn opEquals(other: Value) bool { }
	fn opCmp(otherVal: Value) i32 { }
}

class Bool : Value
{
public:
	value: bool;


public:
	this(value: bool) { }
	fn toText(n: ir.Node, sink: scope (Sink)) { }
	fn toBool(n: ir.Node) bool { }
	fn opEquals(other: Value) bool { }
}

class Text : Value
{
public:
	text: string;


public:
	this(text: string) { }
	fn toText(n: ir.Node, sink: scope (Sink)) { }
	fn toBool(n: ir.Node) bool { }
	fn toSize(n: ir.Node) Value { }
	fn opEquals(other: Value) bool { }
	fn contains(otherVal: Value) bool { }
}

class Array : Value
{
public:
	vals: Value[];


public:
	this(vals: Value[]) { }
	fn toArray(n: ir.Node) Value[] { }
	fn toSize(n: ir.Node) Value { }
	fn ident(n: ir.Node, key: string) Value { }
	fn contains(other: Value) bool { }
	fn opIndex(index: Value) Value { }
}

class Set : Value
{
public:
	parent: Set;
	ctx: Value[string];


public:
	this() { }
	this(parent: Set) { }
	fn ident(n: ir.Node, key: string) Value { }
}

liquid.eval

module liquid.eval;

public import liquid.eval.value;
public import liquid.eval.engine;

liquid.util.build

module liquid.util.build;


fn bFile() ir.File { }
fn bPrint(e: ir.Exp) ir.Print { }
fn bText(str: string) ir.Text { }
fn bAssign(ident: string, exp: ir.Exp) ir.Assign { }
fn bInclude(filename: string, assigns: ir.Assign[]) ir.Include { }
fn bFor(ident: string, exp: ir.Exp, nodes: ir.Node[]) ir.For { }
fn bBinOp(type: ir.BinOp.Type, l: ir.Exp, r: ir.Exp) ir.BinOp { }
fn bIndex(child: ir.Exp, index: ir.Exp) ir.Index { }
fn bIf(invert: bool, exp: ir.Exp, nodes: ir.Node[], elseNodes: ir.Node[]) ir.If { }
fn bAccess(exp: ir.Exp, key: string) ir.Access { }
fn bFilter(exp: ir.Exp, key: string, args: ir.Exp[]) ir.Filter { }
fn bIdent(ident: string) ir.Ident { }
fn bStringLiteral(val: string) ir.StringLiteral { }
fn bNumberLiteral(val: f64, integer: bool) ir.NumberLiteral { }
fn bBoolLiteral(val: bool) ir.BoolLiteral { }
fn bPrintChain(start: string, idents: string[]) ir.Print { }
fn bChain(start: string, idents: string[]) ir.Exp { }
fn bClosingTagNode(name: string) ir.ClosingTagNode { }

liquid.util.sink

module liquid.util.sink;


//! Used as a sink for functions that return multiple nodes.
struct NodeSink
{
public:
	fn push(n: ir.Node) { }
	fn takeArray() ir.Node[] { }
}

liquid.parser

module liquid.parser;

public import liquid.parser.parser;

liquid.parser.errors

module liquid.parser.errors;


fn errorExpected(p: Parser, expected: dchar, found: dchar) Status { }
fn errorExpected(p: Parser, expected: string, found: string) Status { }
fn errorExpectedIdentifier(p: Parser) Status { }
fn errorExpectedIncludeName(p: Parser) Status { }
fn errorExpectedEndComment(p: Parser) Status { }
fn errorUnmatchedClosingTag(p: Parser, name: string) Status { }
fn errorMissingTagEOF(p: Parser, tags: string[]) Status { }
fn errorUnknownStatement(p: Parser, name: string) Status { }

liquid.parser.parser

module liquid.parser.parser;


enum Status
{
	Ok,
	Error,
}

class Parser
{
public:
	enum State
	{
		Text,
		Print,
		Statement,
		End,
	}


public:
	state: State;
	src: Source;
	sink: StringSink;
	//! A description of an error for the user's consumption.
	errorMessage: string;
	raw: bool;


public:
	this(src: Source) { }
	//! Given a state in which we expect a two char string, skip it.
	fn eatSequence(s: string) Status { }
	//! Parse an identifier name into sink.
	fn eatIdent() { }
	//! If the parser is at the given word, return true. No characters are
	//! consumed.
	fn atWord(s: string) bool { }
	//! Parse a include name into sink.
	fn eatIncludeName() { }
	//! Get the contents of the sink, and then reset it.
	fn getSink() string { }
}

fn parse(src: Source, e: Engine) ir.File { }
//! Parse a liquid file.
fn parseFile(p: Parser, file: ir.File) Status { }
//! Parse nodes until we hit a {%  %}. If name is 'elsif', the If node will
//! be placed at the end of nodes.
fn parseNodesUntilTag(p: Parser, nodes: ir.Node[], nameThatEnded: string, names: string[]) Status { }
//! Parse the individual elements of the file until we run out of file.
fn parseNode(p: Parser, node: ir.Node) Status { }
fn atEndRaw(p: Parser) bool { }
//! Parse regular text until we find a tag, or run out of text.
fn parseText(p: Parser, text: ir.Node) Status { }
//! Parse {{ ... }}.
fn parsePrint(p: Parser, print: ir.Node) Status { }
//! Parse an entire Exp expression.
fn parseExp(p: Parser, exp: ir.Exp, justOneExpression: bool) Status { }
fn parseNumberLiteral(p: Parser, exp: ir.Exp) Status { }
fn parseStringLiteral(p: Parser, exp: ir.Exp) Status { }
//! Parse an Access expression.
fn parseAccess(p: Parser, child: ir.Exp, exp: ir.Exp) Status { }
//! Parse a Filter expression.
fn parseFilter(p: Parser, child: ir.Exp, exp: ir.Exp) Status { }
//! Parse Filter arguments (if any).
fn parseFilterArgs(p: Parser, args: ir.Exp[]) Status { }
//! Parse a statement.
fn parseStatement(p: Parser, node: ir.Node) Status { }
fn parseAssign(p: Parser, node: ir.Node) Status { }
fn parseInclude(p: Parser, node: ir.Node) Status { }
fn parseElsIf(p: Parser, node: ir.Node) Status { }
fn parseIf(p: Parser, invert: bool, node: ir.Node) Status { }
fn parseRaw(p: Parser, node: ir.Node) Status { }
fn parseFor(p: Parser, node: ir.Node) Status { }
fn parseComment(p: Parser) Status { }
//! This function parses a ident.
fn parseIdent(p: Parser, name: string) Status { }
//! This function parser a include name.
fn parseIncludeName(p: Parser, name: string) Status { }
//! Parses close statements '%}', handles hyphens.
fn parseCloseStatement(p: Parser) Status { }
//! Parses close statements '%}', handles hyphens.
fn parseClosePrint(p: Parser) Status { }
//! Matches and skips a single char from the source, sets error msg.
fn matchAndSkip(p: Parser, c: dchar) Status { }
//! Returns either a ir.Ident or ir.BoolLiteral.
fn makeIdentOrBool(word: string) ir.Exp { }
//! Returns true if current character is c and skip it.
fn ifAndSkip(p: Parser, c: dchar) bool { }
//! Is the given char a valid character for a include name.
fn isIncludeName(c: dchar) bool { }
//! Is the given char a valid character for a variable name.
fn isIdentName(c: dchar) bool { }

liquid.ir

module liquid.ir;

public import liquid.ir.ir;

liquid.ir.ir

module liquid.ir.ir;

public import watt.text.sink;


//! Control the flow of the visitor.
enum Status
{
	Stop,
	Continue,
	ContinueParent,
}

//! Base class for all nodes.
class Node
{
public:
	this() { }
	fn accept(v: Visitor, sink: scope (Sink)) Status;
}

//! Top level container node.
class File : Node
{
public:
	nodes: Node[];


public:
	this() { }
	fn accept(v: Visitor, sink: scope (Sink)) Status { }
}

//! A string of text to be printed out directly.
class Text : Node
{
public:
	text: string;


public:
	this(text: string) { }
	fn accept(v: Visitor, sink: scope (Sink)) Status { }
}

//! A expression to be evaluated and printed.
class Print : Node
{
public:
	exp: Exp;


public:
	this(exp: Exp) { }
	fn accept(v: Visitor, sink: scope (Sink)) Status { }
}

//! Base class for all expressions.
class Exp : Node
{
public:
	this() { }
}

//! A single identifier to be looked up in the global scope.
class Ident : Exp
{
public:
	ident: string;


public:
	this(ident: string) { }
	fn accept(v: Visitor, sink: scope (Sink)) Status { }
}

//! A string literal.
class StringLiteral : Exp
{
public:
	val: string;


public:
	this(val: string) { }
	fn accept(v: Visitor, sink: scope (Sink)) Status { }
}

//! A bool literal.
class BoolLiteral : Exp
{
public:
	val: bool;


public:
	this(val: bool) { }
	fn accept(v: Visitor, sink: scope (Sink)) Status { }
}

//! A literal for a number.
class NumberLiteral : Exp
{
public:
	val: f64;
	integer: bool;


public:
	this(val: f64, integer: bool) { }
	fn accept(v: Visitor, sink: scope (Sink)) Status { }
}

class BinOp : Exp
{
public:
	enum Type
	{
		Equal,
		NotEqual,
		GreaterThan,
		LessThan,
		GreaterThanOrEqual,
		LessThanOrEqual,
		Or,
		And,
		Contains,
	}


public:
	type: Type;
	l: Exp;
	r: Exp;


public:
	this(type: Type, l: Exp, r: Exp) { }
	fn accept(v: Visitor, sink: scope (Sink)) Status { }
}

//! Lookup symbol into child expression.
class Access : Exp
{
public:
	child: Exp;
	ident: string;


public:
	this(child: Exp, ident: string) { }
	fn accept(v: Visitor, sink: scope (Sink)) Status { }
}

//! Array lookup.
class Index : Exp
{
public:
	child: Exp;
	index: Exp;


public:
	this(child: Exp, index: Exp) { }
	fn accept(v: Visitor, sink: scope (Sink)) Status { }
}

//! Filter expression.
class Filter : Exp
{
public:
	child: Exp;
	ident: string;
	args: Exp[];


public:
	this(child: Exp, ident: string, args: Exp[]) { }
	fn accept(v: Visitor, sink: scope (Sink)) Status { }
}

//! If control statement.
class If : Node
{
public:
	thenNodes: Node[];
	elseNodes: Node[];
	exp: Exp;
	invert: bool;
	elsif: bool;


public:
	this(invert: bool, exp: Exp, thenNodes: Node[], elseNodes: Node[]) { }
	fn accept(v: Visitor, sink: scope (Sink)) Status { }
}

//! For loop control statement.
class For : Node
{
public:
	var: string;
	nodes: Node[];
	exp: Exp;


public:
	this(var: string, exp: Exp, nodes: Node[]) { }
	fn accept(v: Visitor, sink: scope (Sink)) Status { }
}

class Assign : Node
{
public:
	ident: string;
	exp: Exp;


public:
	this(ident: string, exp: Exp) { }
	fn accept(v: Visitor, sink: scope (Sink)) Status { }
}

class Include : Node
{
public:
	filename: string;
	assigns: Assign[];


public:
	this(filename: string, assigns: Assign[]) { }
	fn accept(v: Visitor, sink: scope (Sink)) Status { }
}

//! Not actually output by the parser. Used for things like %endif%, which
//! mark the end of a list of nodes.
class ClosingTagNode : Node
{
public:
	name: string;


public:
	this(name: string) { }
	fn accept(v: Visitor, sink: scope (Sink)) Status { }
}

//! Base visitor class.
class Visitor
{
public:
	alias Status = Status;
	alias Stop = Status.Stop;
	alias Continue = Status.Continue;
	alias ContinueParent = Status.ContinueParent;


public:
	this() { }
	fn enter(File, scope (Sink)) Status;
	fn leave(File, scope (Sink)) Status;
	fn visit(Text, scope (Sink)) Status;
	fn enter(Print, scope (Sink)) Status;
	fn leave(Print, scope (Sink)) Status;
	fn enter(If, scope (Sink)) Status;
	fn leave(If, scope (Sink)) Status;
	fn enter(For, scope (Sink)) Status;
	fn leave(For, scope (Sink)) Status;
	fn enter(Assign, scope (Sink)) Status;
	fn leave(Assign, scope (Sink)) Status;
	fn visit(Include, scope (Sink)) Status;
	fn enter(Access, scope (Sink)) Status;
	fn leave(Access, scope (Sink)) Status;
	fn enter(Filter, scope (Sink)) Status;
	fn leave(Filter, scope (Sink)) Status;
	fn enter(BinOp, scope (Sink)) Status;
	fn leave(BinOp, scope (Sink)) Status;
	fn enter(Index, scope (Sink)) Status;
	fn leave(Index, scope (Sink)) Status;
	fn visit(Ident, scope (Sink)) Status;
	fn visit(StringLiteral, scope (Sink)) Status;
	fn visit(BoolLiteral, scope (Sink)) Status;
	fn visit(NumberLiteral, scope (Sink)) Status;
}

//! Filter out continue parent and turn that into a continue.
fn filterParent(s: Status) Status { }