Document the purpose of most files

This commit is contained in:
dcodeIO 2018-03-17 23:41:48 +01:00
parent d45eb93df6
commit 5eb10d404f
30 changed files with 197 additions and 87 deletions

2
dist/asc.js vendored

File diff suppressed because one or more lines are too long

2
dist/asc.js.map vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,7 @@
/**
* @file Abstract syntax tree representing a source file once parsed.
*/
import {
CommonFlags,
PATH_DELIMITER,

View File

@ -1,3 +1,7 @@
/**
* @file Built-in elements providing otherwise hard-to-implement functionality.
*/
import {
Compiler,
ConversionKind,

View File

@ -1,3 +1,7 @@
/**
* @file The AssemblyScript compiler.
*/
import {
compileCall as compileBuiltinCall,
compileGetConstant as compileBuiltinGetConstant,

View File

@ -1,3 +1,7 @@
/**
* @file A decompiler that generates low-level AssemblyScript from WebAssembly binaries.
*/
import {
Module,
NativeType,

View File

@ -1,3 +1,7 @@
/**
* @file Shared diagnostic handling inherited by the parser and the compiler.
*/
import {
Range
} from "./ast";
@ -16,48 +20,71 @@ export {
diagnosticCodeToString
} from "./diagnosticMessages.generated";
/** Indicates the category of a {@link DiagnosticMessage}. */
export enum DiagnosticCategory {
/** Informatory message. */
INFO,
/** Warning message. */
WARNING,
/** Error message. */
ERROR
}
/** Returns the string representation of the specified diagnostic category. */
export function diagnosticCategoryToString(category: DiagnosticCategory): string {
switch (category) {
case DiagnosticCategory.INFO: return "INFO";
case DiagnosticCategory.WARNING: return "WARNING";
case DiagnosticCategory.ERROR: return "ERROR";
default: return "";
default: {
assert(false);
return "";
}
}
}
const colorBlue: string = "\u001b[93m";
const colorYellow: string = "\u001b[93m";
const colorRed: string = "\u001b[91m";
const colorReset: string = "\u001b[0m";
/** ANSI escape sequence for blue foreground. */
export const COLOR_BLUE: string = "\u001b[93m";
/** ANSI escape sequence for yellow foreground. */
export const COLOR_YELLOW: string = "\u001b[93m";
/** ANSI escape sequence for red foreground. */
export const COLOR_RED: string = "\u001b[91m";
/** ANSI escape sequence to reset the foreground color. */
export const COLOR_RESET: string = "\u001b[0m";
/** Returns the ANSI escape sequence for the specified category. */
export function diagnosticCategoryToColor(category: DiagnosticCategory): string {
switch (category) {
case DiagnosticCategory.INFO: return colorBlue;
case DiagnosticCategory.WARNING: return colorYellow;
case DiagnosticCategory.ERROR: return colorRed;
default: return "";
case DiagnosticCategory.INFO: return COLOR_BLUE;
case DiagnosticCategory.WARNING: return COLOR_YELLOW;
case DiagnosticCategory.ERROR: return COLOR_RED;
default: {
assert(false);
return "";
}
}
}
/** Represents a diagnostic message. */
export class DiagnosticMessage {
/** Message code. */
code: i32;
/** Message category. */
category: DiagnosticCategory;
/** Message text. */
message: string;
/** Respective source range, if any. */
range: Range | null = null;
constructor(code: i32, category: DiagnosticCategory, message: string) {
/** Constructs a new diagnostic message. */
private constructor(code: i32, category: DiagnosticCategory, message: string) {
this.code = code;
this.category = category;
this.message = message;
}
/** Creates a new diagnostic message of the specified category. */
static create(
code: DiagnosticCode,
category: DiagnosticCategory,
@ -72,6 +99,7 @@ export class DiagnosticMessage {
return new DiagnosticMessage(code, category, message);
}
/** Creates a new informatory diagnostic message. */
static createInfo(
code: DiagnosticCode,
arg0: string | null = null,
@ -80,6 +108,7 @@ export class DiagnosticMessage {
return DiagnosticMessage.create(code, DiagnosticCategory.INFO, arg0, arg1);
}
/** Creates a new warning diagnostic message. */
static createWarning(
code: DiagnosticCode,
arg0: string | null = null,
@ -88,6 +117,7 @@ export class DiagnosticMessage {
return DiagnosticMessage.create(code, DiagnosticCategory.WARNING, arg0, arg1);
}
/** Creates a new error diagnostic message. */
static createError(
code: DiagnosticCode,
arg0: string | null = null,
@ -96,11 +126,13 @@ export class DiagnosticMessage {
return DiagnosticMessage.create(code, DiagnosticCategory.ERROR, arg0, arg1);
}
/** Adds a source range to this message. */
withRange(range: Range): this {
this.range = range;
return this;
}
/** Converts this message to a string. */
toString(): string {
if (this.range) {
return (
@ -127,34 +159,33 @@ export class DiagnosticMessage {
}
}
/** Formats a diagnostic message, optionally with terminal colors and source context. */
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) {
context = formatDiagnosticContext(message.range, useColors);
}
// general information
var sb: string[] = [];
if (useColors) sb.push(diagnosticCategoryToColor(message.category));
sb.push(diagnosticCategoryToString(message.category));
if (useColors) sb.push(colorReset);
if (useColors) sb.push(COLOR_RESET);
sb.push(message.code < 1000 ? " AS" : " TS");
sb.push(message.code.toString(10));
sb.push(": ");
sb.push(message.message);
// range information if available
// include range information if available
if (message.range) {
// include context information if requested
let range = message.range;
if (showContext) {
sb.push("\n");
sb.push(context);
sb.push(formatDiagnosticContext(message.range, useColors));
}
sb.push("\n");
sb.push(" in ");
sb.push(range.source.normalizedPath);
@ -167,6 +198,7 @@ export function formatDiagnosticMessage(
return sb.join("");
}
/** Formats the diagnostic context for the specified range, optionally with terminal colors. */
export function formatDiagnosticContext(range: Range, useColors: bool = false): string {
var text = range.source.text;
var len = text.length;
@ -187,7 +219,7 @@ export function formatDiagnosticContext(range: Range, useColors: bool = false):
sb.push(" ");
start++;
}
if (useColors) sb.push(colorRed);
if (useColors) sb.push(COLOR_RED);
if (range.start == range.end) {
sb.push("^");
} else {
@ -195,18 +227,22 @@ export function formatDiagnosticContext(range: Range, useColors: bool = false):
sb.push("~");
}
}
if (useColors) sb.push(colorReset);
if (useColors) sb.push(COLOR_RESET);
return sb.join("");
}
/** Base class of all diagnostic emitters. */
export abstract class DiagnosticEmitter {
/** Diagnostic messages emitted so far. */
diagnostics: DiagnosticMessage[];
constructor(diagnostics: DiagnosticMessage[] | null = null) {
/** Initializes this diagnostic emitter. */
protected constructor(diagnostics: DiagnosticMessage[] | null = null) {
this.diagnostics = diagnostics ? <DiagnosticMessage[]>diagnostics : new Array();
}
/** Emits a diagnostic message of the specified category. */
emitDiagnostic(
code: DiagnosticCode,
category: DiagnosticCategory,
@ -221,16 +257,7 @@ export abstract class DiagnosticEmitter {
// console.log(<string>new Error("stack").stack);
}
error(
code: DiagnosticCode,
range: Range,
arg0: string | null = null,
arg1: string | null = null,
arg2: string | null = null
): void {
this.emitDiagnostic(code, DiagnosticCategory.ERROR, range, arg0, arg1, arg2);
}
/** Emits an informatory diagnostic message. */
info(
code: DiagnosticCode,
range: Range,
@ -241,6 +268,7 @@ export abstract class DiagnosticEmitter {
this.emitDiagnostic(code, DiagnosticCategory.INFO, range, arg0, arg1, arg2);
}
/** Emits a warning diagnostic message. */
warning(
code: DiagnosticCode,
range: Range,
@ -250,4 +278,15 @@ export abstract class DiagnosticEmitter {
): void {
this.emitDiagnostic(code, DiagnosticCategory.WARNING, range, arg0, arg1, arg2);
}
/** Emits an error diagnostic message. */
error(
code: DiagnosticCode,
range: Range,
arg0: string | null = null,
arg1: string | null = null,
arg2: string | null = null
): void {
this.emitDiagnostic(code, DiagnosticCategory.ERROR, range, arg0, arg1, arg2);
}
}

View File

@ -1,13 +1,6 @@
/*
Binaryen's C-API.
The WebAssembly version of the compiler will be linked against Binaryen
compiled to WebAssembly with these functions present in the binary while the
JS version calls them on the global object.
see: https://github.com/WebAssembly/binaryen/blob/master/src/binaryen-c.h
/**
* @file TypeScript definitions for Binaryen's C-API.
* @see https://github.com/WebAssembly/binaryen/blob/master/src/binaryen-c.h
*/
declare function _malloc(size: usize): usize;

View File

@ -1,2 +1,6 @@
/**
* @file Definitions for linking Binaryen with AssemblyScript.
*/
declare function allocate_memory(size: usize): usize;
declare function free_memory(ptr: usize): void;

View File

@ -1,3 +1,7 @@
/**
* @file Glue code for linking Binaryen with AssemblyScript.
*/
// Copy Binaryen exports to global scope
const binaryen = global.Binaryen || require("binaryen");

View File

@ -1,3 +1,7 @@
/**
* @file I64 definitions for JavaScript.
*/
declare type I64 = { __Long__: true }; // opaque
declare function i64_new(lo: i32, hi?: i32): I64;

View File

@ -1,3 +1,8 @@
/**
* @file I64 implementation for JavaScript using long.js.
* @see https://github.com/dcodeIO/long.js
*/
const Long = global.Long || require("long");
global.i64_new = function(lo, hi) {

View File

@ -1,3 +1,7 @@
/**
* @file JavaScript glue code.
*/
import "../../../std/portable";
import "./binaryen";
import "./i64";

View File

@ -1,2 +1,6 @@
/**
* @file Definitions for running JavaScript under node.js.
*/
declare const global: any;
declare function require(name: string): any;

View File

@ -1,3 +1,7 @@
/**
* @file I64 wrapper for WebAssembly.
*/
type I64 = i64;
@global

View File

@ -1 +1,5 @@
/**
* @file WebAssembly glue code.
*/
import "./i64";

View File

@ -1,4 +1,6 @@
//////////////////////// Low-level C-Like Compiler API /////////////////////////
/**
* @file Low-level C-like compiler API.
*/
import {
Compiler,

View File

@ -1,3 +1,7 @@
/**
* @file A thin wrapper around Binaryen's C-API.
*/
import {
Target
} from "./compiler";

View File

@ -1,9 +1,5 @@
/*
This is a custom parser specifically written for the AssemblyScript subset. It accepts some of the
most common TypeScript-only patterns that it knows an appropriate error message for but, though it
uses TypeScript's codes for diagnostics, doesn't ultimately aim at full compatibility.
/**
* @file A TypeScript parser for the AssemblyScript subset.
*/
import {
@ -16,7 +12,8 @@ import {
import {
Tokenizer,
Token,
Range
Range,
CommentHandler
} from "./tokenizer";
import {
@ -37,6 +34,7 @@ import {
CommonTypeNode,
TypeNode,
SignatureNode,
CommentKind,
Expression,
AssertionKind,
@ -93,6 +91,8 @@ export class Parser extends DiagnosticEmitter {
currentDeclareStart: i32 = 0;
currentDeclareEnd: i32 = 0;
onComment: CommentHandler | null = null;
/** Constructs a new parser. */
constructor() {
super();
@ -129,12 +129,14 @@ export class Parser extends DiagnosticEmitter {
// tokenize and parse
var tn = new Tokenizer(source, program.diagnostics);
tn.onComment = this.onComment;
source.tokenizer = tn;
var statements = source.statements;
while (!tn.skip(Token.ENDOFFILE)) {
let statement = this.parseTopLevelStatement(tn);
if (statement) {
statement.parent = source;
source.statements.push(statement);
statements.push(statement);
}
}
tn.finish();

View File

@ -1,3 +1,7 @@
/**
* @file AssemblyScript's intermediate representation describing a program's elements.
*/
import {
Options
} from "./compiler";

View File

@ -1,21 +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.
next() advances the token
peek() peeks for the next token
skip(token) skips over a token if possible
mark() marks at current token
reset() resets to marked state
range() gets the range of the current token
readFloat() on FLOATLITERAL
readIdentifier() on IDENTIFIER
readInteger() on INTEGERLITERAL
readString() on STRINGLITERAL
/**
* @file A TypeScript tokenizer modified for AssemblyScript.
*
* Skips over trivia and provides a general mark/reset mechanism for the parser to utilize on
* ambiguous tokens.
*/
import {
@ -380,6 +367,10 @@ export class Range {
declare function parseFloat(str: string): f64;
/** Handler for intercepting comments while tokenizing. */
export type CommentHandler = (kind: CommentKind, text: string, range: Range) => void;
/** Tokenizes a source to individual {@link Token}s. */
export class Tokenizer extends DiagnosticEmitter {
source: Source;
@ -393,8 +384,9 @@ export class Tokenizer extends DiagnosticEmitter {
nextTokenPos: i32 = 0;
nextTokenOnNewLine: bool = false;
onComment: ((kind: CommentKind, text: string, range: Range) => void) | null = null;
onComment: CommentHandler | null = null;
/** Constructs a new tokenizer. */
constructor(source: Source, diagnostics: DiagnosticMessage[] | null = null) {
super(diagnostics);
this.source = source;

View File

@ -1,3 +1,7 @@
/**
* @file Mappings from AssemblyScript types to WebAssembly types.
*/
import {
Class,
FunctionTarget

View File

@ -1,3 +1,7 @@
/**
* @file Character code utility.
*/
/** An enum of named character codes. */
export const enum CharCode {
@ -170,12 +174,12 @@ export function isWhiteSpace(c: i32): bool {
}
}
/** Tests if the specified character code is a decimal digit. */
/** Tests if the specified character code is a valid decimal digit. */
export function isDecimalDigit(c: i32): bool {
return c >= CharCode._0 && c <= CharCode._9;
}
/** Tests if the specified character code is an octal digit. */
/** Tests if the specified character code is a valid octal digit. */
export function isOctalDigit(c: i32): bool {
return c >= CharCode._0 && c <= CharCode._7;
}

View File

@ -1,3 +1,7 @@
/**
* @file Minimalistic path utility for normalizing and resolving relative paths.
*/
import {
CharCode
} from "./charcode";

View File

@ -1,3 +1,7 @@
/**
* @file Common text utilities.
*/
const indentX1 = " ";
const indentX2 = " ";
const indentX4 = " ";

4
std/assembly.d.ts vendored
View File

@ -1,4 +1,6 @@
// Definitions for the "AssemblyScript" subset.
/**
* @file Environment definitions for compiling AssemblyScript to WebAssembly using asc.
*/
// Types

19
std/portable.d.ts vendored
View File

@ -1,14 +1,17 @@
// Definitions for the "portable AssemblyScript" subset.
/**
* @file Environment definitions for compiling AssemblyScript to JavaScript using tsc.
*
* Note that semantic differences require additional explicit conversions for full compatibility.
* For example, when casting an i32 to an u8, doing `<u8>(someI32 & 0xff)` will yield the same
* result when compiling to WebAssembly or JS while `<u8>someI32` alone does nothing in JS.
*
* Note that i64's are not portable (JS numbers are IEEE754 doubles with a maximum safe integer
* value of 2^53-1) and instead require a compatibility layer to work in JS as well, as for example
* {@link ./glue/js/i64.d.ts} / {@link ./glue/js/i64.js}.
*/
// Portable types
// Note that semantic differences require additional explicit conversions for full compatibility.
// For example, when casting an i32 to an u8, doing `<u8>(someI32 & 0xff)` will yield the same
// result when compiling to WebAssembly or JS while `<u8>someI32` alone does nothing in JS.
// Note that i64's are not portable (JS numbers are IEEE754 doubles with a maximum safe integer value
// of 2^53-1) and instead require a compatibility layer to work in JS as well. See: src/util/i64.ts
declare type i8 = number;
declare type i16 = number;
declare type i32 = number;

View File

@ -1,3 +1,7 @@
/**
* @file Environment implementation for compiling AssemblyScript to JavaScript using tsc.
*/
var globalScope = typeof window !== "undefined" && window || typeof global !== "undefined" && global || self;
Object.defineProperties(