| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681 |
- let flags = globalThis.flags;
- if (flags == null) {
- flags = {};
- flags.alang_source = null;
- flags.alang_output = "./test.c";
- }
- // ██████╗ █████╗ ██████╗ ███████╗ ███████╗
- // ██╔══██╗ ██╔══██╗ ██╔══██╗ ██╔════╝ ██╔════╝
- // ██████╔╝ ███████║ ██████╔╝ ███████╗ █████╗
- // ██╔═══╝ ██╔══██║ ██╔══██╗ ╚════██║ ██╔══╝
- // ██║ ██║ ██║ ██║ ██║ ███████║ ███████╗
- // ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚══════╝
- let specials = [":", ";", ",", "(", ")", "[", "]", "{", "}", "<", ">", "!"];
- let is_comment = false;
- let is_string = false;
- let pos = 0;
- let tokens = [];
- let header = "";
- function is_alpha_numeric(code) {
- return (code > 47 && code < 58) || // 0-9
- (code === 45) || // -
- (code === 43) || // +
- (code === 95) || // _
- (code === 46) || // .
- (code > 64 && code < 91) || // A-Z
- (code > 96 && code < 123); // a-z
- }
- function is_alpha(code) {
- return (code > 96 && code < 123) || // a-z
- (code > 64 && code < 91) || // A-Z
- (code === 95); // _
- }
- function is_numeric(code) {
- return (code > 47 && code < 58); // 0-9
- }
- function is_white_space(code) {
- return code === 32 || // " "
- code === 9 || // "\t"
- code === 13 || // "\r"
- code === 10; // "\n"
- }
- function read_token() {
- // Skip white space
- while (is_white_space(flags.alang_source.charCodeAt(pos))) {
- pos++;
- }
- let token = "";
- let first = true;
- let is_anum = false;
- while (pos < flags.alang_source.length) {
- let c = flags.alang_source.charAt(pos);
- // Comment start
- if (token === "//") {
- is_comment = true;
- }
- if (is_comment) {
- token += c;
- pos++;
- // Comment end
- if (c === "\n") {
- is_comment = false;
- if (token.startsWith("///include") || token.startsWith("///define")) {
- header += "#" + token.substring(3, token.length);
- }
- // Remove comments
- return null;
- }
- // Prevent parsing of comments
- continue;
- }
- // String start / end
- if (c === "\"") {
- // Escaped \"
- let last = token.length > 0 ? token.charAt(token.length - 1) : "";
- let last_last = token.length > 1 ? token.charAt(token.length - 2) : "";
- let is_escaped = last === "\\" && last_last != "\\";
- if (!is_escaped) {
- is_string = !is_string;
- }
- // Token end - string end
- if (!is_string) {
- token += c;
- pos++;
- break;
- }
- }
- if (is_string) {
- if (c == "\r") {
- pos++;
- continue;
- }
- token += c;
- pos++;
- // Prevent parsing of strings
- continue;
- }
- // Token end
- if (is_white_space(flags.alang_source.charCodeAt(pos))) {
- break;
- }
- // Parsing an alphanumeric token
- if (first) {
- first = false;
- is_anum = is_alpha_numeric(c.charCodeAt(0));
- }
- // Token end
- let is_special = specials.indexOf(c) > -1;
- if (is_anum && is_special) {
- break;
- }
- // Add char to token and advance pos
- token += c;
- pos++;
- // Token end, got special
- if (is_special) {
- break;
- }
- }
- return token;
- }
- function alang_parse() {
- tokens = [];
- pos = 0;
- while (true) {
- let token = read_token();
- if (token === "") { // No more tokens
- break;
- }
- if (token === "=" && tokens[tokens.length - 1] === "!") { // Merge "!" and "=" into "!=" token
- tokens[tokens.length - 1] = "!=";
- continue;
- }
- if (token == null) { // Throw away this token
- continue;
- }
- tokens.push(token);
- }
- }
- // ██╗ ██╗ ██████╗
- // ██║ ██║ ██╔══██╗
- // ██║ ██║ ██████╔╝
- // ██║ ██║ ██╔══██╗
- // ███████╗ ██║ ██████╔╝
- // ╚══════╝ ╚═╝ ╚═════╝
- let fhandle;
- let strings = [];
- let tabs = 0;
- let new_line = false;
- let basic_types = ["i8", "u8", "i16", "u16", "i32", "u32", "f32", "i64", "u64", "f64", "bool"];
- let pass_by_value_types = ["vec4_t", "vec3_t", "vec2_t", "quat_t", "mat4_t", "mat3_t"];
- let enums = [];
- let value_types = new Map();
- let struct_types = new Map();
- let fn_declarations = new Map();
- let fn_default_params = new Map();
- let fn_call_stack = [];
- let param_pos_stack = [];
- let is_for_loop = false;
- let global_inits = [];
- let global_ptrs = [];
- function handle_tabs(token) {
- // Entering block, add tab
- if (token === "{") {
- tabs++;
- }
- else if (token === "}") {
- tabs--;
- }
- if (is_for_loop) {
- return;
- }
- // New line, add tabs
- if (new_line) {
- for (let i = 0; i < tabs; ++i) {
- out("\t");
- }
- }
- }
- function handle_new_line(token) {
- if (is_for_loop) {
- return;
- }
- // Insert new line
- new_line = token === ";" || token === "{" || token === "}";
- if (new_line) {
- out("\n");
- }
- }
- let add_space_keywords = ["return", "else"];
- function handle_spaces(token) {
- // Add space to separate keywords
- if (add_space_keywords.indexOf(token) > -1) {
- out(" ");
- }
- }
- function get_token(off = 0) {
- // if (pos + off < tokens.length) {
- return tokens[pos + off];
- // }
- // return "";
- }
- function get_token_after_piece() {
- let _pos = pos;
- skip_piece();
- let t = get_token(1);
- pos = _pos;
- return t;
- }
- function skip_until(s) {
- while (true) {
- let token = get_token();
- if (token === s) {
- break;
- }
- pos++;
- }
- }
- function skip_block() { // { ... }
- pos++; // {
- let nested = 1;
- while (true) {
- let token = get_token();
- if (token === "}") {
- nested--;
- if (nested === 0) {
- break;
- }
- }
- else if (token === "{") {
- nested++;
- }
- pos++;
- }
- }
- function function_return_type() {
- let _pos = pos;
- skip_until("{");
- let t = get_token(-1);
- if (t === "]") { // ): i32[]
- pos -= 2;
- }
- else if (t === ">") { // ): map_t<a, b>
- pos -= 5;
- }
- pos -= 2; // ): i32 {
- let result = get_token() === ":" ? read_type() : "void";
- pos = _pos;
- return result;
- }
- function join_type_name(type, name) {
- value_types.set(name, type);
- if (type.indexOf("(*NAME)(") > 0) { // Function pointer
- return type.replace("NAME", name);
- }
- return type + " " + name;
- }
- function read_type() { // Cursor at ":"
- pos++;
- let type = get_token();
- if (type === "(" && get_token(1) === "(") { // (()=>void)[]
- pos++;
- }
- if (get_token(1) === ")" && get_token(2) === "[") { // (()=>void)[]
- pos++;
- }
- if (type === "(") { // ()=>void
- let params = "(";
- if (get_token(1) != ")") { // Has params
- while (true) {
- skip_until(":");
- params += read_type();
- pos++;
- if (get_token() === ")") { // End of params
- break;
- }
- params += ",";
- }
- }
- else {
- params += "void";
- }
- params += ")";
- skip_until("=>");
- let ret = read_type();
- type = ret + "(*NAME)" + params;
- }
- if (type === "color_t") {
- type = "i32";
- }
- else if (type === "string") {
- type = "string_t";
- }
- if (get_token(1) === "[") { // Array
- if (is_struct(type)) {
- type = type + "_array_t";
- }
- else if (type === "bool") {
- type = "u8_array_t";
- }
- else {
- type = type + "_array_t";
- }
- pos += 2; // Skip "[]"
- }
- if (is_struct(type) && pass_by_value_types.indexOf(type) === -1) {
- type += " *";
- }
- if (type === "map_t *" && get_token(1) === "<") { // Map
- let mv = get_token(4);
- if (mv === "f32") {
- type = "f32_" + type;
- }
- else if (basic_types.indexOf(mv) > -1) {
- let mk = get_token(2);
- if (mk === "i32") {
- type = "i32_i" + type;
- }
- else {
- type = "i32_" + type;
- }
- }
- else {
- let mk = get_token(2);
- if (mk === "i32") {
- type = "any_i" + type;
- }
- else {
- type = "any_" + type;
- }
- }
- skip_until(">"); // Skip <a, b>
- }
- return type;
- }
- function enum_access(s) {
- // Turn enum_t.VALUE into enum_t_VALUE
- if (s.indexOf("_t.") > -1) {
- for (let e of enums) {
- if (s.indexOf(e) > -1) {
- s = s.replaceAll(".", "_");
- break;
- }
- }
- }
- return s;
- }
- function struct_access(s) {
- // Turn a.b into a->b
- let dot = s.indexOf(".");
- if (dot === -1) {
- return s;
- }
- if (is_numeric(s.charCodeAt(dot + 1))) {
- return s;
- }
- if (s.indexOf("\"") > -1) {
- return s;
- }
- if (s.startsWith("GC_ALLOC_INIT")) {
- return s;
- }
- // Accessing pass_by_value_types struct like vec4.x
- let has_minus = s.startsWith("-");
- let base = s.substring(has_minus ? 1 : 0, dot);
- let type = value_types.get(base);
- if (type != null) {
- let dot_last = s.lastIndexOf(".");
- if (dot != dot_last) { // a.vec4.x
- let parts = s.split(".");
- for (let i = 1; i < parts.length - 1; ++i) {
- let struct_value_types = struct_types.get(type);
- if (struct_value_types != null) {
- type = struct_value_types.get(parts[i]);
- // struct my_struct -> my_struct_t
- // my_struct * -> my_struct
- if (type.startsWith("struct ") && type.endsWith(" *")) {
- type = type.substring(0, type.length - 2);
- type = type.substring(7, type.length) + "_t *";
- }
- }
- }
- if (!type.endsWith(" *")) { // vec4_t
- let first = s.substring(0, dot_last).replaceAll(".", "->");
- let last = s.substring(dot_last, s.length);
- return first + last; // a->vec4.x
- }
- }
- else if (!type.endsWith(" *")) { // vec4.x
- return s;
- }
- }
- return s.replaceAll(".", "->");
- }
- function struct_alloc(token, type = null) {
- // "= { a: b, ... }" -> GC_ALLOC_INIT
- if ((get_token(-1) === "=" && token === "{" && get_token(-3) != "type") || type != null) {
- if (type == null) {
- // let a: b = {, a = {, a.b = {
- let i = get_token(-3) === ":" ? -4 : -2;
- let t = struct_access(get_token(i));
- type = value_type(t);
- if (type.endsWith(" *")) { // my_struct * -> my_struct
- type = type.substring(0, type.length - 2);
- }
- if (type.startsWith("struct ")) { // struct my_struct -> my_struct_t
- type = type.substring(7, type.length) + "_t";
- }
- }
- token = "GC_ALLOC_INIT(" + type + ", {";
- pos++; // {
- let ternary = 0;
- while (true) {
- let t = get_token();
- if (t == "}") {
- break;
- }
- let tc = get_token_c();
- tc = string_ops(tc);
- if (get_token(1) === ":" && !ternary) {
- tc = "." + tc; // a: b -> .a = b
- }
- if (t === ":") {
- if (ternary > 0) {
- ternary--;
- }
- else {
- tc = "=";
- }
- }
- else if (t === "?") {
- ternary++;
- }
- else if (t === "[" && get_token(-1) === ":") {
- let member = get_token(-2);
- let types = struct_types.get(type + " *");
- let content_type = types.get(member);
- content_type = content_type.substring(7, content_type.length - 8); // struct my_struct_array_t * -> my_struct
- tc = array_create("[", "", content_type);
- }
- token += tc;
- pos++;
- }
- // "= {}" -> "= {0}", otherwise msvc refuses to init members to zero
- if (get_token(-1) === "{") {
- token += "0";
- }
- token += get_token(); // "}"
- token += ")";
- tabs--;
- }
- return token;
- }
- function array_type(name) {
- let type = value_type(name);
- if (type == null) {
- return "any";
- }
- if (type.startsWith("struct ")) { // struct u8_array * -> u8_array_t *
- type = type.substring(7, type.length - 2) + "_t *";
- }
- type = strip(type, 10); // Strip _array_t *
- if (basic_types.indexOf(type) > -1) { // u8
- return type;
- }
- return "any";
- }
- function array_contents(type) {
- // [1, 2, ..] or [{a:b}, {a:b}, ..] or [a(), b(), ..]
- let contents = [];
- let content = "";
- while (true) {
- pos++;
- let token = get_token();
- if (token === "]") {
- if (content != "") {
- contents.push(content);
- }
- break;
- }
- if (token === ",") {
- contents.push(content);
- content = "";
- continue;
- }
- if (token === "{") {
- token = struct_alloc(token, type);
- tabs++; // Undo tabs-- in struct_alloc
- }
- if (get_token(1) === "(") {
- // Function call
- while (true) {
- pos++;
- token += get_token();
- token = fill_default_params(token);
- if (token.endsWith(")")) {
- break;
- }
- }
- }
- // a / b - > a / (float)b
- if (token === "/") {
- token = "/(float)";
- }
- token = struct_access(token);
- token = string_ops(token);
- content += token;
- }
- return contents;
- }
- function member_name(name) {
- let i = name.lastIndexOf(".");
- if (i > -1) {
- name = name.substring(i + 1, name.length);
- }
- return name;
- }
- function array_create(token, name, content_type = null) {
- if ((get_token(-1) === "=" && token === "[") || content_type != null) {
- if (name === "]") {
- name = get_token(-6); // ar: i32[] = [
- }
- let member = member_name(name);
- let type = array_type(member);
- // = [], = [1, 2, ..] -> any/i32/.._array_create_from_raw
- if (content_type == null) {
- name = struct_access(name);
- content_type = value_type(name);
- if (content_type != null) {
- content_type = content_type.substring(0, content_type.length - 10);
- }
- }
- let contents = array_contents(content_type);
- token = type + "_array_create_from_raw((" + type + "[]){";
- for (let e of contents) {
- token += e + ",";
- }
- token += "}," + contents.length + ")";
- }
- return token;
- }
- function array_access(token) {
- // array[0] -> array->buffer[0]
- if (token === "[" && get_token(-1) != "=") {
- return "->buffer[";
- }
- return token;
- }
- function is_struct(type) {
- // Ends with _t and is not an enum
- return type.endsWith("_t") && enums.indexOf(type) === -1;
- }
- function strip(name, len) {
- return name.substring(0, name.length - len);
- }
- function strip_optional(name) {
- if (name.endsWith("?")) {
- return strip(name, 1); // :val? -> :val
- }
- return name;
- }
- function param_pos() {
- return param_pos_stack[param_pos_stack.length - 1];
- }
- function param_pos_add() {
- param_pos_stack[param_pos_stack.length - 1]++;
- }
- function fn_call() {
- return fn_call_stack[fn_call_stack.length - 1];
- }
- function fill_fn_params(token) {
- if (token === "(") {
- // Function is being called to init this variable
- fn_call_stack.push(get_token(-1));
- param_pos_stack.push(0);
- }
- else if (token === ",") {
- // Param has beed passed manually
- param_pos_add();
- }
- else if (token === ")") {
- // Fill in default parameters if needed
- if (get_token(-1) != "(") {
- // Param has beed passed manually
- param_pos_add();
- }
- // If default param exists, fill it
- let res = "";
- while (fn_default_params.has(fn_call() + param_pos())) {
- if (param_pos() > 0) {
- res += ",";
- }
- res += fn_default_params.get(fn_call() + param_pos());
- param_pos_add();
- }
- fn_call_stack.pop();
- param_pos_stack.pop();
- token = res + token;
- }
- return token;
- }
- function get_token_c() {
- let t = get_token();
- t = enum_access(t);
- t = struct_access(t);
- t = array_access(t);
- return t;
- }
- function fill_default_params(piece) {
- // fn(a, 1, ..)
- if (get_token(1) === ")") {
- let fn_name = "";
- let params = 0;
- let i = 0;
- let nested = 1;
- while (true) {
- let ti = get_token(i);
- if (ti === ")") {
- nested++;
- }
- else if (ti === "(") {
- if (get_token(i - 1) === ":") { // : ()=>void
- return piece;
- }
- nested--;
- if (nested === 0) {
- fn_name = get_token(i - 1);
- if (get_token(i + 1) != ")") {
- params++;
- }
- break;
- }
- }
- else if (ti === ",") {
- params++;
- }
- i--;
- }
- while (fn_default_params.has(fn_name + params)) {
- if (params > 0) {
- piece += ",";
- }
- piece += fn_default_params.get(fn_name + params);
- params++;
- }
- }
- return piece;
- }
- function skip_piece(nested = 0) {
- let t1 = get_token(1);
- if (t1 === "(" || t1 === "[") {
- nested++;
- pos++;
- skip_piece(nested);
- return;
- }
- if (t1 === ")" || t1 === "]") {
- nested--;
- if (nested < 0) {
- return;
- }
- pos++;
- skip_piece(nested);
- return;
- }
- if (nested > 0) {
- pos++;
- skip_piece(nested);
- return;
- }
- if (t1.startsWith(".")) {
- pos++;
- skip_piece();
- return;
- }
- }
- function read_piece(nested = 0) {
- // call(a, b, c), a[b + c]
- let piece = get_token_c();
- piece = string_length(piece);
- piece = map_ops(piece);
- let t1 = get_token(1);
- if (t1 === "(" || t1 === "[") {
- nested++;
- pos++;
- return piece + read_piece(nested);
- }
- if (t1 === ")" || t1 === "]") {
- nested--;
- if (nested < 0) {
- return piece;
- }
- piece = fill_default_params(piece);
- pos++;
- return piece + read_piece(nested);
- }
- if (nested > 0) {
- pos++;
- return piece + read_piece(nested);
- }
- if (t1.startsWith(".")) {
- pos++;
- return piece + read_piece();
- }
- return piece;
- }
- function string_length(token) {
- // "str->length" -> "string_length(str)"
- if (!token.endsWith("->length")) {
- return token;
- }
- let base = strip(token, 8); // ->length
- let type = value_type(base);
- if (type === "string_t *" || type === "struct string *") {
- token = "string_length(" + base + ")";
- }
- return token;
- }
- function value_type(value) {
- let arrow = value.indexOf("->");
- if (arrow > -1) {
- let base = value.substring(0, arrow);
- let type = value_types.get(base);
- let member = value.substring(arrow + 2, value.length);
- let struct_value_types = struct_types.get(type);
- if (struct_value_types != null) {
- return struct_value_types.get(member);
- }
- }
- return value_types.get(value);
- }
- function set_fn_param_types() {
- pos++; // (
- while (true) {
- pos++;
- let t = get_token(); // Param name, ) or ,
- if (t === ")") { // Params end
- break;
- }
- if (t === ",") { // Next param
- continue;
- }
- pos++; // :
- let type = read_type();
- value_types.set(t, type);
- if (get_token(1) === "=") { // Skip default value
- pos += 2;
- }
- }
- }
- function number_to_string(token) {
- let type = value_type(token);
- if (type === "i32") {
- return "i32_to_string(" + token + ")";
- }
- if (type === "f32") {
- return "f32_to_string(" + token + ")";
- }
- return token;
- }
- function token_is_string(token) {
- let is_string = token.startsWith("\"") || value_type(token) === "string_t *";
- if (!is_string) {
- let _pos = pos;
- skip_piece();
- let t1 = get_token(1);
- if (t1 === "+" || t1 === "+=" || t1 === "==" || t1 === "!=") {
- let t2 = get_token(2);
- if (t2.startsWith("\"") || value_type(t2) === "string_t *") {
- is_string = true;
- }
- }
- pos = _pos;
- }
- if (is_string && get_token(2) === "null") {
- is_string = false;
- }
- return is_string;
- }
- function string_add(token) {
- token = "string_join(" + token + ",";
- pos++;
- let token_b = read_piece();
- token_b = number_to_string(token_b);
- token += token_b;
- token += ")";
- return token;
- }
- function string_ops(token) {
- // "str" + str + 1 + ...
- if (!token_is_string(token)) {
- return token;
- }
- let first = true;
- while (get_token_after_piece() === "+") {
- if (first) {
- first = false;
- token = read_piece();
- token = number_to_string(token);
- }
- pos++;
- token = string_add(token);
- }
- // "str" += str + str2
- let p1 = get_token_after_piece();
- if (p1 === "+=") {
- token = read_piece();
- pos++;
- token = token + "=string_join(" + token + ",";
- pos++;
- if (get_token_after_piece() === "+") {
- let token_b = read_piece();
- token_b = number_to_string(token_b);
- while (get_token_after_piece() === "+") {
- pos++;
- token_b = string_add(token_b);
- }
- token += token_b;
- }
- else {
- token += read_piece();
- }
- token += ")";
- }
- // str = str
- else if (p1 === "=") {
- let _pos = pos;
- let t1 = read_piece();
- pos++;
- pos++; // =
- let t2 = read_piece();
- if (get_token(1) === ";" && !t2.startsWith("\"")) { // str = str;
- token = t1 + "=string_copy(" + t2 + ")"; // Copy string
- }
- else {
- pos = _pos;
- }
- }
- // "str" === str
- else if (p1 === "==") {
- token = read_piece();
- pos++;
- token = "string_equals(" + token + ",";
- pos++;
- token += read_piece();
- token += ")";
- }
- // "str" != str
- else if (p1 === "!=") {
- token = read_piece();
- pos++;
- token = "!string_equals(" + token + ",";
- pos++;
- token += read_piece();
- token += ")";
- }
- return token;
- }
- function array_ops(token) {
- // array_push -> i32_array_push/any_array_push
- if (token === "array_push") {
- let value = get_token(2);
- if (get_token(3) === "[") { // raws[i].value
- value = get_token(6).substring(1); // .value
- }
- if (value.lastIndexOf(".") > -1) {
- value = value.substring(value.lastIndexOf(".") + 1, value.length);
- }
- let type = array_type(value);
- token = type + "_array_push";
- }
- // array_remove -> i32_array_remove / char_ptr_array_remove
- else if (token === "array_remove") {
- let value = get_token(2);
- value = struct_access(value);
- let type = value_type(value);
- if (type != null && type.startsWith("struct ")) { // struct u8_array * -> u8_array_t *
- type = type.substring(7, type.length - 2) + "_t *";
- }
- if (type === "i32_array_t *") {
- token = "i32_array_remove";
- }
- else if (type === "string_t_array_t *") {
- token = "char_ptr_array_remove";
- }
- }
- // array_index_of -> i32_array_index_of / char_ptr_array_index_of
- else if (token === "array_index_of") {
- let value = get_token(2);
- value = struct_access(value);
- let type = value_type(value);
- if (type != null && type.startsWith("struct ")) { // struct u8_array * -> u8_array_t *
- type = type.substring(7, type.length - 2) + "_t *";
- }
- if (type === "i32_array_t *") {
- token = "i32_array_index_of";
- }
- else if (type === "string_t_array_t *") {
- token = "char_ptr_array_index_of";
- }
- else {
- let fn = fn_declarations.get(value);
- if (fn != null && fn.startsWith("string_t_array_t *")) {
- token = "char_ptr_array_index_of";
- }
- }
- }
- return token;
- }
- function map_ops(token) {
- if (token === "map_create") {
- let t = value_type(get_token(-2));
- if (t === "i32_map_t *") {
- token = "i32_map_create";
- }
- else if (t === "i32_imap_t *") {
- token = "i32_imap_create";
- }
- else if (t === "any_imap_t *") {
- token = "any_imap_create";
- }
- else {
- token = "any_map_create";
- }
- }
- else if (token === "map_set") {
- let t = value_type(get_token(2));
- if (t === "i32_map_t *") {
- token = "i32_map_set";
- }
- else if (t === "i32_imap_t *") {
- token = "i32_imap_set";
- }
- else if (t === "any_imap_t *") {
- token = "any_imap_set";
- }
- else {
- token = "any_map_set";
- }
- }
- else if (token === "map_get") {
- let t = value_type(get_token(2));
- if (t === "i32_map_t *") {
- token = "i32_map_get";
- }
- else if (t === "i32_imap_t *") {
- token = "i32_imap_get";
- }
- else if (t === "any_imap_t *") {
- token = "any_imap_get";
- }
- else {
- token = "any_map_get";
- }
- }
- else if (token === "map_delete") {
- let t = value_type(get_token(2));
- if (t === "any_imap_t *") {
- token = "imap_delete";
- }
- }
- return token;
- }
- function _t_to_struct(type) {
- // type_t * -> struct type *
- if (type.endsWith("_t *") && type != "string_t *") {
- let type_short = strip(type, 4); // _t *
- if (type_short.endsWith("_array")) { // tex_format_t_array -> i32_array
- for (let e of enums) {
- if (type_short.startsWith(e)) {
- type_short = "i32_array";
- break;
- }
- }
- }
- type = "struct " + type_short + " *";
- }
- return type;
- }
- // ██╗ ██╗ ██████╗ ██╗ ████████╗ ███████╗ ██████╗
- // ██║ ██║ ██╔══██╗ ██║ ╚══██╔══╝ ██╔════╝ ██╔════╝
- // ██║ █╗ ██║ ██████╔╝ ██║ ██║ █████╗ ██║
- // ██║███╗██║ ██╔══██╗ ██║ ██║ ██╔══╝ ██║
- // ╚███╔███╔╝ ██║ ██║ ██║ ██║ ███████╗ ╚██████╗
- // ╚══╝╚══╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚═════╝
- function stream_write(token) {
- fhandle.puts(token);
- }
- function string_write(token) {
- strings[strings.length - 1] += token;
- }
- function null_write(token) {
- return;
- }
- let out = stream_write;
- function write_enums() {
- enums = [];
- for (pos = 0; pos < tokens.length; ++pos) {
- let token = get_token();
- // Turn "enum name {}" into "typedef enum {} name;"
- if (token === "enum") {
- out = get_token(-1) === "declare" ? null_write : stream_write;
- pos++;
- let enum_name = get_token();
- enums.push(enum_name);
- out("typedef enum{\n");
- pos++; // {
- while (true) {
- // Enum contents
- pos++;
- token = get_token(); // Item name
- if (token === "}") { // Enum end
- out("}" + enum_name + ";\n");
- break;
- }
- out("\t" + enum_name + "_" + token);
- pos++; // = or ,
- token = get_token();
- if (token === "=") { // Enum value
- pos++; // n
- token = get_token();
- out("=" + token);
- pos++; // ,
- }
- out(",\n");
- }
- out("\n");
- continue;
- }
- }
- out = stream_write;
- }
- function write_types() {
- for (pos = 0; pos < tokens.length; ++pos) {
- let token = get_token();
- // Turn "type x = {};" into "typedef struct {} x;"
- // Turn "type x = y;" into "typedef x y;"
- if (token === "type") {
- out = get_token(-1) === "declare" ? null_write : stream_write;
- pos++;
- let struct_name = get_token();
- let stuct_name_short = strip(struct_name, 2); // _t
- pos++;
- token = get_token(); // =
- if (token != "=") {
- continue;
- }
- pos++;
- token = get_token();
- // "type x = y;"
- if (token != "{") {
- pos--;
- let type = read_type();
- type = _t_to_struct(type);
- out("typedef " + type + " " + struct_name + ";\n\n");
- skip_until(";");
- continue;
- }
- // "type x = {};"
- out("typedef struct " + stuct_name_short + "{\n");
- let struct_value_types = new Map();
- struct_types.set(struct_name + " *", struct_value_types);
- while (true) {
- // Struct contents
- pos++;
- let name = get_token();
- if (name === "}") { // Struct end
- out("}" + struct_name + ";\n");
- break;
- }
- // val?: i32 -> val: i32
- name = strip_optional(name);
- pos++;
- // :
- let type = read_type();
- // type_t * -> struct type *
- type = _t_to_struct(type);
- // my_struct_t*(*NAME)(my_struct_t *) -> struct my_struct*(*NAME)(struct my_struct*)
- if (type.indexOf("(*NAME)") > -1) {
- let args = type.substring(type.indexOf(")(") + 2, type.lastIndexOf(")"));
- args = args.split(",");
- type = type.substring(0, type.indexOf("(*NAME)"));
- type = _t_to_struct(type);
- type += "(*NAME)(";
- for (let i = 0; i < args.length; ++i) {
- let arg = args[i];
- arg = _t_to_struct(arg);
- if (i > 0) {
- type += ",";
- }
- type += arg;
- }
- type += ")";
- }
- skip_until(";");
- out("\t" + join_type_name(type, name) + ";\n");
- struct_value_types.set(name, type);
- }
- out("\n");
- continue;
- }
- }
- out = stream_write;
- }
- function write_array_types() {
- // Array structs (any_array_t -> scene_t_array_t)
- let array_structs = new Map();
- for (pos = 0; pos < tokens.length; ++pos) {
- let token = get_token();
- if (get_token(1) === "[") {
- let type = token;
- if (type === "string") {
- type = "string_t";
- }
- if (is_struct(type)) {
- if (!array_structs.has(type)) {
- let as = "typedef struct " + type + "_array{" +
- type + "**buffer;int length;int capacity;}" +
- type + "_array_t;";
- array_structs.set(type, as);
- }
- }
- pos += 2; // Skip "[]"
- }
- }
- for (let as of array_structs.values()) {
- out(as);
- out("\n");
- }
- out("\n");
- }
- function write_fn_declarations() {
- fn_declarations = new Map();
- fn_default_params = new Map();
- let last_fn_name = "";
- for (pos = 0; pos < tokens.length; ++pos) {
- let token = get_token();
- if (token === "function") {
- out = get_token(-1) === "declare" ? null_write : stream_write;
- // Return type + name
- pos++;
- let fn_name = get_token();
- let ret = function_return_type();
- if (fn_name === "(") { // Anonymous function
- fn_name = last_fn_name + "_" + (pos - 1);
- pos--;
- }
- else {
- if (fn_name === "main") {
- fn_name = "_main";
- }
- last_fn_name = fn_name;
- }
- // Params
- let _param_pos = 0;
- let params = "(";
- pos++; // (
- while (true) {
- pos++;
- token = get_token(); // Param name, ) or ,
- if (token === ")") { // Params end
- break;
- }
- if (token === ",") { // Next param
- params += ",";
- _param_pos++;
- continue;
- }
- pos++; // :
- let type = read_type();
- params += join_type_name(type, token);
- // Store param default
- if (get_token(1) === "=") {
- let param = get_token(2);
- param = enum_access(param);
- fn_default_params.set(fn_name + _param_pos, param);
- pos += 2;
- }
- }
- params += ")";
- let fn_decl = ret + " " + fn_name + params;
- out(fn_decl + ";\n");
- fn_declarations.set(fn_name, fn_decl);
- }
- }
- out("\n");
- out = stream_write;
- }
- function write_globals() {
- global_inits = [];
- global_ptrs = [];
- for (pos = 0; pos < tokens.length; ++pos) {
- let token = get_token();
- if (token === "let") {
- out = get_token(-1) === "declare" ? null_write : stream_write;
- pos++;
- let name = get_token();
- pos++; // :
- let type = read_type();
- if (basic_types.indexOf(type) === -1 &&
- pass_by_value_types.indexOf(type) === -1 &&
- enums.indexOf(type) === -1) {
- global_ptrs.push(name);
- }
- out(join_type_name(type, name) + ";");
- // Init this var in _kickstart()
- let is_initialized = get_token(1) === "=";
- if (is_initialized) {
- let init = name;
- tabs = 1;
- while (true) {
- pos++;
- token = get_token();
- token = enum_access(token);
- token = array_access(token);
- token = struct_alloc(token);
- if (token === ";") {
- break;
- }
- token = fill_fn_params(token);
- // [] -> _array_create
- token = array_create(token, name);
- if (token === "map_create") {
- let t = value_type(name);
- if (t === "i32_map_t *") {
- token = "i32_map_create";
- }
- else if (t === "i32_imap_t *") {
- token = "i32_imap_create";
- }
- else if (t === "any_imap_t *") {
- token = "any_imap_create";
- }
- else {
- token = "any_map_create";
- }
- }
- init += token;
- }
- global_inits.push(init);
- }
- out("\n");
- }
- // Skip function blocks
- if (token === "function" && get_token(-1) != "declare") {
- skip_until("{");
- skip_block();
- }
- }
- out = stream_write;
- }
- function write_kickstart() {
- // Start function
- out("\nvoid _kickstart() {\n");
- // Init globals
- for (let val of global_inits) {
- out("\t");
- let name = val.split("=")[0];
- let global_alloc = global_ptrs.indexOf(name) > -1 && !val.endsWith("=null") && !val.endsWith("\"");
- if (global_alloc) {
- out("gc_unroot(" + name + ");");
- }
- out(val + ";");
- if (global_alloc) {
- out("gc_root(" + name + ");");
- }
- out("\n");
- }
- out("\t_main();\n");
- out("\t#ifndef NO_IRON_START\n");
- out("\tiron_start();\n");
- out("\t#endif\n");
- out("}\n\n");
- }
- function write_function() {
- // Function declaration
- let fn_name = get_token();
- if (fn_name === "main") {
- fn_name = "_main";
- }
- let fn_decl = fn_declarations.get(fn_name);
- out(fn_decl + "{\n");
- // Function body
- // Re-set function param types into value_types map
- set_fn_param_types();
- skip_until("{");
- tabs = 1;
- new_line = true;
- let mark_as_root = null;
- let nested = [];
- while (true) {
- pos++;
- let token = get_token();
- if (token === "function") { // Begin nested function
- let anon_fn = fn_name + "_" + pos;
- out("&" + anon_fn);
- if (get_token(-1) === "=") {
- out(";\n");
- }
- skip_until("{");
- out = string_write;
- strings.push("");
- let fn_decl = fn_declarations.get(anon_fn);
- out(fn_decl + "{\n");
- let find = fn_decl.substring(0, fn_decl.indexOf("("));
- let fn_pos = parseInt(find.substring(find.lastIndexOf("_") + 1, find.length));
- let _pos = pos;
- pos = fn_pos;
- set_fn_param_types();
- pos = _pos;
- nested.push(1);
- continue;
- }
- if (nested.length > 0) {
- if (token === "{") {
- nested[nested.length - 1]++;
- }
- else if (token === "}") { // End nested function
- nested[nested.length - 1]--;
- if (nested[nested.length - 1] === 0) {
- nested.pop();
- out("}\n\n");
- if (strings.length > 1) {
- let s = strings.pop();
- strings[strings.length - 1] = s + strings[strings.length - 1];
- }
- if (nested.length === 0) {
- out = stream_write;
- }
- continue;
- }
- }
- }
- // Function end
- if (token === "}" && tabs === 1) {
- out("}\n\n");
- break;
- }
- handle_tabs(token);
- if (token === "for") { // Skip new lines in for (;;) loop
- is_for_loop = true;
- }
- else if (token === "{") {
- is_for_loop = false;
- }
- // Write type and name
- else if (token === "let") {
- pos++;
- let name = get_token();
- pos++; // :
- let type = read_type();
- out(join_type_name(type, name));
- // = or ;
- pos++;
- token = get_token();
- }
- // Turn val.a into val_a or val->a
- token = enum_access(token);
- token = struct_access(token);
- // array[0] -> array->buffer[0]
- token = array_access(token);
- // Use static alloc for global pointers
- let is_assign = get_token(1) === "=" || get_token(1) === "+="; // += for string_join
- if (is_assign && token != ":") {
- if (global_ptrs.indexOf(token) > -1) {
- out("gc_unroot(" + token + ");");
- if (get_token(2) != "null") {
- mark_as_root = token;
- }
- }
- }
- if (token === ";" && mark_as_root != null) {
- out(";gc_root(" + mark_as_root + ")");
- mark_as_root = null;
- }
- // "= { ... }" -> GC_ALLOC_INIT
- token = struct_alloc(token);
- // [] -> _array_create
- token = array_create(token, get_token(-2));
- token = array_ops(token);
- // Maps
- token = map_ops(token);
- // Strings
- token = string_ops(token);
- // "str->length" -> "string_length(str)"
- token = string_length(token);
- // a / b - > a / (float)b
- if (token === "/") {
- token = "/(float)";
- }
- // a(1) -> a(1, 2) // a(x: i32, y: i32 = 2)
- token = fill_fn_params(token);
- // Write token
- out(token);
- handle_spaces(token);
- handle_new_line(token);
- }
- }
- function write_functions() {
- for (pos = 0; pos < tokens.length; ++pos) {
- let token = get_token();
- if (token === "function") {
- pos++;
- if (get_token(-2) === "declare") {
- continue;
- }
- write_function();
- }
- // Write anonymous function body
- while (strings.length > 0) {
- let s = strings.pop();
- out(s);
- }
- }
- }
- function write_iron_c() {
- out("#include <iron.h>\n\n");
- out(header);
- write_enums();
- write_types();
- write_array_types();
- write_fn_declarations();
- write_globals();
- write_kickstart();
- write_functions();
- }
- // ██╗ ██╗ ██╗ ██████╗ ██╗ ██╗ ███████╗ ████████╗ █████╗ ██████╗ ████████╗
- // ██║ ██╔╝ ██║ ██╔════╝ ██║ ██╔╝ ██╔════╝ ╚══██╔══╝ ██╔══██╗ ██╔══██╗ ╚══██╔══╝
- // █████╔╝ ██║ ██║ █████╔╝ ███████╗ ██║ ███████║ ██████╔╝ ██║
- // ██╔═██╗ ██║ ██║ ██╔═██╗ ╚════██║ ██║ ██╔══██║ ██╔══██╗ ██║
- // ██║ ██╗ ██║ ╚██████╗ ██║ ██╗ ███████║ ██║ ██║ ██║ ██║ ██║ ██║
- // ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝
- function alang() {
- alang_parse();
- fhandle = std.open(flags.alang_output, "w");
- write_iron_c();
- fhandle.close();
- }
- let t = Date.now();
- alang();
- console.log("alang took " + (Date.now() - t) + "ms.");
|