Init new repository
This commit is contained in:
9
src/wasm_playground/01_hello_world.lc
Normal file
9
src/wasm_playground/01_hello_world.lc
Normal file
@@ -0,0 +1,9 @@
|
||||
// You can edit this code!
|
||||
// Click here and start typing.
|
||||
|
||||
import "libc";
|
||||
|
||||
main :: proc(): int {
|
||||
printf("hello world!\n");
|
||||
return 0;
|
||||
}
|
||||
72
src/wasm_playground/02_conways_game_of_life.lc
Normal file
72
src/wasm_playground/02_conways_game_of_life.lc
Normal file
@@ -0,0 +1,72 @@
|
||||
import c "libc";
|
||||
|
||||
generation_count :: 5;
|
||||
board_x :: 20;
|
||||
board_y :: 10;
|
||||
board_copy: [board_x * board_y]int;
|
||||
board: [board_x * board_y]int = {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
};
|
||||
|
||||
get_neighbor :: proc(xcol: int, yrow: int): int {
|
||||
x := xcol % board_x;
|
||||
y := yrow % board_y;
|
||||
result := board_copy[x + y * board_x];
|
||||
return result;
|
||||
}
|
||||
|
||||
get_neighbor_count :: proc(xcol: int, yrow: int): int {
|
||||
result := 0;
|
||||
for dc := -1; dc <= 1; dc += 1 {
|
||||
for dr := -1; dr <= 1; dr += 1 {
|
||||
if (dr || dc) result += get_neighbor(xcol + dc, yrow + dr);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
main :: proc(): int {
|
||||
for gen := 0; gen < generation_count; gen += 1 {
|
||||
c.printf("generation: %d\n", gen);
|
||||
|
||||
// show cells
|
||||
for y := 0; y < board_y; y += 1 {
|
||||
c.printf("|");
|
||||
for x := 0; x < board_x; x += 1 {
|
||||
cell := board[x + y * board_x];
|
||||
if cell {
|
||||
c.printf("*");
|
||||
} else {
|
||||
c.printf(".");
|
||||
}
|
||||
}
|
||||
c.printf("|\n");
|
||||
}
|
||||
|
||||
// update cells
|
||||
c.memcpy(&board_copy[0], &board[0], sizeof(board));
|
||||
for y := 0; y < board_y; y += 1 {
|
||||
for x := 0; x < board_x; x += 1 {
|
||||
src_cell := board_copy[x + y * board_x];
|
||||
dst_cell := addptr(board, x + y * board_x);
|
||||
|
||||
count := get_neighbor_count(x, y);
|
||||
birth := !src_cell && count == 3;
|
||||
survive := src_cell && (count == 3 || count == 2);
|
||||
dst_cell[0] = birth || survive;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.printf("End\n");
|
||||
return 0;
|
||||
}
|
||||
110
src/wasm_playground/index.html
Normal file
110
src/wasm_playground/index.html
Normal file
@@ -0,0 +1,110 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Playground</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<select id="example-select">
|
||||
<option value="0">hello world</option>
|
||||
<option value="1">conway's game of life</option>
|
||||
</select>
|
||||
<textarea autofocus id="code" name="code" autocorrect="off" autocomplete="off" spellcheck="false" wrap="off" autocapitalize="off"></textarea>
|
||||
<textarea disabled readonly id="output" name="output" autocorrect="off" autocomplete="off" spellcheck="false" wrap="off" autocapitalize="off"></textarea>
|
||||
</body>
|
||||
<style>
|
||||
* { margin: 5px; padding: 0; }
|
||||
body {
|
||||
height: 100%;
|
||||
margin: 60px auto;
|
||||
max-width: 750px;
|
||||
background: #000;
|
||||
}
|
||||
#code { width: 98%; height: 49vh; padding: 10px; }
|
||||
#output { width: 98%; height: 46vh; padding: 10px; }
|
||||
textarea { background: #000; color: #FFF; }
|
||||
</style>
|
||||
|
||||
</html>
|
||||
<script>
|
||||
Programs = [
|
||||
<InsertPrograms>
|
||||
]
|
||||
Program = Programs[0];
|
||||
|
||||
const ExampleSelect = document.getElementById("example-select");
|
||||
const Output = document.getElementById("output");
|
||||
const Code = document.getElementById("code");
|
||||
|
||||
ExampleSelect.addEventListener("change", (event) => {
|
||||
Program = Programs[ExampleSelect.value];
|
||||
Code.value = Program;
|
||||
Output.value = "";
|
||||
WASM_Exports.test();
|
||||
});
|
||||
|
||||
Code.addEventListener("input", (event) => {
|
||||
Program = event.target.value;
|
||||
Code.value = Program;
|
||||
Output.value = "";
|
||||
WASM_Exports.test();
|
||||
});
|
||||
|
||||
Code.addEventListener('keydown', function(e) {
|
||||
if (e.key == 'Tab') {
|
||||
e.preventDefault();
|
||||
var start = this.selectionStart;
|
||||
var end = this.selectionEnd;
|
||||
|
||||
// set textarea value to: text before caret + tab + text after caret
|
||||
this.value = this.value.substring(0, start) +
|
||||
" " + this.value.substring(end);
|
||||
|
||||
// put caret at right position again
|
||||
this.selectionStart = this.selectionEnd = start + 4;
|
||||
}
|
||||
});
|
||||
|
||||
Code.value = Program;
|
||||
|
||||
(async function main() {
|
||||
let request = await fetch('main.wasm')
|
||||
let binary = await request.arrayBuffer()
|
||||
|
||||
WASM_Memory = new WebAssembly['Memory']({ 'initial': 32 })
|
||||
WASM_MemoryU8 = new Uint8Array(WASM_Memory['buffer']) // is this memory iterator?
|
||||
|
||||
WASM_Imports = {
|
||||
memory: WASM_Memory,
|
||||
JS_LoadFile: () => {
|
||||
const buffer = new TextEncoder().encode(Program);
|
||||
const pointer = 30 * 1024 * 64;
|
||||
const slice = new Uint8Array(WASM_Memory.buffer, pointer, buffer.length + 1);
|
||||
slice.set(buffer);
|
||||
slice[buffer.length] = 0; // null byte to null-terminate the string
|
||||
return pointer;
|
||||
},
|
||||
JS_ConsoleLog: (str, len) => {
|
||||
let arr = WASM_MemoryU8.subarray( str, str+len );
|
||||
let out = utf8decoder.decode( arr );
|
||||
Output.value += out;
|
||||
},
|
||||
JS_ParseFloat: (str, len) => {
|
||||
let arr = WASM_MemoryU8.subarray( str, str+len );
|
||||
let out = utf8decoder.decode( arr );
|
||||
let result = parseFloat(out);
|
||||
return result;
|
||||
},
|
||||
}
|
||||
|
||||
let utf8decoder = new TextDecoder( "utf-8" );
|
||||
let program = await WebAssembly['instantiate'](binary, { "env": WASM_Imports})
|
||||
let instance = program['instance']
|
||||
WASM_Exports = instance['exports']
|
||||
WASM_Exports["test"]();
|
||||
})()
|
||||
</script>
|
||||
1
src/wasm_playground/run_server.bat
Normal file
1
src/wasm_playground/run_server.bat
Normal file
@@ -0,0 +1 @@
|
||||
python -m http.server
|
||||
132
src/wasm_playground/wasm_main.c
Normal file
132
src/wasm_playground/wasm_main.c
Normal file
@@ -0,0 +1,132 @@
|
||||
#define WASM_IMPORT(name) __attribute__((import_name(#name))) name
|
||||
#define WASM_EXPORT(name) __attribute__((export_name(#name))) name
|
||||
|
||||
double WASM_IMPORT(JS_ParseFloat)(char *str, int len);
|
||||
void WASM_IMPORT(JS_ConsoleLog)(char *str, int len);
|
||||
char *WASM_IMPORT(JS_LoadFile)(void);
|
||||
|
||||
#define LC_ParseFloat(str, len) JS_ParseFloat(str, len)
|
||||
#define LC_Print(str, len) JS_ConsoleLog(str, len)
|
||||
#define LC_Exit(x) (*(volatile int *)0 = 0)
|
||||
#define LC_THREAD_LOCAL
|
||||
#define LC_MemoryZero(p, size) __builtin_memset(p, 0, size);
|
||||
#define LC_MemoryCopy(dst, src, size) __builtin_memcpy(dst, src, size)
|
||||
|
||||
#include "../standalone_libraries/stb_sprintf.h"
|
||||
#include "../standalone_libraries/stb_sprintf.c"
|
||||
#define LC_vsnprintf stbsp_vsnprintf
|
||||
#include "../compiler/lib_compiler.c"
|
||||
|
||||
bool LC_IsDir(LC_Arena *temp, LC_String path) {
|
||||
if (LC_AreEqual(path, LC_Lit("virtual_dir"), false)) return true;
|
||||
if (LC_AreEqual(path, LC_Lit("virtual_dir/libc"), false)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
LC_FileIter LC_IterateFiles(LC_Arena *arena, LC_String path) {
|
||||
LC_FileIter result = {0};
|
||||
result.is_valid = true;
|
||||
result.is_directory = false;
|
||||
result.filename = LC_Lit("file.lc");
|
||||
|
||||
if (LC_StartsWith(path, LC_Lit("virtual_dir"), false)) {
|
||||
result.absolute_path = LC_Format(arena, "%.*s/file.lc", LC_Expand(path));
|
||||
result.relative_path = LC_Format(arena, "%.*s/file.lc", LC_Expand(path));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool LC_IsValid(LC_FileIter it) {
|
||||
return it.is_valid;
|
||||
}
|
||||
|
||||
void LC_Advance(LC_FileIter *it) {
|
||||
it->is_valid = false;
|
||||
}
|
||||
|
||||
LC_String LC_ReadFile(LC_Arena *arena, LC_String path) {
|
||||
LC_String result = LC_Lit("main :: proc(): int { return 0; }");
|
||||
return result;
|
||||
}
|
||||
|
||||
LC_FUNCTION void LC_VDeallocate(LC_VMemory *m) {}
|
||||
LC_FUNCTION bool LC_VCommit(LC_VMemory *m, size_t commit) { return false; }
|
||||
|
||||
char Memory[64 * 1024 * 24];
|
||||
LC_Arena MainArena;
|
||||
|
||||
LC_Lang *Wasm_LC_LangAlloc(LC_Arena *arena) {
|
||||
LC_Arena *lex_arena = LC_PushStruct(arena, LC_Arena);
|
||||
*lex_arena = LC_PushArena(arena, 64 * 1024 * 4);
|
||||
|
||||
LC_Arena *ast_arena = LC_PushStruct(arena, LC_Arena);
|
||||
*ast_arena = LC_PushArena(arena, 64 * 1024 * 4);
|
||||
|
||||
LC_Arena *decl_arena = LC_PushStruct(arena, LC_Arena);
|
||||
*decl_arena = LC_PushArena(arena, 64 * 1024 * 2);
|
||||
|
||||
LC_Arena *type_arena = LC_PushStruct(arena, LC_Arena);
|
||||
*type_arena = LC_PushArena(arena, 64 * 1024 * 2);
|
||||
|
||||
LC_Lang *l = LC_PushStruct(arena, LC_Lang);
|
||||
l->arena = arena;
|
||||
l->lex_arena = lex_arena;
|
||||
l->decl_arena = decl_arena;
|
||||
l->type_arena = type_arena;
|
||||
l->ast_arena = ast_arena;
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
void Wasm_OnFileLoad(LC_AST *package, LoadedFile *file) {
|
||||
if (LC_StartsWith(file->path, LC_Lit("virtual_dir/libc/file.lc"), false)) {
|
||||
file->content = LC_Lit(
|
||||
" size_t :: typedef ullong; @foreign"
|
||||
" printf :: proc(format: *char, ...): int; @foreign"
|
||||
" memset :: proc(s: *void, value: int, n: size_t): *void; @foreign"
|
||||
" memcpy :: proc(s1: *void, s2: *void, n: size_t): *void; @foreign");
|
||||
} else {
|
||||
file->content.str = JS_LoadFile();
|
||||
file->content.len = LC_StrLen(file->content.str);
|
||||
}
|
||||
}
|
||||
|
||||
void WASM_EXPORT(test)(void) {
|
||||
LC_MemoryZero(&MainArena, sizeof(MainArena));
|
||||
LC_InitArenaFromBuffer(&MainArena, Memory, sizeof(Memory));
|
||||
LC_Lang *lang = Wasm_LC_LangAlloc(&MainArena);
|
||||
{
|
||||
lang->on_file_load = Wasm_OnFileLoad;
|
||||
lang->os = 32;
|
||||
lang->arch = 32;
|
||||
}
|
||||
LC_LangBegin(lang);
|
||||
{
|
||||
LC_AddBuiltinConstInt("LC_WASM", 32);
|
||||
LC_AddBuiltinConstInt("ARCH_WASM", 32);
|
||||
L->tlong->size = 4;
|
||||
L->tlong->align = 4;
|
||||
L->tulong->size = 4;
|
||||
L->tulong->align = 4;
|
||||
LC_SetPointerSizeAndAlign(4, 4);
|
||||
}
|
||||
|
||||
LC_RegisterPackageDir("virtual_dir");
|
||||
|
||||
LC_Intern name = LC_ILit("file");
|
||||
LC_AddSingleFilePackage(name, LC_Lit("file.lc"));
|
||||
LC_ASTRefList packages = LC_ResolvePackageByName(name);
|
||||
|
||||
if (L->errors == 0) {
|
||||
LC_BeginStringGen(L->arena);
|
||||
for (LC_ASTRef *it = packages.first; it; it = it->next) LC_GenCHeader(it->ast);
|
||||
for (LC_ASTRef *it = packages.first; it; it = it->next) LC_GenCImpl(it->ast);
|
||||
LC_String result = LC_EndStringGen(L->arena);
|
||||
|
||||
LC_String code_output = LC_Lit("//\n// Code output\n//");
|
||||
JS_ConsoleLog(code_output.str, code_output.len);
|
||||
JS_ConsoleLog(result.str, (int)result.len);
|
||||
}
|
||||
|
||||
LC_LangEnd(lang);
|
||||
}
|
||||
Reference in New Issue
Block a user