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 { import {
CommonFlags, CommonFlags,
PATH_DELIMITER, PATH_DELIMITER,

View File

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

View File

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

View File

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

View File

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

View File

@ -1,2 +1,6 @@
/**
* @file Definitions for linking Binaryen with AssemblyScript.
*/
declare function allocate_memory(size: usize): usize; declare function allocate_memory(size: usize): usize;
declare function free_memory(ptr: usize): void; 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 // Copy Binaryen exports to global scope
const binaryen = global.Binaryen || require("binaryen"); const binaryen = global.Binaryen || require("binaryen");

View File

@ -1,3 +1,7 @@
/**
* @file I64 definitions for JavaScript.
*/
declare type I64 = { __Long__: true }; // opaque declare type I64 = { __Long__: true }; // opaque
declare function i64_new(lo: i32, hi?: i32): I64; 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"); const Long = global.Long || require("long");
global.i64_new = function(lo, hi) { global.i64_new = function(lo, hi) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,10 +1,6 @@
/* /**
* @file A TypeScript parser for the AssemblyScript subset.
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.
*/
import { import {
Program, Program,
@ -16,7 +12,8 @@ import {
import { import {
Tokenizer, Tokenizer,
Token, Token,
Range Range,
CommentHandler
} from "./tokenizer"; } from "./tokenizer";
import { import {
@ -37,6 +34,7 @@ import {
CommonTypeNode, CommonTypeNode,
TypeNode, TypeNode,
SignatureNode, SignatureNode,
CommentKind,
Expression, Expression,
AssertionKind, AssertionKind,
@ -93,6 +91,8 @@ export class Parser extends DiagnosticEmitter {
currentDeclareStart: i32 = 0; currentDeclareStart: i32 = 0;
currentDeclareEnd: i32 = 0; currentDeclareEnd: i32 = 0;
onComment: CommentHandler | null = null;
/** Constructs a new parser. */ /** Constructs a new parser. */
constructor() { constructor() {
super(); super();
@ -129,12 +129,14 @@ export class Parser extends DiagnosticEmitter {
// tokenize and parse // tokenize and parse
var tn = new Tokenizer(source, program.diagnostics); var tn = new Tokenizer(source, program.diagnostics);
tn.onComment = this.onComment;
source.tokenizer = tn; source.tokenizer = tn;
var statements = source.statements;
while (!tn.skip(Token.ENDOFFILE)) { while (!tn.skip(Token.ENDOFFILE)) {
let statement = this.parseTopLevelStatement(tn); let statement = this.parseTopLevelStatement(tn);
if (statement) { if (statement) {
statement.parent = source; statement.parent = source;
source.statements.push(statement); statements.push(statement);
} }
} }
tn.finish(); tn.finish();

View File

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

View File

@ -1,22 +1,9 @@
/* /**
* @file A TypeScript tokenizer modified for AssemblyScript.
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 * Skips over trivia and provides a general mark/reset mechanism for the parser to utilize on
ambiguous tokens. * 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
*/
import { import {
DiagnosticCode, DiagnosticCode,
@ -380,6 +367,10 @@ export class Range {
declare function parseFloat(str: string): f64; 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 { export class Tokenizer extends DiagnosticEmitter {
source: Source; source: Source;
@ -393,8 +384,9 @@ export class Tokenizer extends DiagnosticEmitter {
nextTokenPos: i32 = 0; nextTokenPos: i32 = 0;
nextTokenOnNewLine: bool = false; 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) { constructor(source: Source, diagnostics: DiagnosticMessage[] | null = null) {
super(diagnostics); super(diagnostics);
this.source = source; this.source = source;

View File

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

View File

@ -1,3 +1,7 @@
/**
* @file Character code utility.
*/
/** An enum of named character codes. */ /** An enum of named character codes. */
export const enum CharCode { 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 { export function isDecimalDigit(c: i32): bool {
return c >= CharCode._0 && c <= CharCode._9; 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 { export function isOctalDigit(c: i32): bool {
return c >= CharCode._0 && c <= CharCode._7; return c >= CharCode._0 && c <= CharCode._7;
} }

View File

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

View File

@ -1,3 +1,7 @@
/**
* @file Common text utilities.
*/
const indentX1 = " "; const indentX1 = " ";
const indentX2 = " "; const indentX2 = " ";
const indentX4 = " "; 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 // 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 // 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 i8 = number;
declare type i16 = number; declare type i16 = number;
declare type i32 = 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; var globalScope = typeof window !== "undefined" && window || typeof global !== "undefined" && global || self;
Object.defineProperties( Object.defineProperties(