mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-13 06:51:34 +00:00
Cleanup; Initial tslint integration
This commit is contained in:
176
src/ast.ts
176
src/ast.ts
@ -434,8 +434,9 @@ export abstract class Node {
|
||||
case "offset": stmt.decoratorKind = DecoratorKind.OFFSET; break;
|
||||
default: stmt.decoratorKind = DecoratorKind.CUSTOM; break;
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
stmt.decoratorKind = DecoratorKind.CUSTOM;
|
||||
}
|
||||
return stmt;
|
||||
}
|
||||
|
||||
@ -499,13 +500,14 @@ export abstract class Node {
|
||||
stmt.path = path;
|
||||
if (path) {
|
||||
var normalizedPath = normalizePath(path.value);
|
||||
if (path.value.startsWith(".")) // relative
|
||||
if (path.value.startsWith(".")) { // relative
|
||||
stmt.normalizedPath = resolvePath(
|
||||
normalizedPath,
|
||||
range.source.normalizedPath
|
||||
);
|
||||
else // absolute
|
||||
} else { // absolute
|
||||
stmt.normalizedPath = normalizedPath;
|
||||
}
|
||||
stmt.internalPath = mangleInternalPath(stmt.normalizedPath);
|
||||
} else {
|
||||
stmt.normalizedPath = null;
|
||||
@ -535,10 +537,11 @@ export abstract class Node {
|
||||
var elem = new ExportMember();
|
||||
elem.range = range;
|
||||
elem.name = name; name.parent = elem;
|
||||
if (!externalName)
|
||||
if (!externalName) {
|
||||
externalName = name;
|
||||
else
|
||||
} else {
|
||||
externalName.parent = elem;
|
||||
}
|
||||
elem.externalName = externalName;
|
||||
return elem;
|
||||
}
|
||||
@ -577,13 +580,14 @@ export abstract class Node {
|
||||
stmt.namespaceName = null;
|
||||
stmt.path = path;
|
||||
var normalizedPath = normalizePath(path.value);
|
||||
if (path.value.startsWith(".")) // relative
|
||||
if (path.value.startsWith(".")) { // relative
|
||||
stmt.normalizedPath = resolvePath(
|
||||
normalizedPath,
|
||||
range.source.normalizedPath
|
||||
);
|
||||
else // absolute
|
||||
} else { // absolute
|
||||
stmt.normalizedPath = normalizedPath;
|
||||
}
|
||||
stmt.internalPath = mangleInternalPath(stmt.normalizedPath);
|
||||
return stmt;
|
||||
}
|
||||
@ -614,10 +618,11 @@ export abstract class Node {
|
||||
var elem = new ImportDeclaration();
|
||||
elem.range = range;
|
||||
elem.externalName = externalName; externalName.parent = elem;
|
||||
if (!name)
|
||||
if (!name) {
|
||||
name = externalName;
|
||||
else
|
||||
} else {
|
||||
name.parent = elem;
|
||||
}
|
||||
elem.name = name;
|
||||
return elem;
|
||||
}
|
||||
@ -996,7 +1001,7 @@ export class CallExpression extends Expression {
|
||||
arguments: Expression[];
|
||||
}
|
||||
|
||||
/** Represents a comma expression composed of multiple sequential expressions. */
|
||||
/** Represents a comma expression composed of multiple expressions. */
|
||||
export class CommaExpression extends Expression {
|
||||
kind = NodeKind.COMMA;
|
||||
|
||||
@ -1223,47 +1228,50 @@ export abstract class DeclarationStatement extends Statement {
|
||||
|
||||
/** Gets the mangled program-level internal name of this declaration. */
|
||||
get programLevelInternalName(): string {
|
||||
if (!this.cachedProgramLevelInternalName)
|
||||
if (!this.cachedProgramLevelInternalName) {
|
||||
this.cachedProgramLevelInternalName = mangleInternalName(this, true);
|
||||
}
|
||||
return this.cachedProgramLevelInternalName;
|
||||
}
|
||||
|
||||
/** Gets the mangled file-level internal name of this declaration. */
|
||||
get fileLevelInternalName(): string {
|
||||
if (!this.cachedFileLevelInternalName)
|
||||
if (!this.cachedFileLevelInternalName) {
|
||||
this.cachedFileLevelInternalName = mangleInternalName(this, false);
|
||||
}
|
||||
return this.cachedFileLevelInternalName;
|
||||
}
|
||||
|
||||
/** Tests if this is a top-level declaration within its source file. */
|
||||
get isTopLevel(): bool {
|
||||
var parent = this.parent;
|
||||
if (!parent)
|
||||
if (!parent) {
|
||||
return false;
|
||||
if (parent.kind == NodeKind.VARIABLE)
|
||||
if (!(parent = parent.parent))
|
||||
return false;
|
||||
}
|
||||
if (parent.kind == NodeKind.VARIABLE && !(parent = parent.parent)) {
|
||||
return false;
|
||||
}
|
||||
return parent.kind == NodeKind.SOURCE;
|
||||
}
|
||||
|
||||
/** Tests if this declaration is a top-level export within its source file. */
|
||||
get isTopLevelExport(): bool {
|
||||
var parent = this.parent;
|
||||
if (!parent)
|
||||
if (!parent || (parent.kind == NodeKind.VARIABLE && !(parent = parent.parent))) {
|
||||
return false;
|
||||
if (parent.kind == NodeKind.VARIABLE)
|
||||
if (!(parent = parent.parent))
|
||||
return false;
|
||||
if (parent.kind == NodeKind.NAMESPACEDECLARATION)
|
||||
}
|
||||
if (parent.kind == NodeKind.NAMESPACEDECLARATION) {
|
||||
return (
|
||||
hasModifier(ModifierKind.EXPORT, this.modifiers) &&
|
||||
(<NamespaceDeclaration>parent).isTopLevelExport
|
||||
);
|
||||
if (parent.kind == NodeKind.CLASSDECLARATION)
|
||||
}
|
||||
if (parent.kind == NodeKind.CLASSDECLARATION) {
|
||||
return (
|
||||
hasModifier(ModifierKind.STATIC, this.modifiers) &&
|
||||
(<ClassDeclaration>parent).isTopLevelExport
|
||||
);
|
||||
}
|
||||
return (
|
||||
parent.kind == NodeKind.SOURCE &&
|
||||
hasModifier(ModifierKind.EXPORT, this.modifiers)
|
||||
@ -1642,9 +1650,7 @@ export class WhileStatement extends Statement {
|
||||
/** Cached unused modifiers for reuse. */
|
||||
var reusableModifiers: Modifier[] | null = null;
|
||||
|
||||
export function setReusableModifiers(
|
||||
modifiers: Modifier[]
|
||||
): void {
|
||||
export function setReusableModifiers(modifiers: Modifier[]): void {
|
||||
reusableModifiers = modifiers;
|
||||
}
|
||||
|
||||
@ -1654,113 +1660,105 @@ export function createModifiers(): Modifier[] {
|
||||
if (reusableModifiers != null) {
|
||||
ret = reusableModifiers;
|
||||
reusableModifiers = null;
|
||||
} else
|
||||
ret = new Array(1);
|
||||
} else {
|
||||
ret = [];
|
||||
}
|
||||
ret.length = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Utility
|
||||
|
||||
/** Adds a modifier to a set of modifiers. Creates a new set if `null`. */
|
||||
export function addModifier(
|
||||
modifier: Modifier,
|
||||
modifiers: Modifier[] | null
|
||||
): Modifier[] {
|
||||
if (modifiers == null)
|
||||
modifiers = createModifiers();
|
||||
export function addModifier(modifier: Modifier, modifiers: Modifier[] | null): Modifier[] {
|
||||
if (modifiers == null) modifiers = createModifiers();
|
||||
modifiers.push(modifier);
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
/** Gets a specific modifier from the specified set of modifiers. */
|
||||
export function getModifier(
|
||||
kind: ModifierKind,
|
||||
modifiers: Modifier[] | null
|
||||
): Modifier | null {
|
||||
if (modifiers)
|
||||
for (var i = 0, k = modifiers.length; i < k; ++i)
|
||||
if (modifiers[i].modifierKind == kind)
|
||||
export function getModifier(kind: ModifierKind, modifiers: Modifier[] | null): Modifier | null {
|
||||
if (modifiers) {
|
||||
for (var i = 0, k = modifiers.length; i < k; ++i) {
|
||||
if (modifiers[i].modifierKind == kind) {
|
||||
return modifiers[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Tests whether a modifier exists in the specified set of modifiers. */
|
||||
export function hasModifier(
|
||||
kind: ModifierKind,
|
||||
modifiers: Modifier[] | null
|
||||
): bool {
|
||||
export function hasModifier(kind: ModifierKind, modifiers: Modifier[] | null): bool {
|
||||
return getModifier(kind, modifiers) != null;
|
||||
}
|
||||
|
||||
/** Gets the first decorator by name within at set of decorators, if present. */
|
||||
export function getFirstDecorator(
|
||||
name: string,
|
||||
decorators: Decorator[] | null
|
||||
): Decorator | null {
|
||||
if (decorators)
|
||||
export function getFirstDecorator(name: string, decorators: Decorator[] | null): Decorator | null {
|
||||
if (decorators) {
|
||||
for (var i = 0, k = decorators.length; i < k; ++i) {
|
||||
var decorator = decorators[i];
|
||||
var expression = decorator.name;
|
||||
if (expression.kind == NodeKind.IDENTIFIER && (<IdentifierExpression>expression).text == name)
|
||||
if (expression.kind == NodeKind.IDENTIFIER && (<IdentifierExpression>expression).text == name) {
|
||||
return decorator;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Tests if a specific decorator is present within the specified decorators. */
|
||||
export function hasDecorator(
|
||||
name: string,
|
||||
decorators: Decorator[] | null
|
||||
): bool {
|
||||
export function hasDecorator(name: string, decorators: Decorator[] | null): bool {
|
||||
return getFirstDecorator(name, decorators) != null;
|
||||
}
|
||||
|
||||
/** Mangles a declaration's name to an internal name. */
|
||||
export function mangleInternalName(
|
||||
declaration: DeclarationStatement,
|
||||
asGlobal: bool = false
|
||||
): string {
|
||||
export function mangleInternalName(declaration: DeclarationStatement, asGlobal: bool = false): string {
|
||||
var name = declaration.name.text;
|
||||
var parent = declaration.parent;
|
||||
if (!parent)
|
||||
return name;
|
||||
if (declaration.kind == NodeKind.VARIABLEDECLARATION && parent.kind == NodeKind.VARIABLE) // skip over
|
||||
if (!(parent = parent.parent))
|
||||
return name;
|
||||
if (parent.kind == NodeKind.CLASSDECLARATION)
|
||||
if (!parent) return name;
|
||||
if (
|
||||
declaration.kind == NodeKind.VARIABLEDECLARATION &&
|
||||
parent.kind == NodeKind.VARIABLE
|
||||
) { // skip over
|
||||
if (!(parent = parent.parent)) return name;
|
||||
}
|
||||
if (parent.kind == NodeKind.CLASSDECLARATION) {
|
||||
return mangleInternalName(<ClassDeclaration>parent, asGlobal) + (
|
||||
hasModifier(ModifierKind.STATIC, declaration.modifiers) ? STATIC_DELIMITER : INSTANCE_DELIMITER
|
||||
hasModifier(ModifierKind.STATIC, declaration.modifiers)
|
||||
? STATIC_DELIMITER
|
||||
: INSTANCE_DELIMITER
|
||||
) + name;
|
||||
if (parent.kind == NodeKind.NAMESPACEDECLARATION || parent.kind == NodeKind.ENUMDECLARATION)
|
||||
return mangleInternalName(<DeclarationStatement>parent, asGlobal) + STATIC_DELIMITER + name;
|
||||
if (asGlobal)
|
||||
return name;
|
||||
return declaration.range.source.internalPath + PATH_DELIMITER + name;
|
||||
}
|
||||
if (
|
||||
parent.kind == NodeKind.NAMESPACEDECLARATION ||
|
||||
parent.kind == NodeKind.ENUMDECLARATION
|
||||
) {
|
||||
return mangleInternalName(<DeclarationStatement>parent, asGlobal) +
|
||||
STATIC_DELIMITER + name;
|
||||
}
|
||||
return asGlobal
|
||||
? name
|
||||
: declaration.range.source.internalPath + PATH_DELIMITER + name;
|
||||
}
|
||||
|
||||
/** Mangles an external to an internal path. */
|
||||
export function mangleInternalPath(
|
||||
path: string
|
||||
): string {
|
||||
if (path.endsWith(".ts"))
|
||||
path = path.substring(0, path.length - 3);
|
||||
export function mangleInternalPath(path: string): string {
|
||||
if (path.endsWith(".ts")) path = path.substring(0, path.length - 3);
|
||||
return path;
|
||||
}
|
||||
|
||||
function setParent(
|
||||
nodes: Node[],
|
||||
parent: Node
|
||||
): void {
|
||||
for (var i = 0, k = nodes.length; i < k; ++i)
|
||||
nodes[i].parent = parent;
|
||||
}
|
||||
// Helpers
|
||||
|
||||
function setParentOpt(
|
||||
nodes: (Node | null)[],
|
||||
parent: Node
|
||||
): void {
|
||||
function setParent(nodes: Node[], parent: Node): void {
|
||||
for (var i = 0, k = nodes.length; i < k; ++i) {
|
||||
var node = nodes[i];
|
||||
if (node)
|
||||
node.parent = parent;
|
||||
nodes[i].parent = parent;
|
||||
}
|
||||
}
|
||||
|
||||
function setParentOpt(nodes: (Node | null)[], parent: Node): void {
|
||||
for (var i = 0, k = nodes.length; i < k; ++i) {
|
||||
var node = nodes[i];
|
||||
if (node) node.parent = parent;
|
||||
}
|
||||
}
|
||||
|
1304
src/builtins.ts
1304
src/builtins.ts
File diff suppressed because it is too large
Load Diff
2226
src/compiler.ts
2226
src/compiler.ts
File diff suppressed because it is too large
Load Diff
@ -38,8 +38,7 @@ export class Decompiler {
|
||||
this.push(name);
|
||||
this.push("(");
|
||||
for (var i: Index = 0, k: Index = _BinaryenFunctionGetNumParams(func); i < k; ++i) {
|
||||
if (i > 0)
|
||||
this.push(", ");
|
||||
if (i > 0) this.push(", ");
|
||||
this.push("$");
|
||||
this.push(i.toString(10));
|
||||
this.push(": ");
|
||||
@ -119,8 +118,9 @@ export class Decompiler {
|
||||
this.push("break ");
|
||||
this.push(string);
|
||||
this.push(";\n");
|
||||
} else
|
||||
} else {
|
||||
this.push("break;\n");
|
||||
}
|
||||
return;
|
||||
|
||||
case ExpressionId.Switch:
|
||||
|
@ -1,4 +1,5 @@
|
||||
// code below is generated from diagnosticsMessages.json by scripts/build-diagnostics
|
||||
/* tslint:disable:max-line-length */
|
||||
|
||||
export enum DiagnosticCode {
|
||||
Operation_not_supported = 100,
|
||||
|
@ -8,7 +8,6 @@ import {
|
||||
} from "./diagnosticMessages.generated";
|
||||
|
||||
import {
|
||||
CharCode,
|
||||
isLineBreak
|
||||
} from "./util/charcode";
|
||||
|
||||
@ -59,24 +58,39 @@ export class DiagnosticMessage {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
static create(code: DiagnosticCode, category: DiagnosticCategory, arg0: string | null = null, arg1: string | null = null): DiagnosticMessage {
|
||||
static create(
|
||||
code: DiagnosticCode,
|
||||
category: DiagnosticCategory,
|
||||
arg0: string | null = null,
|
||||
arg1: string | null = null
|
||||
): DiagnosticMessage {
|
||||
var message = diagnosticCodeToString(code);
|
||||
if (arg0 != null)
|
||||
message = message.replace("{0}", arg0);
|
||||
if (arg1 != null)
|
||||
message = message.replace("{1}", arg1);
|
||||
if (arg0 != null) message = message.replace("{0}", arg0);
|
||||
if (arg1 != null) message = message.replace("{1}", arg1);
|
||||
return new DiagnosticMessage(code, category, message);
|
||||
}
|
||||
|
||||
static createInfo(code: DiagnosticCode, arg0: string | null = null, arg1: string | null = null): DiagnosticMessage {
|
||||
static createInfo(
|
||||
code: DiagnosticCode,
|
||||
arg0: string | null = null,
|
||||
arg1: string | null = null
|
||||
): DiagnosticMessage {
|
||||
return DiagnosticMessage.create(code, DiagnosticCategory.INFO, arg0, arg1);
|
||||
}
|
||||
|
||||
static createWarning(code: DiagnosticCode, arg0: string | null = null, arg1: string | null = null): DiagnosticMessage {
|
||||
static createWarning(
|
||||
code: DiagnosticCode,
|
||||
arg0: string | null = null,
|
||||
arg1: string | null = null
|
||||
): DiagnosticMessage {
|
||||
return DiagnosticMessage.create(code, DiagnosticCategory.WARNING, arg0, arg1);
|
||||
}
|
||||
|
||||
static createError(code: DiagnosticCode, arg0: string | null = null, arg1: string | null = null): DiagnosticMessage {
|
||||
static createError(
|
||||
code: DiagnosticCode,
|
||||
arg0: string | null = null,
|
||||
arg1: string | null = null
|
||||
): DiagnosticMessage {
|
||||
return DiagnosticMessage.create(code, DiagnosticCategory.ERROR, arg0, arg1);
|
||||
}
|
||||
|
||||
@ -86,17 +100,41 @@ export class DiagnosticMessage {
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
if (this.range)
|
||||
return diagnosticCategoryToString(this.category) + " " + this.code.toString(10) + ": \"" + this.message + "\" in " + this.range.source.normalizedPath + " @ " + this.range.start.toString(10) + "," + this.range.end.toString(10);
|
||||
return diagnosticCategoryToString(this.category) + " " + this.code.toString(10) + ": " + this.message;
|
||||
if (this.range) {
|
||||
return (
|
||||
diagnosticCategoryToString(this.category) +
|
||||
" " +
|
||||
this.code.toString(10) +
|
||||
": \"" +
|
||||
this.message +
|
||||
"\" in " +
|
||||
this.range.source.normalizedPath +
|
||||
" @ " +
|
||||
this.range.start.toString(10) +
|
||||
"," +
|
||||
this.range.end.toString(10)
|
||||
);
|
||||
}
|
||||
return (
|
||||
diagnosticCategoryToString(this.category) +
|
||||
" " +
|
||||
this.code.toString(10) +
|
||||
": " +
|
||||
this.message
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function formatDiagnosticMessage(message: DiagnosticMessage, useColors: bool = false, showContext: bool = false): string {
|
||||
export function formatDiagnosticMessage(
|
||||
message: DiagnosticMessage,
|
||||
useColors: bool = false,
|
||||
showContext: bool = false
|
||||
): string {
|
||||
// format context first (uses same string builder)
|
||||
var context = "";
|
||||
if (message.range && showContext)
|
||||
if (message.range && showContext) {
|
||||
context = formatDiagnosticContext(message.range, useColors);
|
||||
}
|
||||
|
||||
// general information
|
||||
var sb: string[] = [];
|
||||
@ -111,7 +149,6 @@ export function formatDiagnosticMessage(message: DiagnosticMessage, useColors: b
|
||||
// range information if available
|
||||
if (message.range) {
|
||||
var range = message.range;
|
||||
var text = range.source.text;
|
||||
if (showContext) {
|
||||
sb.push("\n");
|
||||
sb.push(context);
|
||||
@ -133,10 +170,12 @@ export function formatDiagnosticContext(range: Range, useColors: bool = false):
|
||||
var len = text.length;
|
||||
var start = range.start;
|
||||
var end = range.end;
|
||||
while (start > 0 && !isLineBreak(text.charCodeAt(start - 1)))
|
||||
while (start > 0 && !isLineBreak(text.charCodeAt(start - 1))) {
|
||||
start--;
|
||||
while (end < len && !isLineBreak(text.charCodeAt(end)))
|
||||
}
|
||||
while (end < len && !isLineBreak(text.charCodeAt(end))) {
|
||||
end++;
|
||||
}
|
||||
var sb: string[] = [
|
||||
"\n ",
|
||||
text.substring(start, end),
|
||||
@ -149,8 +188,11 @@ export function formatDiagnosticContext(range: Range, useColors: bool = false):
|
||||
if (useColors) sb.push(colorRed);
|
||||
if (range.start == range.end) {
|
||||
sb.push("^");
|
||||
} else while (start++ < range.end)
|
||||
sb.push("~");
|
||||
} else {
|
||||
while (start++ < range.end) {
|
||||
sb.push("~");
|
||||
}
|
||||
}
|
||||
if (useColors) sb.push(colorReset);
|
||||
return sb.join("");
|
||||
}
|
||||
@ -164,7 +206,13 @@ export abstract class DiagnosticEmitter {
|
||||
this.diagnostics = diagnostics ? <DiagnosticMessage[]>diagnostics : new Array();
|
||||
}
|
||||
|
||||
emitDiagnostic(code: DiagnosticCode, category: DiagnosticCategory, range: Range, arg0: string | null = null, arg1: string | null = null) {
|
||||
emitDiagnostic(
|
||||
code: DiagnosticCode,
|
||||
category: DiagnosticCategory,
|
||||
range: Range,
|
||||
arg0: string | null = null,
|
||||
arg1: string | null = null
|
||||
) {
|
||||
var message = DiagnosticMessage.create(code, category, arg0, arg1).withRange(range);
|
||||
this.diagnostics.push(message);
|
||||
// console.log(formatDiagnosticMessage(message, true, true) + "\n"); // temporary
|
||||
|
750
src/extra/ast.ts
750
src/extra/ast.ts
File diff suppressed because it is too large
Load Diff
362
src/module.ts
362
src/module.ts
@ -108,7 +108,7 @@ export enum UnaryOp {
|
||||
// ExtendI16ToI64 = _BinaryenExtendS16Int64()
|
||||
// ExtendI32ToI64 = _BinaryenExtendS32Int64()
|
||||
|
||||
// see: https://github.com/WebAssembly/nontrapping-float-to-int-conversions/blob/master/proposals/nontrapping-float-to-int-conversion/Overview.md#design
|
||||
// see: https://github.com/WebAssembly/nontrapping-float-to-int-conversions
|
||||
// TruncF32ToI32Sat
|
||||
// TruncF32ToU32Sat
|
||||
// TruncF64ToI32Sat
|
||||
@ -204,7 +204,7 @@ export enum HostOp {
|
||||
GrowMemory = _BinaryenGrowMemory(),
|
||||
HasFeature = _BinaryenHasFeature(),
|
||||
|
||||
// see: https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md#design
|
||||
// see: https://github.com/WebAssembly/bulk-memory-operations
|
||||
// MoveMemory
|
||||
// SetMemory
|
||||
}
|
||||
@ -262,7 +262,11 @@ export class Module {
|
||||
|
||||
// types
|
||||
|
||||
addFunctionType(name: string, result: NativeType, paramTypes: NativeType[]): FunctionRef {
|
||||
addFunctionType(
|
||||
name: string,
|
||||
result: NativeType,
|
||||
paramTypes: NativeType[]
|
||||
): FunctionRef {
|
||||
var cStr = allocString(name);
|
||||
var cArr = allocI32Array(paramTypes);
|
||||
try {
|
||||
@ -273,7 +277,10 @@ export class Module {
|
||||
}
|
||||
}
|
||||
|
||||
getFunctionTypeBySignature(result: NativeType, paramTypes: NativeType[]): FunctionTypeRef {
|
||||
getFunctionTypeBySignature(
|
||||
result: NativeType,
|
||||
paramTypes: NativeType[]
|
||||
): FunctionTypeRef {
|
||||
var cArr = allocI32Array(paramTypes);
|
||||
try {
|
||||
return _BinaryenGetFunctionTypeBySignature(this.ref, result, cArr, paramTypes.length);
|
||||
@ -282,7 +289,7 @@ export class Module {
|
||||
}
|
||||
}
|
||||
|
||||
// expressions
|
||||
// constants
|
||||
|
||||
createI32(value: i32): ExpressionRef {
|
||||
var out = this.out;
|
||||
@ -290,9 +297,9 @@ export class Module {
|
||||
return _BinaryenConst(this.ref, out);
|
||||
}
|
||||
|
||||
createI64(lo: i32, hi: i32 = 0): ExpressionRef {
|
||||
createI64(valueLow: i32, valueHigh: i32 = 0): ExpressionRef {
|
||||
var out = this.out;
|
||||
_BinaryenLiteralInt64(out, lo, hi);
|
||||
_BinaryenLiteralInt64(out, valueLow, valueHigh);
|
||||
return _BinaryenConst(this.ref, out);
|
||||
}
|
||||
|
||||
@ -308,15 +315,28 @@ export class Module {
|
||||
return _BinaryenConst(this.ref, out);
|
||||
}
|
||||
|
||||
createUnary(op: UnaryOp, expr: ExpressionRef): ExpressionRef {
|
||||
// expressions
|
||||
|
||||
createUnary(
|
||||
op: UnaryOp,
|
||||
expr: ExpressionRef
|
||||
): ExpressionRef {
|
||||
return _BinaryenUnary(this.ref, op, expr);
|
||||
}
|
||||
|
||||
createBinary(op: BinaryOp, left: ExpressionRef, right: ExpressionRef): ExpressionRef {
|
||||
createBinary(
|
||||
op: BinaryOp,
|
||||
left: ExpressionRef,
|
||||
right: ExpressionRef
|
||||
): ExpressionRef {
|
||||
return _BinaryenBinary(this.ref, op, left, right);
|
||||
}
|
||||
|
||||
createHost(op: HostOp, name: string | null = null, operands: ExpressionRef[] | null = null): ExpressionRef {
|
||||
createHost(
|
||||
op: HostOp,
|
||||
name: string | null = null,
|
||||
operands: ExpressionRef[] | null = null
|
||||
): ExpressionRef {
|
||||
var cStr = allocString(name);
|
||||
var cArr = allocI32Array(operands);
|
||||
try {
|
||||
@ -327,15 +347,24 @@ export class Module {
|
||||
}
|
||||
}
|
||||
|
||||
createGetLocal(index: i32, type: NativeType): ExpressionRef {
|
||||
createGetLocal(
|
||||
index: i32,
|
||||
type: NativeType
|
||||
): ExpressionRef {
|
||||
return _BinaryenGetLocal(this.ref, index, type);
|
||||
}
|
||||
|
||||
createTeeLocal(index: i32, value: ExpressionRef): ExpressionRef {
|
||||
createTeeLocal(
|
||||
index: i32,
|
||||
value: ExpressionRef
|
||||
): ExpressionRef {
|
||||
return _BinaryenTeeLocal(this.ref, index, value);
|
||||
}
|
||||
|
||||
createGetGlobal(name: string, type: NativeType): ExpressionRef {
|
||||
createGetGlobal(
|
||||
name: string,
|
||||
type: NativeType
|
||||
): ExpressionRef {
|
||||
var cStr = allocString(name);
|
||||
try {
|
||||
return _BinaryenGetGlobal(this.ref, cStr, type);
|
||||
@ -344,45 +373,96 @@ export class Module {
|
||||
}
|
||||
}
|
||||
|
||||
createLoad(bytes: Index, signed: bool, ptr: ExpressionRef, type: NativeType, offset: Index = 0): ExpressionRef {
|
||||
createLoad(
|
||||
bytes: Index,
|
||||
signed: bool,
|
||||
ptr: ExpressionRef,
|
||||
type: NativeType,
|
||||
offset: Index = 0
|
||||
): ExpressionRef {
|
||||
return _BinaryenLoad(this.ref, bytes, signed ? 1 : 0, offset, /* always aligned */ bytes, type, ptr);
|
||||
}
|
||||
|
||||
createStore(bytes: Index, ptr: ExpressionRef, value: ExpressionRef, type: NativeType, offset: Index = 0): ExpressionRef {
|
||||
createStore(
|
||||
bytes: Index,
|
||||
ptr: ExpressionRef,
|
||||
value: ExpressionRef,
|
||||
type: NativeType,
|
||||
offset: Index = 0
|
||||
): ExpressionRef {
|
||||
return _BinaryenStore(this.ref, bytes, offset, /* always aligned */ bytes, ptr, value, type);
|
||||
}
|
||||
|
||||
createAtomicLoad(bytes: Index, ptr: ExpressionRef, type: NativeType, offset: Index = 0): ExpressionRef {
|
||||
createAtomicLoad(
|
||||
bytes: Index,
|
||||
ptr: ExpressionRef,
|
||||
type: NativeType,
|
||||
offset: Index = 0
|
||||
): ExpressionRef {
|
||||
return _BinaryenAtomicLoad(this.ref, bytes, offset, type, ptr);
|
||||
}
|
||||
|
||||
createAtomicStore(bytes: Index, ptr: ExpressionRef, value: ExpressionRef, type: NativeType, offset: Index = 0): ExpressionRef {
|
||||
createAtomicStore(
|
||||
bytes: Index,
|
||||
ptr: ExpressionRef,
|
||||
value: ExpressionRef,
|
||||
type: NativeType,
|
||||
offset: Index = 0
|
||||
): ExpressionRef {
|
||||
return _BinaryenAtomicStore(this.ref, bytes, offset, ptr, value, type);
|
||||
}
|
||||
|
||||
createAtomicRMW(op: AtomicRMWOp, bytes: Index, offset: Index, ptr: ExpressionRef, value: ExpressionRef, type: NativeType): ExpressionRef {
|
||||
createAtomicRMW(
|
||||
op: AtomicRMWOp,
|
||||
bytes: Index,
|
||||
offset: Index,
|
||||
ptr: ExpressionRef,
|
||||
value: ExpressionRef,
|
||||
type: NativeType
|
||||
): ExpressionRef {
|
||||
return _BinaryenAtomicRMW(this.ref, op, bytes, offset, ptr, value, type);
|
||||
}
|
||||
|
||||
createAtomicCmpxchg(bytes: Index, offset: Index, ptr: ExpressionRef, expected: ExpressionRef, replacement: ExpressionRef, type: NativeType): ExpressionRef {
|
||||
createAtomicCmpxchg(
|
||||
bytes: Index,
|
||||
offset: Index,
|
||||
ptr: ExpressionRef,
|
||||
expected: ExpressionRef,
|
||||
replacement: ExpressionRef,
|
||||
type: NativeType
|
||||
): ExpressionRef {
|
||||
return _BinaryenAtomicCmpxchg(this.ref, bytes, offset, ptr, expected, replacement, type);
|
||||
}
|
||||
|
||||
createAtomicWait(ptr: ExpressionRef, expected: ExpressionRef, timeout: ExpressionRef, expectedType: NativeType): ExpressionRef {
|
||||
createAtomicWait(
|
||||
ptr: ExpressionRef,
|
||||
expected: ExpressionRef,
|
||||
timeout: ExpressionRef,
|
||||
expectedType: NativeType
|
||||
): ExpressionRef {
|
||||
return _BinaryenAtomicWait(this.ref, ptr, expected, timeout, expectedType);
|
||||
}
|
||||
|
||||
createAtomicWake(ptr: ExpressionRef, wakeCount: ExpressionRef): ExpressionRef {
|
||||
createAtomicWake(
|
||||
ptr: ExpressionRef,
|
||||
wakeCount: ExpressionRef
|
||||
): ExpressionRef {
|
||||
return _BinaryenAtomicWake(this.ref, ptr, wakeCount);
|
||||
}
|
||||
|
||||
// statements
|
||||
|
||||
createSetLocal(index: Index, value: ExpressionRef): ExpressionRef {
|
||||
createSetLocal(
|
||||
index: Index,
|
||||
value: ExpressionRef
|
||||
): ExpressionRef {
|
||||
return _BinaryenSetLocal(this.ref, index, value);
|
||||
}
|
||||
|
||||
createSetGlobal(name: string, value: ExpressionRef): ExpressionRef {
|
||||
createSetGlobal(
|
||||
name: string,
|
||||
value: ExpressionRef
|
||||
): ExpressionRef {
|
||||
var cStr = allocString(name);
|
||||
try {
|
||||
return _BinaryenSetGlobal(this.ref, cStr, value);
|
||||
@ -391,7 +471,11 @@ export class Module {
|
||||
}
|
||||
}
|
||||
|
||||
createBlock(label: string | null, children: ExpressionRef[], type: NativeType = NativeType.Auto): ExpressionRef {
|
||||
createBlock(
|
||||
label: string | null,
|
||||
children: ExpressionRef[],
|
||||
type: NativeType = NativeType.None
|
||||
): ExpressionRef {
|
||||
var cStr = allocString(label);
|
||||
var cArr = allocI32Array(children);
|
||||
try {
|
||||
@ -402,7 +486,11 @@ export class Module {
|
||||
}
|
||||
}
|
||||
|
||||
createBreak(label: string | null, condition: ExpressionRef = 0, value: ExpressionRef = 0): ExpressionRef {
|
||||
createBreak(
|
||||
label: string | null,
|
||||
condition: ExpressionRef = 0,
|
||||
value: ExpressionRef = 0
|
||||
): ExpressionRef {
|
||||
var cStr = allocString(label);
|
||||
try {
|
||||
return _BinaryenBreak(this.ref, cStr, condition, value);
|
||||
@ -411,11 +499,16 @@ export class Module {
|
||||
}
|
||||
}
|
||||
|
||||
createDrop(expression: ExpressionRef): ExpressionRef {
|
||||
createDrop(
|
||||
expression: ExpressionRef
|
||||
): ExpressionRef {
|
||||
return _BinaryenDrop(this.ref, expression);
|
||||
}
|
||||
|
||||
createLoop(label: string | null, body: ExpressionRef): ExpressionRef {
|
||||
createLoop(
|
||||
label: string | null,
|
||||
body: ExpressionRef
|
||||
): ExpressionRef {
|
||||
var cStr = allocString(label);
|
||||
try {
|
||||
return _BinaryenLoop(this.ref, cStr, body);
|
||||
@ -424,7 +517,11 @@ export class Module {
|
||||
}
|
||||
}
|
||||
|
||||
createIf(condition: ExpressionRef, ifTrue: ExpressionRef, ifFalse: ExpressionRef = 0): ExpressionRef {
|
||||
createIf(
|
||||
condition: ExpressionRef,
|
||||
ifTrue: ExpressionRef,
|
||||
ifFalse: ExpressionRef = 0
|
||||
): ExpressionRef {
|
||||
return _BinaryenIf(this.ref, condition, ifTrue, ifFalse);
|
||||
}
|
||||
|
||||
@ -432,18 +529,30 @@ export class Module {
|
||||
return _BinaryenNop(this.ref);
|
||||
}
|
||||
|
||||
createReturn(expression: ExpressionRef = 0): ExpressionRef {
|
||||
createReturn(
|
||||
expression: ExpressionRef = 0
|
||||
): ExpressionRef {
|
||||
return _BinaryenReturn(this.ref, expression);
|
||||
}
|
||||
|
||||
createSelect(ifTrue: ExpressionRef, ifFalse: ExpressionRef, condition: ExpressionRef): ExpressionRef {
|
||||
createSelect(
|
||||
ifTrue: ExpressionRef,
|
||||
ifFalse: ExpressionRef,
|
||||
condition: ExpressionRef
|
||||
): ExpressionRef {
|
||||
return _BinaryenSelect(this.ref, condition, ifTrue, ifFalse);
|
||||
}
|
||||
|
||||
createSwitch(names: string[], defaultName: string | null, condition: ExpressionRef, value: ExpressionRef = 0): ExpressionRef {
|
||||
createSwitch(
|
||||
names: string[],
|
||||
defaultName: string | null,
|
||||
condition: ExpressionRef,
|
||||
value: ExpressionRef = 0
|
||||
): ExpressionRef {
|
||||
var strs = new Array<usize>(names.length);
|
||||
for (var i = 0, k: i32 = names.length; i < k; ++i)
|
||||
for (var i = 0, k: i32 = names.length; i < k; ++i) {
|
||||
strs[i] = allocString(names[i]);
|
||||
}
|
||||
var cArr = allocI32Array(strs);
|
||||
var cStr = allocString(defaultName);
|
||||
try {
|
||||
@ -455,7 +564,11 @@ export class Module {
|
||||
}
|
||||
}
|
||||
|
||||
createCall(target: string, operands: ExpressionRef[] | null, returnType: NativeType): ExpressionRef {
|
||||
createCall(
|
||||
target: string,
|
||||
operands: ExpressionRef[] | null,
|
||||
returnType: NativeType
|
||||
): ExpressionRef {
|
||||
var cStr = allocString(target);
|
||||
var cArr = allocI32Array(operands);
|
||||
try {
|
||||
@ -466,7 +579,11 @@ export class Module {
|
||||
}
|
||||
}
|
||||
|
||||
createCallImport(target: string, operands: ExpressionRef[] | null, returnType: NativeType): ExpressionRef {
|
||||
createCallImport(
|
||||
target: string,
|
||||
operands: ExpressionRef[] | null,
|
||||
returnType: NativeType
|
||||
): ExpressionRef {
|
||||
var cStr = allocString(target);
|
||||
var cArr = allocI32Array(operands);
|
||||
try {
|
||||
@ -483,7 +600,12 @@ export class Module {
|
||||
|
||||
// meta
|
||||
|
||||
addGlobal(name: string, type: NativeType, mutable: bool, initializer: ExpressionRef): GlobalRef {
|
||||
addGlobal(
|
||||
name: string,
|
||||
type: NativeType,
|
||||
mutable: bool,
|
||||
initializer: ExpressionRef
|
||||
): GlobalRef {
|
||||
var cStr = allocString(name);
|
||||
try {
|
||||
return _BinaryenAddGlobal(this.ref, cStr, type, mutable ? 1 : 0, initializer);
|
||||
@ -492,7 +614,12 @@ export class Module {
|
||||
}
|
||||
}
|
||||
|
||||
addFunction(name: string, type: FunctionTypeRef, varTypes: NativeType[], body: ExpressionRef): FunctionRef {
|
||||
addFunction(
|
||||
name: string,
|
||||
type: FunctionTypeRef,
|
||||
varTypes: NativeType[],
|
||||
body: ExpressionRef
|
||||
): FunctionRef {
|
||||
var cStr = allocString(name);
|
||||
var cArr = allocI32Array(varTypes);
|
||||
try {
|
||||
@ -512,7 +639,10 @@ export class Module {
|
||||
}
|
||||
}
|
||||
|
||||
addFunctionExport(internalName: string, externalName: string): ExportRef {
|
||||
addFunctionExport(
|
||||
internalName: string,
|
||||
externalName: string
|
||||
): ExportRef {
|
||||
var cStr1 = allocString(internalName);
|
||||
var cStr2 = allocString(externalName);
|
||||
try {
|
||||
@ -523,7 +653,10 @@ export class Module {
|
||||
}
|
||||
}
|
||||
|
||||
addTableExport(internalName: string, externalName: string): ExportRef {
|
||||
addTableExport(
|
||||
internalName: string,
|
||||
externalName: string
|
||||
): ExportRef {
|
||||
var cStr1 = allocString(internalName);
|
||||
var cStr2 = allocString(externalName);
|
||||
try {
|
||||
@ -534,7 +667,10 @@ export class Module {
|
||||
}
|
||||
}
|
||||
|
||||
addMemoryExport(internalName: string, externalName: string): ExportRef {
|
||||
addMemoryExport(
|
||||
internalName: string,
|
||||
externalName: string
|
||||
): ExportRef {
|
||||
var cStr1 = allocString(internalName);
|
||||
var cStr2 = allocString(externalName);
|
||||
try {
|
||||
@ -545,7 +681,10 @@ export class Module {
|
||||
}
|
||||
}
|
||||
|
||||
addGlobalExport(internalName: string, externalName: string): ExportRef {
|
||||
addGlobalExport(
|
||||
internalName: string,
|
||||
externalName: string
|
||||
): ExportRef {
|
||||
var cStr1 = allocString(internalName);
|
||||
var cStr2 = allocString(externalName);
|
||||
try {
|
||||
@ -565,7 +704,12 @@ export class Module {
|
||||
}
|
||||
}
|
||||
|
||||
addFunctionImport(internalName: string, externalModuleName: string, externalBaseName: string, functionType: FunctionTypeRef): ImportRef {
|
||||
addFunctionImport(
|
||||
internalName: string,
|
||||
externalModuleName: string,
|
||||
externalBaseName: string,
|
||||
functionType: FunctionTypeRef
|
||||
): ImportRef {
|
||||
var cStr1 = allocString(internalName);
|
||||
var cStr2 = allocString(externalModuleName);
|
||||
var cStr3 = allocString(externalBaseName);
|
||||
@ -578,7 +722,11 @@ export class Module {
|
||||
}
|
||||
}
|
||||
|
||||
addTableImport(internalName: string, externalModuleName: string, externalBaseName: string): ImportRef {
|
||||
addTableImport(
|
||||
internalName: string,
|
||||
externalModuleName: string,
|
||||
externalBaseName: string
|
||||
): ImportRef {
|
||||
var cStr1 = allocString(internalName);
|
||||
var cStr2 = allocString(externalModuleName);
|
||||
var cStr3 = allocString(externalBaseName);
|
||||
@ -591,7 +739,11 @@ export class Module {
|
||||
}
|
||||
}
|
||||
|
||||
addMemoryImport(internalName: string, externalModuleName: string, externalBaseName: string): ImportRef {
|
||||
addMemoryImport(
|
||||
internalName: string,
|
||||
externalModuleName: string,
|
||||
externalBaseName: string
|
||||
): ImportRef {
|
||||
var cStr1 = allocString(internalName);
|
||||
var cStr2 = allocString(externalModuleName);
|
||||
var cStr3 = allocString(externalBaseName);
|
||||
@ -604,7 +756,12 @@ export class Module {
|
||||
}
|
||||
}
|
||||
|
||||
addGlobalImport(internalName: string, externalModuleName: string, externalBaseName: string, globalType: NativeType): ImportRef {
|
||||
addGlobalImport(
|
||||
internalName: string,
|
||||
externalModuleName: string,
|
||||
externalBaseName: string,
|
||||
globalType: NativeType
|
||||
): ImportRef {
|
||||
var cStr1 = allocString(internalName);
|
||||
var cStr2 = allocString(externalModuleName);
|
||||
var cStr3 = allocString(externalBaseName);
|
||||
@ -626,7 +783,13 @@ export class Module {
|
||||
}
|
||||
}
|
||||
|
||||
setMemory(initial: Index, maximum: Index, segments: MemorySegment[], target: Target, exportName: string | null = null): void {
|
||||
setMemory(
|
||||
initial: Index,
|
||||
maximum: Index,
|
||||
segments: MemorySegment[],
|
||||
target: Target,
|
||||
exportName: string | null = null
|
||||
): void {
|
||||
var cStr = allocString(exportName);
|
||||
var k = segments.length;
|
||||
var segs = new Array<usize>(k);
|
||||
@ -691,14 +854,16 @@ export class Module {
|
||||
runPasses(passes: string[], func: FunctionRef = 0): void {
|
||||
var k = passes.length;
|
||||
var names = new Array<usize>(k);
|
||||
for (var i = 0; i < k; ++i)
|
||||
for (var i = 0; i < k; ++i) {
|
||||
names[i] = allocString(passes[i]);
|
||||
}
|
||||
var cArr = allocI32Array(names);
|
||||
try {
|
||||
if (func)
|
||||
if (func) {
|
||||
_BinaryenFunctionRunPasses(func, this.ref, cArr, k);
|
||||
else
|
||||
} else {
|
||||
_BinaryenModuleRunPasses(this.ref, cArr, k);
|
||||
}
|
||||
} finally {
|
||||
free_memory(cArr);
|
||||
for (; i >= 0; --i) free_memory(names[i]);
|
||||
@ -752,10 +917,12 @@ export class Module {
|
||||
return Relooper.create(this);
|
||||
}
|
||||
|
||||
// currently supports side effect free expressions only
|
||||
cloneExpression(expr: ExpressionRef, noSideEffects: bool = false, maxDepth: i32 = i32.MAX_VALUE): ExpressionRef {
|
||||
if (maxDepth < 0)
|
||||
return 0;
|
||||
cloneExpression(expr: ExpressionRef,
|
||||
noSideEffects: bool = false,
|
||||
maxDepth: i32 = i32.MAX_VALUE
|
||||
): ExpressionRef { // currently supports side effect free expressions only
|
||||
if (maxDepth < 0) return 0;
|
||||
maxDepth -= 1;
|
||||
|
||||
var nested1: ExpressionRef,
|
||||
nested2: ExpressionRef;
|
||||
@ -764,39 +931,65 @@ export class Module {
|
||||
|
||||
case ExpressionId.Const:
|
||||
switch (_BinaryenExpressionGetType(expr)) {
|
||||
case NativeType.I32: return this.createI32(_BinaryenConstGetValueI32(expr));
|
||||
case NativeType.I64: return this.createI64(_BinaryenConstGetValueI64Low(expr), _BinaryenConstGetValueI64High(expr));
|
||||
case NativeType.F32: return this.createF32(_BinaryenConstGetValueF32(expr));
|
||||
case NativeType.F64: return this.createF64(_BinaryenConstGetValueF64(expr));
|
||||
default: throw new Error("concrete type expected");
|
||||
case NativeType.I32:
|
||||
return this.createI32(_BinaryenConstGetValueI32(expr));
|
||||
case NativeType.I64:
|
||||
return this.createI64(
|
||||
_BinaryenConstGetValueI64Low(expr),
|
||||
_BinaryenConstGetValueI64High(expr)
|
||||
);
|
||||
case NativeType.F32:
|
||||
return this.createF32(_BinaryenConstGetValueF32(expr));
|
||||
case NativeType.F64:
|
||||
return this.createF64(_BinaryenConstGetValueF64(expr));
|
||||
default:
|
||||
throw new Error("concrete type expected");
|
||||
}
|
||||
|
||||
case ExpressionId.GetLocal:
|
||||
return _BinaryenGetLocal(this.ref, _BinaryenGetLocalGetIndex(expr), _BinaryenExpressionGetType(expr));
|
||||
return _BinaryenGetLocal(this.ref,
|
||||
_BinaryenGetLocalGetIndex(expr),
|
||||
_BinaryenExpressionGetType(expr)
|
||||
);
|
||||
|
||||
case ExpressionId.GetGlobal:
|
||||
var globalName = _BinaryenGetGlobalGetName(expr);
|
||||
if (!globalName)
|
||||
break;
|
||||
if (!globalName) break;
|
||||
return _BinaryenGetGlobal(this.ref, globalName, _BinaryenExpressionGetType(expr));
|
||||
|
||||
case ExpressionId.Load:
|
||||
if (!(nested1 = this.cloneExpression(_BinaryenLoadGetPtr(expr), noSideEffects, maxDepth - 1)))
|
||||
if (!(nested1 = this.cloneExpression(_BinaryenLoadGetPtr(expr), noSideEffects, maxDepth))) {
|
||||
break;
|
||||
}
|
||||
return _BinaryenLoadIsAtomic(expr)
|
||||
? _BinaryenAtomicLoad(this.ref, _BinaryenLoadGetBytes(expr), _BinaryenLoadGetOffset(expr), _BinaryenExpressionGetType(expr), nested1)
|
||||
: _BinaryenLoad(this.ref, _BinaryenLoadGetBytes(expr), _BinaryenLoadIsSigned(expr) ? 1 : 0, _BinaryenLoadGetOffset(expr), _BinaryenLoadGetAlign(expr), _BinaryenExpressionGetType(expr), nested1);
|
||||
? _BinaryenAtomicLoad(this.ref,
|
||||
_BinaryenLoadGetBytes(expr),
|
||||
_BinaryenLoadGetOffset(expr),
|
||||
_BinaryenExpressionGetType(expr),
|
||||
nested1
|
||||
)
|
||||
: _BinaryenLoad(this.ref,
|
||||
_BinaryenLoadGetBytes(expr),
|
||||
_BinaryenLoadIsSigned(expr) ? 1 : 0,
|
||||
_BinaryenLoadGetOffset(expr),
|
||||
_BinaryenLoadGetAlign(expr),
|
||||
_BinaryenExpressionGetType(expr),
|
||||
nested1
|
||||
);
|
||||
|
||||
case ExpressionId.Unary:
|
||||
if (!(nested1 = this.cloneExpression(_BinaryenUnaryGetValue(expr), noSideEffects, maxDepth - 1)))
|
||||
if (!(nested1 = this.cloneExpression(_BinaryenUnaryGetValue(expr), noSideEffects, maxDepth))) {
|
||||
break;
|
||||
}
|
||||
return _BinaryenUnary(this.ref, _BinaryenUnaryGetOp(expr), nested1);
|
||||
|
||||
case ExpressionId.Binary:
|
||||
if (!(nested1 = this.cloneExpression(_BinaryenBinaryGetLeft(expr), noSideEffects, maxDepth - 1)))
|
||||
if (!(nested1 = this.cloneExpression(_BinaryenBinaryGetLeft(expr), noSideEffects, maxDepth))) {
|
||||
break;
|
||||
if (!(nested2 = this.cloneExpression(_BinaryenBinaryGetRight(expr), noSideEffects, maxDepth - 1)))
|
||||
}
|
||||
if (!(nested2 = this.cloneExpression(_BinaryenBinaryGetRight(expr), noSideEffects, maxDepth))) {
|
||||
break;
|
||||
}
|
||||
return _BinaryenBinary(this.ref, _BinaryenBinaryGetOp(expr), nested1, nested2);
|
||||
}
|
||||
return 0;
|
||||
@ -817,7 +1010,13 @@ export class Module {
|
||||
return readString(_BinaryenModuleGetDebugInfoFileName(this.ref, index));
|
||||
}
|
||||
|
||||
setDebugLocation(func: FunctionRef, expr: ExpressionRef, fileIndex: Index, lineNumber: Index, columnNumber: Index): void {
|
||||
setDebugLocation(
|
||||
func: FunctionRef,
|
||||
expr: ExpressionRef,
|
||||
fileIndex: Index,
|
||||
lineNumber: Index,
|
||||
columnNumber: Index
|
||||
): void {
|
||||
_BinaryenFunctionSetDebugLocation(func, expr, fileIndex, lineNumber, columnNumber);
|
||||
}
|
||||
}
|
||||
@ -876,8 +1075,9 @@ function allocU8Array(u8s: Uint8Array | null): usize {
|
||||
if (!u8s) return 0;
|
||||
var ptr = allocate_memory(u8s.length);
|
||||
var idx = ptr;
|
||||
for (var i = 0, k = u8s.length; i < k; ++i)
|
||||
for (var i = 0, k = u8s.length; i < k; ++i) {
|
||||
store<u8>(idx++, u8s[i]);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@ -901,20 +1101,22 @@ function stringLengthUTF8(str: string): usize {
|
||||
var len = 0;
|
||||
for (var i = 0, k = str.length; i < k; ++i) {
|
||||
var u = str.charCodeAt(i);
|
||||
if (u >= 0xD800 && u <= 0xDFFF && i + 1 < k)
|
||||
if (u >= 0xD800 && u <= 0xDFFF && i + 1 < k) {
|
||||
u = 0x10000 + ((u & 0x3FF) << 10) | (str.charCodeAt(++i) & 0x3FF);
|
||||
if (u <= 0x7F)
|
||||
}
|
||||
if (u <= 0x7F) {
|
||||
++len;
|
||||
else if (u <= 0x7FF)
|
||||
} else if (u <= 0x7FF) {
|
||||
len += 2;
|
||||
else if (u <= 0xFFFF)
|
||||
} else if (u <= 0xFFFF) {
|
||||
len += 3;
|
||||
else if (u <= 0x1FFFFF)
|
||||
} else if (u <= 0x1FFFFF) {
|
||||
len += 4;
|
||||
else if (u <= 0x3FFFFFF)
|
||||
} else if (u <= 0x3FFFFFF) {
|
||||
len += 5;
|
||||
else
|
||||
} else {
|
||||
len += 6;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
@ -925,11 +1127,12 @@ function allocString(str: string | null): usize {
|
||||
var idx = ptr;
|
||||
for (var i = 0, k = str.length; i < k; ++i) {
|
||||
var u = str.charCodeAt(i);
|
||||
if (u >= 0xD800 && u <= 0xDFFF && i + 1 < k)
|
||||
if (u >= 0xD800 && u <= 0xDFFF && i + 1 < k) {
|
||||
u = 0x10000 + ((u & 0x3FF) << 10) | (str.charCodeAt(++i) & 0x3FF);
|
||||
if (u <= 0x7F)
|
||||
}
|
||||
if (u <= 0x7F) {
|
||||
store<u8>(idx++, u as u8);
|
||||
else if (u <= 0x7FF) {
|
||||
} else if (u <= 0x7FF) {
|
||||
store<u8>(idx++, (0xC0 | (u >>> 6) ) as u8);
|
||||
store<u8>(idx++, (0x80 | ( u & 63)) as u8);
|
||||
} else if (u <= 0xFFFF) {
|
||||
@ -971,8 +1174,9 @@ export function readInt(ptr: usize): i32 {
|
||||
|
||||
export function readBuffer(ptr: usize, length: usize): Uint8Array {
|
||||
var ret = new Uint8Array(length);
|
||||
for (var i: usize = 0; i < length; ++i)
|
||||
for (var i: usize = 0; i < length; ++i) {
|
||||
ret[i] = load<u8>(ptr + i);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
1850
src/parser.ts
1850
src/parser.ts
File diff suppressed because it is too large
Load Diff
1470
src/program.ts
1470
src/program.ts
File diff suppressed because it is too large
Load Diff
409
src/tokenizer.ts
409
src/tokenizer.ts
@ -1,8 +1,8 @@
|
||||
/*
|
||||
|
||||
This is a modified version of TypeScript's scanner that doesn't perform
|
||||
as much bookkeeping, simply skips over trivia and provides a more general
|
||||
mark/reset mechanism for the parser to utilize on ambiguous tokens.
|
||||
This is a modified version of TypeScript's scanner that doesn't perform as much bookkeeping, simply
|
||||
skips over trivia and provides a more general mark/reset mechanism for the parser to utilize on
|
||||
ambiguous tokens.
|
||||
|
||||
next() advances the token
|
||||
peek() peeks for the next token
|
||||
@ -285,21 +285,29 @@ export class Range {
|
||||
}
|
||||
|
||||
static join(a: Range, b: Range): Range {
|
||||
if (a.source != b.source)
|
||||
throw new Error("source mismatch");
|
||||
return new Range(a.source, a.start < b.start ? a.start : b.start, a.end > b.end ? a.end : b.end);
|
||||
if (a.source != b.source) throw new Error("source mismatch");
|
||||
return new Range(a.source,
|
||||
a.start < b.start ? a.start : b.start,
|
||||
a.end > b.end ? a.end : b.end
|
||||
);
|
||||
}
|
||||
|
||||
get atStart(): Range { return new Range(this.source, this.start, this.start); }
|
||||
get atEnd(): Range { return new Range(this.source, this.end, this.end); }
|
||||
get atStart(): Range {
|
||||
return new Range(this.source, this.start, this.start);
|
||||
}
|
||||
get atEnd(): Range {
|
||||
return new Range(this.source, this.end, this.end);
|
||||
}
|
||||
|
||||
get line(): i32 {
|
||||
var text = this.source.text;
|
||||
var pos = this.start;
|
||||
var line = 1;
|
||||
while (pos-- > 0)
|
||||
if (text.charCodeAt(pos) == CharCode.LINEFEED)
|
||||
while (pos-- > 0) {
|
||||
if (text.charCodeAt(pos) == CharCode.LINEFEED) {
|
||||
line++;
|
||||
}
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
@ -308,8 +316,7 @@ export class Range {
|
||||
var pos = this.start;
|
||||
var column = 0;
|
||||
while (pos-- > 0) {
|
||||
if (text.charCodeAt(pos) == CharCode.LINEFEED)
|
||||
break;
|
||||
if (text.charCodeAt(pos) == CharCode.LINEFEED) break;
|
||||
column++;
|
||||
}
|
||||
return column;
|
||||
@ -350,14 +357,26 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
var text = source.text;
|
||||
|
||||
// skip bom
|
||||
if (this.pos < this.end && text.charCodeAt(this.pos) == CharCode.BYTEORDERMARK)
|
||||
if (
|
||||
this.pos < this.end &&
|
||||
text.charCodeAt(this.pos) == CharCode.BYTEORDERMARK
|
||||
) {
|
||||
++this.pos;
|
||||
}
|
||||
|
||||
// skip shebang
|
||||
if (this.pos + 1 < this.end && text.charCodeAt(this.pos) == CharCode.HASH && text.charCodeAt(this.pos + 1) == CharCode.EXCLAMATION) {
|
||||
if (
|
||||
this.pos + 1 < this.end &&
|
||||
text.charCodeAt(this.pos) == CharCode.HASH &&
|
||||
text.charCodeAt(this.pos + 1) == CharCode.EXCLAMATION
|
||||
) {
|
||||
this.pos += 2;
|
||||
while (this.pos < this.end && text.charCodeAt(this.pos) != CharCode.LINEFEED)
|
||||
while (
|
||||
this.pos < this.end &&
|
||||
text.charCodeAt(this.pos) != CharCode.LINEFEED
|
||||
) {
|
||||
++this.pos;
|
||||
}
|
||||
// 'next' now starts at lf or eof
|
||||
}
|
||||
}
|
||||
@ -367,19 +386,20 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
return this.token = this.unsafeNext(preferIdentifier);
|
||||
}
|
||||
|
||||
private unsafeNext(preferIdentifier: bool = false, maxCompoundLength: i32 = i32.MAX_VALUE): Token {
|
||||
private unsafeNext(preferIdentifier: bool = false, maxTokenLength: i32 = i32.MAX_VALUE): Token {
|
||||
var text = this.source.text;
|
||||
while (true) {
|
||||
if (this.pos >= this.end)
|
||||
return Token.ENDOFFILE;
|
||||
|
||||
while (this.pos < this.end) {
|
||||
this.tokenPos = this.pos;
|
||||
var c = text.charCodeAt(this.pos);
|
||||
switch (c) {
|
||||
|
||||
case CharCode.CARRIAGERETURN:
|
||||
if (++this.pos < this.end && text.charCodeAt(this.pos) == CharCode.LINEFEED)
|
||||
if (
|
||||
++this.pos < this.end &&
|
||||
text.charCodeAt(this.pos) == CharCode.LINEFEED
|
||||
) {
|
||||
++this.pos;
|
||||
}
|
||||
break;
|
||||
|
||||
case CharCode.LINEFEED:
|
||||
@ -392,9 +412,15 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
|
||||
case CharCode.EXCLAMATION:
|
||||
++this.pos;
|
||||
if (maxCompoundLength > 1 && this.pos < this.end && text.charCodeAt(this.pos) == CharCode.EQUALS) {
|
||||
if (
|
||||
maxTokenLength > 1 && this.pos < this.end &&
|
||||
text.charCodeAt(this.pos) == CharCode.EQUALS
|
||||
) {
|
||||
++this.pos;
|
||||
if (maxCompoundLength > 2 && this.pos < this.end && text.charCodeAt(this.pos) == CharCode.EQUALS) {
|
||||
if (
|
||||
maxTokenLength > 2 && this.pos < this.end &&
|
||||
text.charCodeAt(this.pos) == CharCode.EQUALS
|
||||
) {
|
||||
++this.pos;
|
||||
return Token.EXCLAMATION_EQUALS_EQUALS;
|
||||
}
|
||||
@ -409,7 +435,10 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
|
||||
case CharCode.PERCENT:
|
||||
++this.pos;
|
||||
if (maxCompoundLength > 1 && this.pos < this.end && text.charCodeAt(this.pos) == CharCode.EQUALS) {
|
||||
if (
|
||||
maxTokenLength > 1 && this.pos < this.end &&
|
||||
text.charCodeAt(this.pos) == CharCode.EQUALS
|
||||
) {
|
||||
++this.pos;
|
||||
return Token.PERCENT_EQUALS;
|
||||
}
|
||||
@ -417,7 +446,7 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
|
||||
case CharCode.AMPERSAND:
|
||||
++this.pos;
|
||||
if (maxCompoundLength > 1 && this.pos < this.end) {
|
||||
if (maxTokenLength > 1 && this.pos < this.end) {
|
||||
if (text.charCodeAt(this.pos) == CharCode.AMPERSAND) {
|
||||
++this.pos;
|
||||
return Token.AMPERSAND_AMPERSAND;
|
||||
@ -439,14 +468,17 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
|
||||
case CharCode.ASTERISK:
|
||||
++this.pos;
|
||||
if (maxCompoundLength > 1 && this.pos < this.end) {
|
||||
if (maxTokenLength > 1 && this.pos < this.end) {
|
||||
if (text.charCodeAt(this.pos) == CharCode.EQUALS) {
|
||||
++this.pos;
|
||||
return Token.ASTERISK_EQUALS;
|
||||
}
|
||||
if (text.charCodeAt(this.pos) == CharCode.ASTERISK) {
|
||||
++this.pos;
|
||||
if (maxCompoundLength > 2 && this.pos < this.end && text.charCodeAt(this.pos) == CharCode.EQUALS) {
|
||||
if (
|
||||
maxTokenLength > 2 && this.pos < this.end &&
|
||||
text.charCodeAt(this.pos) == CharCode.EQUALS
|
||||
) {
|
||||
++this.pos;
|
||||
return Token.ASTERISK_ASTERISK_EQUALS;
|
||||
}
|
||||
@ -457,7 +489,7 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
|
||||
case CharCode.PLUS:
|
||||
++this.pos;
|
||||
if (maxCompoundLength > 1 && this.pos < this.end) {
|
||||
if (maxTokenLength > 1 && this.pos < this.end) {
|
||||
if (text.charCodeAt(this.pos) == CharCode.PLUS) {
|
||||
++this.pos;
|
||||
return Token.PLUS_PLUS;
|
||||
@ -475,7 +507,7 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
|
||||
case CharCode.MINUS:
|
||||
++this.pos;
|
||||
if (maxCompoundLength > 1 && this.pos < this.end) {
|
||||
if (maxTokenLength > 1 && this.pos < this.end) {
|
||||
if (text.charCodeAt(this.pos) == CharCode.MINUS) {
|
||||
++this.pos;
|
||||
return Token.MINUS_MINUS;
|
||||
@ -489,12 +521,16 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
|
||||
case CharCode.DOT:
|
||||
++this.pos;
|
||||
if (maxCompoundLength > 1 && this.pos < this.end) {
|
||||
if (maxTokenLength > 1 && this.pos < this.end) {
|
||||
if (isDecimalDigit(text.charCodeAt(this.pos))) {
|
||||
--this.pos;
|
||||
return Token.FLOATLITERAL; // expects a call to readFloat
|
||||
}
|
||||
if (maxCompoundLength > 2 && text.charCodeAt(this.pos) == CharCode.DOT && this.pos + 1 < this.end && text.charCodeAt(this.pos + 1) == CharCode.DOT) {
|
||||
if (
|
||||
maxTokenLength > 2 && this.pos + 1 < this.end &&
|
||||
text.charCodeAt(this.pos) == CharCode.DOT &&
|
||||
text.charCodeAt(this.pos + 1) == CharCode.DOT
|
||||
) {
|
||||
this.pos += 2;
|
||||
return Token.DOT_DOT_DOT;
|
||||
}
|
||||
@ -503,29 +539,39 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
|
||||
case CharCode.SLASH:
|
||||
++this.pos;
|
||||
if (maxCompoundLength > 1 && this.pos < this.end) {
|
||||
if (text.charCodeAt(this.pos) == CharCode.SLASH) { // single-line comment
|
||||
if (this.pos + 1 < this.end && text.charCodeAt(this.pos + 1) == CharCode.SLASH) {
|
||||
// TODO: triple-slash directives, i.e. '/// <reference path="some.d.ts" />'
|
||||
}
|
||||
if (maxTokenLength > 1 && this.pos < this.end) {
|
||||
if (text.charCodeAt(this.pos) == CharCode.SLASH) { // single-line
|
||||
// TODO: triple-slash?
|
||||
// if (
|
||||
// this.pos + 1 < this.end &&
|
||||
// text.charCodeAt(this.pos + 1) == CharCode.SLASH
|
||||
// ) {
|
||||
// }
|
||||
while (++this.pos < this.end) {
|
||||
if (isLineBreak(text.charCodeAt(this.pos)))
|
||||
break;
|
||||
if (isLineBreak(text.charCodeAt(this.pos))) break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (text.charCodeAt(this.pos) == CharCode.ASTERISK) { // multi-line comment
|
||||
if (text.charCodeAt(this.pos) == CharCode.ASTERISK) { // multi-line
|
||||
var closed = false;
|
||||
while (++this.pos < this.end) {
|
||||
c = text.charCodeAt(this.pos);
|
||||
if (c == CharCode.ASTERISK && this.pos + 1 < this.end && text.charCodeAt(this.pos + 1) == CharCode.SLASH) {
|
||||
if (
|
||||
c == CharCode.ASTERISK &&
|
||||
this.pos + 1 < this.end &&
|
||||
text.charCodeAt(this.pos + 1) == CharCode.SLASH
|
||||
) {
|
||||
this.pos += 2;
|
||||
closed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!closed)
|
||||
this.error(DiagnosticCode._0_expected, this.range(this.pos), "*/");
|
||||
if (!closed) {
|
||||
this.error(
|
||||
DiagnosticCode._0_expected,
|
||||
this.range(this.pos), "*/"
|
||||
);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (text.charCodeAt(this.pos) == CharCode.EQUALS) {
|
||||
@ -559,10 +605,14 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
|
||||
case CharCode.LESSTHAN:
|
||||
++this.pos;
|
||||
if (maxCompoundLength > 1 && this.pos < this.end) {
|
||||
if (maxTokenLength > 1 && this.pos < this.end) {
|
||||
if (text.charCodeAt(this.pos) == CharCode.LESSTHAN) {
|
||||
++this.pos;
|
||||
if (maxCompoundLength > 2 && this.pos < this.end && text.charCodeAt(this.pos) == CharCode.EQUALS) {
|
||||
if (
|
||||
maxTokenLength > 2 &&
|
||||
this.pos < this.end &&
|
||||
text.charCodeAt(this.pos) == CharCode.EQUALS
|
||||
) {
|
||||
++this.pos;
|
||||
return Token.LESSTHAN_LESSTHAN_EQUALS;
|
||||
}
|
||||
@ -577,10 +627,14 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
|
||||
case CharCode.EQUALS:
|
||||
++this.pos;
|
||||
if (maxCompoundLength > 1 && this.pos < this.end) {
|
||||
if (maxTokenLength > 1 && this.pos < this.end) {
|
||||
if (text.charCodeAt(this.pos) == CharCode.EQUALS) {
|
||||
++this.pos;
|
||||
if (maxCompoundLength > 2 && this.pos < this.end && text.charCodeAt(this.pos) == CharCode.EQUALS) {
|
||||
if (
|
||||
maxTokenLength > 2 &&
|
||||
this.pos < this.end &&
|
||||
text.charCodeAt(this.pos) == CharCode.EQUALS
|
||||
) {
|
||||
++this.pos;
|
||||
return Token.EQUALS_EQUALS_EQUALS;
|
||||
}
|
||||
@ -595,13 +649,16 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
|
||||
case CharCode.GREATERTHAN:
|
||||
++this.pos;
|
||||
if (maxCompoundLength > 1 && this.pos < this.end) {
|
||||
if (maxTokenLength > 1 && this.pos < this.end) {
|
||||
if (text.charCodeAt(this.pos) == CharCode.GREATERTHAN) {
|
||||
++this.pos;
|
||||
if (maxCompoundLength > 2 && this.pos < this.end) {
|
||||
if (maxTokenLength > 2 && this.pos < this.end) {
|
||||
if (text.charCodeAt(this.pos) == CharCode.GREATERTHAN) {
|
||||
++this.pos;
|
||||
if (maxCompoundLength > 3 && this.pos < this.end && text.charCodeAt(this.pos) == CharCode.EQUALS) {
|
||||
if (
|
||||
maxTokenLength > 3 && this.pos < this.end &&
|
||||
text.charCodeAt(this.pos) == CharCode.EQUALS
|
||||
) {
|
||||
++this.pos;
|
||||
return Token.GREATERTHAN_GREATERTHAN_GREATERTHAN_EQUALS;
|
||||
}
|
||||
@ -635,7 +692,10 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
|
||||
case CharCode.CARET:
|
||||
++this.pos;
|
||||
if (maxCompoundLength > 1 && this.pos < this.end && text.charCodeAt(this.pos) == CharCode.EQUALS) {
|
||||
if (
|
||||
maxTokenLength > 1 && this.pos < this.end &&
|
||||
text.charCodeAt(this.pos) == CharCode.EQUALS
|
||||
) {
|
||||
++this.pos;
|
||||
return Token.CARET_EQUALS;
|
||||
}
|
||||
@ -647,7 +707,7 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
|
||||
case CharCode.BAR:
|
||||
++this.pos;
|
||||
if (maxCompoundLength > 1 && this.pos < this.end) {
|
||||
if (maxTokenLength > 1 && this.pos < this.end) {
|
||||
if (text.charCodeAt(this.pos) == CharCode.BAR) {
|
||||
++this.pos;
|
||||
return Token.BAR_BAR;
|
||||
@ -675,7 +735,10 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
if (isIdentifierStart(c)) {
|
||||
if (isKeywordCharacter(c)) {
|
||||
var posBefore = this.pos;
|
||||
while (++this.pos < this.end && isIdentifierPart(c = text.charCodeAt(this.pos))) {
|
||||
while (
|
||||
++this.pos < this.end &&
|
||||
isIdentifierPart(c = text.charCodeAt(this.pos))
|
||||
) {
|
||||
if (!isKeywordCharacter(c)) {
|
||||
this.pos = posBefore;
|
||||
return Token.IDENTIFIER;
|
||||
@ -683,8 +746,12 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
}
|
||||
var keywordText = text.substring(posBefore, this.pos);
|
||||
var keywordToken = Token.fromKeyword(keywordText);
|
||||
if (keywordToken != Token.INVALID && !(preferIdentifier && Token.isAlsoIdentifier(keywordToken)))
|
||||
if (
|
||||
keywordToken != Token.INVALID &&
|
||||
!(preferIdentifier && Token.isAlsoIdentifier(keywordToken))
|
||||
) {
|
||||
return keywordToken;
|
||||
}
|
||||
this.pos = posBefore;
|
||||
}
|
||||
return Token.IDENTIFIER; // expects a call to readIdentifier
|
||||
@ -692,14 +759,22 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
++this.pos;
|
||||
break;
|
||||
}
|
||||
this.error(DiagnosticCode.Invalid_character, this.range(this.pos, this.pos + 1));
|
||||
this.error(
|
||||
DiagnosticCode.Invalid_character,
|
||||
this.range(this.pos, this.pos + 1)
|
||||
);
|
||||
++this.pos;
|
||||
return Token.INVALID;
|
||||
}
|
||||
}
|
||||
return Token.ENDOFFILE;
|
||||
}
|
||||
|
||||
peek(checkOnNewLine: bool = false, preferIdentifier: bool = false, maxCompoundLength: i32 = i32.MAX_VALUE): Token {
|
||||
peek(
|
||||
checkOnNewLine: bool = false,
|
||||
preferIdentifier: bool = false,
|
||||
maxCompoundLength: i32 = i32.MAX_VALUE
|
||||
): Token {
|
||||
var text = this.source.text;
|
||||
if (this.nextToken < 0) {
|
||||
var posBefore = this.pos;
|
||||
@ -732,7 +807,8 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
maxCompoundLength = 1;
|
||||
break;
|
||||
}
|
||||
if ((this.token = this.unsafeNext(token == Token.IDENTIFIER, maxCompoundLength)) == token) {
|
||||
this.token = this.unsafeNext(token == Token.IDENTIFIER, maxCompoundLength);
|
||||
if (this.token == token) {
|
||||
this.nextToken = -1;
|
||||
return true;
|
||||
} else {
|
||||
@ -771,15 +847,19 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
if (start < 0) {
|
||||
start = this.tokenPos;
|
||||
end = this.pos;
|
||||
} else if (end < 0)
|
||||
} else if (end < 0) {
|
||||
end = start;
|
||||
}
|
||||
return new Range(this.source, start, end);
|
||||
}
|
||||
|
||||
readIdentifier(): string {
|
||||
var text = this.source.text;
|
||||
var start = this.pos;
|
||||
while (++this.pos < this.end && isIdentifierPart(text.charCodeAt(this.pos)));
|
||||
while (
|
||||
++this.pos < this.end &&
|
||||
isIdentifierPart(text.charCodeAt(this.pos))
|
||||
);
|
||||
return text.substring(start, this.pos);
|
||||
}
|
||||
|
||||
@ -791,7 +871,10 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
while (true) {
|
||||
if (this.pos >= this.end) {
|
||||
result += text.substring(start, this.pos);
|
||||
this.error(DiagnosticCode.Unterminated_string_literal, this.range(start - 1, this.end));
|
||||
this.error(
|
||||
DiagnosticCode.Unterminated_string_literal,
|
||||
this.range(start - 1, this.end)
|
||||
);
|
||||
break;
|
||||
}
|
||||
var c = text.charCodeAt(this.pos);
|
||||
@ -807,7 +890,10 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
}
|
||||
if (isLineBreak(c)) {
|
||||
result += text.substring(start, this.pos);
|
||||
this.error(DiagnosticCode.Unterminated_string_literal, this.range(start - 1, this.pos));
|
||||
this.error(
|
||||
DiagnosticCode.Unterminated_string_literal,
|
||||
this.range(start - 1, this.pos)
|
||||
);
|
||||
break;
|
||||
}
|
||||
++this.pos;
|
||||
@ -817,7 +903,10 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
|
||||
readEscapeSequence(): string {
|
||||
if (++this.pos >= this.end) {
|
||||
this.error(DiagnosticCode.Unexpected_end_of_text, this.range(this.end));
|
||||
this.error(
|
||||
DiagnosticCode.Unexpected_end_of_text,
|
||||
this.range(this.end)
|
||||
);
|
||||
return "";
|
||||
}
|
||||
|
||||
@ -853,7 +942,10 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
return "\"";
|
||||
|
||||
case CharCode.u: {
|
||||
if (this.pos < this.end && text.charCodeAt(this.pos) == CharCode.OPENBRACE) {
|
||||
if (
|
||||
this.pos < this.end &&
|
||||
text.charCodeAt(this.pos) == CharCode.OPENBRACE
|
||||
) {
|
||||
++this.pos;
|
||||
return this.readExtendedUnicodeEscape(); // \u{DDDDDDDD}
|
||||
}
|
||||
@ -861,8 +953,12 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
}
|
||||
|
||||
case CharCode.CARRIAGERETURN:
|
||||
if (this.pos < this.end && text.charCodeAt(this.pos) == CharCode.LINEFEED)
|
||||
if (
|
||||
this.pos < this.end &&
|
||||
text.charCodeAt(this.pos) == CharCode.LINEFEED
|
||||
) {
|
||||
++this.pos;
|
||||
}
|
||||
// fall through
|
||||
|
||||
case CharCode.LINEFEED:
|
||||
@ -880,7 +976,10 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
var escaped = false;
|
||||
while (true) {
|
||||
if (this.pos >= this.end) {
|
||||
this.error(DiagnosticCode.Unterminated_regular_expression_literal, this.range(start, this.end));
|
||||
this.error(
|
||||
DiagnosticCode.Unterminated_regular_expression_literal,
|
||||
this.range(start, this.end)
|
||||
);
|
||||
break;
|
||||
}
|
||||
if (text.charCodeAt(this.pos) == CharCode.BACKSLASH) {
|
||||
@ -889,10 +988,12 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
continue;
|
||||
}
|
||||
var c = text.charCodeAt(this.pos);
|
||||
if (c == CharCode.SLASH && !escaped)
|
||||
break;
|
||||
if (c == CharCode.SLASH && !escaped) break;
|
||||
if (isLineBreak(c)) {
|
||||
this.error(DiagnosticCode.Unterminated_regular_expression_literal, this.range(start, this.pos));
|
||||
this.error(
|
||||
DiagnosticCode.Unterminated_regular_expression_literal,
|
||||
this.range(start, this.pos)
|
||||
);
|
||||
break;
|
||||
}
|
||||
++this.pos;
|
||||
@ -907,18 +1008,20 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
var flags = 0;
|
||||
while (this.pos < this.end) {
|
||||
var c: i32 = text.charCodeAt(this.pos);
|
||||
if (!isIdentifierPart(c))
|
||||
break;
|
||||
if (!isIdentifierPart(c)) break;
|
||||
++this.pos;
|
||||
|
||||
// make sure each supported flag is unique
|
||||
switch (c) {
|
||||
|
||||
// make sure each supported flag is unique
|
||||
case CharCode.g:
|
||||
flags |= flags & 1 ? -1 : 1;
|
||||
break;
|
||||
|
||||
case CharCode.i:
|
||||
flags |= flags & 2 ? -1 : 2;
|
||||
break;
|
||||
|
||||
case CharCode.m:
|
||||
flags |= flags & 4 ? -1 : 4;
|
||||
break;
|
||||
@ -928,8 +1031,12 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (flags == -1)
|
||||
this.error(DiagnosticCode.Invalid_regular_expression_flags, this.range(start, this.pos));
|
||||
if (flags == -1) {
|
||||
this.error(
|
||||
DiagnosticCode.Invalid_regular_expression_flags,
|
||||
this.range(start, this.pos)
|
||||
);
|
||||
}
|
||||
return text.substring(start, this.pos);
|
||||
}
|
||||
|
||||
@ -949,10 +1056,10 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
var pos = this.pos;
|
||||
while (pos < this.end) {
|
||||
var c = text.charCodeAt(pos);
|
||||
if (c == CharCode.DOT || c == CharCode.E || c == CharCode.e)
|
||||
if (c == CharCode.DOT || c == CharCode.E || c == CharCode.e) {
|
||||
return false;
|
||||
if (c < CharCode._0 || c > CharCode._9)
|
||||
break;
|
||||
}
|
||||
if (c < CharCode._0 || c > CharCode._9) break;
|
||||
pos++;
|
||||
}
|
||||
return true;
|
||||
@ -962,14 +1069,17 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
var text = this.source.text;
|
||||
if (text.charCodeAt(this.pos) == CharCode._0 && this.pos + 2 < this.end) {
|
||||
switch (text.charCodeAt(this.pos + 1)) {
|
||||
|
||||
case CharCode.X:
|
||||
case CharCode.x:
|
||||
this.pos += 2;
|
||||
return this.readHexInteger();
|
||||
|
||||
case CharCode.B:
|
||||
case CharCode.b:
|
||||
this.pos += 2;
|
||||
return this.readBinaryInteger();
|
||||
|
||||
case CharCode.O:
|
||||
case CharCode.o:
|
||||
this.pos += 2;
|
||||
@ -979,7 +1089,10 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
var start = this.pos;
|
||||
++this.pos;
|
||||
var value = this.readOctalInteger();
|
||||
this.error(DiagnosticCode.Octal_literals_are_not_allowed_in_strict_mode, this.range(start, this.pos));
|
||||
this.error(
|
||||
DiagnosticCode.Octal_literals_are_not_allowed_in_strict_mode,
|
||||
this.range(start, this.pos)
|
||||
);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@ -995,19 +1108,33 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
var c = text.charCodeAt(this.pos);
|
||||
if (c >= CharCode._0 && c <= CharCode._9) {
|
||||
// value = value * 16 + c - CharCode._0;
|
||||
value = i64_add(i64_mul(value, i64_16), i64_new(c - CharCode._0, 0));
|
||||
value = i64_add(
|
||||
i64_mul(value, i64_16),
|
||||
i64_new(c - CharCode._0, 0)
|
||||
);
|
||||
} else if (c >= CharCode.A && c <= CharCode.F) {
|
||||
// value = value * 16 + 10 + c - CharCode.A;
|
||||
value = i64_add(i64_mul(value, i64_16), i64_new(10 + c - CharCode.A, 0));
|
||||
value = i64_add(
|
||||
i64_mul(value, i64_16),
|
||||
i64_new(10 + c - CharCode.A, 0)
|
||||
);
|
||||
} else if (c >= CharCode.a && c <= CharCode.f) {
|
||||
// value = value * 16 + 10 + c - CharCode.a;
|
||||
value = i64_add(i64_mul(value, i64_16), i64_new(10 + c - CharCode.a, 0));
|
||||
} else
|
||||
value = i64_add(
|
||||
i64_mul(value, i64_16),
|
||||
i64_new(10 + c - CharCode.a, 0)
|
||||
);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
++this.pos;
|
||||
}
|
||||
if (this.pos == start)
|
||||
this.error(DiagnosticCode.Hexadecimal_digit_expected, this.range(start));
|
||||
if (this.pos == start) {
|
||||
this.error(
|
||||
DiagnosticCode.Hexadecimal_digit_expected,
|
||||
this.range(start)
|
||||
);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -1020,13 +1147,21 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
var c = text.charCodeAt(this.pos);
|
||||
if (c >= CharCode._0 && c <= CharCode._9) {
|
||||
// value = value * 10 + c - CharCode._0;
|
||||
value = i64_add(i64_mul(value, i64_10), i64_new(c - CharCode._0, 0));
|
||||
} else
|
||||
value = i64_add(
|
||||
i64_mul(value, i64_10),
|
||||
i64_new(c - CharCode._0, 0)
|
||||
);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
++this.pos;
|
||||
}
|
||||
if (this.pos == start)
|
||||
this.error(DiagnosticCode.Digit_expected, this.range(start));
|
||||
if (this.pos == start) {
|
||||
this.error(
|
||||
DiagnosticCode.Digit_expected,
|
||||
this.range(start)
|
||||
);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -1039,13 +1174,21 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
var c = text.charCodeAt(this.pos);
|
||||
if (c >= CharCode._0 && c <= CharCode._7) {
|
||||
// value = value * 8 + c - CharCode._0;
|
||||
value = i64_add(i64_mul(value, i64_8), i64_new(c - CharCode._0, 0));
|
||||
} else
|
||||
value = i64_add(
|
||||
i64_mul(value, i64_8),
|
||||
i64_new(c - CharCode._0, 0)
|
||||
);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
++this.pos;
|
||||
}
|
||||
if (this.pos == start)
|
||||
this.error(DiagnosticCode.Octal_digit_expected, this.range(start));
|
||||
if (this.pos == start) {
|
||||
this.error(
|
||||
DiagnosticCode.Octal_digit_expected,
|
||||
this.range(start)
|
||||
);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -1059,36 +1202,57 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
var c = text.charCodeAt(this.pos);
|
||||
if (c == CharCode._0) {
|
||||
// value = value * 2;
|
||||
value = i64_mul(value, i64_2);
|
||||
value = i64_mul(
|
||||
value,
|
||||
i64_2
|
||||
);
|
||||
} else if (c == CharCode._1) {
|
||||
// value = value * 2 + 1;
|
||||
value = i64_add(i64_mul(value, i64_2), i64_1);
|
||||
} else
|
||||
value = i64_add(
|
||||
i64_mul(value, i64_2),
|
||||
i64_1
|
||||
);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
++this.pos;
|
||||
}
|
||||
if (this.pos == start)
|
||||
this.error(DiagnosticCode.Binary_digit_expected, this.range(start));
|
||||
if (this.pos == start) {
|
||||
this.error(
|
||||
DiagnosticCode.Binary_digit_expected,
|
||||
this.range(start)
|
||||
);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
readFloat(): f64 {
|
||||
var start = this.pos;
|
||||
var text = this.source.text;
|
||||
while (this.pos < this.end && isDecimalDigit(text.charCodeAt(this.pos)))
|
||||
while (this.pos < this.end && isDecimalDigit(text.charCodeAt(this.pos))) {
|
||||
++this.pos;
|
||||
}
|
||||
if (this.pos < this.end && text.charCodeAt(this.pos) == CharCode.DOT) {
|
||||
++this.pos;
|
||||
while (this.pos < this.end && isDecimalDigit(text.charCodeAt(this.pos)))
|
||||
while (this.pos < this.end && isDecimalDigit(text.charCodeAt(this.pos))) {
|
||||
++this.pos;
|
||||
}
|
||||
}
|
||||
if (this.pos < this.end) {
|
||||
var c = text.charCodeAt(this.pos);
|
||||
if (c == CharCode.E || c == CharCode.e) {
|
||||
if (++this.pos < this.end && (text.charCodeAt(this.pos) == CharCode.MINUS || text.charCodeAt(this.pos) == CharCode.PLUS) && isDecimalDigit(text.charCodeAt(this.pos + 1)))
|
||||
if (
|
||||
++this.pos < this.end && (
|
||||
text.charCodeAt(this.pos) == CharCode.MINUS ||
|
||||
text.charCodeAt(this.pos) == CharCode.PLUS
|
||||
) &&
|
||||
isDecimalDigit(text.charCodeAt(this.pos + 1))
|
||||
) {
|
||||
++this.pos;
|
||||
while (this.pos < this.end && isDecimalDigit(text.charCodeAt(this.pos)))
|
||||
}
|
||||
while (this.pos < this.end && isDecimalDigit(text.charCodeAt(this.pos))) {
|
||||
++this.pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
return parseFloat(text.substring(start, this.pos));
|
||||
@ -1100,21 +1264,26 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
var text = this.source.text;
|
||||
while (this.pos < this.end) {
|
||||
var c = text.charCodeAt(this.pos++);
|
||||
if (c >= CharCode._0 && c <= CharCode._9)
|
||||
if (c >= CharCode._0 && c <= CharCode._9) {
|
||||
value = value * 16 + c - CharCode._0;
|
||||
else if (c >= CharCode.A && c <= CharCode.F)
|
||||
} else if (c >= CharCode.A && c <= CharCode.F) {
|
||||
value = value * 16 + 10 + c - CharCode.A;
|
||||
else if (c >= CharCode.a && c <= CharCode.f)
|
||||
} else if (c >= CharCode.a && c <= CharCode.f) {
|
||||
value = value * 16 + 10 + c - CharCode.a;
|
||||
else {
|
||||
this.error(DiagnosticCode.Hexadecimal_digit_expected, this.range(this.pos - 1, this.pos));
|
||||
} else {
|
||||
this.error(
|
||||
DiagnosticCode.Hexadecimal_digit_expected,
|
||||
this.range(this.pos - 1, this.pos)
|
||||
);
|
||||
return "";
|
||||
}
|
||||
if (--remain == 0)
|
||||
break;
|
||||
if (--remain == 0) break;
|
||||
}
|
||||
if (remain) {
|
||||
this.error(DiagnosticCode.Unexpected_end_of_text, this.range(this.pos));
|
||||
this.error(
|
||||
DiagnosticCode.Unexpected_end_of_text,
|
||||
this.range(this.pos)
|
||||
);
|
||||
return "";
|
||||
}
|
||||
return String.fromCharCode(value);
|
||||
@ -1128,25 +1297,39 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
|
||||
assert(!i64_high(value));
|
||||
if (value32 > 0x10FFFF) {
|
||||
this.error(DiagnosticCode.An_extended_Unicode_escape_value_must_be_between_0x0_and_0x10FFFF_inclusive, this.range(start, this.pos));
|
||||
this.error(
|
||||
DiagnosticCode.An_extended_Unicode_escape_value_must_be_between_0x0_and_0x10FFFF_inclusive,
|
||||
this.range(start, this.pos)
|
||||
);
|
||||
invalid = true;
|
||||
}
|
||||
|
||||
var text = this.source.text;
|
||||
if (this.pos >= this.end) {
|
||||
this.error(DiagnosticCode.Unexpected_end_of_text, this.range(start, this.end));
|
||||
this.error(
|
||||
DiagnosticCode.Unexpected_end_of_text,
|
||||
this.range(start, this.end)
|
||||
);
|
||||
invalid = true;
|
||||
} else if (text.charCodeAt(this.pos) == CharCode.CLOSEBRACE) {
|
||||
++this.pos;
|
||||
} else {
|
||||
this.error(DiagnosticCode.Unterminated_Unicode_escape_sequence, this.range(start, this.pos));
|
||||
this.error(
|
||||
DiagnosticCode.Unterminated_Unicode_escape_sequence,
|
||||
this.range(start, this.pos)
|
||||
);
|
||||
invalid = true;
|
||||
}
|
||||
|
||||
if (invalid)
|
||||
return "";
|
||||
if (invalid) return "";
|
||||
return value32 < 65536
|
||||
? String.fromCharCode(value32)
|
||||
: String.fromCharCode((((value32 - 65536) / 1024 | 0) + 0xD800) as i32, ((value32 - 65536) % 1024 + 0xDC00) as i32);
|
||||
: String.fromCharCode(
|
||||
(((value32 - 65536) / 1024 | 0) + 0xD800) as i32,
|
||||
( (value32 - 65536) % 1024 + 0xDC00) as i32
|
||||
);
|
||||
}
|
||||
|
||||
finish(): void {
|
||||
}
|
||||
}
|
||||
|
30
src/types.ts
30
src/types.ts
@ -1,7 +1,3 @@
|
||||
import {
|
||||
Target
|
||||
} from "./compiler";
|
||||
|
||||
import {
|
||||
Class,
|
||||
Function
|
||||
@ -158,9 +154,11 @@ export class Type {
|
||||
case TypeKind.U64: return "u64";
|
||||
case TypeKind.USIZE:
|
||||
if (kindOnly) return "usize";
|
||||
return this.classType ? this.classType.toString()
|
||||
: this.functionType ? this.functionType.toTypeString()
|
||||
: "usize";
|
||||
return this.classType
|
||||
? this.classType.toString()
|
||||
: this.functionType
|
||||
? this.functionType.toTypeString()
|
||||
: "usize";
|
||||
case TypeKind.BOOL: return "bool";
|
||||
case TypeKind.F32: return "f32";
|
||||
case TypeKind.F64: return "f64";
|
||||
@ -209,8 +207,7 @@ export class Type {
|
||||
|
||||
case TypeKind.ISIZE:
|
||||
case TypeKind.USIZE:
|
||||
if (this.size != 64)
|
||||
return module.createI32(0);
|
||||
if (this.size != 64) return module.createI32(0);
|
||||
// fall-through
|
||||
|
||||
case TypeKind.I64:
|
||||
@ -237,8 +234,7 @@ export class Type {
|
||||
|
||||
case TypeKind.ISIZE:
|
||||
case TypeKind.USIZE:
|
||||
if (this.size != 64)
|
||||
return module.createI32(1);
|
||||
if (this.size != 64) return module.createI32(1);
|
||||
// fall-through
|
||||
|
||||
case TypeKind.I64:
|
||||
@ -265,8 +261,7 @@ export class Type {
|
||||
|
||||
case TypeKind.ISIZE:
|
||||
case TypeKind.USIZE:
|
||||
if (this.size != 64)
|
||||
return module.createI32(-1);
|
||||
if (this.size != 64) return module.createI32(-1);
|
||||
// fall-through
|
||||
|
||||
case TypeKind.I64:
|
||||
@ -436,18 +431,19 @@ export class Type {
|
||||
export function typesToNativeTypes(types: Type[]): NativeType[] {
|
||||
var k = types.length;
|
||||
var ret = new Array<NativeType>(k);
|
||||
for (var i = 0; i < k; ++i)
|
||||
for (var i = 0; i < k; ++i) {
|
||||
ret[i] = types[i].toNativeType();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Converts an array of types to its combined string representation. */
|
||||
export function typesToString(types: Type[]): string {
|
||||
var k = types.length;
|
||||
if (!k)
|
||||
return "";
|
||||
if (!k) return "";
|
||||
var sb = new Array<string>(k);
|
||||
for (var i = 0; i < k; ++i)
|
||||
for (var i = 0; i < k; ++i) {
|
||||
sb[i] = types[i].toString();
|
||||
}
|
||||
return sb.join(", ");
|
||||
}
|
||||
|
@ -338,8 +338,7 @@ const unicodeIdentifierPart: u16[] = [
|
||||
];
|
||||
|
||||
function lookupInUnicodeMap(code: u16, map: u16[]): bool {
|
||||
if (code < map[0])
|
||||
return false;
|
||||
if (code < map[0]) return false;
|
||||
|
||||
var lo = 0;
|
||||
var hi = map.length;
|
||||
@ -348,12 +347,14 @@ function lookupInUnicodeMap(code: u16, map: u16[]): bool {
|
||||
while (lo + 1 < hi) {
|
||||
mid = lo + (hi - lo) / 2;
|
||||
mid -= mid % 2;
|
||||
if (map[mid] <= code && code <= map[mid + 1])
|
||||
if (map[mid] <= code && code <= map[mid + 1]) {
|
||||
return true;
|
||||
if (code < map[mid])
|
||||
}
|
||||
if (code < map[mid]) {
|
||||
hi = mid;
|
||||
else
|
||||
} else {
|
||||
lo = mid + 2;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -93,8 +93,9 @@ export function normalize(path: string): string {
|
||||
|
||||
/** Resolves the specified path relative to the specified origin. */
|
||||
export function resolve(normalizedPath: string, origin: string): string {
|
||||
if (normalizedPath.startsWith("std/"))
|
||||
if (normalizedPath.startsWith("std/")) {
|
||||
return normalizedPath;
|
||||
}
|
||||
return normalize(
|
||||
dirname(origin) + String.fromCharCode(separator) + normalizedPath
|
||||
);
|
||||
@ -103,8 +104,10 @@ export function resolve(normalizedPath: string, origin: string): string {
|
||||
/** Obtains the directory portion of a normalized path. */
|
||||
export function dirname(normalizedPath: string): string {
|
||||
var pos = normalizedPath.length;
|
||||
while (--pos > 0)
|
||||
if (normalizedPath.charCodeAt(pos) == separator)
|
||||
while (--pos > 0) {
|
||||
if (normalizedPath.charCodeAt(pos) == separator) {
|
||||
return normalizedPath.substring(0, pos);
|
||||
}
|
||||
}
|
||||
return ".";
|
||||
}
|
||||
|
Reference in New Issue
Block a user