mirror of
https://github.com/Noratrieb/riverdelta.git
synced 2026-01-14 16:35:03 +01:00
many things
This commit is contained in:
parent
f582a5b4c3
commit
924236532c
13 changed files with 264 additions and 85 deletions
30
src/ast.ts
30
src/ast.ts
|
|
@ -1,6 +1,6 @@
|
||||||
import { Span } from "./error";
|
import { DUMMY_SPAN, Span } from "./error";
|
||||||
import { LitIntType } from "./lexer";
|
import { LitIntType } from "./lexer";
|
||||||
import { ComplexMap } from "./utils";
|
import { ComplexMap, unwrap } from "./utils";
|
||||||
|
|
||||||
export type Phase = {
|
export type Phase = {
|
||||||
res: unknown;
|
res: unknown;
|
||||||
|
|
@ -430,6 +430,9 @@ export const BUILTINS = [
|
||||||
"__i64_load",
|
"__i64_load",
|
||||||
"__string_ptr",
|
"__string_ptr",
|
||||||
"__string_len",
|
"__string_len",
|
||||||
|
"__memory_size",
|
||||||
|
"__memory_grow",
|
||||||
|
"__i32_extend_to_i64_u"
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export type BuiltinName = (typeof BUILTINS)[number];
|
export type BuiltinName = (typeof BUILTINS)[number];
|
||||||
|
|
@ -521,6 +524,29 @@ export type TypeckResults = {
|
||||||
main: Resolution | undefined;
|
main: Resolution | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function findCrateItem<P extends Phase>(
|
||||||
|
crate: Crate<P>,
|
||||||
|
id: ItemId
|
||||||
|
): Item<P> {
|
||||||
|
if (id.crateId !== crate.id) {
|
||||||
|
throw new Error("trying to get item from the wrong crate");
|
||||||
|
}
|
||||||
|
if (id.itemIdx === 0) {
|
||||||
|
// Return a synthetic module representing the crate root.
|
||||||
|
return {
|
||||||
|
kind: "mod",
|
||||||
|
node: {
|
||||||
|
contents: crate.rootItems,
|
||||||
|
name: crate.packageName,
|
||||||
|
},
|
||||||
|
span: DUMMY_SPAN,
|
||||||
|
id,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return unwrap(crate.itemsById.get(id));
|
||||||
|
}
|
||||||
|
|
||||||
// folders
|
// folders
|
||||||
|
|
||||||
export type FoldFn<From, To> = (value: From) => To;
|
export type FoldFn<From, To> = (value: From) => To;
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ export function spanMerge(a: Span, b: Span): Span {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DUMMY_SPAN = { start: 0, end: 0 };
|
export const DUMMY_SPAN = { start: 0, end: 0 };
|
||||||
|
export const EOF_SPAN = {start: Number.MAX_SAFE_INTEGER, end: Number.MAX_SAFE_INTEGER};
|
||||||
|
|
||||||
export class CompilerError extends Error {
|
export class CompilerError extends Error {
|
||||||
msg: string;
|
msg: string;
|
||||||
|
|
@ -59,7 +60,10 @@ function renderError(input: string, filename: string, e: CompilerError) {
|
||||||
const startRelLine =
|
const startRelLine =
|
||||||
e.span.start === Number.MAX_SAFE_INTEGER ? 0 : e.span.start - line.start;
|
e.span.start === Number.MAX_SAFE_INTEGER ? 0 : e.span.start - line.start;
|
||||||
|
|
||||||
const spanLength = min(e.span.end, line.end) - e.span.start;
|
const spanLength =
|
||||||
|
e.span.start === Number.MAX_SAFE_INTEGER
|
||||||
|
? 1
|
||||||
|
: min(e.span.end, line.end) - e.span.start;
|
||||||
|
|
||||||
console.error(
|
console.error(
|
||||||
`${" ".repeat(String(lineNo).length)} ${" ".repeat(
|
`${" ".repeat(String(lineNo).length)} ${" ".repeat(
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,12 @@ import { Crate, Built, Typecked } from "./ast";
|
||||||
import { Ids } from "./utils";
|
import { Ids } from "./utils";
|
||||||
|
|
||||||
const INPUT = `
|
const INPUT = `
|
||||||
global HELLO: I32 = 0_I32;
|
extern mod std;
|
||||||
|
|
||||||
|
type A = { a: String };
|
||||||
|
|
||||||
function main() = (
|
function main() = (
|
||||||
HELLO = 1_I32;
|
std.rt.allocateItem(0_I32, 0_I32);
|
||||||
);
|
);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
@ -135,6 +137,8 @@ function loadCrate(
|
||||||
const tokens = tokenize(input);
|
const tokens = tokenize(input);
|
||||||
const ast = parse(name, tokens, crateId.next());
|
const ast = parse(name, tokens, crateId.next());
|
||||||
const [resolved, crates] = resolve(ast, loadCrate);
|
const [resolved, crates] = resolve(ast, loadCrate);
|
||||||
|
console.log(resolved);
|
||||||
|
|
||||||
|
|
||||||
const typecked = typeck(resolved, [...existingCrates, ...crates]);
|
const typecked = typeck(resolved, [...existingCrates, ...crates]);
|
||||||
return [typecked, crates];
|
return [typecked, crates];
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,8 @@ export type DatalessToken =
|
||||||
| "=="
|
| "=="
|
||||||
| "<="
|
| "<="
|
||||||
| ">="
|
| ">="
|
||||||
| "!=";
|
| "!="
|
||||||
|
| "end of file";
|
||||||
|
|
||||||
export type TokenIdent = { kind: "identifier"; ident: string };
|
export type TokenIdent = { kind: "identifier"; ident: string };
|
||||||
|
|
||||||
|
|
@ -109,6 +110,9 @@ export function tokenize(input: string): Token[] {
|
||||||
throw new CompilerError("unterminated block comment", span);
|
throw new CompilerError("unterminated block comment", span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
i++;
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SINGLE_PUNCT.includes(next)) {
|
if (SINGLE_PUNCT.includes(next)) {
|
||||||
|
|
|
||||||
82
src/lower.ts
82
src/lower.ts
|
|
@ -13,6 +13,7 @@ import {
|
||||||
TyFn,
|
TyFn,
|
||||||
TyTuple,
|
TyTuple,
|
||||||
Typecked,
|
Typecked,
|
||||||
|
findCrateItem,
|
||||||
varUnreachable,
|
varUnreachable,
|
||||||
} from "./ast";
|
} from "./ast";
|
||||||
import { printTy } from "./printer";
|
import { printTy } from "./printer";
|
||||||
|
|
@ -30,6 +31,8 @@ const WASM_PAGE = 65536;
|
||||||
|
|
||||||
const DUMMY_IDX = 9999999;
|
const DUMMY_IDX = 9999999;
|
||||||
|
|
||||||
|
const ALLOCATE_SYMBOL = "nil__std__rt__allocateItem";
|
||||||
|
|
||||||
type RelocationKind =
|
type RelocationKind =
|
||||||
| {
|
| {
|
||||||
kind: "funccall";
|
kind: "funccall";
|
||||||
|
|
@ -86,7 +89,7 @@ function appendData(cx: Context, newData: Uint8Array): number {
|
||||||
mode: {
|
mode: {
|
||||||
kind: "active",
|
kind: "active",
|
||||||
memory: 0,
|
memory: 0,
|
||||||
offset: [{ kind: "i32.const", imm: 0 }],
|
offset: [{ kind: "i32.const", imm: 0n }],
|
||||||
},
|
},
|
||||||
_name: "staticdata",
|
_name: "staticdata",
|
||||||
});
|
});
|
||||||
|
|
@ -103,8 +106,9 @@ function appendData(cx: Context, newData: Uint8Array): number {
|
||||||
}
|
}
|
||||||
|
|
||||||
function findItem(cx: Context, id: ItemId): Item<Typecked> {
|
function findItem(cx: Context, id: ItemId): Item<Typecked> {
|
||||||
return unwrap(
|
return findCrateItem(
|
||||||
unwrap(cx.crates.find((crate) => crate.id === id.crateId)).itemsById.get(id)
|
unwrap(cx.crates.find((crate) => crate.id === id.crateId)),
|
||||||
|
id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -271,7 +275,7 @@ function lowerGlobal(
|
||||||
|
|
||||||
const init: wasm.Instr = {
|
const init: wasm.Instr = {
|
||||||
kind: `${valtype}.const`,
|
kind: `${valtype}.const`,
|
||||||
imm: def.init.value.value,
|
imm: BigInt(def.init.value.value),
|
||||||
};
|
};
|
||||||
|
|
||||||
cx.mod.globals.push({
|
cx.mod.globals.push({
|
||||||
|
|
@ -300,6 +304,11 @@ type ArgRetAbi = wasm.ValType[];
|
||||||
|
|
||||||
type VarLocation = { localIdx: number; types: wasm.ValType[] };
|
type VarLocation = { localIdx: number; types: wasm.ValType[] };
|
||||||
|
|
||||||
|
type StructLayout = {
|
||||||
|
size: number,
|
||||||
|
align: number,
|
||||||
|
}
|
||||||
|
|
||||||
function lowerFunc(
|
function lowerFunc(
|
||||||
cx: Context,
|
cx: Context,
|
||||||
item: Item<Typecked>,
|
item: Item<Typecked>,
|
||||||
|
|
@ -438,18 +447,18 @@ function lowerExpr(
|
||||||
const utf8 = encodeUtf8(expr.value.value);
|
const utf8 = encodeUtf8(expr.value.value);
|
||||||
const idx = appendData(fcx.cx, utf8);
|
const idx = appendData(fcx.cx, utf8);
|
||||||
|
|
||||||
instrs.push({ kind: "i32.const", imm: idx });
|
instrs.push({ kind: "i32.const", imm: BigInt(idx) });
|
||||||
instrs.push({ kind: "i32.const", imm: utf8.length });
|
instrs.push({ kind: "i32.const", imm: BigInt(utf8.length) });
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "int":
|
case "int":
|
||||||
switch (expr.value.type) {
|
switch (expr.value.type) {
|
||||||
case "Int":
|
case "Int":
|
||||||
instrs.push({ kind: "i64.const", imm: expr.value.value });
|
instrs.push({ kind: "i64.const", imm: BigInt(expr.value.value) });
|
||||||
break;
|
break;
|
||||||
case "I32":
|
case "I32":
|
||||||
instrs.push({ kind: "i32.const", imm: expr.value.value });
|
instrs.push({ kind: "i32.const", imm: BigInt(expr.value.value) });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -487,10 +496,10 @@ function lowerExpr(
|
||||||
case "builtin":
|
case "builtin":
|
||||||
switch (res.name) {
|
switch (res.name) {
|
||||||
case "false":
|
case "false":
|
||||||
instrs.push({ kind: "i32.const", imm: 0 });
|
instrs.push({ kind: "i32.const", imm: 0n });
|
||||||
break;
|
break;
|
||||||
case "true":
|
case "true":
|
||||||
instrs.push({ kind: "i32.const", imm: 1 });
|
instrs.push({ kind: "i32.const", imm: 1n });
|
||||||
break;
|
break;
|
||||||
case "print":
|
case "print":
|
||||||
todo("print function");
|
todo("print function");
|
||||||
|
|
@ -603,11 +612,18 @@ function lowerExpr(
|
||||||
case "!":
|
case "!":
|
||||||
if (ty.kind === "bool") {
|
if (ty.kind === "bool") {
|
||||||
// `xor RHS, 1` flips the lowermost bit.
|
// `xor RHS, 1` flips the lowermost bit.
|
||||||
instrs.push({ kind: "i64.const", imm: 1 });
|
instrs.push({ kind: "i64.const", imm: 1n });
|
||||||
instrs.push({ kind: "i64.xor" });
|
instrs.push({ kind: "i64.xor" });
|
||||||
} else if (ty.kind === "int") {
|
} else if (ty.kind === "int") {
|
||||||
// `xor RHS, -1` flips all bits.
|
// `xor RHS, -1` flips all bits.
|
||||||
todo("Thanks to JS, we cannot represent -1 i64 yet");
|
instrs.push({ kind: "i64.const", imm: -1n });
|
||||||
|
instrs.push({ kind: "i64.xor" });
|
||||||
|
} else if (ty.kind === "i32") {
|
||||||
|
// `xor RHS, -1` flips all bits.
|
||||||
|
instrs.push({ kind: "i32.const", imm: -1n });
|
||||||
|
instrs.push({ kind: "i32.xor" });
|
||||||
|
} else {
|
||||||
|
throw new Error("invalid type for !");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "-":
|
case "-":
|
||||||
|
|
@ -621,36 +637,44 @@ function lowerExpr(
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = expr.lhs.kind === "ident" ? expr.lhs.value.res : expr.lhs.res;
|
const res = expr.lhs.kind === "ident" ? expr.lhs.value.res : expr.lhs.res;
|
||||||
|
|
||||||
if (res.kind === "builtin") {
|
if (res.kind === "builtin") {
|
||||||
|
const assertArgs = (n: number) => {
|
||||||
|
if (expr.args.length !== n) throw new Error("nope");
|
||||||
|
};
|
||||||
switch (res.name) {
|
switch (res.name) {
|
||||||
case "trap": {
|
case "trap": {
|
||||||
|
assertArgs(0);
|
||||||
instrs.push({ kind: "unreachable" });
|
instrs.push({ kind: "unreachable" });
|
||||||
break exprKind;
|
break exprKind;
|
||||||
}
|
}
|
||||||
case "__i32_load": {
|
case "__i32_load": {
|
||||||
|
assertArgs(1);
|
||||||
lowerExpr(fcx, instrs, expr.args[0]);
|
lowerExpr(fcx, instrs, expr.args[0]);
|
||||||
instrs.push({ kind: "i64.load", imm: {} });
|
instrs.push({ kind: "i64.load", imm: {} });
|
||||||
break exprKind;
|
break exprKind;
|
||||||
}
|
}
|
||||||
case "__i64_load": {
|
case "__i64_load": {
|
||||||
|
assertArgs(1);
|
||||||
lowerExpr(fcx, instrs, expr.args[0]);
|
lowerExpr(fcx, instrs, expr.args[0]);
|
||||||
instrs.push({ kind: "i64.load", imm: {} });
|
instrs.push({ kind: "i64.load", imm: {} });
|
||||||
break exprKind;
|
break exprKind;
|
||||||
}
|
}
|
||||||
case "__i32_store": {
|
case "__i32_store": {
|
||||||
|
assertArgs(2);
|
||||||
lowerExpr(fcx, instrs, expr.args[0]);
|
lowerExpr(fcx, instrs, expr.args[0]);
|
||||||
lowerExpr(fcx, instrs, expr.args[1]);
|
lowerExpr(fcx, instrs, expr.args[1]);
|
||||||
instrs.push({ kind: "i32.store", imm: {} });
|
instrs.push({ kind: "i32.store", imm: {} });
|
||||||
break exprKind;
|
break exprKind;
|
||||||
}
|
}
|
||||||
case "__i64_store": {
|
case "__i64_store": {
|
||||||
|
assertArgs(3);
|
||||||
lowerExpr(fcx, instrs, expr.args[0]);
|
lowerExpr(fcx, instrs, expr.args[0]);
|
||||||
lowerExpr(fcx, instrs, expr.args[1]);
|
lowerExpr(fcx, instrs, expr.args[1]);
|
||||||
instrs.push({ kind: "i64.store", imm: {} });
|
instrs.push({ kind: "i64.store", imm: {} });
|
||||||
break exprKind;
|
break exprKind;
|
||||||
}
|
}
|
||||||
case "__string_ptr": {
|
case "__string_ptr": {
|
||||||
|
assertArgs(1);
|
||||||
lowerExpr(fcx, instrs, expr.args[0]);
|
lowerExpr(fcx, instrs, expr.args[0]);
|
||||||
// ptr, len
|
// ptr, len
|
||||||
instrs.push({ kind: "drop" });
|
instrs.push({ kind: "drop" });
|
||||||
|
|
@ -658,14 +682,32 @@ function lowerExpr(
|
||||||
break exprKind;
|
break exprKind;
|
||||||
}
|
}
|
||||||
case "__string_len": {
|
case "__string_len": {
|
||||||
|
assertArgs(1);
|
||||||
lowerExpr(fcx, instrs, expr.args[0]);
|
lowerExpr(fcx, instrs, expr.args[0]);
|
||||||
// ptr, len
|
// ptr, len
|
||||||
instrs.push({ kind: "i32.const", imm: 0 });
|
instrs.push({ kind: "i32.const", imm: 0n });
|
||||||
// ptr, len, 0
|
// ptr, len, 0
|
||||||
instrs.push({ kind: "select" });
|
instrs.push({ kind: "select" });
|
||||||
// len
|
// len
|
||||||
break exprKind;
|
break exprKind;
|
||||||
}
|
}
|
||||||
|
case "__memory_size": {
|
||||||
|
assertArgs(0);
|
||||||
|
instrs.push({ kind: "memory.size" });
|
||||||
|
break exprKind;
|
||||||
|
}
|
||||||
|
case "__memory_grow": {
|
||||||
|
assertArgs(1);
|
||||||
|
lowerExpr(fcx, instrs, expr.args[0]);
|
||||||
|
instrs.push({ kind: "memory.grow" });
|
||||||
|
break exprKind;
|
||||||
|
}
|
||||||
|
case "__i32_extend_to_i64_u": {
|
||||||
|
assertArgs(1);
|
||||||
|
lowerExpr(fcx, instrs, expr.args[0]);
|
||||||
|
instrs.push({ kind: "i64.extend_i32_u" });
|
||||||
|
break exprKind;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1016,18 +1058,18 @@ function addRt(cx: Context, crates: Crate<Typecked>[]) {
|
||||||
type: internFuncType(cx, { params: [POINTER, USIZE], returns: [] }),
|
type: internFuncType(cx, { params: [POINTER, USIZE], returns: [] }),
|
||||||
body: [
|
body: [
|
||||||
// get the pointer and store it in the iovec
|
// get the pointer and store it in the iovec
|
||||||
{ kind: "i32.const", imm: iovecArray },
|
{ kind: "i32.const", imm: BigInt(iovecArray) },
|
||||||
{ kind: "local.get", imm: 0 },
|
{ kind: "local.get", imm: 0 },
|
||||||
{ kind: "i32.store", imm: { offset: 0, align: 4 } },
|
{ kind: "i32.store", imm: { offset: 0, align: 4 } },
|
||||||
// get the length and store it in the iovec
|
// get the length and store it in the iovec
|
||||||
{ kind: "i32.const", imm: iovecArray + 4 },
|
{ kind: "i32.const", imm: BigInt(iovecArray + 4) },
|
||||||
{ kind: "local.get", imm: 1 },
|
{ kind: "local.get", imm: 1 },
|
||||||
{ kind: "i32.store", imm: { offset: 0, align: 4 } },
|
{ kind: "i32.store", imm: { offset: 0, align: 4 } },
|
||||||
// now call stuff
|
// now call stuff
|
||||||
{ kind: "i32.const", imm: /*stdout*/ 1 },
|
{ kind: "i32.const", imm: /*stdout*/ 1n },
|
||||||
{ kind: "i32.const", imm: iovecArray },
|
{ kind: "i32.const", imm: BigInt(iovecArray) },
|
||||||
{ kind: "i32.const", imm: /*iovec len*/ 1 },
|
{ kind: "i32.const", imm: /*iovec len*/ 1n },
|
||||||
{ kind: "i32.const", imm: /*out ptr*/ printReturnValue },
|
{ kind: "i32.const", imm: /*out ptr*/ BigInt(printReturnValue) },
|
||||||
{ kind: "call", func: 0 },
|
{ kind: "call", func: 0 },
|
||||||
{ kind: "drop" },
|
{ kind: "drop" },
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ import {
|
||||||
ItemId,
|
ItemId,
|
||||||
GlobalItem,
|
GlobalItem,
|
||||||
} from "./ast";
|
} from "./ast";
|
||||||
import { CompilerError, Span, spanMerge } from "./error";
|
import { CompilerError, DUMMY_SPAN, EOF_SPAN, Span, spanMerge } from "./error";
|
||||||
import { BaseToken, Token, TokenIdent, TokenLitString } from "./lexer";
|
import { BaseToken, Token, TokenIdent, TokenLitString } from "./lexer";
|
||||||
import { ComplexMap, ComplexSet, Ids } from "./utils";
|
import { ComplexMap, ComplexSet, Ids } from "./utils";
|
||||||
|
|
||||||
|
|
@ -165,7 +165,7 @@ function parseItem(t: Token[]): [Token[], Item<Parsed>] {
|
||||||
|
|
||||||
const contents: Item<Parsed>[] = [];
|
const contents: Item<Parsed>[] = [];
|
||||||
|
|
||||||
while (next(t)[1].kind !== ")") {
|
while (peekKind(t) !== ")") {
|
||||||
let item;
|
let item;
|
||||||
[t, item] = parseItem(t);
|
[t, item] = parseItem(t);
|
||||||
|
|
||||||
|
|
@ -287,13 +287,15 @@ function mkParserExprBinary(
|
||||||
let lhs;
|
let lhs;
|
||||||
[t, lhs] = lower(t);
|
[t, lhs] = lower(t);
|
||||||
|
|
||||||
const [, peek] = next(t);
|
const peek = peekKind(t);
|
||||||
if (kinds.includes(peek.kind)) {
|
if (peek && kinds.includes(peek)) {
|
||||||
[t] = next(t);
|
let tok;
|
||||||
|
[t, tok] = next(t);
|
||||||
let rhs;
|
let rhs;
|
||||||
[t, rhs] = parser(t);
|
[t, rhs] = parser(t);
|
||||||
const span = spanMerge(lhs.span, rhs.span);
|
const span = spanMerge(lhs.span, rhs.span);
|
||||||
return [t, mkExpr(lhs, rhs, span, peek.kind)];
|
|
||||||
|
return [t, mkExpr(lhs, rhs, span, tok.kind)];
|
||||||
}
|
}
|
||||||
|
|
||||||
return [t, lhs];
|
return [t, lhs];
|
||||||
|
|
@ -326,17 +328,19 @@ const parseExprAssignment = mkParserExprBinary(
|
||||||
);
|
);
|
||||||
|
|
||||||
function parseExprUnary(t: Token[]): [Token[], Expr<Parsed>] {
|
function parseExprUnary(t: Token[]): [Token[], Expr<Parsed>] {
|
||||||
const [, peak] = next(t);
|
const peek = peekKind(t);
|
||||||
if (peak.kind in UNARY_KINDS) {
|
if (peek && UNARY_KINDS.includes(peek as UnaryKind)) {
|
||||||
|
let tok: Token;
|
||||||
|
[t, tok] = expectNext(t, peek);
|
||||||
let rhs;
|
let rhs;
|
||||||
[t, rhs] = parseExprUnary(t);
|
[t, rhs] = parseExprUnary(t);
|
||||||
return [
|
return [
|
||||||
t,
|
t,
|
||||||
{
|
{
|
||||||
kind: "unary",
|
kind: "unary",
|
||||||
unaryKind: peak.kind as UnaryKind,
|
unaryKind: tok.kind as UnaryKind,
|
||||||
rhs,
|
rhs,
|
||||||
span: peak.span,
|
span: tok.span,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
@ -347,7 +351,7 @@ function parseExprCall(t: Token[]): [Token[], Expr<Parsed>] {
|
||||||
let lhs: Expr<Parsed>;
|
let lhs: Expr<Parsed>;
|
||||||
[t, lhs] = parseExprAtom(t);
|
[t, lhs] = parseExprAtom(t);
|
||||||
|
|
||||||
while (next(t)[1].kind === "(" || next(t)[1].kind === ".") {
|
while (peekKind(t) === "(" || peekKind(t) === ".") {
|
||||||
let tok;
|
let tok;
|
||||||
[t, tok] = next(t);
|
[t, tok] = next(t);
|
||||||
|
|
||||||
|
|
@ -402,7 +406,7 @@ function parseExprAtom(startT: Token[]): [Token[], Expr<Parsed>] {
|
||||||
// It's a block.
|
// It's a block.
|
||||||
if (peek.kind === ";") {
|
if (peek.kind === ";") {
|
||||||
const exprs = [expr];
|
const exprs = [expr];
|
||||||
while (next(t)[1].kind !== ")") {
|
while (peekKind(t) !== ")") {
|
||||||
[t] = expectNext(t, ";");
|
[t] = expectNext(t, ";");
|
||||||
[t, expr] = parseExpr(t);
|
[t, expr] = parseExpr(t);
|
||||||
exprs.push(expr);
|
exprs.push(expr);
|
||||||
|
|
@ -578,14 +582,14 @@ function parseType(t: Token[]): [Token[], Type<Parsed>] {
|
||||||
// `()` is a the unit type, an empty tuple.
|
// `()` is a the unit type, an empty tuple.
|
||||||
// `(T)` is just `T`
|
// `(T)` is just `T`
|
||||||
// `(T,)` is a tuple
|
// `(T,)` is a tuple
|
||||||
if (next(t)[1]?.kind === ")") {
|
if (peekKind(t) === ")") {
|
||||||
[t] = next(t);
|
[t] = next(t);
|
||||||
return [t, { kind: "tuple", elems: [], span }];
|
return [t, { kind: "tuple", elems: [], span }];
|
||||||
}
|
}
|
||||||
let head;
|
let head;
|
||||||
[t, head] = parseType(t);
|
[t, head] = parseType(t);
|
||||||
|
|
||||||
if (next(t)[1]?.kind === ")") {
|
if (peekKind(t) === ")") {
|
||||||
[t] = next(t);
|
[t] = next(t);
|
||||||
// Just a type inside parens, not a tuple. `(T,)` is a tuple.
|
// Just a type inside parens, not a tuple. `(T,)` is a tuple.
|
||||||
return [t, head];
|
return [t, head];
|
||||||
|
|
@ -618,7 +622,7 @@ function parseCommaSeparatedList<R>(
|
||||||
|
|
||||||
// () | (a) | (a,) | (a, b)
|
// () | (a) | (a,) | (a, b)
|
||||||
|
|
||||||
while (next(t)[1]?.kind !== terminator) {
|
while (peekKind(t) !== terminator) {
|
||||||
let nextValue;
|
let nextValue;
|
||||||
[t, nextValue] = parser(t);
|
[t, nextValue] = parser(t);
|
||||||
|
|
||||||
|
|
@ -629,7 +633,7 @@ function parseCommaSeparatedList<R>(
|
||||||
if (!comma) {
|
if (!comma) {
|
||||||
// No comma? Fine, you don't like trailing commas.
|
// No comma? Fine, you don't like trailing commas.
|
||||||
// But this better be the end.
|
// But this better be the end.
|
||||||
if (next(t)[1]?.kind !== terminator) {
|
if (peekKind(t) !== terminator) {
|
||||||
unexpectedToken(next(t)[1], `, or ${terminator}`);
|
unexpectedToken(next(t)[1], `, or ${terminator}`);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -645,19 +649,28 @@ function eat<T extends BaseToken>(
|
||||||
t: Token[],
|
t: Token[],
|
||||||
kind: T["kind"]
|
kind: T["kind"]
|
||||||
): [Token[], T | undefined] {
|
): [Token[], T | undefined] {
|
||||||
const [tnext, tok] = next(t);
|
if (peekKind(t) === kind) {
|
||||||
if (tok.kind === kind) {
|
return expectNext(t, kind);
|
||||||
return [tnext, tok as unknown as T];
|
|
||||||
}
|
}
|
||||||
return [t, undefined];
|
return [t, undefined];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function peekKind(t: Token[]): Token["kind"] | undefined {
|
||||||
|
return maybeNextT(t)?.[1]?.kind;
|
||||||
|
}
|
||||||
|
|
||||||
function expectNext<T extends BaseToken>(
|
function expectNext<T extends BaseToken>(
|
||||||
t: Token[],
|
t: Token[],
|
||||||
kind: T["kind"]
|
kind: T["kind"]
|
||||||
): [Token[], T & Token] {
|
): [Token[], T & Token] {
|
||||||
let tok;
|
let tok;
|
||||||
[t, tok] = next(t);
|
[t, tok] = maybeNextT(t);
|
||||||
|
if (!tok) {
|
||||||
|
throw new CompilerError(
|
||||||
|
`expected \`${kind}\`, found end of file`,
|
||||||
|
EOF_SPAN
|
||||||
|
);
|
||||||
|
}
|
||||||
if (tok.kind !== kind) {
|
if (tok.kind !== kind) {
|
||||||
throw new CompilerError(
|
throw new CompilerError(
|
||||||
`expected \`${kind}\`, found \`${tok.kind}\``,
|
`expected \`${kind}\`, found \`${tok.kind}\``,
|
||||||
|
|
@ -670,10 +683,7 @@ function expectNext<T extends BaseToken>(
|
||||||
function next(t: Token[]): [Token[], Token] {
|
function next(t: Token[]): [Token[], Token] {
|
||||||
const [rest, next] = maybeNextT(t);
|
const [rest, next] = maybeNextT(t);
|
||||||
if (!next) {
|
if (!next) {
|
||||||
throw new CompilerError("unexpected end of file", {
|
throw new CompilerError("unexpected end of file", EOF_SPAN);
|
||||||
start: Number.MAX_SAFE_INTEGER,
|
|
||||||
end: Number.MAX_SAFE_INTEGER,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return [rest, next];
|
return [rest, next];
|
||||||
}
|
}
|
||||||
|
|
@ -757,6 +767,7 @@ function buildCrate(
|
||||||
crateId: number
|
crateId: number
|
||||||
): Crate<Built> {
|
): Crate<Built> {
|
||||||
const itemId = new Ids();
|
const itemId = new Ids();
|
||||||
|
itemId.next(); // crate root ID
|
||||||
const loopId = new Ids();
|
const loopId = new Ids();
|
||||||
|
|
||||||
const ast: Crate<Built> = {
|
const ast: Crate<Built> = {
|
||||||
|
|
@ -789,5 +800,7 @@ function buildCrate(
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return foldAst(ast, assigner);
|
const crate = foldAst(ast, assigner);
|
||||||
|
|
||||||
|
return crate;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import {
|
||||||
superFoldType,
|
superFoldType,
|
||||||
ExternItem,
|
ExternItem,
|
||||||
Typecked,
|
Typecked,
|
||||||
|
findCrateItem,
|
||||||
} from "./ast";
|
} from "./ast";
|
||||||
import { CompilerError, Span, spanMerge } from "./error";
|
import { CompilerError, Span, spanMerge } from "./error";
|
||||||
import { ComplexMap, Ids, unwrap } from "./utils";
|
import { ComplexMap, Ids, unwrap } from "./utils";
|
||||||
|
|
@ -40,6 +41,13 @@ type Context = {
|
||||||
crateId: Ids;
|
crateId: Ids;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function findItem(cx: Context, id: ItemId): Item<Built> {
|
||||||
|
const crate = unwrap(
|
||||||
|
[cx.ast, ...cx.crates].find((crate) => crate.id === id.crateId)
|
||||||
|
);
|
||||||
|
return findCrateItem(crate, id);
|
||||||
|
}
|
||||||
|
|
||||||
function resolveModItem(
|
function resolveModItem(
|
||||||
cx: Context,
|
cx: Context,
|
||||||
mod: ModItem<Built> | ExternItem,
|
mod: ModItem<Built> | ExternItem,
|
||||||
|
|
@ -56,21 +64,15 @@ function resolveModItem(
|
||||||
if ("contents" in mod) {
|
if ("contents" in mod) {
|
||||||
contents = new Map(mod.contents.map((item) => [item.node.name, item.id]));
|
contents = new Map(mod.contents.map((item) => [item.node.name, item.id]));
|
||||||
} else {
|
} else {
|
||||||
console.log("resolve...");
|
|
||||||
|
|
||||||
const [loadedCrate, itsDeps] = cx.crateLoader(
|
const [loadedCrate, itsDeps] = cx.crateLoader(
|
||||||
item.node.name,
|
item.node.name,
|
||||||
item.span,
|
item.span,
|
||||||
cx.crateId,
|
cx.crateId,
|
||||||
cx.crates
|
cx.crates
|
||||||
);
|
);
|
||||||
console.log("hmm");
|
|
||||||
|
|
||||||
cx.crates.push(loadedCrate);
|
cx.crates.push(loadedCrate);
|
||||||
cx.crates.push(...itsDeps);
|
cx.crates.push(...itsDeps);
|
||||||
|
|
||||||
console.log(cx.crates);
|
|
||||||
|
|
||||||
contents = new Map(
|
contents = new Map(
|
||||||
loadedCrate.rootItems.map((item) => [item.node.name, item.id])
|
loadedCrate.rootItems.map((item) => [item.node.name, item.id])
|
||||||
);
|
);
|
||||||
|
|
@ -157,6 +159,13 @@ function resolveModule(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ident.name === cx.ast.packageName) {
|
||||||
|
return {
|
||||||
|
kind: "item",
|
||||||
|
id: new ItemId(cx.ast.id, 0),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (BUILTIN_SET.has(ident.name)) {
|
if (BUILTIN_SET.has(ident.name)) {
|
||||||
return { kind: "builtin", name: ident.name as BuiltinName };
|
return { kind: "builtin", name: ident.name as BuiltinName };
|
||||||
}
|
}
|
||||||
|
|
@ -271,7 +280,8 @@ function resolveModule(
|
||||||
lhs.kind === "ident" ? [lhs.value.name] : lhs.segments;
|
lhs.kind === "ident" ? [lhs.value.name] : lhs.segments;
|
||||||
|
|
||||||
if (res.kind === "item") {
|
if (res.kind === "item") {
|
||||||
const module = unwrap(cx.ast.itemsById.get(res.id));
|
const module = findItem(cx, res.id);
|
||||||
|
|
||||||
if (module.kind === "mod" || module.kind === "extern") {
|
if (module.kind === "mod" || module.kind === "extern") {
|
||||||
if (typeof expr.field.value === "number") {
|
if (typeof expr.field.value === "number") {
|
||||||
throw new CompilerError(
|
throw new CompilerError(
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ import {
|
||||||
Typecked,
|
Typecked,
|
||||||
TyStruct,
|
TyStruct,
|
||||||
Item,
|
Item,
|
||||||
|
findCrateItem,
|
||||||
} from "./ast";
|
} from "./ast";
|
||||||
import { CompilerError, Span } from "./error";
|
import { CompilerError, Span } from "./error";
|
||||||
import { printTy } from "./printer";
|
import { printTy } from "./printer";
|
||||||
|
|
@ -79,6 +80,12 @@ function typeOfBuiltinValue(name: BuiltinName, span: Span): Ty {
|
||||||
return mkTyFn([TY_STRING], TY_I32);
|
return mkTyFn([TY_STRING], TY_I32);
|
||||||
case "__string_len":
|
case "__string_len":
|
||||||
return mkTyFn([TY_STRING], TY_I32);
|
return mkTyFn([TY_STRING], TY_I32);
|
||||||
|
case "__memory_size":
|
||||||
|
return mkTyFn([], TY_I32);
|
||||||
|
case "__memory_grow":
|
||||||
|
return mkTyFn([TY_I32], TY_I32);
|
||||||
|
case "__i32_extend_to_i64_u":
|
||||||
|
return mkTyFn([TY_I32], TY_INT);
|
||||||
default: {
|
default: {
|
||||||
throw new CompilerError(`\`${name}\` cannot be used as a value`, span);
|
throw new CompilerError(`\`${name}\` cannot be used as a value`, span);
|
||||||
}
|
}
|
||||||
|
|
@ -123,12 +130,10 @@ export function typeck(
|
||||||
|
|
||||||
function typeOfItem(itemId: ItemId, cause: Span): Ty {
|
function typeOfItem(itemId: ItemId, cause: Span): Ty {
|
||||||
if (itemId.crateId !== ast.id) {
|
if (itemId.crateId !== ast.id) {
|
||||||
console.log(otherCrates);
|
|
||||||
|
|
||||||
const crate = unwrap(
|
const crate = unwrap(
|
||||||
otherCrates.find((crate) => crate.id === itemId.crateId)
|
otherCrates.find((crate) => crate.id === itemId.crateId)
|
||||||
);
|
);
|
||||||
const item = unwrap(crate.itemsById.get(itemId));
|
const item = findCrateItem(crate, itemId);
|
||||||
switch (item.kind) {
|
switch (item.kind) {
|
||||||
case "function":
|
case "function":
|
||||||
case "import":
|
case "import":
|
||||||
|
|
@ -150,7 +155,7 @@ export function typeck(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const item = unwrap(ast.itemsById.get(itemId));
|
const item = findCrateItem(ast, itemId);
|
||||||
const ty = itemTys.get(itemId);
|
const ty = itemTys.get(itemId);
|
||||||
if (ty) {
|
if (ty) {
|
||||||
return ty;
|
return ty;
|
||||||
|
|
@ -236,12 +241,11 @@ export function typeck(
|
||||||
|
|
||||||
function findItem(itemId: ItemId): Item<Resolved> {
|
function findItem(itemId: ItemId): Item<Resolved> {
|
||||||
if (itemId.crateId === ast.id) {
|
if (itemId.crateId === ast.id) {
|
||||||
return unwrap(ast.itemsById.get(itemId));
|
return findCrateItem(ast, itemId);
|
||||||
}
|
}
|
||||||
return unwrap(
|
return findCrateItem(
|
||||||
unwrap(
|
unwrap(otherCrates.find((crate) => crate.id === itemId.crateId)),
|
||||||
otherCrates.find((crate) => crate.id === itemId.crateId)
|
itemId
|
||||||
).itemsById.get(itemId)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1056,6 +1060,10 @@ function checkBinary(
|
||||||
return { ...expr, lhs, rhs, ty: TY_BOOL };
|
return { ...expr, lhs, rhs, ty: TY_BOOL };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lhsTy.kind === "i32" && rhsTy.kind === "i32") {
|
||||||
|
return { ...expr, lhs, rhs, ty: TY_BOOL };
|
||||||
|
}
|
||||||
|
|
||||||
if (lhsTy.kind === "string" && rhsTy.kind === "string") {
|
if (lhsTy.kind === "string" && rhsTy.kind === "string") {
|
||||||
return { ...expr, lhs, rhs, ty: TY_BOOL };
|
return { ...expr, lhs, rhs, ty: TY_BOOL };
|
||||||
}
|
}
|
||||||
|
|
@ -1096,7 +1104,7 @@ function checkUnary(
|
||||||
|
|
||||||
if (
|
if (
|
||||||
expr.unaryKind === "!" &&
|
expr.unaryKind === "!" &&
|
||||||
(rhsTy.kind === "int" || rhsTy.kind === "bool")
|
(rhsTy.kind === "int" || rhsTy.kind === "i32" || rhsTy.kind === "bool")
|
||||||
) {
|
) {
|
||||||
return { ...expr, rhs, ty: rhsTy };
|
return { ...expr, rhs, ty: rhsTy };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
// Base types.
|
// Base types.
|
||||||
|
|
||||||
export type u32 = number;
|
export type u32 = number;
|
||||||
export type u64 = number;
|
export type u64 = bigint;
|
||||||
export type f32 = number;
|
export type f32 = number;
|
||||||
export type f64 = number;
|
export type f64 = number;
|
||||||
export type VecByte = Uint8Array;
|
export type VecByte = Uint8Array;
|
||||||
|
|
@ -73,7 +73,7 @@ export type BitWidth = "32" | "64";
|
||||||
export type Sign = "u" | "s";
|
export type Sign = "u" | "s";
|
||||||
|
|
||||||
export type NumericInstr =
|
export type NumericInstr =
|
||||||
| { kind: "i32.const"; imm: u32 }
|
| { kind: "i32.const"; imm: bigint }
|
||||||
| { kind: "i64.const"; imm: u64 }
|
| { kind: "i64.const"; imm: u64 }
|
||||||
| { kind: "f32.const"; imm: f32 }
|
| { kind: "f32.const"; imm: f32 }
|
||||||
| { kind: "f64.const"; imm: f64 }
|
| { kind: "f64.const"; imm: f64 }
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ const EXAMPLE_MODULE: Module = {
|
||||||
type: { kind: "typeidx", idx: 1 },
|
type: { kind: "typeidx", idx: 1 },
|
||||||
instrs: [{ kind: "local.get", imm: 0 }],
|
instrs: [{ kind: "local.get", imm: 0 }],
|
||||||
},
|
},
|
||||||
{ kind: "i32.const", imm: 1 },
|
{ kind: "i32.const", imm: 1n },
|
||||||
{ kind: "i32.add" },
|
{ kind: "i32.add" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
@ -49,7 +49,7 @@ const EXAMPLE_MODULE: Module = {
|
||||||
globals: [
|
globals: [
|
||||||
{
|
{
|
||||||
type: { mut: "const", type: "i32" },
|
type: { mut: "const", type: "i32" },
|
||||||
init: [{ kind: "i32.const", imm: 0 }],
|
init: [{ kind: "i32.const", imm: 0n }],
|
||||||
_name: "globalling",
|
_name: "globalling",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
@ -70,7 +70,7 @@ const EXAMPLE_MODULE: Module = {
|
||||||
mode: {
|
mode: {
|
||||||
kind: "active",
|
kind: "active",
|
||||||
memory: 0,
|
memory: 0,
|
||||||
offset: [{ kind: "i32.const", imm: 0 }],
|
offset: [{ kind: "i32.const", imm: 0n }],
|
||||||
},
|
},
|
||||||
init: new Uint8Array(),
|
init: new Uint8Array(),
|
||||||
_name: "very-active-data",
|
_name: "very-active-data",
|
||||||
|
|
@ -86,7 +86,7 @@ it("should print a Wasm module with the correct formatting", () => {
|
||||||
(type (func (param i32) (result i32)))
|
(type (func (param i32) (result i32)))
|
||||||
(type (func (param) (result i32)))
|
(type (func (param) (result i32)))
|
||||||
(import "left-pad" "padLeft" (func (type 0)))
|
(import "left-pad" "padLeft" (func (type 0)))
|
||||||
(func $addOne (type 0)
|
(func $addOne (;1;) (type 0)
|
||||||
(local i32 i32)
|
(local i32 i32)
|
||||||
local.set 0
|
local.set 0
|
||||||
block (type 1)
|
block (type 1)
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ class FmtCtx {
|
||||||
this.word(word, chalk.blue);
|
this.word(word, chalk.blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
type(word: string | number) {
|
type(word: string | number | bigint) {
|
||||||
this.word(word, chalk.green);
|
this.word(word, chalk.green);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,7 +90,10 @@ class FmtCtx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
word(word: string | number, color: (s: string) => string = identity) {
|
word(
|
||||||
|
word: string | number | bigint,
|
||||||
|
color: (s: string) => string = identity
|
||||||
|
) {
|
||||||
const last = this.wordsInSexpr.length - 1;
|
const last = this.wordsInSexpr.length - 1;
|
||||||
if (this.wordsInSexpr[last] > 0 && !this.freshLinebreak) {
|
if (this.wordsInSexpr[last] > 0 && !this.freshLinebreak) {
|
||||||
// The first word hugs the left parenthesis.
|
// The first word hugs the left parenthesis.
|
||||||
|
|
@ -436,10 +439,17 @@ function printInstr(instr: Instr, f: FmtCtx) {
|
||||||
case "call": {
|
case "call": {
|
||||||
f.controlFlow(instr.kind);
|
f.controlFlow(instr.kind);
|
||||||
f.word(instr.func);
|
f.word(instr.func);
|
||||||
const name = f.mod.funcs[instr.func]?._name;
|
if (instr.func < f.mod.imports.length) {
|
||||||
|
const name = f.mod.imports[instr.func]?.name;
|
||||||
if (name !== undefined) {
|
if (name !== undefined) {
|
||||||
f.comment(name);
|
f.comment(name);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
const name = f.mod.funcs[instr.func - f.mod.imports.length]?._name;
|
||||||
|
if (name !== undefined) {
|
||||||
|
f.comment(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "call_indirect":
|
case "call_indirect":
|
||||||
|
|
|
||||||
64
std.nil
64
std.nil
|
|
@ -1,8 +1,15 @@
|
||||||
|
function printlnI32(x: I32) = (
|
||||||
|
printI32(x);
|
||||||
|
print("\n");
|
||||||
|
);
|
||||||
|
|
||||||
function printlnInt(x: Int) = (
|
function printlnInt(x: Int) = (
|
||||||
printInt(x);
|
printInt(x);
|
||||||
print("\n");
|
print("\n");
|
||||||
);
|
);
|
||||||
|
|
||||||
|
function printI32(x: I32) = printInt(i32ToInt(x));
|
||||||
|
|
||||||
function printInt(x: Int) = (
|
function printInt(x: Int) = (
|
||||||
let mag = log10(x);
|
let mag = log10(x);
|
||||||
|
|
||||||
|
|
@ -58,8 +65,59 @@ function println(s: String) = (
|
||||||
print("\n");
|
print("\n");
|
||||||
);
|
);
|
||||||
|
|
||||||
mod alloc (
|
mod rt (
|
||||||
function allocateItem(size: I32): I32 = (
|
// Start the heap at 1024. In practice this could probably be as low as we want.
|
||||||
|
global BASE_PTR: I32 = 1024_I32;
|
||||||
|
global HEAD_PTR: I32 = 1024_I32;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Every struct has a header of an I32 as a refcount.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Allocate a new item. We do not deallocate anything yet.
|
||||||
|
// lol.
|
||||||
|
function allocateItem(objSize: I32, align: I32): I32 = (
|
||||||
|
if align < 4_I32 then std.abort("invalid alignment");
|
||||||
|
|
||||||
|
// Include the refcount header.
|
||||||
|
let actualSize = 4_I32 + objSize;
|
||||||
|
|
||||||
|
// Let's see whether we can fit the refcount into the align bits.
|
||||||
|
// I happen to know that everything will always be at least 4 bytes aligned.
|
||||||
|
let alignedPtr = std.alignUp(HEAD_PTR, align);
|
||||||
|
let actualObjPtr = if (alignedPtr - HEAD_PTR) > align then (
|
||||||
|
alignedPtr - 4_I32
|
||||||
|
) else (
|
||||||
|
// Take up the next spot.
|
||||||
|
alignedPtr + align - 4_I32
|
||||||
);
|
);
|
||||||
)
|
|
||||||
|
let newHeadPtr = actualObjPtr + actualSize;
|
||||||
|
|
||||||
|
if newHeadPtr > __memory_size() then (
|
||||||
|
// 16 pages, very arbitrary.
|
||||||
|
let result = __memory_grow(16_I32);
|
||||||
|
// If allocation failed we get -1. We don't have negative numbers yet, lol.
|
||||||
|
if result > 100000000_I32 then (
|
||||||
|
std.abort("failed to grow memory");
|
||||||
|
);
|
||||||
|
);
|
||||||
|
|
||||||
|
0_I32
|
||||||
|
);
|
||||||
|
);
|
||||||
|
|
||||||
|
function alignUp(x: I32, align: I32): I32 = (x + (align - 1_I32)) & !(align - 1_I32);
|
||||||
|
|
||||||
|
function i32ToInt(x: I32): Int = __i32_extend_to_i64_u(x);
|
||||||
|
|
||||||
|
function abort(message: String) = (
|
||||||
|
print("fatal error: ");
|
||||||
|
print(message);
|
||||||
|
println(".. aborting");
|
||||||
|
trap();
|
||||||
|
);
|
||||||
|
|
||||||
|
function main() = (
|
||||||
|
std.rt.allocateItem(100000000_I32, 8_I32);
|
||||||
|
);
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||||
|
|
||||||
/* Language and Environment */
|
/* Language and Environment */
|
||||||
"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
"target": "ES2022" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
||||||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||||
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
||||||
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue