mirror of
https://github.com/Noratrieb/riverdelta.git
synced 2026-01-14 16:35:03 +01:00
move rt to separate file and make loader understand it
This commit is contained in:
parent
309a286a1a
commit
a1d04d264e
5 changed files with 100 additions and 61 deletions
|
|
@ -13,7 +13,6 @@ import { GlobalContext, parseArgs } from "./context";
|
||||||
import { loadCrate } from "./loader";
|
import { loadCrate } from "./loader";
|
||||||
|
|
||||||
const INPUT = `
|
const INPUT = `
|
||||||
extern mod a;
|
|
||||||
type A = { a: Int };
|
type A = { a: Int };
|
||||||
|
|
||||||
function main() = (
|
function main() = (
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,22 @@ export function loadModuleFile(
|
||||||
moduleName: string,
|
moduleName: string,
|
||||||
span: Span
|
span: Span
|
||||||
): LoadedFile {
|
): LoadedFile {
|
||||||
|
let searchDir: string;
|
||||||
|
if (relativeTo.endsWith(".mod.nil")) {
|
||||||
|
// x/uwu.mod.nil searches in x/
|
||||||
|
searchDir = path.dirname(relativeTo);
|
||||||
|
} else if (relativeTo.endsWith(".nil")) {
|
||||||
|
throw new CompilerError(
|
||||||
|
`.nil files cannot have submodules. use .mod.nil in a subdirectory`,
|
||||||
|
span
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
searchDir = relativeTo;
|
||||||
|
}
|
||||||
|
|
||||||
const options = [
|
const options = [
|
||||||
path.join(relativeTo, `${moduleName}.nil`),
|
path.join(searchDir, `${moduleName}.nil`),
|
||||||
path.join(relativeTo, moduleName, `${moduleName}.mod.nil`),
|
path.join(searchDir, moduleName, `${moduleName}.mod.nil`),
|
||||||
];
|
];
|
||||||
|
|
||||||
let content: string | undefined = undefined;
|
let content: string | undefined = undefined;
|
||||||
|
|
@ -45,15 +58,17 @@ export const loadCrate: CrateLoader = (
|
||||||
// We really, really want a good algorithm for finding crates.
|
// We really, really want a good algorithm for finding crates.
|
||||||
// But right now we just look for files in the CWD.
|
// But right now we just look for files in the CWD.
|
||||||
|
|
||||||
const existing = gcx.finalizedCrates.find((crate) => crate.packageName === name);
|
const existing = gcx.finalizedCrates.find(
|
||||||
|
(crate) => crate.packageName === name
|
||||||
|
);
|
||||||
if (existing) {
|
if (existing) {
|
||||||
return existing;
|
return existing;
|
||||||
}
|
}
|
||||||
|
|
||||||
const file = loadModuleFile(".", name, span);
|
|
||||||
|
|
||||||
return withErrorPrinter(
|
return withErrorPrinter(
|
||||||
(): DepCrate => {
|
(): DepCrate => {
|
||||||
|
const file = loadModuleFile(".", name, span);
|
||||||
|
|
||||||
const crateId = gcx.crateId.next();
|
const crateId = gcx.crateId.next();
|
||||||
|
|
||||||
const tokens = tokenize(file);
|
const tokens = tokenize(file);
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,14 @@ import {
|
||||||
StructLiteralField,
|
StructLiteralField,
|
||||||
} from "./ast";
|
} from "./ast";
|
||||||
import { CompilerError, LoadedFile, Span } from "./error";
|
import { CompilerError, LoadedFile, Span } from "./error";
|
||||||
import { BaseToken, Token, TokenIdent, TokenLitString } from "./lexer";
|
import {
|
||||||
|
BaseToken,
|
||||||
|
Token,
|
||||||
|
TokenIdent,
|
||||||
|
TokenLitString,
|
||||||
|
tokenize,
|
||||||
|
} from "./lexer";
|
||||||
|
import { loadModuleFile } from "./loader";
|
||||||
import { ComplexMap, ComplexSet, Ids } from "./utils";
|
import { ComplexMap, ComplexSet, Ids } from "./utils";
|
||||||
|
|
||||||
export type ParseState = { tokens: Token[]; file: LoadedFile };
|
export type ParseState = { tokens: Token[]; file: LoadedFile };
|
||||||
|
|
@ -46,6 +53,16 @@ export function parse(
|
||||||
t: State,
|
t: State,
|
||||||
crateId: number
|
crateId: number
|
||||||
): Crate<Built> {
|
): Crate<Built> {
|
||||||
|
const [, items] = parseItems(t);
|
||||||
|
|
||||||
|
const ast: Crate<Built> = buildCrate(packageName, items, crateId, t.file);
|
||||||
|
|
||||||
|
validateAst(ast);
|
||||||
|
|
||||||
|
return ast;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseItems(t: State): [State, Item<Parsed>[]] {
|
||||||
const items: Item<Parsed>[] = [];
|
const items: Item<Parsed>[] = [];
|
||||||
|
|
||||||
while (t.tokens.length > 0) {
|
while (t.tokens.length > 0) {
|
||||||
|
|
@ -54,11 +71,7 @@ export function parse(
|
||||||
items.push(item);
|
items.push(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ast: Crate<Built> = buildCrate(packageName, items, crateId, t.file);
|
return [t, items];
|
||||||
|
|
||||||
validateAst(ast);
|
|
||||||
|
|
||||||
return ast;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseItem(t: State): [State, Item<Parsed>] {
|
function parseItem(t: State): [State, Item<Parsed>] {
|
||||||
|
|
@ -165,10 +178,11 @@ function parseItem(t: State): [State, Item<Parsed>] {
|
||||||
let name;
|
let name;
|
||||||
[t, name] = expectNext<TokenIdent>(t, "identifier");
|
[t, name] = expectNext<TokenIdent>(t, "identifier");
|
||||||
|
|
||||||
[t] = expectNext(t, "(");
|
let contents: Item<Parsed>[] = [];
|
||||||
|
|
||||||
const contents: Item<Parsed>[] = [];
|
|
||||||
|
|
||||||
|
let popen = undefined;
|
||||||
|
[t, popen] = eat(t, "(");
|
||||||
|
if (popen) {
|
||||||
while (peekKind(t) !== ")") {
|
while (peekKind(t) !== ")") {
|
||||||
let item;
|
let item;
|
||||||
[t, item] = parseItem(t);
|
[t, item] = parseItem(t);
|
||||||
|
|
@ -177,6 +191,19 @@ function parseItem(t: State): [State, Item<Parsed>] {
|
||||||
}
|
}
|
||||||
|
|
||||||
[t] = expectNext(t, ")");
|
[t] = expectNext(t, ")");
|
||||||
|
} else {
|
||||||
|
if (name.span.file.path === undefined) {
|
||||||
|
throw new CompilerError(
|
||||||
|
`no known source file for statement, cannot load file relative to it`,
|
||||||
|
name.span
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const file = loadModuleFile(name.span.file.path, name.ident, name.span);
|
||||||
|
|
||||||
|
const tokens = tokenize(file);
|
||||||
|
[, contents] = parseItems({ file, tokens });
|
||||||
|
}
|
||||||
|
|
||||||
[t] = expectNext(t, ";");
|
[t] = expectNext(t, ";");
|
||||||
|
|
||||||
const node: ModItem<Parsed> = {
|
const node: ModItem<Parsed> = {
|
||||||
|
|
|
||||||
38
std/rt.nil
Normal file
38
std/rt.nil
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
// Start the heap at 1024. In practice this could probably be as low as we want.
|
||||||
|
// TODO: The compiler should set this global to whatever it has calculated the heap
|
||||||
|
// start to be. But well, 1024 ought to be enough for now. lol.
|
||||||
|
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 > 4294967295_I32 then (
|
||||||
|
std.abort("failed to grow memory");
|
||||||
|
);
|
||||||
|
);
|
||||||
|
|
||||||
|
actualObjPtr
|
||||||
|
);
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
mod rt;
|
||||||
|
|
||||||
function printlnI32(x: I32) = (
|
function printlnI32(x: I32) = (
|
||||||
printI32(x);
|
printI32(x);
|
||||||
print("\n");
|
print("\n");
|
||||||
|
|
@ -65,48 +67,6 @@ function println(s: String) = (
|
||||||
print("\n");
|
print("\n");
|
||||||
);
|
);
|
||||||
|
|
||||||
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 > 4294967295_I32 then (
|
|
||||||
std.abort("failed to grow memory");
|
|
||||||
);
|
|
||||||
);
|
|
||||||
|
|
||||||
actualObjPtr
|
|
||||||
);
|
|
||||||
);
|
|
||||||
|
|
||||||
function alignUp(x: I32, align: I32): I32 = (x + (align - 1_I32)) & !(align - 1_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 i32ToInt(x: I32): Int = __i32_extend_to_i64_u(x);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue