mirror of
https://github.com/Noratrieb/riverdelta.git
synced 2026-01-14 16:35:03 +01:00
allocators and type aliases
This commit is contained in:
parent
60c743d656
commit
f05e5520f3
16 changed files with 283 additions and 121 deletions
|
|
@ -51,6 +51,7 @@ module.exports = {
|
||||||
// This lint is horrible with noisy false positives every time there are typescript errors.
|
// This lint is horrible with noisy false positives every time there are typescript errors.
|
||||||
"@typescript-eslint/no-unsafe-return": "off",
|
"@typescript-eslint/no-unsafe-return": "off",
|
||||||
"@typescript-eslint/no-unsafe-assignment": "off",
|
"@typescript-eslint/no-unsafe-assignment": "off",
|
||||||
|
"eslint@typescript-eslint/no-unsafe-argument": "off",
|
||||||
|
|
||||||
// Useful extra lints that are not on by default:
|
// Useful extra lints that are not on by default:
|
||||||
"@typescript-eslint/explicit-module-boundary-types": "warn",
|
"@typescript-eslint/explicit-module-boundary-types": "warn",
|
||||||
|
|
|
||||||
36
src/ast.ts
36
src/ast.ts
|
|
@ -144,10 +144,20 @@ export type FunctionArg<P extends Phase> = {
|
||||||
|
|
||||||
export type TypeDef<P extends Phase> = {
|
export type TypeDef<P extends Phase> = {
|
||||||
name: string;
|
name: string;
|
||||||
fields: FieldDef<P>[];
|
type: TypeDefKind<P>;
|
||||||
ty?: TyStruct;
|
ty?: TyStruct;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TypeDefKind<P extends Phase> =
|
||||||
|
| {
|
||||||
|
kind: "struct";
|
||||||
|
fields: FieldDef<P>[];
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
kind: "alias";
|
||||||
|
type: Type<P>;
|
||||||
|
};
|
||||||
|
|
||||||
export type FieldDef<P extends Phase> = {
|
export type FieldDef<P extends Phase> = {
|
||||||
name: Ident;
|
name: Ident;
|
||||||
type: Type<P>;
|
type: Type<P>;
|
||||||
|
|
@ -624,15 +634,29 @@ export function superFoldItem<From extends Phase, To extends Phase>(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case "type": {
|
case "type": {
|
||||||
const fields = item.node.fields.map(({ name, type }) => ({
|
const typeKind = item.node.type;
|
||||||
name,
|
let type: TypeDefKind<To>;
|
||||||
type: folder.type(type),
|
switch (typeKind.kind) {
|
||||||
}));
|
case "struct": {
|
||||||
|
const fields = typeKind.fields.map(({ name, type }) => ({
|
||||||
|
name,
|
||||||
|
type: folder.type(type),
|
||||||
|
}));
|
||||||
|
type = { kind: "struct", fields };
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "alias": {
|
||||||
|
type = {
|
||||||
|
kind: "alias",
|
||||||
|
type: folder.type(typeKind.type),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
kind: "type",
|
kind: "type",
|
||||||
node: { name: item.node.name, fields },
|
node: { name: item.node.name, type },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case "import": {
|
case "import": {
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,8 @@ const WASM_PAGE = 65536;
|
||||||
|
|
||||||
const DUMMY_IDX = 9999999;
|
const DUMMY_IDX = 9999999;
|
||||||
|
|
||||||
const ALLOCATE_ITEM: string[] = ["std", "rt", "allocateItem"];
|
const ALLOCATE_ITEM: string[] = ["std", "rt", "alloc", "allocateItem"];
|
||||||
const DEALLOCATE_ITEM: string[] = ["std", "rt", "deallocateItem"];
|
const DEALLOCATE_ITEM: string[] = ["std", "rt", "alloc", "deallocateItem"];
|
||||||
|
|
||||||
type RelocationKind =
|
type RelocationKind =
|
||||||
| {
|
| {
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,11 @@ export function parseArgs(hardcodedInput: string): Options {
|
||||||
}
|
}
|
||||||
|
|
||||||
input = fs.readFileSync(filename, { encoding: "utf-8" });
|
input = fs.readFileSync(filename, { encoding: "utf-8" });
|
||||||
packageName = path.basename(filename, ".nil");
|
if (filename.endsWith(".mod.nil")) {
|
||||||
|
packageName = path.basename(filename, ".mod.nil");
|
||||||
|
} else {
|
||||||
|
packageName = path.basename(filename, ".nil");
|
||||||
|
}
|
||||||
|
|
||||||
const debugArg = process.argv.find((arg) => arg.startsWith("--debug="));
|
const debugArg = process.argv.find((arg) => arg.startsWith("--debug="));
|
||||||
if (debugArg !== undefined) {
|
if (debugArg !== undefined) {
|
||||||
|
|
|
||||||
13
src/index.ts
13
src/index.ts
|
|
@ -13,9 +13,14 @@ import { GlobalContext, parseArgs } from "./context";
|
||||||
import { loadCrate } from "./loader";
|
import { loadCrate } from "./loader";
|
||||||
|
|
||||||
const INPUT = `
|
const INPUT = `
|
||||||
type A = { a: Int };
|
type A = struct { a: Int };
|
||||||
|
|
||||||
|
type What = What;
|
||||||
|
|
||||||
|
type Uwu = (Int, Int);
|
||||||
|
|
||||||
function main() = (
|
function main() = (
|
||||||
|
let a: What = 0;
|
||||||
uwu();
|
uwu();
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -28,7 +33,7 @@ function uwu() = (
|
||||||
/*-1*/
|
/*-1*/
|
||||||
);
|
);
|
||||||
|
|
||||||
type B = {
|
type B = struct {
|
||||||
a: (Int, Int, Int, Int, Int),
|
a: (Int, Int, Int, Int, Int),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -59,7 +64,9 @@ function main() {
|
||||||
() => {
|
() => {
|
||||||
const start = Date.now();
|
const start = Date.now();
|
||||||
|
|
||||||
gcx.crateLoader(gcx, "std", Span.startOfFile(file));
|
if (packageName !== "std") {
|
||||||
|
gcx.crateLoader(gcx, "std", Span.startOfFile(file));
|
||||||
|
}
|
||||||
|
|
||||||
const tokens = tokenize(file);
|
const tokens = tokenize(file);
|
||||||
if (debug.has("tokens")) {
|
if (debug.has("tokens")) {
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ export type DatalessToken =
|
||||||
| "extern"
|
| "extern"
|
||||||
| "mod"
|
| "mod"
|
||||||
| "global"
|
| "global"
|
||||||
|
| "struct"
|
||||||
| "("
|
| "("
|
||||||
| ")"
|
| ")"
|
||||||
| "{"
|
| "{"
|
||||||
|
|
@ -323,6 +324,7 @@ const KEYOWRDS: DatalessToken[] = [
|
||||||
"extern",
|
"extern",
|
||||||
"mod",
|
"mod",
|
||||||
"global",
|
"global",
|
||||||
|
"struct",
|
||||||
];
|
];
|
||||||
|
|
||||||
const KEYWORD_SET = new Set<string>(KEYOWRDS);
|
const KEYWORD_SET = new Set<string>(KEYOWRDS);
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import {
|
||||||
ItemId,
|
ItemId,
|
||||||
GlobalItem,
|
GlobalItem,
|
||||||
StructLiteralField,
|
StructLiteralField,
|
||||||
|
TypeDefKind,
|
||||||
} from "./ast";
|
} from "./ast";
|
||||||
import { CompilerError, LoadedFile, Span } from "./error";
|
import { CompilerError, LoadedFile, Span } from "./error";
|
||||||
import {
|
import {
|
||||||
|
|
@ -107,32 +108,46 @@ 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, "=");
|
[t] = expectNext(t, "=");
|
||||||
[t] = expectNext(t, "{");
|
|
||||||
|
|
||||||
let fields;
|
let type: TypeDefKind<Parsed>;
|
||||||
[t, fields] = parseCommaSeparatedList<FieldDef<Parsed>>(t, "}", (t) => {
|
|
||||||
let name;
|
let struct;
|
||||||
[t, name] = expectNext<TokenIdent>(t, "identifier");
|
[t, struct] = eat(t, "struct");
|
||||||
[t] = expectNext(t, ":");
|
if (struct) {
|
||||||
let type;
|
[t] = expectNext(t, "{");
|
||||||
[t, type] = parseType(t);
|
|
||||||
return [
|
let fields;
|
||||||
t,
|
[t, fields] = parseCommaSeparatedList<FieldDef<Parsed>>(t, "}", (t) => {
|
||||||
{
|
let name;
|
||||||
name: {
|
[t, name] = expectNext<TokenIdent>(t, "identifier");
|
||||||
name: name.ident,
|
[t] = expectNext(t, ":");
|
||||||
span: name.span,
|
let type;
|
||||||
|
[t, type] = parseType(t);
|
||||||
|
return [
|
||||||
|
t,
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
name: name.ident,
|
||||||
|
span: name.span,
|
||||||
|
},
|
||||||
|
type,
|
||||||
},
|
},
|
||||||
type,
|
];
|
||||||
},
|
});
|
||||||
];
|
|
||||||
});
|
type = { kind: "struct", fields };
|
||||||
|
} else {
|
||||||
|
let aliased: Type<Parsed>;
|
||||||
|
[t, aliased] = parseType(t);
|
||||||
|
|
||||||
|
type = { kind: "alias", type: aliased };
|
||||||
|
}
|
||||||
|
|
||||||
[t] = expectNext(t, ";");
|
[t] = expectNext(t, ";");
|
||||||
|
|
||||||
const def: TypeDef<Parsed> = {
|
const def: TypeDef<Parsed> = {
|
||||||
name: name.ident,
|
name: name.ident,
|
||||||
fields,
|
type,
|
||||||
};
|
};
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
|
||||||
|
|
@ -63,14 +63,22 @@ function printFunction(func: FunctionDef<AnyPhase>): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
function printTypeDef(type: TypeDef<AnyPhase>): string {
|
function printTypeDef(type: TypeDef<AnyPhase>): string {
|
||||||
const fields = type.fields.map(
|
switch (type.type.kind) {
|
||||||
({ name, type }) => `${ind(1)}${name.name}: ${printType(type)},`,
|
case "struct": {
|
||||||
);
|
const { fields } = type.type;
|
||||||
|
|
||||||
const fieldPart =
|
const fieldStr = fields.map(
|
||||||
type.fields.length === 0 ? "{}" : `{\n${fields.join("\n")}\n}`;
|
({ name, type }) => `${ind(1)}${name.name}: ${printType(type)},`,
|
||||||
|
);
|
||||||
|
const fieldPart =
|
||||||
|
fields.length === 0 ? "{}" : `{\n${fieldStr.join("\n")}\n}`;
|
||||||
|
|
||||||
return `type ${type.name} = ${fieldPart};`;
|
return `type ${type.name} = ${fieldPart};`;
|
||||||
|
}
|
||||||
|
case "alias": {
|
||||||
|
return `type ${type.name} = ${printType(type.type.type)}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function printImportDef(def: ImportDef<AnyPhase>): string {
|
function printImportDef(def: ImportDef<AnyPhase>): string {
|
||||||
|
|
|
||||||
|
|
@ -175,23 +175,29 @@ export function typeck(
|
||||||
return ty;
|
return ty;
|
||||||
}
|
}
|
||||||
case "type": {
|
case "type": {
|
||||||
const ty: Ty = {
|
switch (item.node.type.kind) {
|
||||||
kind: "struct",
|
case "struct": {
|
||||||
name: item.node.name,
|
const ty: Ty = {
|
||||||
fields: [
|
kind: "struct",
|
||||||
/*dummy*/
|
name: item.node.name,
|
||||||
],
|
fields: [
|
||||||
};
|
/*dummy*/
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
itemTys.set(item.id, ty);
|
itemTys.set(item.id, ty);
|
||||||
|
|
||||||
const fields = item.node.fields.map<[string, Ty]>(({ name, type }) => [
|
const fields = item.node.type.fields.map<[string, Ty]>(
|
||||||
name.name,
|
({ name, type }) => [name.name, lowerAstTy(type)],
|
||||||
lowerAstTy(type),
|
);
|
||||||
]);
|
|
||||||
|
|
||||||
ty.fields = fields;
|
ty.fields = fields;
|
||||||
return ty;
|
return ty;
|
||||||
|
}
|
||||||
|
case "alias": {
|
||||||
|
return lowerAstTy(item.node.type.type);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case "mod": {
|
case "mod": {
|
||||||
throw new CompilerError(
|
throw new CompilerError(
|
||||||
|
|
@ -313,32 +319,51 @@ export function typeck(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case "type": {
|
case "type": {
|
||||||
const fieldNames = new Set();
|
switch (item.node.type.kind) {
|
||||||
item.node.fields.forEach(({ name }) => {
|
case "struct": {
|
||||||
if (fieldNames.has(name)) {
|
const fieldNames = new Set();
|
||||||
throw new CompilerError(
|
item.node.type.fields.forEach(({ name }) => {
|
||||||
`type ${item.node.name} has a duplicate field: ${name.name}`,
|
if (fieldNames.has(name)) {
|
||||||
name.span,
|
throw new CompilerError(
|
||||||
);
|
`type ${item.node.name} has a duplicate field: ${name.name}`,
|
||||||
}
|
name.span,
|
||||||
fieldNames.add(name);
|
);
|
||||||
});
|
}
|
||||||
|
fieldNames.add(name);
|
||||||
|
});
|
||||||
|
|
||||||
const ty = typeOfItem(item.id, item.span) as TyStruct;
|
const ty = typeOfItem(item.id, item.span) as TyStruct;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
node: {
|
node: {
|
||||||
name: item.node.name,
|
name: item.node.name,
|
||||||
fields: item.node.fields.map((field, i) => ({
|
type: {
|
||||||
name: field.name,
|
kind: "struct",
|
||||||
type: {
|
fields: item.node.type.fields.map((field, i) => ({
|
||||||
...field.type,
|
name: field.name,
|
||||||
ty: ty.fields[i][1],
|
type: {
|
||||||
|
...field.type,
|
||||||
|
ty: ty.fields[i][1],
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})),
|
};
|
||||||
},
|
}
|
||||||
};
|
case "alias": {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
node: {
|
||||||
|
name: item.node.name,
|
||||||
|
type: {
|
||||||
|
kind: "alias",
|
||||||
|
type: item.node.type.type,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case "mod": {
|
case "mod": {
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
44
std/rt.nil
44
std/rt.nil
|
|
@ -1,44 +0,0 @@
|
||||||
// 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");
|
|
||||||
);
|
|
||||||
);
|
|
||||||
|
|
||||||
HEAD_PTR = newHeadPtr;
|
|
||||||
|
|
||||||
actualObjPtr
|
|
||||||
);
|
|
||||||
|
|
||||||
function deallocateItem(ptr: I32, objSize: I32) = (
|
|
||||||
std.println("uwu deawwocate :3");
|
|
||||||
);
|
|
||||||
112
std/rt/alloc.nil
Normal file
112
std/rt/alloc.nil
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
// 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");
|
||||||
|
);
|
||||||
|
);
|
||||||
|
|
||||||
|
HEAD_PTR = newHeadPtr;
|
||||||
|
|
||||||
|
actualObjPtr
|
||||||
|
);
|
||||||
|
|
||||||
|
function deallocateItem(ptr: I32, objSize: I32) = (
|
||||||
|
std.println("uwu deawwocate :3");
|
||||||
|
);
|
||||||
|
|
||||||
|
// Port of https://github.com/CCareaga/heap_allocator
|
||||||
|
//
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Copyright (c) 2017 Chris Careaga
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
|
||||||
|
global HEAP_START: I32 = 2048_I32;
|
||||||
|
// heap size = start+end+bin_t*BIN_COUNT
|
||||||
|
// 4+ 4+ 4* 9 = 8+36=42 (round to 64)
|
||||||
|
global HEAP_REGION_START: I32 = 2112_I32;
|
||||||
|
|
||||||
|
// typedef struct node_t {
|
||||||
|
// uint hole;
|
||||||
|
// uint size;
|
||||||
|
// struct node_t* next;
|
||||||
|
// struct node_t* prev;
|
||||||
|
// } node_t;
|
||||||
|
|
||||||
|
// typedef struct {
|
||||||
|
// node_t *header;
|
||||||
|
// } footer_t;
|
||||||
|
|
||||||
|
// typedef struct {
|
||||||
|
// node_t* head;
|
||||||
|
// } bin_t;
|
||||||
|
|
||||||
|
global SIZEOF_NODE: I32 = 16_I32;
|
||||||
|
global SIZEOF_FOOTER: I32 = 4_I32;
|
||||||
|
|
||||||
|
function initHeap() = (
|
||||||
|
let heap_init_size = 65536_I32 - HEAP_REGION_START;
|
||||||
|
|
||||||
|
__i32_store(HEAP_REGION_START, 1_I32); // START.hole =
|
||||||
|
__i32_store(HEAP_REGION_START + 4_I32, heap_init_size - SIZEOF_NODE - SIZEOF_FOOTER); // START.size =
|
||||||
|
);
|
||||||
|
|
||||||
|
function createFoot(head_node: I32) = (
|
||||||
|
let foot = getFoot(head_node);
|
||||||
|
__i32_store(foot, head_node); // foot.header = head_node
|
||||||
|
);
|
||||||
|
|
||||||
|
function getFoot(node: I32): I32 = (
|
||||||
|
let node_size = __i32_load(node + 4_I32); // node.size
|
||||||
|
node + SIZEOF_NODE + node_size
|
||||||
|
);
|
||||||
|
|
||||||
|
function addNode(bin: I32, node: I32) = ;
|
||||||
|
|
||||||
|
function test() =;
|
||||||
1
std/rt/rt.mod.nil
Normal file
1
std/rt/rt.mod.nil
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
mod alloc;
|
||||||
|
|
@ -79,5 +79,5 @@ function abort(message: String) = (
|
||||||
);
|
);
|
||||||
|
|
||||||
function main() = (
|
function main() = (
|
||||||
std.rt.allocateItem(100000000_I32, 8_I32);
|
std.rt.alloc.test();
|
||||||
);
|
);
|
||||||
7
ui-tests/ui/type_alias.nil
Normal file
7
ui-tests/ui/type_alias.nil
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
//@check-pass
|
||||||
|
|
||||||
|
type A = (Int, Int);
|
||||||
|
|
||||||
|
function main() = (
|
||||||
|
let a: A = (0, 0);
|
||||||
|
);
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
//@check-pass
|
//@check-pass
|
||||||
|
|
||||||
type CustomType = {};
|
type CustomType = struct {};
|
||||||
|
|
||||||
function main() = ();
|
function main() = ();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
"patterns": [
|
"patterns": [
|
||||||
{
|
{
|
||||||
"name": "keyword.control.riverdelta",
|
"name": "keyword.control.riverdelta",
|
||||||
"match": "\\b(function|let|if|then|else|type|loop|break|import|extern|mod|global)\\b"
|
"match": "\\b(function|let|if|then|else|type|loop|break|import|extern|mod|global|struct)\\b"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue