@@ -12,6 +12,7 @@ import volta.ir.toplevel;
import volta.ir.declaration;
import volta.ir.expression;
import volta.ir.location;
import volta.ir.templates;

enum Status
{
@@ -74,6 +75,7 @@ public:
Reserved,
FunctionParam,
EnumDeclaration,
TemplateInstance,
}


@@ -209,6 +211,15 @@ public:
this.kind = Kind.EnumDeclaration;
}

this(Scope parent, TemplateInstance ti)
{
this();
this.parent = parent;
this.node = ti;
this.kind = Kind.TemplateInstance;
this.name = ti.instanceName;
}

/*!
* Construct an invalid Store.
* Used for copying Stores for CTFE, do not use for anything else.
@@ -546,6 +557,17 @@ public:
return store;
}

/*!
* Add a template instance to the scope.
*/
Store addTemplateInstance(TemplateInstance ti, out Status status)
{
errorOn(ti, ti.instanceName, /*#out*/status);
auto store = new Store(this, ti);
symbols[ti.instanceName] = store;
return store;
}

/*!
* Add a named expression to the scope.
*
@@ -56,11 +56,6 @@ abstract class Declaration : Node
this(NodeType nt, Declaration old)
{
super(nt, old);
copy(old);
}

void copy(Declaration old)
{
this.annotations = old.annotations.dup();
}
}
@@ -411,7 +406,7 @@ public:
bool isLoweredScopeSuccess;
//! @}

TemplateInstance templateInstance; //!< Optional. Non-null if this is a template instantiation.
TemplateInstance templateInstance; //!< Optional. Filled in by the template lifter for template instances.
//! If an enum declaration etc is added, it'll show up here so the visitor can visit it.
Node[] templateAdditions;
//! If an attribute is applied to a function with a template instance, it goes here.
@@ -424,31 +419,19 @@ public:
this(Function old)
{
super(NodeType.Function, old);
copy(old, false);
}

void copy(Function old, bool liftingTemplate)
{
if (liftingTemplate) {
super.copy(old);
}
this.isResolved = old.isResolved;
this.isActualized = old.isActualized;
this.access = old.access;
if (!liftingTemplate) {
this.myScope = old.myScope;
}
this.myScope = old.myScope;
this.kind = old.kind;
this.type = old.type;
this.params = old.params.dup();
this.nestedFunctions = old.nestedFunctions.dup();
this.scopeSuccesses = old.scopeSuccesses.dup();
this.scopeExits = old.scopeExits.dup();
this.scopeFailures = old.scopeFailures.dup();
if (!liftingTemplate) {
this.name = old.name;
this.mangledName = old.mangledName;
}
this.name = old.name;
this.mangledName = old.mangledName;
this.outParameter = old.outParameter;
this.parsedIn = old.parsedIn;
this.parsedOut = old.parsedOut;
@@ -472,11 +455,9 @@ public:
this.isLoweredScopeExit = old.isLoweredScopeExit;
this.isLoweredScopeFailure = old.isLoweredScopeFailure;
this.isLoweredScopeSuccess = old.isLoweredScopeSuccess;
if (!liftingTemplate) {
this.templateInstance = old.templateInstance;
this.templateAdditions = old.templateAdditions.dup();
this.delayedAttributes = old.delayedAttributes.dup();
}
this.templateInstance = old.templateInstance;
this.templateAdditions = old.templateAdditions.dup();
this.delayedAttributes = old.delayedAttributes.dup();
}

// These also check parsedFoo because artificial functions may lack the tokens.
@@ -37,9 +37,14 @@ class TemplateInstance : Node
public:
TemplateKind kind;
QualifiedName name;
string instanceName;
Node[] arguments; // Either a Type or an Exp.
bool explicitMixin;
string[] names; // Set by the lifter.
Scope myScope; // Set by gatherer.

Struct _struct;
Function _function;

public:
this()
@@ -54,6 +59,11 @@ public:
this.name = old.name;
this.arguments = old.arguments.dup();
this.names = old.names.dup();
this.instanceName = old.instanceName;
this.explicitMixin = old.explicitMixin;
this.myScope = old.myScope;
this._struct = old._struct;
this._function = old._function;
}
}

@@ -417,8 +417,6 @@ public:

bool isFinal;

TemplateInstance templateInstance; //!< Optional. Non-null if this is a template instantiation.

public:
this() { super(NodeType.Class); }

@@ -443,7 +441,6 @@ public:
this.isObject = old.isObject;
this.isAbstract = old.isAbstract;
this.isFinal = old.isFinal;
this.templateInstance = old.templateInstance;
}
}

@@ -464,8 +461,6 @@ public:
//! How a lowered interface will look internally.
Struct layoutStruct;

TemplateInstance templateInstance; //!< Optional. Non-null if this is a template instantiation.

public:
this() { super(NodeType.Interface); }

@@ -476,7 +471,6 @@ public:
this.parentInterfaces = old.parentInterfaces.dup();

this.layoutStruct = old.layoutStruct;
this.templateInstance = old.templateInstance;
}
}

@@ -495,16 +489,13 @@ class Union : PODAggregate
public:
size_t totalSize; // Total size in memory.

TemplateInstance templateInstance; //!< Optional. Non-null if this is a template instantiation.

public:
this() { super(NodeType.Union); }

this(Union old)
{
super(NodeType.Union, old);
this.totalSize = old.totalSize;
this.templateInstance = old.templateInstance;
}
}

@@ -522,8 +513,7 @@ class Struct : PODAggregate
{
public:
Node loweredNode; //!< If not null, this struct was lowered from this.

TemplateInstance templateInstance; //!< Optional. Non-null if this is a template instantiation.
TemplateInstance templateInstance; //!< Filled in by the lifter, if instantiated from a template.

public:
this() { super(NodeType.Struct); }
@@ -27,9 +27,9 @@ ParseStatus parseVariable(ParserStream ps, NodeSinkDg dgt)
{
if (ps == TokenType.Alias) {
if (ps.magicFlagD && isTemplateInstance(ps)) {
ir.Struct s;
parseLegacyTemplateInstance(ps, /*#out*/s);
dgt(s);
ir.TemplateInstance ti;
parseLegacyTemplateInstance(ps, /*#out*/ti);
dgt(ti);
return Succeeded;
}
ir.Alias a;
@@ -49,7 +49,13 @@ ParseStatus parseVariable(ParserStream ps, NodeSinkDg dgt)
}

if (ps == TokenType.Fn) {
if (isTemplateDefinition(ps)) {
if (isTemplateInstance(ps)) {
ir.TemplateInstance ti;
auto succeeded = parseTemplateInstance(ps, /*#out*/ti);
if (succeeded) {
dgt(ti);
}
} else if (isTemplateDefinition(ps)) {
ir.TemplateDefinition td;
auto succeeded = parseTemplateDefinition(ps, /*#out*/td);
if (!succeeded) {
@@ -999,11 +1005,6 @@ ParseStatus parseNewFunction(ParserStream ps, out ir.Function func, string templ

Token nameTok;
if (templateName.length == 0) {
if (isTemplateInstance(ps)) {
func.type = null;
return parseTemplateInstance(ps, /*#out*/func.templateInstance, /*#out*/func.name);
}

auto succeeded = match(ps, func, TokenType.Fn);
if (!succeeded) {
return succeeded;
@@ -126,18 +126,14 @@ bool isUnambigouslyType(ParserStream ps)
return retval;
}

ParseStatus parseLegacyTemplateInstance(ParserStream ps, out ir.Struct s)
ParseStatus parseLegacyTemplateInstance(ParserStream ps, out ir.TemplateInstance ti)
{
s = new ir.Struct();
s.loc = ps.peek.loc;
string nam;
auto succeeded = parseTemplateInstance(ps, /*#out*/s.templateInstance, /*#out*/nam);
s.templateInstance.explicitMixin = true;
s.name = nam;
auto succeeded = parseTemplateInstance(ps, /*#out*/ti);
ti.explicitMixin = true;
return succeeded;
}

ParseStatus parseTemplateInstance(ParserStream ps, out ir.TemplateInstance ti, out string instanceName)
ParseStatus parseTemplateInstance(ParserStream ps, out ir.TemplateInstance ti)
{
ti = new ir.TemplateInstance();
auto origin = ps.peek.loc;
@@ -172,7 +168,7 @@ ParseStatus parseTemplateInstance(ParserStream ps, out ir.TemplateInstance ti, o
if (!succeeded) {
return succeeded;
}
instanceName = nameTok.value;
ti.instanceName = nameTok.value;

succeeded = match(ps, ti, TokenType.Assign);
if (!succeeded) {
@@ -119,6 +119,19 @@ body

auto sink = new NodeSink();

bool parseIfTemplateInstance()
{
if (!isTemplateInstance(ps)) {
return false;
}
ir.TemplateInstance ti;
succeeded = parseTemplateInstance(ps, /*#out*/ti);
if (succeeded) {
sink.push(ti);
}
return true;
}

switch (ps.peek.type) {
case TokenType.Import:
ir.Import _import;
@@ -163,6 +176,12 @@ body
sink.push(td);
break;
}
if (parseIfTemplateInstance()) {
if (!succeeded) {
return parseFailed(ps, ir.NodeType.TopLevelBlock);
}
break;
}
succeeded = parseUnion(ps, /*#out*/u);
if (!succeeded) {
return parseFailed(ps, ir.NodeType.TopLevelBlock);
@@ -180,6 +199,12 @@ body
sink.push(td);
break;
}
if (parseIfTemplateInstance()) {
if (!succeeded) {
return parseFailed(ps, ir.NodeType.TopLevelBlock);
}
break;
}
succeeded = parseStruct(ps, /*#out*/s);
if (!succeeded) {
return parseFailed(ps, ir.NodeType.TopLevelBlock);
@@ -197,6 +222,12 @@ body
sink.push(td);
break;
}
if (parseIfTemplateInstance()) {
if (!succeeded) {
return parseFailed(ps, ir.NodeType.TopLevelBlock);
}
break;
}
succeeded = parseClass(ps, /*#out*/c);
if (!succeeded) {
return parseFailed(ps, ir.NodeType.TopLevelBlock);
@@ -214,6 +245,12 @@ body
sink.push(td);
break;
}
if (parseIfTemplateInstance()) {
if (!succeeded) {
return parseFailed(ps, ir.NodeType.TopLevelBlock);
}
break;
}
succeeded = parseInterface(ps, /*#out*/i);
if (!succeeded) {
return parseFailed(ps, ir.NodeType.TopLevelBlock);
@@ -669,9 +706,6 @@ ParseStatus parseClass(ParserStream ps, out ir.Class c, string templateName = ""
c.docComment = ps.comment();

if (templateName.length == 0) {
if (isTemplateInstance(ps)) {
return parseTemplateInstance(ps, /*#out*/c.templateInstance, /*#out*/c.name);
}
auto succeeded = match(ps, ir.NodeType.Class,
[TokenType.Class, TokenType.Identifier]);
if (!succeeded) {
@@ -723,10 +757,6 @@ ParseStatus parseInterface(ParserStream ps, out ir._Interface i, string template
i.docComment = ps.comment();

if (templateName.length == 0) {
if (isTemplateInstance(ps)) {
return parseTemplateInstance(ps, /*#out*/i.templateInstance, /*#out*/i.name);
}

auto succeeded = match(ps, ir.NodeType.Interface,
[TokenType.Interface, TokenType.Identifier]);
if (!succeeded) {
@@ -777,10 +807,6 @@ ParseStatus parseUnion(ParserStream ps, out ir.Union u, string templateName="")


if (templateName.length == 0) {
if (isTemplateInstance(ps)) {
return parseTemplateInstance(ps, /*#out*/u.templateInstance, /*#out*/u.name);
}

if (ps.peek.type != TokenType.Union) {
return unexpectedToken(ps, ir.NodeType.Union);
}
@@ -832,10 +858,6 @@ ParseStatus parseStruct(ParserStream ps, out ir.Struct s, string templateName=""
s.docComment = ps.comment();

if (templateName.length == 0) {
if (isTemplateInstance(ps)) {
return parseTemplateInstance(ps, /*#out*/s.templateInstance, /*#out*/s.name);
}

if (ps.peek.type != TokenType.Struct) {
return unexpectedToken(ps, ir.NodeType.Struct);
}