many things

This commit is contained in:
nora 2023-07-31 22:39:17 +02:00
parent f582a5b4c3
commit 924236532c
13 changed files with 264 additions and 85 deletions

View file

@ -1,6 +1,6 @@
import { Span } from "./error";
import { DUMMY_SPAN, Span } from "./error";
import { LitIntType } from "./lexer";
import { ComplexMap } from "./utils";
import { ComplexMap, unwrap } from "./utils";
export type Phase = {
res: unknown;
@ -430,6 +430,9 @@ export const BUILTINS = [
"__i64_load",
"__string_ptr",
"__string_len",
"__memory_size",
"__memory_grow",
"__i32_extend_to_i64_u"
] as const;
export type BuiltinName = (typeof BUILTINS)[number];
@ -521,6 +524,29 @@ export type TypeckResults = {
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
export type FoldFn<From, To> = (value: From) => To;

View file

@ -11,6 +11,7 @@ export function spanMerge(a: Span, b: Span): Span {
}
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 {
msg: string;
@ -59,7 +60,10 @@ function renderError(input: string, filename: string, e: CompilerError) {
const startRelLine =
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(
`${" ".repeat(String(lineNo).length)} ${" ".repeat(

View file

@ -13,10 +13,12 @@ import { Crate, Built, Typecked } from "./ast";
import { Ids } from "./utils";
const INPUT = `
global HELLO: I32 = 0_I32;
extern mod std;
type A = { a: String };
function main() = (
HELLO = 1_I32;
std.rt.allocateItem(0_I32, 0_I32);
);
`;
@ -135,6 +137,8 @@ function loadCrate(
const tokens = tokenize(input);
const ast = parse(name, tokens, crateId.next());
const [resolved, crates] = resolve(ast, loadCrate);
console.log(resolved);
const typecked = typeck(resolved, [...existingCrates, ...crates]);
return [typecked, crates];

View file

@ -37,7 +37,8 @@ export type DatalessToken =
| "=="
| "<="
| ">="
| "!=";
| "!="
| "end of file";
export type TokenIdent = { kind: "identifier"; ident: string };
@ -109,6 +110,9 @@ export function tokenize(input: string): Token[] {
throw new CompilerError("unterminated block comment", span);
}
}
i++;
i++;
continue;
}
if (SINGLE_PUNCT.includes(next)) {

View file

@ -13,6 +13,7 @@ import {
TyFn,
TyTuple,
Typecked,
findCrateItem,
varUnreachable,
} from "./ast";
import { printTy } from "./printer";
@ -30,6 +31,8 @@ const WASM_PAGE = 65536;
const DUMMY_IDX = 9999999;
const ALLOCATE_SYMBOL = "nil__std__rt__allocateItem";
type RelocationKind =
| {
kind: "funccall";
@ -86,7 +89,7 @@ function appendData(cx: Context, newData: Uint8Array): number {
mode: {
kind: "active",
memory: 0,
offset: [{ kind: "i32.const", imm: 0 }],
offset: [{ kind: "i32.const", imm: 0n }],
},
_name: "staticdata",
});
@ -103,8 +106,9 @@ function appendData(cx: Context, newData: Uint8Array): number {
}
function findItem(cx: Context, id: ItemId): Item<Typecked> {
return unwrap(
unwrap(cx.crates.find((crate) => crate.id === id.crateId)).itemsById.get(id)
return findCrateItem(
unwrap(cx.crates.find((crate) => crate.id === id.crateId)),
id
);
}
@ -271,7 +275,7 @@ function lowerGlobal(
const init: wasm.Instr = {
kind: `${valtype}.const`,
imm: def.init.value.value,
imm: BigInt(def.init.value.value),
};
cx.mod.globals.push({
@ -300,6 +304,11 @@ type ArgRetAbi = wasm.ValType[];
type VarLocation = { localIdx: number; types: wasm.ValType[] };
type StructLayout = {
size: number,
align: number,
}
function lowerFunc(
cx: Context,
item: Item<Typecked>,
@ -438,18 +447,18 @@ function lowerExpr(
const utf8 = encodeUtf8(expr.value.value);
const idx = appendData(fcx.cx, utf8);
instrs.push({ kind: "i32.const", imm: idx });
instrs.push({ kind: "i32.const", imm: utf8.length });
instrs.push({ kind: "i32.const", imm: BigInt(idx) });
instrs.push({ kind: "i32.const", imm: BigInt(utf8.length) });
break;
}
case "int":
switch (expr.value.type) {
case "Int":
instrs.push({ kind: "i64.const", imm: expr.value.value });
instrs.push({ kind: "i64.const", imm: BigInt(expr.value.value) });
break;
case "I32":
instrs.push({ kind: "i32.const", imm: expr.value.value });
instrs.push({ kind: "i32.const", imm: BigInt(expr.value.value) });
break;
}
break;
@ -487,10 +496,10 @@ function lowerExpr(
case "builtin":
switch (res.name) {
case "false":
instrs.push({ kind: "i32.const", imm: 0 });
instrs.push({ kind: "i32.const", imm: 0n });
break;
case "true":
instrs.push({ kind: "i32.const", imm: 1 });
instrs.push({ kind: "i32.const", imm: 1n });
break;
case "print":
todo("print function");
@ -603,11 +612,18 @@ function lowerExpr(
case "!":
if (ty.kind === "bool") {
// `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" });
} else if (ty.kind === "int") {
// `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;
case "-":
@ -621,36 +637,44 @@ function lowerExpr(
}
const res = expr.lhs.kind === "ident" ? expr.lhs.value.res : expr.lhs.res;
if (res.kind === "builtin") {
const assertArgs = (n: number) => {
if (expr.args.length !== n) throw new Error("nope");
};
switch (res.name) {
case "trap": {
assertArgs(0);
instrs.push({ kind: "unreachable" });
break exprKind;
}
case "__i32_load": {
assertArgs(1);
lowerExpr(fcx, instrs, expr.args[0]);
instrs.push({ kind: "i64.load", imm: {} });
break exprKind;
}
case "__i64_load": {
assertArgs(1);
lowerExpr(fcx, instrs, expr.args[0]);
instrs.push({ kind: "i64.load", imm: {} });
break exprKind;
}
case "__i32_store": {
assertArgs(2);
lowerExpr(fcx, instrs, expr.args[0]);
lowerExpr(fcx, instrs, expr.args[1]);
instrs.push({ kind: "i32.store", imm: {} });
break exprKind;
}
case "__i64_store": {
assertArgs(3);
lowerExpr(fcx, instrs, expr.args[0]);
lowerExpr(fcx, instrs, expr.args[1]);
instrs.push({ kind: "i64.store", imm: {} });
break exprKind;
}
case "__string_ptr": {
assertArgs(1);
lowerExpr(fcx, instrs, expr.args[0]);
// ptr, len
instrs.push({ kind: "drop" });
@ -658,14 +682,32 @@ function lowerExpr(
break exprKind;
}
case "__string_len": {
assertArgs(1);
lowerExpr(fcx, instrs, expr.args[0]);
// ptr, len
instrs.push({ kind: "i32.const", imm: 0 });
instrs.push({ kind: "i32.const", imm: 0n });
// ptr, len, 0
instrs.push({ kind: "select" });
// len
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: [] }),
body: [
// 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: "i32.store", imm: { offset: 0, align: 4 } },
// 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: "i32.store", imm: { offset: 0, align: 4 } },
// now call stuff
{ kind: "i32.const", imm: /*stdout*/ 1 },
{ kind: "i32.const", imm: iovecArray },
{ kind: "i32.const", imm: /*iovec len*/ 1 },
{ kind: "i32.const", imm: /*out ptr*/ printReturnValue },
{ kind: "i32.const", imm: /*stdout*/ 1n },
{ kind: "i32.const", imm: BigInt(iovecArray) },
{ kind: "i32.const", imm: /*iovec len*/ 1n },
{ kind: "i32.const", imm: /*out ptr*/ BigInt(printReturnValue) },
{ kind: "call", func: 0 },
{ kind: "drop" },
],

View file

@ -31,7 +31,7 @@ import {
ItemId,
GlobalItem,
} 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 { ComplexMap, ComplexSet, Ids } from "./utils";
@ -165,7 +165,7 @@ function parseItem(t: Token[]): [Token[], Item<Parsed>] {
const contents: Item<Parsed>[] = [];
while (next(t)[1].kind !== ")") {
while (peekKind(t) !== ")") {
let item;
[t, item] = parseItem(t);
@ -287,13 +287,15 @@ function mkParserExprBinary(
let lhs;
[t, lhs] = lower(t);
const [, peek] = next(t);
if (kinds.includes(peek.kind)) {
[t] = next(t);
const peek = peekKind(t);
if (peek && kinds.includes(peek)) {
let tok;
[t, tok] = next(t);
let rhs;
[t, rhs] = parser(t);
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];
@ -326,17 +328,19 @@ const parseExprAssignment = mkParserExprBinary(
);
function parseExprUnary(t: Token[]): [Token[], Expr<Parsed>] {
const [, peak] = next(t);
if (peak.kind in UNARY_KINDS) {
const peek = peekKind(t);
if (peek && UNARY_KINDS.includes(peek as UnaryKind)) {
let tok: Token;
[t, tok] = expectNext(t, peek);
let rhs;
[t, rhs] = parseExprUnary(t);
return [
t,
{
kind: "unary",
unaryKind: peak.kind as UnaryKind,
unaryKind: tok.kind as UnaryKind,
rhs,
span: peak.span,
span: tok.span,
},
];
}
@ -347,7 +351,7 @@ function parseExprCall(t: Token[]): [Token[], Expr<Parsed>] {
let lhs: Expr<Parsed>;
[t, lhs] = parseExprAtom(t);
while (next(t)[1].kind === "(" || next(t)[1].kind === ".") {
while (peekKind(t) === "(" || peekKind(t) === ".") {
let tok;
[t, tok] = next(t);
@ -402,7 +406,7 @@ function parseExprAtom(startT: Token[]): [Token[], Expr<Parsed>] {
// It's a block.
if (peek.kind === ";") {
const exprs = [expr];
while (next(t)[1].kind !== ")") {
while (peekKind(t) !== ")") {
[t] = expectNext(t, ";");
[t, expr] = parseExpr(t);
exprs.push(expr);
@ -578,14 +582,14 @@ function parseType(t: Token[]): [Token[], Type<Parsed>] {
// `()` is a the unit type, an empty tuple.
// `(T)` is just `T`
// `(T,)` is a tuple
if (next(t)[1]?.kind === ")") {
if (peekKind(t) === ")") {
[t] = next(t);
return [t, { kind: "tuple", elems: [], span }];
}
let head;
[t, head] = parseType(t);
if (next(t)[1]?.kind === ")") {
if (peekKind(t) === ")") {
[t] = next(t);
// Just a type inside parens, not a tuple. `(T,)` is a tuple.
return [t, head];
@ -618,7 +622,7 @@ function parseCommaSeparatedList<R>(
// () | (a) | (a,) | (a, b)
while (next(t)[1]?.kind !== terminator) {
while (peekKind(t) !== terminator) {
let nextValue;
[t, nextValue] = parser(t);
@ -629,7 +633,7 @@ function parseCommaSeparatedList<R>(
if (!comma) {
// No comma? Fine, you don't like trailing commas.
// But this better be the end.
if (next(t)[1]?.kind !== terminator) {
if (peekKind(t) !== terminator) {
unexpectedToken(next(t)[1], `, or ${terminator}`);
}
break;
@ -645,19 +649,28 @@ function eat<T extends BaseToken>(
t: Token[],
kind: T["kind"]
): [Token[], T | undefined] {
const [tnext, tok] = next(t);
if (tok.kind === kind) {
return [tnext, tok as unknown as T];
if (peekKind(t) === kind) {
return expectNext(t, kind);
}
return [t, undefined];
}
function peekKind(t: Token[]): Token["kind"] | undefined {
return maybeNextT(t)?.[1]?.kind;
}
function expectNext<T extends BaseToken>(
t: Token[],
kind: T["kind"]
): [Token[], T & Token] {
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) {
throw new CompilerError(
`expected \`${kind}\`, found \`${tok.kind}\``,
@ -670,10 +683,7 @@ function expectNext<T extends BaseToken>(
function next(t: Token[]): [Token[], Token] {
const [rest, next] = maybeNextT(t);
if (!next) {
throw new CompilerError("unexpected end of file", {
start: Number.MAX_SAFE_INTEGER,
end: Number.MAX_SAFE_INTEGER,
});
throw new CompilerError("unexpected end of file", EOF_SPAN);
}
return [rest, next];
}
@ -757,6 +767,7 @@ function buildCrate(
crateId: number
): Crate<Built> {
const itemId = new Ids();
itemId.next(); // crate root ID
const loopId = new Ids();
const ast: Crate<Built> = {
@ -789,5 +800,7 @@ function buildCrate(
},
};
return foldAst(ast, assigner);
const crate = foldAst(ast, assigner);
return crate;
}

View file

@ -18,6 +18,7 @@ import {
superFoldType,
ExternItem,
Typecked,
findCrateItem,
} from "./ast";
import { CompilerError, Span, spanMerge } from "./error";
import { ComplexMap, Ids, unwrap } from "./utils";
@ -40,6 +41,13 @@ type Context = {
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(
cx: Context,
mod: ModItem<Built> | ExternItem,
@ -56,21 +64,15 @@ function resolveModItem(
if ("contents" in mod) {
contents = new Map(mod.contents.map((item) => [item.node.name, item.id]));
} else {
console.log("resolve...");
const [loadedCrate, itsDeps] = cx.crateLoader(
item.node.name,
item.span,
cx.crateId,
cx.crates
);
console.log("hmm");
cx.crates.push(loadedCrate);
cx.crates.push(...itsDeps);
console.log(cx.crates);
contents = new Map(
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)) {
return { kind: "builtin", name: ident.name as BuiltinName };
}
@ -271,7 +280,8 @@ function resolveModule(
lhs.kind === "ident" ? [lhs.value.name] : lhs.segments;
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 (typeof expr.field.value === "number") {
throw new CompilerError(

View file

@ -29,6 +29,7 @@ import {
Typecked,
TyStruct,
Item,
findCrateItem,
} from "./ast";
import { CompilerError, Span } from "./error";
import { printTy } from "./printer";
@ -79,6 +80,12 @@ function typeOfBuiltinValue(name: BuiltinName, span: Span): Ty {
return mkTyFn([TY_STRING], TY_I32);
case "__string_len":
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: {
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 {
if (itemId.crateId !== ast.id) {
console.log(otherCrates);
const crate = unwrap(
otherCrates.find((crate) => crate.id === itemId.crateId)
);
const item = unwrap(crate.itemsById.get(itemId));
const item = findCrateItem(crate, itemId);
switch (item.kind) {
case "function":
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);
if (ty) {
return ty;
@ -236,12 +241,11 @@ export function typeck(
function findItem(itemId: ItemId): Item<Resolved> {
if (itemId.crateId === ast.id) {
return unwrap(ast.itemsById.get(itemId));
return findCrateItem(ast, itemId);
}
return unwrap(
unwrap(
otherCrates.find((crate) => crate.id === itemId.crateId)
).itemsById.get(itemId)
return findCrateItem(
unwrap(otherCrates.find((crate) => crate.id === itemId.crateId)),
itemId
);
}
@ -1056,6 +1060,10 @@ function checkBinary(
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") {
return { ...expr, lhs, rhs, ty: TY_BOOL };
}
@ -1096,7 +1104,7 @@ function checkUnary(
if (
expr.unaryKind === "!" &&
(rhsTy.kind === "int" || rhsTy.kind === "bool")
(rhsTy.kind === "int" || rhsTy.kind === "i32" || rhsTy.kind === "bool")
) {
return { ...expr, rhs, ty: rhsTy };
}

View file

@ -4,7 +4,7 @@
// Base types.
export type u32 = number;
export type u64 = number;
export type u64 = bigint;
export type f32 = number;
export type f64 = number;
export type VecByte = Uint8Array;
@ -73,7 +73,7 @@ export type BitWidth = "32" | "64";
export type Sign = "u" | "s";
export type NumericInstr =
| { kind: "i32.const"; imm: u32 }
| { kind: "i32.const"; imm: bigint }
| { kind: "i64.const"; imm: u64 }
| { kind: "f32.const"; imm: f32 }
| { kind: "f64.const"; imm: f64 }

View file

@ -29,7 +29,7 @@ const EXAMPLE_MODULE: Module = {
type: { kind: "typeidx", idx: 1 },
instrs: [{ kind: "local.get", imm: 0 }],
},
{ kind: "i32.const", imm: 1 },
{ kind: "i32.const", imm: 1n },
{ kind: "i32.add" },
],
},
@ -49,7 +49,7 @@ const EXAMPLE_MODULE: Module = {
globals: [
{
type: { mut: "const", type: "i32" },
init: [{ kind: "i32.const", imm: 0 }],
init: [{ kind: "i32.const", imm: 0n }],
_name: "globalling",
},
],
@ -70,7 +70,7 @@ const EXAMPLE_MODULE: Module = {
mode: {
kind: "active",
memory: 0,
offset: [{ kind: "i32.const", imm: 0 }],
offset: [{ kind: "i32.const", imm: 0n }],
},
init: new Uint8Array(),
_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) (result i32)))
(import "left-pad" "padLeft" (func (type 0)))
(func $addOne (type 0)
(func $addOne (;1;) (type 0)
(local i32 i32)
local.set 0
block (type 1)

View file

@ -72,7 +72,7 @@ class FmtCtx {
this.word(word, chalk.blue);
}
type(word: string | number) {
type(word: string | number | bigint) {
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;
if (this.wordsInSexpr[last] > 0 && !this.freshLinebreak) {
// The first word hugs the left parenthesis.
@ -436,10 +439,17 @@ function printInstr(instr: Instr, f: FmtCtx) {
case "call": {
f.controlFlow(instr.kind);
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) {
f.comment(name);
}
} else {
const name = f.mod.funcs[instr.func - f.mod.imports.length]?._name;
if (name !== undefined) {
f.comment(name);
}
}
break;
}
case "call_indirect":

64
std.nil
View file

@ -1,8 +1,15 @@
function printlnI32(x: I32) = (
printI32(x);
print("\n");
);
function printlnInt(x: Int) = (
printInt(x);
print("\n");
);
function printI32(x: I32) = printInt(i32ToInt(x));
function printInt(x: Int) = (
let mag = log10(x);
@ -58,8 +65,59 @@ function println(s: String) = (
print("\n");
);
mod alloc (
function allocateItem(size: I32): I32 = (
mod rt (
// 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);
);

View file

@ -11,7 +11,7 @@
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* 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. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */