Skip to content

Commit

Permalink
Add shortcuts for some non-tagged string templates (AssemblyScript#2014)
Browse files Browse the repository at this point in the history
  • Loading branch information
MaxGraey authored Aug 2, 2021
1 parent 75890dc commit 551b312
Show file tree
Hide file tree
Showing 4 changed files with 1,896 additions and 1,740 deletions.
106 changes: 81 additions & 25 deletions src/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8156,16 +8156,71 @@ export class Compiler extends DiagnosticEmitter {
var expressions = expression.expressions;
assert(numParts - 1 == expressions.length);

// Shortcut if just a (multi-line) string
if (tag === null && numParts == 1) {
return this.ensureStaticString(parts[0]);
}

var module = this.module;
var stringType = this.program.stringInstance.type;
var stringInstance = this.program.stringInstance;
var stringType = stringInstance.type;

// Compile to a `StaticArray<string>#join("")` if untagged
if (tag === null) {
// Shortcut if just a (multi-line) string
if (numParts == 1) {
return this.ensureStaticString(parts[0]);
}

// Shortcut for `${expr}`, `<prefix>${expr}`, `${expr}<suffix>`
if (numParts == 2) {
let expression = expressions[0];
let lhsLen = parts[0].length;
let rhsLen = parts[1].length;
// Shortcut for `${expr}` -> expr.toString()
if (!lhsLen && !rhsLen) {
return this.makeToString(
this.compileExpression(expression, stringType),
this.currentType, expression
);
}
// Shortcuts for
// `<prefix>${expr}` -> "<prefix>" + expr.toString()
// `${expr}<suffix>` -> expr.toString() + "<suffix>"
let hasPrefix = lhsLen != 0;
// @ts-ignore: cast
if (hasPrefix ^ (rhsLen != 0)) {
let lhs: ExpressionRef;
let rhs: ExpressionRef;
let expr = this.makeToString(
this.compileExpression(expression, stringType),
this.currentType, expression
);
if (hasPrefix) {
lhs = this.ensureStaticString(parts[0]);
rhs = expr;
} else {
// suffix
lhs = expr;
rhs = this.ensureStaticString(parts[1]);
}
let concatMethod = assert(stringInstance.getMethod("concat"));
return this.makeCallDirect(concatMethod, [ lhs, rhs ], expression);
}
}

// Shortcut for `${exprA}${exprB}` -> exprA.toString() + exprB.toString()
if (numParts == 3 && !parts[0].length && !parts[1].length && !parts[2].length) {
let exprA = expressions[0];
let exprB = expressions[1];

let lhs = this.makeToString(
this.compileExpression(exprA, stringType),
this.currentType, exprA
);
let rhs = this.makeToString(
this.compileExpression(exprB, stringType),
this.currentType, exprB
);
let concatMethod = assert(stringInstance.getMethod("concat"));
return this.makeCallDirect(concatMethod, [ lhs, rhs ], expression);
}

// Compile to a `StaticArray<string>#join("") for general case
let length = 2 * numParts - 1;
let values = new Array<usize>(length);
values[0] = this.ensureStaticString(parts[0]);
Expand All @@ -8178,26 +8233,22 @@ export class Compiler extends DiagnosticEmitter {
let offset = i64_add(segment.offset, i64_new(this.program.totalOverhead));
let joinInstance = assert(arrayInstance.getMethod("join"));
let indexedSetInstance = assert(arrayInstance.lookupOverload(OperatorKind.INDEXED_SET, true));
let stmts = new Array<ExpressionRef>();
let stmts = new Array<ExpressionRef>(numParts);
for (let i = 0, k = numParts - 1; i < k; ++i) {
let expression = expressions[i];
stmts.push(
this.makeCallDirect(indexedSetInstance, [
module.usize(offset),
module.i32(2 * i + 1),
this.makeToString(
this.compileExpression(expression, stringType),
this.currentType, expression
)
], expression)
);
}
stmts.push(
this.makeCallDirect(joinInstance, [
stmts[i] = this.makeCallDirect(indexedSetInstance, [
module.usize(offset),
this.ensureStaticString("")
], expression)
);
module.i32(2 * i + 1),
this.makeToString(
this.compileExpression(expression, stringType),
this.currentType, expression
)
], expression);
}
stmts[numParts - 1] = this.makeCallDirect(joinInstance, [
module.usize(offset),
this.ensureStaticString("")
], expression);
return module.flatten(stmts, stringType.toRef());
}

Expand All @@ -8210,7 +8261,12 @@ export class Compiler extends DiagnosticEmitter {
if (target) {
switch (target.kind) {
case ElementKind.FUNCTION_PROTOTYPE: {
let instance = this.resolver.resolveFunction(<FunctionPrototype>target, null, uniqueMap<string,Type>(), ReportMode.SWALLOW);
let instance = this.resolver.resolveFunction(
<FunctionPrototype>target,
null,
uniqueMap<string,Type>(),
ReportMode.SWALLOW
);
if (!instance) break;
target = instance;
// fall-through
Expand Down
Loading

0 comments on commit 551b312

Please sign in to comment.