Compare commits
2 Commits
1670b64aaf
...
b190367681
Author | SHA1 | Date | |
---|---|---|---|
b190367681 | |||
e601749866 |
9
doc/text/.gitignore
vendored
Normal file
9
doc/text/.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/*
|
||||||
|
!/img
|
||||||
|
!/src
|
||||||
|
!/.gitignore
|
||||||
|
!/build
|
||||||
|
!/document.md
|
||||||
|
!/README.md
|
||||||
|
!/requirements.md
|
||||||
|
!/template.html
|
1
doc/text/README.md
Normal file
1
doc/text/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
This is the main body of my thesis. **BE WARNED!** It is quite lengthy and written in Bulgarian.
|
45
doc/text/build
Executable file
45
doc/text/build
Executable file
@ -0,0 +1,45 @@
|
|||||||
|
#!/bin/luajit -lsrc.build
|
||||||
|
|
||||||
|
local config = require "config";
|
||||||
|
|
||||||
|
function profession(val)
|
||||||
|
if val == "sys" then
|
||||||
|
return {
|
||||||
|
profession = "481020 „Системен програмист“",
|
||||||
|
specialty = "4810201 „Системно програмиране“",
|
||||||
|
};
|
||||||
|
elseif val == "net" then
|
||||||
|
return combine {
|
||||||
|
profession = "523050 „Техник на компютърни системи“",
|
||||||
|
specialty = "5230502 „Компютърни мрежи“",
|
||||||
|
};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
emit {
|
||||||
|
target = "res.html",
|
||||||
|
template {
|
||||||
|
template = "template.html",
|
||||||
|
|
||||||
|
build {
|
||||||
|
"requirements.md",
|
||||||
|
content = "requirements",
|
||||||
|
},
|
||||||
|
build {
|
||||||
|
"document.md",
|
||||||
|
content = "content",
|
||||||
|
toc = "toc",
|
||||||
|
ctx = {
|
||||||
|
chapter_format = "Глава %s<br/>",
|
||||||
|
chapter_format_plain = "Глава %s: ",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
profession(config.profession),
|
||||||
|
|
||||||
|
year = os.date "%Y",
|
||||||
|
prev_year = os.date "%Y" - 1,
|
||||||
|
|
||||||
|
config,
|
||||||
|
},
|
||||||
|
}
|
1252
doc/text/document.md
Normal file
1252
doc/text/document.md
Normal file
File diff suppressed because it is too large
Load Diff
BIN
doc/text/img/debugging-example.png
Normal file
BIN
doc/text/img/debugging-example.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 96 KiB |
4
doc/text/img/dependencies.svg
Normal file
4
doc/text/img/dependencies.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 41 KiB |
BIN
doc/text/img/stack-arr.png
Normal file
BIN
doc/text/img/stack-arr.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
14
doc/text/requirements.md
Normal file
14
doc/text/requirements.md
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
title: Requirements
|
||||||
|
---
|
||||||
|
|
||||||
|
1. Тема: Среда за изпълнение на „EcmaScript 5“ код за виртуалната машина на „Java“
|
||||||
|
2. Изисквания
|
||||||
|
- Покритие на „ECMA-262 5.1 Edition“ стандарта
|
||||||
|
- Задоволително бързодействие
|
||||||
|
- Възможност за лесно вграждане в други софтуерни продукти
|
||||||
|
- Добри тестове, подробна документация и удобен и интуитивен публичен интерфейс за разработчици
|
||||||
|
3. Съдържание
|
||||||
|
1. Теоретична част
|
||||||
|
2. Практическа част
|
||||||
|
3. Приложение
|
728
doc/text/src/build.lua
Normal file
728
doc/text/src/build.lua
Normal file
@ -0,0 +1,728 @@
|
|||||||
|
---@diagnostic disable: undefined-field
|
||||||
|
require "src.utils";
|
||||||
|
local json = require "src.json";
|
||||||
|
|
||||||
|
local function reader(fd, ...)
|
||||||
|
if type(fd) == "string" then
|
||||||
|
fd = assert(io.open(fd, ... or "r"));
|
||||||
|
elseif type(fd) == "function" then
|
||||||
|
return fd;
|
||||||
|
else
|
||||||
|
assert(fd, ...);
|
||||||
|
end
|
||||||
|
|
||||||
|
return function ()
|
||||||
|
if fd == nil then error "File is closed" end
|
||||||
|
local res = fd:read(1024);
|
||||||
|
|
||||||
|
if res == nil then
|
||||||
|
fd:close();
|
||||||
|
fd = nil;
|
||||||
|
return nil;
|
||||||
|
else
|
||||||
|
return res;
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
|
||||||
|
local function read_to_str(fd, ...)
|
||||||
|
local res = {};
|
||||||
|
|
||||||
|
for val in reader(fd, ...) do
|
||||||
|
res[#res + 1] = val;
|
||||||
|
end
|
||||||
|
|
||||||
|
return table.concat(res);
|
||||||
|
end
|
||||||
|
|
||||||
|
local flag = {};
|
||||||
|
function flag.has(name, ...)
|
||||||
|
if name == ... then
|
||||||
|
return true;
|
||||||
|
elseif ... == nil then
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return flag.has(name, select(2, ...));
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function flag.add(name, ...)
|
||||||
|
if flag.has(name, ...) then
|
||||||
|
return ...;
|
||||||
|
else
|
||||||
|
return name, ...;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local converters = {};
|
||||||
|
|
||||||
|
local function sanitize(str)
|
||||||
|
return (str
|
||||||
|
:gsub("<", "<")
|
||||||
|
:gsub(">", ">")
|
||||||
|
);
|
||||||
|
end
|
||||||
|
|
||||||
|
local function get_indent(ctx, n)
|
||||||
|
return ("\t"):rep((ctx.indent or 0) + (n or 0));
|
||||||
|
end
|
||||||
|
local function indent(ctx)
|
||||||
|
ctx.indent = (ctx.indent or 0) + 1;
|
||||||
|
end
|
||||||
|
local function undent(ctx)
|
||||||
|
ctx.indent = (ctx.indent or 1) - 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
local function convert(data, ctx, ...)
|
||||||
|
local func = converters[data.t];
|
||||||
|
if func == nil then
|
||||||
|
error(table.concat { "Unknown node '", data.t, "': ", to_readable(data) });
|
||||||
|
else
|
||||||
|
return func(data.c, ctx, ...);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local function convert_all(arr, ctx, ...)
|
||||||
|
local res = array {};
|
||||||
|
local plain = array {};
|
||||||
|
local inline = true;
|
||||||
|
|
||||||
|
for i = 1, #arr do
|
||||||
|
local a, b, c = convert(arr[i], ctx, ...);
|
||||||
|
res:append(a);
|
||||||
|
plain:append(b);
|
||||||
|
|
||||||
|
if not c then
|
||||||
|
inline = false;
|
||||||
|
res:append("\n", get_indent(ctx));
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return res, plain, inline;
|
||||||
|
end
|
||||||
|
|
||||||
|
local function make_id(id, readable, ctx)
|
||||||
|
ctx.ids = ctx.ids or {};
|
||||||
|
local res;
|
||||||
|
|
||||||
|
if ctx.ids[id] ~= nil then
|
||||||
|
ctx.ids[id] = ctx.ids[id] + 1;
|
||||||
|
res = id .. "-" .. ctx.ids[id];
|
||||||
|
else
|
||||||
|
ctx.ids[id] = 0;
|
||||||
|
res = id;
|
||||||
|
end
|
||||||
|
|
||||||
|
if readable then
|
||||||
|
ctx.citables = ctx.citables or {};
|
||||||
|
ctx.citables[id] = readable;
|
||||||
|
end
|
||||||
|
|
||||||
|
return res;
|
||||||
|
end
|
||||||
|
local function last_id(id, ctx)
|
||||||
|
ctx.ids = ctx.ids or {};
|
||||||
|
if ctx.ids[id] ~= nil and ctx.ids[id] > 0 then
|
||||||
|
return id .. "-" .. ctx.ids[id];
|
||||||
|
else
|
||||||
|
return id;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function count_headers(array)
|
||||||
|
local res = 0;
|
||||||
|
|
||||||
|
for i = 1, #array do
|
||||||
|
if not array[i].ignored then
|
||||||
|
res = res + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return res;
|
||||||
|
end
|
||||||
|
|
||||||
|
local function read_attributes(data, readable, ctx, no_id)
|
||||||
|
local res = {};
|
||||||
|
|
||||||
|
if data[1] ~= "" then
|
||||||
|
res.id = data[1];
|
||||||
|
end
|
||||||
|
for i = 1, #data[2] do
|
||||||
|
res[data[2][i]] = true;
|
||||||
|
end
|
||||||
|
for i = 1, #data[3] do
|
||||||
|
local curr = data[3][i];
|
||||||
|
res[curr[1]] = curr[2];
|
||||||
|
end
|
||||||
|
|
||||||
|
if not no_id and res.id then
|
||||||
|
res.id = make_id(res.id, readable, ctx);
|
||||||
|
end
|
||||||
|
|
||||||
|
return res;
|
||||||
|
end
|
||||||
|
|
||||||
|
function converters.Table(data, ctx)
|
||||||
|
local options = data[3];
|
||||||
|
local header = data[4];
|
||||||
|
local body = data[5][1];
|
||||||
|
|
||||||
|
local text = array {};
|
||||||
|
|
||||||
|
local function convert_cell(cell, tag, options)
|
||||||
|
local align = options[1].t;
|
||||||
|
indent(ctx);
|
||||||
|
text:push("<", tag);
|
||||||
|
if align == "AlignRight" then
|
||||||
|
text:push [[ class="right"]];
|
||||||
|
elseif align == "AlignLeft" then
|
||||||
|
text:push [[ class="left"]];
|
||||||
|
elseif align == "AlignCenter" then
|
||||||
|
text:push [[ class="center"]];
|
||||||
|
end
|
||||||
|
text:push(">\n", get_indent(ctx));
|
||||||
|
text:append((convert_all(cell[5], ctx)));
|
||||||
|
undent(ctx);
|
||||||
|
text:push("\n", get_indent(ctx), "</" .. tag .. ">");
|
||||||
|
end
|
||||||
|
|
||||||
|
local function convert_row(row, tag)
|
||||||
|
text:push("<tr>");
|
||||||
|
|
||||||
|
for i = 1, #row[2] do
|
||||||
|
local cell = row[2][i];
|
||||||
|
|
||||||
|
indent(ctx);
|
||||||
|
text:push("\n", get_indent(ctx));
|
||||||
|
convert_cell(cell, tag, options[i]);
|
||||||
|
undent(ctx);
|
||||||
|
end
|
||||||
|
|
||||||
|
text:push("\n", get_indent(ctx), "</tr>");
|
||||||
|
end
|
||||||
|
|
||||||
|
text:push [[<table class="graphic-table">]];
|
||||||
|
|
||||||
|
indent(ctx);
|
||||||
|
indent(ctx);
|
||||||
|
|
||||||
|
text:push("\n", get_indent(ctx, -1), "<thead>");
|
||||||
|
text:push("\n", get_indent(ctx));
|
||||||
|
convert_row(header[2][1], "th");
|
||||||
|
text:push("\n", get_indent(ctx, -1), "</thead>");
|
||||||
|
text:push("\n", get_indent(ctx, -1), "<tbody>");
|
||||||
|
|
||||||
|
for i = 1, #body[4] do
|
||||||
|
text:push("\n", get_indent(ctx));
|
||||||
|
convert_row(body[4][i], "td");
|
||||||
|
end
|
||||||
|
|
||||||
|
text:push("\n", get_indent(ctx, -1), "</tbody>");
|
||||||
|
|
||||||
|
undent(ctx);
|
||||||
|
undent(ctx);
|
||||||
|
text:push("\n", get_indent(ctx), "</table>");
|
||||||
|
|
||||||
|
return text, array { "[table]" };
|
||||||
|
end
|
||||||
|
function converters.BulletList(data, ctx)
|
||||||
|
local text = array { "<ul class=\"bullet\">" };
|
||||||
|
local plain = array {};
|
||||||
|
|
||||||
|
indent(ctx);
|
||||||
|
for i = 1, #data do
|
||||||
|
local el_text, el_plain = convert_all(data[i], ctx);
|
||||||
|
|
||||||
|
text
|
||||||
|
:push("\n", get_indent(ctx), "<li>")
|
||||||
|
:append(el_text)
|
||||||
|
:push("</li>");
|
||||||
|
plain:push("* "):append(el_plain):push("\n");
|
||||||
|
end
|
||||||
|
undent(ctx);
|
||||||
|
|
||||||
|
text:push("\n", get_indent(ctx), "</ul>");
|
||||||
|
|
||||||
|
return text, plain;
|
||||||
|
end
|
||||||
|
function converters.OrderedList(data, ctx)
|
||||||
|
local text = array { "<ol>" };
|
||||||
|
local plain = array {};
|
||||||
|
|
||||||
|
indent(ctx);
|
||||||
|
for i = 1, #data[2] do
|
||||||
|
local el_text, el_plain = convert_all(data[2][i], ctx);
|
||||||
|
|
||||||
|
text
|
||||||
|
:push("\n", get_indent(ctx), "<li value=\"", i, "\">")
|
||||||
|
:append(el_text)
|
||||||
|
:push("</li>");
|
||||||
|
plain:push(i .. ") "):append(el_plain):push("\n");
|
||||||
|
end
|
||||||
|
undent(ctx);
|
||||||
|
|
||||||
|
text:push("\n", get_indent(ctx), "</ol>");
|
||||||
|
|
||||||
|
return text, plain;
|
||||||
|
end
|
||||||
|
|
||||||
|
function converters.Code(data, ctx)
|
||||||
|
local content = data[2];
|
||||||
|
|
||||||
|
return array { "<code>", sanitize(content), "</code>" }, array { content };
|
||||||
|
end
|
||||||
|
function converters.CodeBlock(data, ctx)
|
||||||
|
local attribs = read_attributes(data[1], nil, ctx);
|
||||||
|
local content = data[2];
|
||||||
|
|
||||||
|
local text = array { "<pre><code" };
|
||||||
|
|
||||||
|
local classes = array {};
|
||||||
|
|
||||||
|
for k, v in next, attribs do
|
||||||
|
if v == true then
|
||||||
|
classes:push("language-" .. k);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if #classes > 0 then
|
||||||
|
text:push(" class=\"", classes:join " ", "\"");
|
||||||
|
end
|
||||||
|
|
||||||
|
text:push(">", sanitize(content), "</code></pre>");
|
||||||
|
|
||||||
|
return text, array { content };
|
||||||
|
end
|
||||||
|
function converters.Image(data, ctx)
|
||||||
|
local alt, alt_plain = convert_all(data[2], ctx);
|
||||||
|
local url = data[3][1];
|
||||||
|
local title = data[3][2];
|
||||||
|
local attribs = read_attributes(data[1], title or alt_plain:join " ", ctx);
|
||||||
|
|
||||||
|
local classes = array {};
|
||||||
|
if attribs.small then classes:push("small") end
|
||||||
|
if attribs.big then classes:push("big") end
|
||||||
|
|
||||||
|
local text = array {}
|
||||||
|
:push("<img title=\"", title, "\" src=\"", url, "\" alt=\"")
|
||||||
|
:append(alt)
|
||||||
|
:push("\"");
|
||||||
|
|
||||||
|
if #classes > 0 then
|
||||||
|
text:push(" class=\"", classes:join " ", "\"");
|
||||||
|
end
|
||||||
|
|
||||||
|
text:push("/>");
|
||||||
|
|
||||||
|
return text, title and { title } or alt_plain or url or "[picture]";
|
||||||
|
end
|
||||||
|
function converters.Figure(data, ctx)
|
||||||
|
local chapter_i = #(ctx.headers or {});
|
||||||
|
ctx.figures_indices = ctx.figures_indices or {};
|
||||||
|
ctx.figures_indices[chapter_i] = (ctx.figures_indices[chapter_i] or 0) + 1;
|
||||||
|
local figure_i = ctx.figures_indices[chapter_i];
|
||||||
|
|
||||||
|
local prefix = ("%s.%s."):format(chapter_i, figure_i);
|
||||||
|
|
||||||
|
local attribs = read_attributes(data[1], prefix, ctx);
|
||||||
|
local id = attribs.id;
|
||||||
|
|
||||||
|
indent(ctx);
|
||||||
|
indent(ctx);
|
||||||
|
|
||||||
|
local name, name_plain = convert_all(data[2][1], ctx);
|
||||||
|
local content, plain = convert_all(data[3], ctx);
|
||||||
|
|
||||||
|
undent(ctx);
|
||||||
|
undent(ctx);
|
||||||
|
local text = array { "<figure" };
|
||||||
|
if id then text:push(" id=\"", id, "\"") end
|
||||||
|
text:push(">");
|
||||||
|
|
||||||
|
text
|
||||||
|
:push("\n", get_indent(ctx, 1), "<div class=\"fig-content\">", "\n", get_indent(ctx, 2))
|
||||||
|
:append(content)
|
||||||
|
:push("\n", get_indent(ctx, 1), "</div>", "\n", get_indent(ctx, 1), "<figcaption>", "\n", get_indent(ctx, 2))
|
||||||
|
:push(prefix, " ")
|
||||||
|
:append(name)
|
||||||
|
:push("\n", get_indent(ctx, 1), "</figcaption>")
|
||||||
|
:push("\n", get_indent(ctx), "</figure>");
|
||||||
|
plain
|
||||||
|
:push(" (", prefix, " ")
|
||||||
|
:append(name_plain)
|
||||||
|
:push(")");
|
||||||
|
|
||||||
|
ctx.citables = ctx.citables or {};
|
||||||
|
if id then ctx.citables[id] = prefix end
|
||||||
|
|
||||||
|
return text, plain;
|
||||||
|
end
|
||||||
|
function converters.Div(data, ctx)
|
||||||
|
local attribs = read_attributes(data[1], nil, ctx, true);
|
||||||
|
|
||||||
|
if attribs.figure then
|
||||||
|
local separator_i = data[2]:find_i(function (v) return v.t == "HorizontalRule" end);
|
||||||
|
|
||||||
|
local content_data, title_data;
|
||||||
|
|
||||||
|
if separator_i == nil then
|
||||||
|
content_data = array { data[2][1] };
|
||||||
|
title_data = data[2]:slice(2);
|
||||||
|
else
|
||||||
|
content_data = data[2]:slice(1, separator_i - 1);
|
||||||
|
title_data = data[2]:slice(separator_i + 1);
|
||||||
|
end
|
||||||
|
|
||||||
|
if #title_data == 1 and title_data[1].t == "Para" then
|
||||||
|
title_data = title_data[1].c
|
||||||
|
end
|
||||||
|
|
||||||
|
return converters.Figure(array {
|
||||||
|
data[1],
|
||||||
|
array { title_data },
|
||||||
|
content_data,
|
||||||
|
}, ctx);
|
||||||
|
else
|
||||||
|
error "Divs are not supported";
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function converters.Cite(data, ctx)
|
||||||
|
local citation = data[1][1];
|
||||||
|
local id = last_id(citation.citationId, ctx);
|
||||||
|
|
||||||
|
local function target()
|
||||||
|
local res = (ctx.citables or {})[id];
|
||||||
|
if res == nil then
|
||||||
|
io.stderr:write("WARNING! Citation '" .. id .. "' doesn't exist!\n");
|
||||||
|
res = id;
|
||||||
|
end
|
||||||
|
|
||||||
|
return res;
|
||||||
|
end
|
||||||
|
|
||||||
|
return array { "<a href=\"#", id, "\">", target, "</a>" }, array { target }, true;
|
||||||
|
end
|
||||||
|
function converters.Header(data, ctx)
|
||||||
|
local level = data[1];
|
||||||
|
local attribs = read_attributes(data[2], nil, ctx);
|
||||||
|
|
||||||
|
ctx.headers = ctx.headers or array {};
|
||||||
|
ctx.header_stack = ctx.header_stack or array {};
|
||||||
|
|
||||||
|
local parent = ctx.header_stack[level - 1];
|
||||||
|
if level > 1 and parent == nil then error "Heading hierarchy inconsistent" end
|
||||||
|
|
||||||
|
local text, plain = convert_all(data[3], ctx);
|
||||||
|
|
||||||
|
local header = {
|
||||||
|
id = attribs.id,
|
||||||
|
level = level,
|
||||||
|
children = array {},
|
||||||
|
ignored = attribs.nonum or false,
|
||||||
|
};
|
||||||
|
|
||||||
|
local text_prefix, plain_prefix = "", "";
|
||||||
|
|
||||||
|
if level == 1 then
|
||||||
|
ctx.headers:push(header);
|
||||||
|
else
|
||||||
|
parent.children:push(header);
|
||||||
|
end
|
||||||
|
|
||||||
|
if not header.ignored then
|
||||||
|
local prefix = array { count_headers(ctx.headers) };
|
||||||
|
local text_format, plain_format;
|
||||||
|
|
||||||
|
for i = 1, level - 1 do
|
||||||
|
--- @diagnostic disable-next-line: undefined-field
|
||||||
|
prefix:push(count_headers(ctx.header_stack[i].children));
|
||||||
|
end
|
||||||
|
|
||||||
|
header.prefix = prefix:join ".";
|
||||||
|
|
||||||
|
if level == 1 then
|
||||||
|
text_format = ctx.chapter_format or "Chapter %s<br>";
|
||||||
|
plain_format = ctx.chapter_format_plain or "Chapter %s: ";
|
||||||
|
else
|
||||||
|
text_format = "%s. ";
|
||||||
|
plain_format = "%s. ";
|
||||||
|
end
|
||||||
|
|
||||||
|
text_prefix = text_format:format(header.prefix);
|
||||||
|
plain_prefix = plain_format:format(header.prefix);
|
||||||
|
end
|
||||||
|
|
||||||
|
ctx.header_stack = ctx.header_stack:fill(nil, level + 1, #ctx.header_stack);
|
||||||
|
ctx.header_stack[level] = header;
|
||||||
|
|
||||||
|
header.text = text_prefix .. text:join "";
|
||||||
|
header.plain = plain_prefix .. plain:join "";
|
||||||
|
|
||||||
|
if attribs.id then
|
||||||
|
ctx.citables = ctx.citables or {};
|
||||||
|
ctx.citables[attribs.id] = header.plain;
|
||||||
|
end
|
||||||
|
|
||||||
|
return
|
||||||
|
arrays.concat({ ("<h%d id=%q>"):format(level, attribs.id), text_prefix }, text, { ("</h%d>"):format(level) }),
|
||||||
|
array { plain_prefix }:append(plain);
|
||||||
|
end
|
||||||
|
function converters.Link(data, ctx)
|
||||||
|
local content, content_plain = convert_all(data[2], ctx);
|
||||||
|
|
||||||
|
local url = data[3][1];
|
||||||
|
local attribs = read_attributes(data[1], nil, ctx);
|
||||||
|
local id = attribs.id or data[3][2];
|
||||||
|
|
||||||
|
if id == "" then id = nil end
|
||||||
|
|
||||||
|
|
||||||
|
if id then
|
||||||
|
ctx.link_i = (ctx.link_i or 0) + 1;
|
||||||
|
local i = ctx.link_i;
|
||||||
|
ctx.citables = ctx.citables or {};
|
||||||
|
ctx.citables[id] = "[" .. i .. "]";
|
||||||
|
end
|
||||||
|
|
||||||
|
local plain = array {};
|
||||||
|
plain:push("<a href=\"", url, "\"");
|
||||||
|
|
||||||
|
if id ~= nil then
|
||||||
|
plain:push(" id=\"", id, "\"");
|
||||||
|
end
|
||||||
|
|
||||||
|
plain:push(">");
|
||||||
|
plain:append(content);
|
||||||
|
plain:push("</a>");
|
||||||
|
|
||||||
|
|
||||||
|
return plain, content_plain:push(" (", url, ")"), true;
|
||||||
|
end
|
||||||
|
|
||||||
|
function converters.Para(data, ctx)
|
||||||
|
indent(ctx);
|
||||||
|
local text, plain = convert_all(data, ctx);
|
||||||
|
undent(ctx);
|
||||||
|
return
|
||||||
|
array {}
|
||||||
|
:push "<p>"
|
||||||
|
:append(text)
|
||||||
|
:append "</p>",
|
||||||
|
plain;
|
||||||
|
end
|
||||||
|
function converters.Emph(data, ctx)
|
||||||
|
local text, plain = convert_all(data, ctx);
|
||||||
|
return arrays.concat({ "<i>" }, text, { "</i>" }), plain, true;
|
||||||
|
end
|
||||||
|
function converters.Strong(data, ctx)
|
||||||
|
local text, plain = convert_all(data, ctx);
|
||||||
|
return arrays.concat({ "<strong>" }, text, { "</strong>" }), plain, true;
|
||||||
|
end
|
||||||
|
function converters.Str(data)
|
||||||
|
return array { sanitize(data) }, array { data }, true;
|
||||||
|
end
|
||||||
|
function converters.Plain(data, ctx)
|
||||||
|
return convert_all(data, ctx);
|
||||||
|
end
|
||||||
|
|
||||||
|
function converters.RawBlock(data)
|
||||||
|
return array {}, array {}, true;
|
||||||
|
end
|
||||||
|
function converters.MetaInlines(data, ctx)
|
||||||
|
return convert_all(data, ctx);
|
||||||
|
end
|
||||||
|
|
||||||
|
function converters.LineBreak()
|
||||||
|
return array { "<br>" }, array { " " }, true;
|
||||||
|
end
|
||||||
|
function converters.SoftBreak()
|
||||||
|
return array { "­" }, array { " " }, true;
|
||||||
|
end
|
||||||
|
function converters.HorizontalRule()
|
||||||
|
return array { "<br class=\"pg-break\"/>" }, array { " " };
|
||||||
|
end
|
||||||
|
function converters.Space()
|
||||||
|
return array { " " }, array { " " }, true;
|
||||||
|
end
|
||||||
|
|
||||||
|
local function parse_meta(meta)
|
||||||
|
local res = {};
|
||||||
|
|
||||||
|
for k, v in next, meta do
|
||||||
|
local text, plain = convert(v, {});
|
||||||
|
res[k] = text:concat "";
|
||||||
|
end
|
||||||
|
|
||||||
|
return res;
|
||||||
|
end
|
||||||
|
|
||||||
|
local function convert_headers(headers, ctx)
|
||||||
|
ctx = ctx or { indent = 0 };
|
||||||
|
indent(ctx);
|
||||||
|
local res = arrays.concat(
|
||||||
|
{ "<ul>" },
|
||||||
|
headers:flat_map(function (child)
|
||||||
|
return arrays.concat(
|
||||||
|
{
|
||||||
|
"\n", get_indent(ctx),
|
||||||
|
"<li><a href=\"#",
|
||||||
|
child.id,
|
||||||
|
"\"><span class=\"name\">",
|
||||||
|
child.plain,
|
||||||
|
"</span><span class=\"page\">Page</span></a>"
|
||||||
|
},
|
||||||
|
#child.children > 0 and convert_headers(child.children, ctx) or { "" },
|
||||||
|
{ "</li>" }
|
||||||
|
);
|
||||||
|
end),
|
||||||
|
{
|
||||||
|
"\n", get_indent(ctx, -1),
|
||||||
|
"</ul>"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
undent(ctx);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
end
|
||||||
|
|
||||||
|
local function parse(...)
|
||||||
|
local stream, err = io.popen("pandoc --highlight-style kate --from markdown-raw_html --to json -o - " .. array { ... }:join " ");
|
||||||
|
local str = read_to_str(stream, err);
|
||||||
|
local raw = json.parse(str);
|
||||||
|
|
||||||
|
return {
|
||||||
|
metadata = parse_meta(raw.meta),
|
||||||
|
content = raw.blocks or array {},
|
||||||
|
};
|
||||||
|
end
|
||||||
|
|
||||||
|
local function convert_page(data, ctx)
|
||||||
|
ctx = ctx or {};
|
||||||
|
ctx.headers = ctx.headers or array {};
|
||||||
|
|
||||||
|
local curr_page = array {};
|
||||||
|
local pages = array {};
|
||||||
|
|
||||||
|
for i = 1, #data.content do
|
||||||
|
local curr = data.content[i];
|
||||||
|
if curr.t == "Header" then
|
||||||
|
if curr.c[1] == 1 then
|
||||||
|
if #pages > 0 or #curr_page > 0 then
|
||||||
|
pages:append(curr_page);
|
||||||
|
end
|
||||||
|
curr_page = array {};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local text, _, inline = convert(curr, ctx);
|
||||||
|
curr_page:append(text);
|
||||||
|
if not inline then
|
||||||
|
curr_page:push("\n");
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
pages:append(curr_page);
|
||||||
|
|
||||||
|
local function mapper(v)
|
||||||
|
if type(v) == "function" then
|
||||||
|
return v();
|
||||||
|
else
|
||||||
|
return v;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
content = pages:map(mapper, true):join "",
|
||||||
|
toc = convert_headers(ctx.headers):map(mapper, true):join "",
|
||||||
|
};
|
||||||
|
end
|
||||||
|
|
||||||
|
local function subst(template, variables)
|
||||||
|
local replaces = array {};
|
||||||
|
|
||||||
|
for k, v in next, variables do
|
||||||
|
local i = 1;
|
||||||
|
local search = "{{" .. k .. "}}";
|
||||||
|
|
||||||
|
while true do
|
||||||
|
local b, e = string.find(template, search, i, true);
|
||||||
|
if b == nil then break end
|
||||||
|
|
||||||
|
replaces:push { b = b, e = e, v = v };
|
||||||
|
i = e + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
table.sort(replaces, function (a, b) return a.b < b.b end);
|
||||||
|
|
||||||
|
local parts = array {};
|
||||||
|
local prev = 1;
|
||||||
|
|
||||||
|
for i = 1, #replaces do
|
||||||
|
local curr = replaces[i];
|
||||||
|
parts:push(template:sub(prev, curr.b - 1), curr.v);
|
||||||
|
prev = curr.e + 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
parts:push(template:sub(prev));
|
||||||
|
|
||||||
|
return parts:join "";
|
||||||
|
end
|
||||||
|
|
||||||
|
function build(options)
|
||||||
|
local toc = options.toc;
|
||||||
|
local content = options.content;
|
||||||
|
local ctx = options.ctx or {};
|
||||||
|
|
||||||
|
print(table.concat { "Building ", array(options):join ", ", "..." });
|
||||||
|
|
||||||
|
local res = convert_page(parse(unpack(options)), ctx);
|
||||||
|
|
||||||
|
if toc == nil and content == nil then
|
||||||
|
return res.content;
|
||||||
|
end
|
||||||
|
|
||||||
|
local obj = {};
|
||||||
|
if toc ~= nil then obj[toc] = res.toc end
|
||||||
|
if content ~= nil then obj[content] = res.content end
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
end
|
||||||
|
|
||||||
|
function combine(objects)
|
||||||
|
local res = {};
|
||||||
|
|
||||||
|
for i = 1, #objects do
|
||||||
|
for k, v in next, objects[i] do
|
||||||
|
res[k] = v;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return res;
|
||||||
|
end
|
||||||
|
|
||||||
|
function template(options)
|
||||||
|
print("Templating into " .. options.template .. "...");
|
||||||
|
options = combine(array { options }:append(options));
|
||||||
|
return subst(read_to_str(io.open(options.template, "r")), options);
|
||||||
|
end
|
||||||
|
|
||||||
|
function emit(values)
|
||||||
|
local f = io.stdout;
|
||||||
|
|
||||||
|
if values.target then
|
||||||
|
f = assert(io.open(values.target, "w"));
|
||||||
|
print("Emitting to " .. values.target .. "...");
|
||||||
|
else
|
||||||
|
print("Emitting to stdout...");
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 1, #values do
|
||||||
|
assert(f:write(values[i]));
|
||||||
|
end
|
||||||
|
|
||||||
|
if f ~= io.stdout then
|
||||||
|
f:close();
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- return main;
|
244
doc/text/src/json.lua
Normal file
244
doc/text/src/json.lua
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
local json = { null = {} };
|
||||||
|
|
||||||
|
-- Internal functions.
|
||||||
|
|
||||||
|
local function kind_of(obj)
|
||||||
|
if type(obj) ~= "table" then return type(obj) end
|
||||||
|
|
||||||
|
local i = 1;
|
||||||
|
for _ in pairs(obj) do
|
||||||
|
if obj[i] ~= nil then
|
||||||
|
i = i + 1;
|
||||||
|
else
|
||||||
|
return "table";
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if i == 1 then
|
||||||
|
return "table";
|
||||||
|
else
|
||||||
|
return "array";
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function escape_str(s)
|
||||||
|
local in_char = { "\\", "\"", "/", "\b", "\f", "\n", "\r", "\t" };
|
||||||
|
local out_char = { "\\", "\"", "/", "b", "f", "n", "r", "t" };
|
||||||
|
for i, c in ipairs(in_char) do
|
||||||
|
s = s:gsub(c, "\\" .. out_char[i]);
|
||||||
|
end
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Returns pos, did_find; there are two cases:
|
||||||
|
-- 1. Delimiter found: pos = pos after leading space + delim; did_find = true.
|
||||||
|
-- 2. Delimiter not found: pos = pos after leading space; did_find = false.
|
||||||
|
-- This throws an error if err_if_missing is true and the delim is not found.
|
||||||
|
local function skip_delim(str, pos, delim, err_if_missing)
|
||||||
|
pos = string.find(str, "%S", pos) or pos;
|
||||||
|
|
||||||
|
if string.sub(str, pos, pos) ~= delim then
|
||||||
|
if err_if_missing then
|
||||||
|
error(table.concat { "Expected ", delim, " near position ", pos });
|
||||||
|
end
|
||||||
|
|
||||||
|
return pos, false;
|
||||||
|
end
|
||||||
|
|
||||||
|
return pos + 1, true;
|
||||||
|
end
|
||||||
|
|
||||||
|
local esc_map = { b = "\b", f = "\f", n = "\n", r = "\r", t = "\t", v = "\v" };
|
||||||
|
|
||||||
|
-- Expects the given pos to be the first character after the opening quote.
|
||||||
|
-- Returns val, pos; the returned pos is after the closing quote character.
|
||||||
|
local function parse_str_val(str, pos, check)
|
||||||
|
if pos > #str then error("End of input found while parsing string") end
|
||||||
|
|
||||||
|
if check then
|
||||||
|
if string.sub(str, pos, pos) ~= "\"" then
|
||||||
|
return nil, pos;
|
||||||
|
else
|
||||||
|
pos = pos + 1;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
pos = pos + 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
local res = {};
|
||||||
|
|
||||||
|
while true do
|
||||||
|
local c = string.sub(str, pos, pos);
|
||||||
|
if c == "\"" then
|
||||||
|
return table.concat(res), pos + 1;
|
||||||
|
elseif c == "\\" then
|
||||||
|
c = string.sub(str, pos + 1, pos + 1);
|
||||||
|
res[#res + 1] = esc_map[c] or c;
|
||||||
|
pos = pos + 2;
|
||||||
|
else
|
||||||
|
res[#res + 1] = c;
|
||||||
|
pos = pos + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Returns val, pos; the returned pos is after the number's final character.
|
||||||
|
local function parse_num_val(str, pos)
|
||||||
|
local num_str = string.match(str, "^-?%d+%.?%d*[eE]?[+-]?%d*", pos);
|
||||||
|
local val = tonumber(num_str);
|
||||||
|
|
||||||
|
if not val then error(table.concat { "Error parsing number at position ", pos, "." }) end
|
||||||
|
return val, pos + #num_str;
|
||||||
|
end
|
||||||
|
|
||||||
|
local json_end = { "eof" };
|
||||||
|
|
||||||
|
local function parse_impl(str, pos, end_delim)
|
||||||
|
pos = pos or 1;
|
||||||
|
if pos > #str then error("Reached unexpected end of input") end
|
||||||
|
|
||||||
|
pos = str:find("%S", pos) or pos;
|
||||||
|
local c = str:sub(pos, pos);
|
||||||
|
local delim_found;
|
||||||
|
|
||||||
|
if c == "{" then
|
||||||
|
pos = pos + 1;
|
||||||
|
|
||||||
|
local key;
|
||||||
|
local obj = {};
|
||||||
|
|
||||||
|
c = string.sub(str, pos, pos);
|
||||||
|
if c == "}" then
|
||||||
|
return obj, pos
|
||||||
|
else
|
||||||
|
while true do
|
||||||
|
key, pos = parse_str_val(str, pos, true);
|
||||||
|
if key == nil then error("Expected a string key") end
|
||||||
|
|
||||||
|
pos = skip_delim(str, pos, ":", true); -- true -> error if missing.
|
||||||
|
obj[key], pos = parse_impl(str, pos);
|
||||||
|
|
||||||
|
pos, delim_found = skip_delim(str, pos, "}");
|
||||||
|
if delim_found then return obj, pos end
|
||||||
|
|
||||||
|
pos, delim_found = skip_delim(str, pos, ",");
|
||||||
|
if not delim_found then error("Expected semicolon or comma") end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif c == "[" then
|
||||||
|
pos = pos + 1
|
||||||
|
|
||||||
|
local arr = array {};
|
||||||
|
local val;
|
||||||
|
local delim_found = true;
|
||||||
|
|
||||||
|
while true do
|
||||||
|
val, pos = parse_impl(str, pos, "]");
|
||||||
|
if val == json_end then return arr, pos end
|
||||||
|
if not delim_found then error("Comma missing between array items: " .. str:sub(pos, pos + 25)) end
|
||||||
|
|
||||||
|
arr[#arr + 1] = val;
|
||||||
|
pos, delim_found = skip_delim(str, pos, ",");
|
||||||
|
end
|
||||||
|
elseif c == "\"" then -- Parse a string.
|
||||||
|
return parse_str_val(str, pos, false);
|
||||||
|
elseif c == "-" or c:find("%d") then -- Parse a number.
|
||||||
|
return parse_num_val(str, pos);
|
||||||
|
elseif c == end_delim then -- End of an object or array.
|
||||||
|
return json_end, pos + 1, true;
|
||||||
|
elseif str:sub(pos, pos + 3) == "null" then
|
||||||
|
return nil, pos + 4;
|
||||||
|
elseif str:sub(pos, pos + 3) == "true" then
|
||||||
|
return true, pos + 4;
|
||||||
|
elseif str:sub(pos, pos + 4) == "false" then
|
||||||
|
return true, pos + 5;
|
||||||
|
else
|
||||||
|
error(table.concat { "Invalid json syntax starting at position ", pos, ": ", str:sub(pos, pos + 10) });
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function stringify_impl(obj, all, indent_str, n)
|
||||||
|
local s = {}; -- We'll build the string as an array of strings to be concatenated.
|
||||||
|
local kind = kind_of(obj); -- This is 'array' if it's an array or type(obj) otherwise.
|
||||||
|
|
||||||
|
if kind == "array" then
|
||||||
|
for i, val in ipairs(obj) do
|
||||||
|
s[i] = stringify_impl(val, all, indent_str, n + 1);
|
||||||
|
end
|
||||||
|
|
||||||
|
if not indent_str then
|
||||||
|
return "[" .. table.concat(s, ",") .. "]";
|
||||||
|
elseif #s == 0 then
|
||||||
|
return "[]";
|
||||||
|
else
|
||||||
|
local indent = "\n" .. string.rep(indent_str, n + 1);
|
||||||
|
return table.concat {
|
||||||
|
"[",
|
||||||
|
indent, table.concat(s, "," .. indent),
|
||||||
|
"\n", string.rep(indent_str, n), "]"
|
||||||
|
};
|
||||||
|
end
|
||||||
|
elseif kind == "table" then
|
||||||
|
for k, v in pairs(obj) do
|
||||||
|
local sep = indent_str and ": " or ":";
|
||||||
|
local val = stringify_impl(v, all, indent_str, n + 1);
|
||||||
|
if val ~= nil then
|
||||||
|
if type(k) == "string" then
|
||||||
|
s[#s + 1] = stringify_impl(k) .. sep .. val;
|
||||||
|
elseif type(k) == "number" then
|
||||||
|
s[#s + 1] = "\"" .. k .. "\"" .. sep .. val;
|
||||||
|
elseif type(k) == "boolean" then
|
||||||
|
s[#s + 1] = "\"" .. k .. "\"" .. sep .. val;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not indent_str then
|
||||||
|
return "{" .. table.concat(s, ",") .. "}";
|
||||||
|
elseif #s == 0 then
|
||||||
|
return "{}";
|
||||||
|
else
|
||||||
|
local indent = "\n" .. string.rep(indent_str, n + 1);
|
||||||
|
return table.concat {
|
||||||
|
"{",
|
||||||
|
indent, table.concat(s, "," .. indent),
|
||||||
|
"\n", string.rep(indent_str, n), "}"
|
||||||
|
};
|
||||||
|
end
|
||||||
|
return "{" .. table.concat(s, ",") .. "}";
|
||||||
|
elseif kind == "string" then
|
||||||
|
return "\"" .. escape_str(obj) .. "\"";
|
||||||
|
elseif kind == "number" then
|
||||||
|
return tostring(obj);
|
||||||
|
elseif kind == 'boolean' then
|
||||||
|
return tostring(obj);
|
||||||
|
elseif kind == "nil" then
|
||||||
|
return "null";
|
||||||
|
elseif all then
|
||||||
|
return tostring(obj);
|
||||||
|
else
|
||||||
|
return nil;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- local indent_str = " ";
|
||||||
|
|
||||||
|
function json.stringify(obj, indent_str)
|
||||||
|
if indent_str == true then
|
||||||
|
indent_str = " ";
|
||||||
|
end
|
||||||
|
return stringify_impl(obj, false, indent_str, 0);
|
||||||
|
end
|
||||||
|
function json.pretty(obj)
|
||||||
|
return stringify_impl(obj, true, " ", 0);
|
||||||
|
end
|
||||||
|
json.null = {}; -- This is a one-off table to represent the null value.
|
||||||
|
|
||||||
|
---@param str string
|
||||||
|
---@return unknown
|
||||||
|
function json.parse(str)
|
||||||
|
local obj = parse_impl(str, 1);
|
||||||
|
return obj;
|
||||||
|
end
|
||||||
|
|
||||||
|
return json
|
30
doc/text/src/perf.lua
Normal file
30
doc/text/src/perf.lua
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
local ffi = require "ffi";
|
||||||
|
|
||||||
|
ffi.cdef [[
|
||||||
|
typedef struct timeval {
|
||||||
|
long tv_sec;
|
||||||
|
long tv_usec;
|
||||||
|
} timeval;
|
||||||
|
|
||||||
|
int gettimeofday(struct timeval* t, void* tzp);
|
||||||
|
]];
|
||||||
|
|
||||||
|
local function now()
|
||||||
|
local target = ffi.new "timeval";
|
||||||
|
ffi.C.gettimeofday(target, nil);
|
||||||
|
return tonumber(target.tv_sec) + tonumber(target.tv_usec) / 1000000;
|
||||||
|
end
|
||||||
|
|
||||||
|
local function measure(func, ...)
|
||||||
|
local start = now();
|
||||||
|
|
||||||
|
return (function(...)
|
||||||
|
io.stderr:write(("Took %s seconds\n"):format(now() - start));
|
||||||
|
return ...;
|
||||||
|
end)(func(...));
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
now = now,
|
||||||
|
measure = measure,
|
||||||
|
}
|
429
doc/text/src/utils.lua
Normal file
429
doc/text/src/utils.lua
Normal file
@ -0,0 +1,429 @@
|
|||||||
|
-- TILL - TopchetoEU's "immaculate" lua libs
|
||||||
|
-- Some useful utilities every lua-er should use.
|
||||||
|
-- Might break shit, don't use in production for crying out loud
|
||||||
|
|
||||||
|
-- Reimplement this for lua <5.1
|
||||||
|
if table.move == nil then
|
||||||
|
--- @diagnostic disable: duplicate-set-field
|
||||||
|
function table.move(src, src_b, src_e, dst_b, dst)
|
||||||
|
if dst == nil then dst = src end
|
||||||
|
local offset = dst_b - src_b;
|
||||||
|
|
||||||
|
if dst_b < src_b then
|
||||||
|
for i = src_e, src_b, -1 do
|
||||||
|
dst[i + offset] = src[i];
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for i = src_b, src_e do
|
||||||
|
dst[i + offset] = src[i];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Why did we *remove* this from the spec again? Classical PUC
|
||||||
|
unpack = table.unpack or unpack;
|
||||||
|
table.unpack = unpack;
|
||||||
|
|
||||||
|
--- Prepares the object to be a class - puts an __index member in it pointing to the object itself
|
||||||
|
--- @generic T
|
||||||
|
--- @param obj T
|
||||||
|
--- @return T | { __index: T }
|
||||||
|
function class(obj)
|
||||||
|
--- @diagnostic disable-next-line: inject-field
|
||||||
|
obj.__index = obj;
|
||||||
|
return obj;
|
||||||
|
end
|
||||||
|
|
||||||
|
-- arrays
|
||||||
|
|
||||||
|
--- @alias array<T> T[] | arraylib
|
||||||
|
|
||||||
|
--- Converts the object to an array by putting "arrays" as its metatable
|
||||||
|
--- @generic T: unknown
|
||||||
|
--- @param obj T[]
|
||||||
|
--- @return array<T>
|
||||||
|
--- @overload fun(val: string): array<string>
|
||||||
|
function array(obj)
|
||||||
|
if type(obj) == "string" then
|
||||||
|
return obj:split "";
|
||||||
|
else
|
||||||
|
return arrays.mk(obj);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @class arraylib
|
||||||
|
arrays = class {};
|
||||||
|
|
||||||
|
--- Creates an array
|
||||||
|
function arrays.mk(obj)
|
||||||
|
return setmetatable(obj, arrays);
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Adds every element of every passed array to the end of this array
|
||||||
|
function arrays:append(...)
|
||||||
|
local res = self;
|
||||||
|
local n = #res + 1;
|
||||||
|
|
||||||
|
for i = 1, select("#", ...) do
|
||||||
|
local curr = select(i, ...);
|
||||||
|
for j = 1, #curr do
|
||||||
|
res[n] = curr[j];
|
||||||
|
n = n + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return res;
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns all the given arrays, concatenated to one
|
||||||
|
function arrays.concat(...)
|
||||||
|
--- @diagnostic disable-next-line: missing-fields
|
||||||
|
return arrays.append(array {}, ...);
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Adds all the given elements to the end of this array
|
||||||
|
function arrays:push(...)
|
||||||
|
return self:append({ ... });
|
||||||
|
end
|
||||||
|
--- Removes the last element of the array and returns it
|
||||||
|
--- @generic T
|
||||||
|
--- @param self array<T>
|
||||||
|
--- @return T val? The removed element, or nil if none
|
||||||
|
function arrays:pop()
|
||||||
|
local res = self[#self];
|
||||||
|
self[#self] = nil;
|
||||||
|
return res;
|
||||||
|
end
|
||||||
|
--- @generic T
|
||||||
|
--- @param self array<T>
|
||||||
|
--- @return T val? The last element of this array, or nil of none
|
||||||
|
function arrays:peek()
|
||||||
|
return self[#self];
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the result of mapping the values in table t through the function f
|
||||||
|
--- @param mutate boolean? If true, will operate directly on the given array
|
||||||
|
function arrays:map(f, mutate)
|
||||||
|
local out;
|
||||||
|
|
||||||
|
if mutate then
|
||||||
|
out = self;
|
||||||
|
else
|
||||||
|
out = array {};
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 1, #self do
|
||||||
|
out[i] = f(self[i], i, self);
|
||||||
|
end
|
||||||
|
|
||||||
|
return out;
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Finds the index of the given element, or nil if it doesn't exist
|
||||||
|
function arrays:find_i(f)
|
||||||
|
for i = 1, #self do
|
||||||
|
if f(self[i], i, self) then
|
||||||
|
return i;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Like arrays:map, but will expect the function to return arrays, and will :append them to the result array instead
|
||||||
|
function arrays:flat_map(f)
|
||||||
|
local out = array {};
|
||||||
|
|
||||||
|
for i = 1, #self do
|
||||||
|
out:append(f(self[i], i, self));
|
||||||
|
end
|
||||||
|
|
||||||
|
return out;
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Sets each value from b to e to val in the given array
|
||||||
|
function arrays:fill(val, b, e)
|
||||||
|
if b == nil then b = 1 end
|
||||||
|
if e == nil then e = self end
|
||||||
|
if b < 0 then b = #self + 1 - b end
|
||||||
|
if e < 0 then e = #self + 1 - e end
|
||||||
|
|
||||||
|
for i = b, e do
|
||||||
|
self[i] = val;
|
||||||
|
end
|
||||||
|
|
||||||
|
return self;
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Every element from start to stop is removed from this array and are replaced with the given elements
|
||||||
|
function arrays:splice(start, stop, ...)
|
||||||
|
-- TODO: optimize
|
||||||
|
if select("#") > 0 then
|
||||||
|
local n = stop - start + 1;
|
||||||
|
|
||||||
|
while n > 0 do
|
||||||
|
table.remove(self, start);
|
||||||
|
n = n - 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 1, select("#") do
|
||||||
|
table.insert(self, start, (select(i, ...)));
|
||||||
|
end
|
||||||
|
|
||||||
|
return self;
|
||||||
|
else
|
||||||
|
local res = {};
|
||||||
|
|
||||||
|
for i = start, stop do
|
||||||
|
table.insert(res, self[i]);
|
||||||
|
end
|
||||||
|
|
||||||
|
return res;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Every element from start to stop is removed from this array and are replaced with the given elements
|
||||||
|
function arrays:slice(start, stop)
|
||||||
|
start = start or 1;
|
||||||
|
stop = stop or #self;
|
||||||
|
local res = array {};
|
||||||
|
|
||||||
|
for i = start, stop do
|
||||||
|
res:push(self[i]);
|
||||||
|
end
|
||||||
|
|
||||||
|
return res;
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Equivalent of table.concat { table.unpack(self) }
|
||||||
|
--- @param sep string? Separator (defaults to empty)
|
||||||
|
--- @param b number? First element to take (defaults to beginning)
|
||||||
|
--- @param e number? Last element to take (defaults to end)
|
||||||
|
function arrays:join(sep, b, e)
|
||||||
|
return table.concat(self, sep, b, e);
|
||||||
|
end
|
||||||
|
|
||||||
|
function arrays:__concat(other)
|
||||||
|
return arrays.concat(self, other);
|
||||||
|
end
|
||||||
|
|
||||||
|
-- strings
|
||||||
|
|
||||||
|
--- Splits the text into an array of separate lines.
|
||||||
|
--- @param self string
|
||||||
|
function string:split(sep)
|
||||||
|
sep = sep or "";
|
||||||
|
local lines = arrays {};
|
||||||
|
local pos = 1;
|
||||||
|
|
||||||
|
if sep == "" then
|
||||||
|
for i = 1, #self do
|
||||||
|
lines:push(self:sub(1, 1));
|
||||||
|
end
|
||||||
|
else
|
||||||
|
while true do
|
||||||
|
local b, e = self:find(sep, pos);
|
||||||
|
|
||||||
|
if not b then
|
||||||
|
table.insert(lines, self:sub(pos));
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
table.insert(lines, self:sub(pos, b - 1));
|
||||||
|
pos = e + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
end
|
||||||
|
--- Gets the nth character
|
||||||
|
--- @param self string
|
||||||
|
--- @param i number
|
||||||
|
function string:at(i)
|
||||||
|
return self:sub(i, i);
|
||||||
|
end
|
||||||
|
--- Performs a plain string replace
|
||||||
|
--- @param self string
|
||||||
|
--- @param old string
|
||||||
|
--- @param new string
|
||||||
|
function string:replace(old, new)
|
||||||
|
local b, e = self:find(old, 1, true);
|
||||||
|
|
||||||
|
if b == nil then
|
||||||
|
return self;
|
||||||
|
else
|
||||||
|
return self:sub(1, b - 1) .. new .. self:sub(e + 1);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function escape_str(s)
|
||||||
|
local in_char = { "\\", "\"", "/", "\b", "\f", "\n", "\r", "\t" };
|
||||||
|
local out_char = { "\\", "\"", "/", "b", "f", "n", "r", "t" };
|
||||||
|
for i, c in ipairs(in_char) do
|
||||||
|
s = s:gsub(c, "\\" .. out_char[i]);
|
||||||
|
end
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
|
||||||
|
local function stringify_impl(obj, indent_str, n, passed)
|
||||||
|
local s = {}; -- We'll build the string as an array of strings to be concatenated.
|
||||||
|
local kind = type(obj); -- This is 'array' if it's an array or type(obj) otherwise.
|
||||||
|
|
||||||
|
if kind == "table" then
|
||||||
|
if passed[obj] then return "<circular>" end
|
||||||
|
passed[obj] = true;
|
||||||
|
|
||||||
|
local len = #obj;
|
||||||
|
|
||||||
|
for i = 1, len do
|
||||||
|
s[i] = stringify_impl(obj[i], indent_str, n + 1, passed) .. ",";
|
||||||
|
end
|
||||||
|
|
||||||
|
local keys = {};
|
||||||
|
|
||||||
|
for k, v in pairs(obj) do
|
||||||
|
if type(k) ~= "number" or k > len then
|
||||||
|
keys[#keys + 1] = { k, v };
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
table.sort(keys, function (a, b)
|
||||||
|
if type(a[1]) == "number" and type(b[1]) == "number" then
|
||||||
|
return a[1] < b[1];
|
||||||
|
elseif type(a[1]) == "string" and type(b[1]) == "string" then
|
||||||
|
return a[1] < b[1];
|
||||||
|
else
|
||||||
|
return type(a[1]) < type(b[1]) or tostring(a[1]) < tostring(b[1]);
|
||||||
|
end
|
||||||
|
end);
|
||||||
|
|
||||||
|
for i = 1, #keys do
|
||||||
|
local k = keys[i][1];
|
||||||
|
local v = keys[i][2];
|
||||||
|
|
||||||
|
local val = stringify_impl(v, indent_str, n + 1, passed);
|
||||||
|
if val ~= nil then
|
||||||
|
if type(k) == "string" then
|
||||||
|
s[#s + 1] = table.concat { k, ": ", val, "," };
|
||||||
|
else
|
||||||
|
s[#s + 1] = table.concat { "[", stringify_impl(k, indent_str, n + 1, passed), "]: ", val, "," };
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local meta = getmetatable(obj);
|
||||||
|
if meta ~= nil and meta ~= arrays then
|
||||||
|
s[#s + 1] = "<meta> = " .. stringify_impl(meta, indent_str, n + 1, passed) .. ",";
|
||||||
|
end
|
||||||
|
|
||||||
|
passed[obj] = false;
|
||||||
|
|
||||||
|
if #s == 0 then
|
||||||
|
if meta == arrays then
|
||||||
|
return "[]";
|
||||||
|
else
|
||||||
|
return "{}";
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local contents = table.concat(s, " "):sub(1, -2);
|
||||||
|
if #contents > 80 then
|
||||||
|
local indent = "\n" .. string.rep(indent_str, n + 1);
|
||||||
|
|
||||||
|
contents = table.concat {
|
||||||
|
indent,
|
||||||
|
table.concat(s, indent),
|
||||||
|
"\n", string.rep(indent_str, n)
|
||||||
|
};
|
||||||
|
else
|
||||||
|
contents = " " .. contents .. " ";
|
||||||
|
end
|
||||||
|
|
||||||
|
if meta == arrays then
|
||||||
|
return table.concat { "[", contents, "]" };
|
||||||
|
else
|
||||||
|
return table.concat { "{", contents, "}" };
|
||||||
|
end
|
||||||
|
elseif kind == "string" then
|
||||||
|
return "\"" .. escape_str(obj) .. "\"";
|
||||||
|
elseif kind == "function" then
|
||||||
|
local data = debug.getinfo(obj, "S");
|
||||||
|
return table.concat { tostring(obj), " @ ", data.short_src, ":", data.linedefined };
|
||||||
|
elseif kind == "nil" then
|
||||||
|
return "null";
|
||||||
|
else
|
||||||
|
return tostring(obj);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Turns the given value to a human-readable string.
|
||||||
|
--- Should be used only for debugging and display purposes
|
||||||
|
function to_readable(obj, indent_str)
|
||||||
|
return stringify_impl(obj, indent_str or " ", 0, {});
|
||||||
|
end
|
||||||
|
|
||||||
|
function print(...)
|
||||||
|
for i = 1, select("#", ...) do
|
||||||
|
if i > 1 then
|
||||||
|
io.stderr:write("\t");
|
||||||
|
end
|
||||||
|
|
||||||
|
io.stderr:write(tostring((select(i, ...))));
|
||||||
|
end
|
||||||
|
|
||||||
|
io.stderr:write("\n");
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Prints the given values in a human-readable manner to stderr
|
||||||
|
--- Should be used only for debugging
|
||||||
|
function pprint(...)
|
||||||
|
for i = 1, select("#", ...) do
|
||||||
|
if i > 1 then
|
||||||
|
io.stderr:write("\t");
|
||||||
|
end
|
||||||
|
|
||||||
|
io.stderr:write(to_readable((select(i, ...))));
|
||||||
|
end
|
||||||
|
|
||||||
|
io.stderr:write("\n");
|
||||||
|
end
|
||||||
|
|
||||||
|
-- functions
|
||||||
|
|
||||||
|
--- @class functions
|
||||||
|
functions = class {};
|
||||||
|
|
||||||
|
--- Constructs a function, such that it calls the first function with the passed arguments,
|
||||||
|
--- the second function with the return of the first, and so on. The return value of the last function is returned
|
||||||
|
---
|
||||||
|
--- In short, does the following, if the passed functions are a, b and c: return c(b(a(...)))
|
||||||
|
---
|
||||||
|
--- Sometimes less cumbersome to write (a | b | c | d)(args...) than d(c(b(a(args...))))
|
||||||
|
--- @param self function
|
||||||
|
function functions:pipe(...)
|
||||||
|
if ... == nil then
|
||||||
|
return self;
|
||||||
|
else
|
||||||
|
local next = ...;
|
||||||
|
|
||||||
|
return functions.pipe(function (...)
|
||||||
|
return next(self(...));
|
||||||
|
end, select(2, ...));
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--- Calls pipe with a and b; Alternative syntax for older Lua installation
|
||||||
|
function functions.__sub(a, b)
|
||||||
|
return functions.pipe(a, b);
|
||||||
|
end
|
||||||
|
--- Calls pipe with a and b
|
||||||
|
function functions.__bor(a, b)
|
||||||
|
return functions.pipe(a, b);
|
||||||
|
end
|
||||||
|
|
||||||
|
-- It's not vital to have this metatable, so we will just try our very best
|
||||||
|
if debug then
|
||||||
|
debug.setmetatable(load, functions);
|
||||||
|
end
|
555
doc/text/template.html
Normal file
555
doc/text/template.html
Normal file
@ -0,0 +1,555 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Дипломна работа {{author}}</title>
|
||||||
|
<style>
|
||||||
|
@page {
|
||||||
|
size: A4;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
break-before: page;
|
||||||
|
}
|
||||||
|
.pg-break {
|
||||||
|
break-after: page;
|
||||||
|
}
|
||||||
|
figure {
|
||||||
|
break-inside: avoid-page;
|
||||||
|
}
|
||||||
|
.page h1, .page h2 {
|
||||||
|
break-before: unset !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: Georgia, 'Times New Roman', Times, serif;
|
||||||
|
font-size: 14pt;
|
||||||
|
line-height: 1.75;
|
||||||
|
}
|
||||||
|
|
||||||
|
p::before {
|
||||||
|
width: 3em;
|
||||||
|
display: inline-block;
|
||||||
|
content: ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
.page {
|
||||||
|
line-height: 1.25;
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
li > ul {
|
||||||
|
padding-left: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
display: contents;
|
||||||
|
width: 100%;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
nav ul {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
nav span {
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
nav a {
|
||||||
|
line-height: 1.25;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
justify-content: space-between;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
nav a::after {
|
||||||
|
z-index: -1;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
float: right;
|
||||||
|
overflow: hidden;
|
||||||
|
width: max-content;
|
||||||
|
content:
|
||||||
|
'. . . . . . . . . . . . . . . . . . '
|
||||||
|
'. . . . . . . . . . . . . . . . . . '
|
||||||
|
'. . . . . . . . . . . . . . . . . . '
|
||||||
|
'. . . . . . . . . . . . . . . . . . '
|
||||||
|
'. . . . . . . . . . . . . . . . . . '
|
||||||
|
'. . . . . . . . . . . . . . . . . . '
|
||||||
|
'. . . . . . . . . . . . . . . . . . '
|
||||||
|
'. . . . . . . . . . . . . . . . . . '
|
||||||
|
'. . . . . . . . . . . . . . . . . . '
|
||||||
|
'. . . . . . . . . . . . . . . . . . ';
|
||||||
|
}
|
||||||
|
nav a span {
|
||||||
|
z-index: 10000;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: rgb(207, 37, 37);
|
||||||
|
}
|
||||||
|
|
||||||
|
figure {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: .5em;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 1em 0;
|
||||||
|
}
|
||||||
|
figure .fig-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 1em;
|
||||||
|
justify-content: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
figcaption {
|
||||||
|
font-style: italic;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.small {
|
||||||
|
max-width: 50%;
|
||||||
|
max-height: 25%;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
font-size: .65em;
|
||||||
|
margin: .5em 0;
|
||||||
|
}
|
||||||
|
pre > code {
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: 1.25;
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-ln-code {
|
||||||
|
padding-left: .5em !important;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-ln-numbers {
|
||||||
|
-webkit-touch-callout: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-khtml-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
text-align: center;
|
||||||
|
color: #ccc;
|
||||||
|
border-right: 1px solid #CCC;
|
||||||
|
vertical-align: top;
|
||||||
|
padding-right: .5em !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page {
|
||||||
|
height: 100%;
|
||||||
|
font-size: 12pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.school-header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
width: 100%;
|
||||||
|
gap: 2em;
|
||||||
|
}
|
||||||
|
.school-img {
|
||||||
|
height: 5em;
|
||||||
|
width: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pg-break {
|
||||||
|
break-after: page;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-page {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.title-authors {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 3em;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.title-author {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.asm-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.asm-signature {
|
||||||
|
display: block;
|
||||||
|
text-align: right;
|
||||||
|
/* flex-direction: column;
|
||||||
|
text-align: right; */
|
||||||
|
}
|
||||||
|
.asm-title {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.asm-content {
|
||||||
|
display: grid;
|
||||||
|
padding-top: 5em;
|
||||||
|
grid-template-rows: auto auto min-content;
|
||||||
|
/* flex-direction: column;
|
||||||
|
gap: .5em;
|
||||||
|
justify-content: space-between; */
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.asm-page {
|
||||||
|
height: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.graphic-table {
|
||||||
|
font-size: .9em;
|
||||||
|
line-height: 1.25;
|
||||||
|
border-collapse: collapse;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.graphic-table tr:nth-child() {
|
||||||
|
line-height: 1.25;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
.graphic-table .left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.graphic-table .right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.graphic-table .center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.graphic-table td, .graphic-table th {
|
||||||
|
border: 1px solid black;
|
||||||
|
padding: .25em;
|
||||||
|
margin: 0;
|
||||||
|
/* border */
|
||||||
|
}
|
||||||
|
.graphic-table thead tr {
|
||||||
|
background-color: #dadada;
|
||||||
|
}
|
||||||
|
.graphic-table tbody tr {
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
.graphic-table tbody tr:nth-child(even) {
|
||||||
|
background-color: #ececec;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style keep>
|
||||||
|
@media print {
|
||||||
|
nav a {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/default.min.css">
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/highlightjs/styles/vs.css">
|
||||||
|
<script src="https://unpkg.com/@highlightjs/cdn-assets/highlight.min.js"></script>
|
||||||
|
<script src="https://unpkg.com/pagedjs/dist/paged.js"></script>
|
||||||
|
<script src="https://unpkg.com/highlightjs-line-numbers.js/src/highlightjs-line-numbers.js"></script>
|
||||||
|
<script>
|
||||||
|
// This godless solution works, so it is fine
|
||||||
|
class RepeatingTableHeadersHandler extends Paged.Handler {
|
||||||
|
constructor(chunker, polisher, caller) {
|
||||||
|
super(chunker, polisher, caller);
|
||||||
|
this.splitTablesRefs = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
afterPageLayout(pageElement, page, breakToken, chunker) {
|
||||||
|
this.chunker = chunker;
|
||||||
|
this.splitTablesRefs = [];
|
||||||
|
|
||||||
|
if (breakToken) {
|
||||||
|
const node = breakToken.node;
|
||||||
|
const tables = this.findAllAncestors(node, "table");
|
||||||
|
if (node.tagName === "TABLE") {
|
||||||
|
tables.push(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tables.length > 0) {
|
||||||
|
this.splitTablesRefs = tables.map(t => t.dataset.ref);
|
||||||
|
|
||||||
|
//checks if split inside thead and if so, set breakToken to next sibling element
|
||||||
|
let thead = node.tagName === "THEAD" ? node : this.findFirstAncestor(node, "thead");
|
||||||
|
if (thead) {
|
||||||
|
let lastTheadNode = thead.hasChildNodes() ? thead.lastChild : thead;
|
||||||
|
breakToken.node = this.nodeAfter(lastTheadNode, chunker.source);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hideEmptyTables(pageElement, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hideEmptyTables(pageElement, breakTokenNode) {
|
||||||
|
this.splitTablesRefs.forEach(ref => {
|
||||||
|
let table = pageElement.querySelector("[data-ref='" + ref + "']");
|
||||||
|
if (table) {
|
||||||
|
let sourceBody = table.querySelector("tbody > tr");
|
||||||
|
if (!sourceBody || this.refEquals(sourceBody.firstElementChild, breakTokenNode)) {
|
||||||
|
table.style.visibility = "hidden";
|
||||||
|
table.style.position = "absolute";
|
||||||
|
let lineSpacer = table.nextSibling;
|
||||||
|
if (lineSpacer) {
|
||||||
|
lineSpacer.style.visibility = "hidden";
|
||||||
|
lineSpacer.style.position = "absolute";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
refEquals(a, b) {
|
||||||
|
return a && a.dataset && b && b.dataset && a.dataset.ref === b.dataset.ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
findFirstAncestor(element, selector) {
|
||||||
|
while (element.parentNode && element.parentNode.nodeType === 1) {
|
||||||
|
if (element.parentNode.matches(selector)) {
|
||||||
|
return element.parentNode;
|
||||||
|
}
|
||||||
|
element = element.parentNode;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
findAllAncestors(element, selector) {
|
||||||
|
const ancestors = [];
|
||||||
|
while (element.parentNode && element.parentNode.nodeType === 1) {
|
||||||
|
if (element.parentNode.matches(selector)) {
|
||||||
|
ancestors.unshift(element.parentNode);
|
||||||
|
}
|
||||||
|
element = element.parentNode;
|
||||||
|
}
|
||||||
|
return ancestors;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The addition of repeating Table Headers is done here because this hook is triggered before overflow handling
|
||||||
|
layout(rendered, layout) {
|
||||||
|
this.splitTablesRefs.forEach(ref => {
|
||||||
|
const renderedTable = rendered.querySelector("[data-ref='" + ref + "']");
|
||||||
|
if (renderedTable) {
|
||||||
|
// this event can be triggered multiple times
|
||||||
|
// added a flag repeated-headers to control when table headers already repeated in current page.
|
||||||
|
if (!renderedTable.getAttribute("repeated-headers")) {
|
||||||
|
const sourceTable = this.chunker.source.querySelector("[data-ref='" + ref + "']");
|
||||||
|
this.repeatColgroup(sourceTable, renderedTable);
|
||||||
|
this.repeatTHead(sourceTable, renderedTable);
|
||||||
|
renderedTable.setAttribute("repeated-headers", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
repeatColgroup(sourceTable, renderedTable) {
|
||||||
|
let colgroup = sourceTable.querySelectorAll("colgroup");
|
||||||
|
let firstChild = renderedTable.firstChild;
|
||||||
|
colgroup.forEach((colgroup) => {
|
||||||
|
let clonedColgroup = colgroup.cloneNode(true);
|
||||||
|
renderedTable.insertBefore(clonedColgroup, firstChild);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
repeatTHead(sourceTable, renderedTable) {
|
||||||
|
let thead = sourceTable.querySelector("thead");
|
||||||
|
if (thead) {
|
||||||
|
let clonedThead = thead.cloneNode(true);
|
||||||
|
renderedTable.insertBefore(clonedThead, renderedTable.firstChild);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the functions below are from pagedjs utils/dom.js
|
||||||
|
nodeAfter(node, limiter) {
|
||||||
|
if (limiter && node === limiter) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let significantNode = this.nextSignificantNode(node);
|
||||||
|
if (significantNode) {
|
||||||
|
return significantNode;
|
||||||
|
}
|
||||||
|
if (node.parentNode) {
|
||||||
|
while ((node = node.parentNode)) {
|
||||||
|
if (limiter && node === limiter) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
significantNode = this.nextSignificantNode(node);
|
||||||
|
if (significantNode) {
|
||||||
|
return significantNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nextSignificantNode(sib) {
|
||||||
|
while ((sib = sib.nextSibling)) {
|
||||||
|
if (!this.isIgnorable(sib)) return sib;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
isIgnorable(node) {
|
||||||
|
return (node.nodeType === 8) || // A comment node
|
||||||
|
((node.nodeType === 3) && this.isAllWhitespace(node)); // a text node, all whitespace
|
||||||
|
}
|
||||||
|
|
||||||
|
isAllWhitespace(node) {
|
||||||
|
return !(/[^\t\n\r ]/.test(node.textContent));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
Paged.registerHandlers(RepeatingTableHeadersHandler);
|
||||||
|
|
||||||
|
window.onload = async evn => {
|
||||||
|
hljs.highlightAll();
|
||||||
|
hljs.initLineNumbersOnLoad();
|
||||||
|
|
||||||
|
await new Promise(res => setTimeout(res, 50));
|
||||||
|
const { Previewer, DOMContent } = Paged;
|
||||||
|
|
||||||
|
evn.preventDefault();
|
||||||
|
const p = new Previewer();
|
||||||
|
const styles = [...document.head.getElementsByTagName("style")]
|
||||||
|
.filter(v => !v.hasAttribute("keep"))
|
||||||
|
.map(v => {
|
||||||
|
v.remove();
|
||||||
|
return { [window.location.href]: v.textContent };
|
||||||
|
});
|
||||||
|
|
||||||
|
const flow = await p.preview(DOMContent, styles, document.body);
|
||||||
|
const pages = flow.pages.map(v => v.element);
|
||||||
|
|
||||||
|
for (const nav of document.getElementsByTagName("nav")) {
|
||||||
|
|
||||||
|
for (let el of nav.getElementsByTagName("li")) {
|
||||||
|
el = el.children[0];
|
||||||
|
if (!(el instanceof HTMLAnchorElement)) continue;
|
||||||
|
const name = [...el.children].find(v => v.classList.contains("name"));
|
||||||
|
const page = [...el.children].find(v => v.classList.contains("page"));
|
||||||
|
|
||||||
|
const href = decodeURIComponent(/#(.+)$/.exec(el.href)?.[1]);
|
||||||
|
const target = document.getElementById(href);
|
||||||
|
const i = pages.findIndex(v => v.contains(target));
|
||||||
|
|
||||||
|
page.innerText = i + 1;
|
||||||
|
page.href = "#" + href;
|
||||||
|
// console.log(target, name, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="page title-page">
|
||||||
|
<div class="school-header">
|
||||||
|
<img class="school-img" src="{{school_img}}"/>
|
||||||
|
<h4>{{school_name}}</h4>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="title-content">
|
||||||
|
<h2>ДИПЛОМНА РАБОТА</h2>
|
||||||
|
<h4>по професия код {{profession}}</h4>
|
||||||
|
<h4>специалност код {{specialty}}</h4>
|
||||||
|
<div>Тема: {{topic}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="title-authors">
|
||||||
|
<div class="title-author">
|
||||||
|
<div class="author-type">Дипломант:</div>
|
||||||
|
<div class="author-name">{{author}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="title-author">
|
||||||
|
<div class="author-type">Научен ръководител:</div>
|
||||||
|
<div class="author-name">{{supervisor}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="title-end">СОФИЯ - {{year}}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="page asm-page">
|
||||||
|
<div class="school-header">
|
||||||
|
<img class="school-img" src="{{school_img}}"/>
|
||||||
|
<h4>{{school_name}}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="asm-header">
|
||||||
|
<div class="asm-header-dates">
|
||||||
|
<div>Дата на заданието: 28.10.{{prev_year}} г.</div>
|
||||||
|
<div>Дата на предаване: 28.01.{{year}} г.</div>
|
||||||
|
</div>
|
||||||
|
<div class="asm-signature">
|
||||||
|
<div class="asm-signature-place">Утвърждавам: ..............................</div>
|
||||||
|
<div class="asm-signature-person">/{{ensurer_name}}/ </div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="asm-content">
|
||||||
|
<div class="asm-title">
|
||||||
|
<h2>ЗАДАНИЕ</h2>
|
||||||
|
<h2>за дипломна работа</h2>
|
||||||
|
<h4>ДЪРЖАВЕН ИЗПИТ ЗА ПРИДОБИВАНЕ НА ТРЕТА СТЕПЕН НА ПРОФЕСИОНАЛНА КВАЛИФИКАЦИЯ</h4>
|
||||||
|
<h4>по професия код {{profession}}</h4>
|
||||||
|
<h4>специалност код {{specialty}}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="asm-requirements">
|
||||||
|
на ученика {{author}} от {{class}} клас<br/>
|
||||||
|
{{requirements}}
|
||||||
|
</div>
|
||||||
|
<div class="asm-authors">
|
||||||
|
<div class="asm-signature">
|
||||||
|
<div class="author-type">Дипломант: ...........................................</div>
|
||||||
|
<div class="author-name">/{{author}}/</div>
|
||||||
|
</div>
|
||||||
|
<div class="asm-signature">
|
||||||
|
<div class="author-type">Ръководител: ...........................................</div>
|
||||||
|
<div class="author-name">/{{supervisor}}/</div>
|
||||||
|
</div>
|
||||||
|
<div class="asm-signature">
|
||||||
|
<div class="author-type">{{head_teacher_title}}: ...........................................</div>
|
||||||
|
<div class="author-name">/{{head_teacher_name}}/</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{content}}
|
||||||
|
|
||||||
|
<nav>
|
||||||
|
{{toc}}
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -20,7 +20,7 @@ import me.topchetoeu.j2s.runtime.values.primitives.StringValue;
|
|||||||
import me.topchetoeu.j2s.runtime.values.primitives.SymbolValue;
|
import me.topchetoeu.j2s.runtime.values.primitives.SymbolValue;
|
||||||
import me.topchetoeu.j2s.runtime.values.primitives.numbers.NumberValue;
|
import me.topchetoeu.j2s.runtime.values.primitives.numbers.NumberValue;
|
||||||
|
|
||||||
public class ScopeObject extends Value {
|
public class ScopeObject implements Value {
|
||||||
public static final class ScopeMember extends FieldMember {
|
public static final class ScopeMember extends FieldMember {
|
||||||
public final Frame frame;
|
public final Frame frame;
|
||||||
public final int i;
|
public final int i;
|
||||||
|
@ -29,7 +29,7 @@ import me.topchetoeu.j2s.runtime.values.primitives.SymbolValue;
|
|||||||
import me.topchetoeu.j2s.runtime.values.primitives.VoidValue;
|
import me.topchetoeu.j2s.runtime.values.primitives.VoidValue;
|
||||||
import me.topchetoeu.j2s.runtime.values.primitives.numbers.NumberValue;
|
import me.topchetoeu.j2s.runtime.values.primitives.numbers.NumberValue;
|
||||||
|
|
||||||
public abstract class Value {
|
public interface Value {
|
||||||
public static enum State {
|
public static enum State {
|
||||||
NORMAL(true, true, true),
|
NORMAL(true, true, true),
|
||||||
NON_EXTENDABLE(false, true, true),
|
NON_EXTENDABLE(false, true, true),
|
||||||
@ -76,28 +76,43 @@ public abstract class Value {
|
|||||||
public abstract StringValue type();
|
public abstract StringValue type();
|
||||||
public abstract boolean isPrimitive();
|
public abstract boolean isPrimitive();
|
||||||
|
|
||||||
public final boolean isNaN() {
|
public default boolean isNaN() {
|
||||||
return this == NumberValue.NAN || this instanceof NumberValue num && Double.isNaN(num.getDouble());
|
return this == NumberValue.NAN || this instanceof NumberValue num && Double.isNaN(num.getDouble());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Value apply(Environment env, Value self, Value ...args) {
|
public default Value apply(Environment env, Value self, Value ...args) {
|
||||||
throw EngineException.ofType("Value is not a function");
|
throw EngineException.ofType("Value is not a function");
|
||||||
}
|
}
|
||||||
public Value construct(Environment env, Value target, Value ...args) {
|
public default Value construct(Environment env, Value target, Value ...args) {
|
||||||
throw EngineException.ofType("Value is not a constructor");
|
throw EngineException.ofType("Value is not a constructor");
|
||||||
}
|
}
|
||||||
|
|
||||||
public final Value constructNoSelf(Environment env, Value ...args) {
|
public default Value constructNoSelf(Environment env, Value ...args) {
|
||||||
return this.construct(env, this, args);
|
return this.construct(env, this, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Value toPrimitive(Environment env);
|
||||||
|
public NumberValue toNumber(Environment env);
|
||||||
|
public String toString(Environment env);
|
||||||
|
public boolean toBoolean();
|
||||||
|
|
||||||
public abstract Value toPrimitive(Environment env);
|
public Member getOwnMember(Environment env, KeyCache key);
|
||||||
public abstract NumberValue toNumber(Environment env);
|
public Set<String> getOwnMembers(Environment env, boolean onlyEnumerable);
|
||||||
public abstract String toString(Environment env);
|
public Set<SymbolValue> getOwnSymbolMembers(Environment env, boolean onlyEnumerable);
|
||||||
public abstract boolean toBoolean();
|
public boolean defineOwnField(Environment env, KeyCache key, Value val, Boolean writable, Boolean enumerable, Boolean configurable);
|
||||||
|
public boolean defineOwnProperty(Environment env, KeyCache key, Optional<FunctionValue> get, Optional<FunctionValue> set, Boolean enumerable, Boolean configurable);
|
||||||
|
public boolean deleteOwnMember(Environment env, KeyCache key);
|
||||||
|
|
||||||
public final boolean isInstanceOf(Environment env, Value proto) {
|
public ObjectValue getPrototype(Environment env);
|
||||||
|
public boolean setPrototype(Environment env, ObjectValue val);
|
||||||
|
|
||||||
|
public State getState();
|
||||||
|
|
||||||
|
public void preventExtensions();
|
||||||
|
public void seal();
|
||||||
|
public void freeze();
|
||||||
|
|
||||||
|
public default boolean isInstanceOf(Environment env, Value proto) {
|
||||||
for (var val = getPrototype(env); val != null; val = val.getPrototype(env)) {
|
for (var val = getPrototype(env); val != null; val = val.getPrototype(env)) {
|
||||||
if (val.equals(proto)) return true;
|
if (val.equals(proto)) return true;
|
||||||
}
|
}
|
||||||
@ -105,91 +120,75 @@ public abstract class Value {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract Member getOwnMember(Environment env, KeyCache key);
|
public default Member getOwnMember(Environment env, Value key) {
|
||||||
public abstract Set<String> getOwnMembers(Environment env, boolean onlyEnumerable);
|
|
||||||
public abstract Set<SymbolValue> getOwnSymbolMembers(Environment env, boolean onlyEnumerable);
|
|
||||||
public abstract boolean defineOwnField(Environment env, KeyCache key, Value val, Boolean writable, Boolean enumerable, Boolean configurable);
|
|
||||||
public abstract boolean defineOwnProperty(Environment env, KeyCache key, Optional<FunctionValue> get, Optional<FunctionValue> set, Boolean enumerable, Boolean configurable);
|
|
||||||
public abstract boolean deleteOwnMember(Environment env, KeyCache key);
|
|
||||||
|
|
||||||
public abstract ObjectValue getPrototype(Environment env);
|
|
||||||
public abstract boolean setPrototype(Environment env, ObjectValue val);
|
|
||||||
|
|
||||||
public abstract State getState();
|
|
||||||
|
|
||||||
public abstract void preventExtensions();
|
|
||||||
public abstract void seal();
|
|
||||||
public abstract void freeze();
|
|
||||||
|
|
||||||
public final Member getOwnMember(Environment env, Value key) {
|
|
||||||
return getOwnMember(env, new KeyCache(key));
|
return getOwnMember(env, new KeyCache(key));
|
||||||
}
|
}
|
||||||
public final Member getOwnMember(Environment env, String key) {
|
public default Member getOwnMember(Environment env, String key) {
|
||||||
return getOwnMember(env, new KeyCache(key));
|
return getOwnMember(env, new KeyCache(key));
|
||||||
}
|
}
|
||||||
public final Member getOwnMember(Environment env, int key) {
|
public default Member getOwnMember(Environment env, int key) {
|
||||||
return getOwnMember(env, new KeyCache(key));
|
return getOwnMember(env, new KeyCache(key));
|
||||||
}
|
}
|
||||||
public final Member getOwnMember(Environment env, double key) {
|
public default Member getOwnMember(Environment env, double key) {
|
||||||
return getOwnMember(env, new KeyCache(key));
|
return getOwnMember(env, new KeyCache(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean defineOwnProperty(Environment env, Value key, Optional<FunctionValue> get, Optional<FunctionValue> set, Boolean enumerable, Boolean configurable) {
|
public default boolean defineOwnProperty(Environment env, Value key, Optional<FunctionValue> get, Optional<FunctionValue> set, Boolean enumerable, Boolean configurable) {
|
||||||
return defineOwnProperty(env, new KeyCache(key), get, set, enumerable, configurable);
|
return defineOwnProperty(env, new KeyCache(key), get, set, enumerable, configurable);
|
||||||
}
|
}
|
||||||
public final boolean defineOwnProperty(Environment env, String key, Optional<FunctionValue> get, Optional<FunctionValue> set, Boolean enumerable, Boolean configurable) {
|
public default boolean defineOwnProperty(Environment env, String key, Optional<FunctionValue> get, Optional<FunctionValue> set, Boolean enumerable, Boolean configurable) {
|
||||||
return defineOwnProperty(env, new KeyCache(key), get, set, enumerable, configurable);
|
return defineOwnProperty(env, new KeyCache(key), get, set, enumerable, configurable);
|
||||||
}
|
}
|
||||||
public final boolean defineOwnProperty(Environment env, int key, Optional<FunctionValue> get, Optional<FunctionValue> set, Boolean enumerable, Boolean configurable) {
|
public default boolean defineOwnProperty(Environment env, int key, Optional<FunctionValue> get, Optional<FunctionValue> set, Boolean enumerable, Boolean configurable) {
|
||||||
return defineOwnProperty(env, new KeyCache(key), get, set, enumerable, configurable);
|
return defineOwnProperty(env, new KeyCache(key), get, set, enumerable, configurable);
|
||||||
}
|
}
|
||||||
public final boolean defineOwnProperty(Environment env, double key, Optional<FunctionValue> get, Optional<FunctionValue> set, Boolean enumerable, Boolean configurable) {
|
public default boolean defineOwnProperty(Environment env, double key, Optional<FunctionValue> get, Optional<FunctionValue> set, Boolean enumerable, Boolean configurable) {
|
||||||
return defineOwnProperty(env, new KeyCache(key), get, set, enumerable, configurable);
|
return defineOwnProperty(env, new KeyCache(key), get, set, enumerable, configurable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean defineOwnField(Environment env, Value key, Value val, Boolean writable, Boolean enumerable, Boolean configurable) {
|
public default boolean defineOwnField(Environment env, Value key, Value val, Boolean writable, Boolean enumerable, Boolean configurable) {
|
||||||
return defineOwnField(env, new KeyCache(key), val, writable, enumerable, configurable);
|
return defineOwnField(env, new KeyCache(key), val, writable, enumerable, configurable);
|
||||||
}
|
}
|
||||||
public final boolean defineOwnField(Environment env, String key, Value val, Boolean writable, Boolean enumerable, Boolean configurable) {
|
public default boolean defineOwnField(Environment env, String key, Value val, Boolean writable, Boolean enumerable, Boolean configurable) {
|
||||||
return defineOwnField(env, new KeyCache(key), val, writable, enumerable, configurable);
|
return defineOwnField(env, new KeyCache(key), val, writable, enumerable, configurable);
|
||||||
}
|
}
|
||||||
public final boolean defineOwnField(Environment env, int key, Value val, Boolean writable, Boolean enumerable, Boolean configurable) {
|
public default boolean defineOwnField(Environment env, int key, Value val, Boolean writable, Boolean enumerable, Boolean configurable) {
|
||||||
return defineOwnField(env, new KeyCache(key), val, writable, enumerable, configurable);
|
return defineOwnField(env, new KeyCache(key), val, writable, enumerable, configurable);
|
||||||
}
|
}
|
||||||
public final boolean defineOwnField(Environment env, double key, Value val, Boolean writable, Boolean enumerable, Boolean configurable) {
|
public default boolean defineOwnField(Environment env, double key, Value val, Boolean writable, Boolean enumerable, Boolean configurable) {
|
||||||
return defineOwnField(env, new KeyCache(key), val, writable, enumerable, configurable);
|
return defineOwnField(env, new KeyCache(key), val, writable, enumerable, configurable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean defineOwnField(Environment env, KeyCache key, Value val) {
|
public default boolean defineOwnField(Environment env, KeyCache key, Value val) {
|
||||||
return defineOwnField(env, key, val, true, true, true);
|
return defineOwnField(env, key, val, true, true, true);
|
||||||
}
|
}
|
||||||
public final boolean defineOwnField(Environment env, Value key, Value val) {
|
public default boolean defineOwnField(Environment env, Value key, Value val) {
|
||||||
return defineOwnField(env, new KeyCache(key), val);
|
return defineOwnField(env, new KeyCache(key), val);
|
||||||
}
|
}
|
||||||
public final boolean defineOwnField(Environment env, String key, Value val) {
|
public default boolean defineOwnField(Environment env, String key, Value val) {
|
||||||
return defineOwnField(env, new KeyCache(key), val);
|
return defineOwnField(env, new KeyCache(key), val);
|
||||||
}
|
}
|
||||||
public final boolean defineOwnField(Environment env, int key, Value val) {
|
public default boolean defineOwnField(Environment env, int key, Value val) {
|
||||||
return defineOwnField(env, new KeyCache(key), val);
|
return defineOwnField(env, new KeyCache(key), val);
|
||||||
}
|
}
|
||||||
public final boolean defineOwnField(Environment env, double key, Value val) {
|
public default boolean defineOwnField(Environment env, double key, Value val) {
|
||||||
return defineOwnField(env, new KeyCache(key), val);
|
return defineOwnField(env, new KeyCache(key), val);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean deleteOwnMember(Environment env, Value key) {
|
public default boolean deleteOwnMember(Environment env, Value key) {
|
||||||
return deleteOwnMember(env, new KeyCache(key));
|
return deleteOwnMember(env, new KeyCache(key));
|
||||||
}
|
}
|
||||||
public final boolean deleteOwnMember(Environment env, String key) {
|
public default boolean deleteOwnMember(Environment env, String key) {
|
||||||
return deleteOwnMember(env, new KeyCache(key));
|
return deleteOwnMember(env, new KeyCache(key));
|
||||||
}
|
}
|
||||||
public final boolean deleteOwnMember(Environment env, int key) {
|
public default boolean deleteOwnMember(Environment env, int key) {
|
||||||
return deleteOwnMember(env, new KeyCache(key));
|
return deleteOwnMember(env, new KeyCache(key));
|
||||||
}
|
}
|
||||||
public final boolean deleteOwnMember(Environment env, double key) {
|
public default boolean deleteOwnMember(Environment env, double key) {
|
||||||
return deleteOwnMember(env, new KeyCache(key));
|
return deleteOwnMember(env, new KeyCache(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
public final Value getMemberOrNull(Environment env, KeyCache key) {
|
public default Value getMemberOrNull(Environment env, KeyCache key) {
|
||||||
for (Value obj = this; obj != null; obj = obj.getPrototype(env)) {
|
for (Value obj = this; obj != null; obj = obj.getPrototype(env)) {
|
||||||
var member = obj.getOwnMember(env, key);
|
var member = obj.getOwnMember(env, key);
|
||||||
if (member != null) return member.get(env, this);
|
if (member != null) return member.get(env, this);
|
||||||
@ -197,38 +196,38 @@ public abstract class Value {
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
public final Value getMemberOrNull(Environment env, Value key) {
|
public default Value getMemberOrNull(Environment env, Value key) {
|
||||||
return getMemberOrNull(env, new KeyCache(key));
|
return getMemberOrNull(env, new KeyCache(key));
|
||||||
}
|
}
|
||||||
public final Value getMemberOrNull(Environment env, String key) {
|
public default Value getMemberOrNull(Environment env, String key) {
|
||||||
return getMemberOrNull(env, new KeyCache(key));
|
return getMemberOrNull(env, new KeyCache(key));
|
||||||
}
|
}
|
||||||
public final Value getMemberOrNull(Environment env, int key) {
|
public default Value getMemberOrNull(Environment env, int key) {
|
||||||
return getMemberOrNull(env, new KeyCache(key));
|
return getMemberOrNull(env, new KeyCache(key));
|
||||||
}
|
}
|
||||||
public final Value getMemberOrNull(Environment env, double key) {
|
public default Value getMemberOrNull(Environment env, double key) {
|
||||||
return getMemberOrNull(env, new KeyCache(key));
|
return getMemberOrNull(env, new KeyCache(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
public final Value getMember(Environment env, KeyCache key) {
|
public default Value getMember(Environment env, KeyCache key) {
|
||||||
var res = getMemberOrNull(env, key);
|
var res = getMemberOrNull(env, key);
|
||||||
if (res != null) return res;
|
if (res != null) return res;
|
||||||
else return Value.UNDEFINED;
|
else return Value.UNDEFINED;
|
||||||
}
|
}
|
||||||
public final Value getMember(Environment env, Value key) {
|
public default Value getMember(Environment env, Value key) {
|
||||||
return getMember(env, new KeyCache(key));
|
return getMember(env, new KeyCache(key));
|
||||||
}
|
}
|
||||||
public final Value getMember(Environment env, String key) {
|
public default Value getMember(Environment env, String key) {
|
||||||
return getMember(env, new KeyCache(key));
|
return getMember(env, new KeyCache(key));
|
||||||
}
|
}
|
||||||
public final Value getMember(Environment env, int key) {
|
public default Value getMember(Environment env, int key) {
|
||||||
return getMember(env, new KeyCache(key));
|
return getMember(env, new KeyCache(key));
|
||||||
}
|
}
|
||||||
public final Value getMember(Environment env, double key) {
|
public default Value getMember(Environment env, double key) {
|
||||||
return getMember(env, new KeyCache(key));
|
return getMember(env, new KeyCache(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean setMember(Environment env, KeyCache key, Value val) {
|
public default boolean setMember(Environment env, KeyCache key, Value val) {
|
||||||
for (Value obj = this; obj != null; obj = obj.getPrototype(env)) {
|
for (Value obj = this; obj != null; obj = obj.getPrototype(env)) {
|
||||||
var member = obj.getOwnMember(env, key);
|
var member = obj.getOwnMember(env, key);
|
||||||
if (member != null && (member instanceof PropertyMember || obj == this)) {
|
if (member != null && (member instanceof PropertyMember || obj == this)) {
|
||||||
@ -249,20 +248,20 @@ public abstract class Value {
|
|||||||
}
|
}
|
||||||
else return false;
|
else return false;
|
||||||
}
|
}
|
||||||
public final boolean setMember(Environment env, Value key, Value val) {
|
public default boolean setMember(Environment env, Value key, Value val) {
|
||||||
return setMember(env, new KeyCache(key), val);
|
return setMember(env, new KeyCache(key), val);
|
||||||
}
|
}
|
||||||
public final boolean setMember(Environment env, String key, Value val) {
|
public default boolean setMember(Environment env, String key, Value val) {
|
||||||
return setMember(env, new KeyCache(key), val);
|
return setMember(env, new KeyCache(key), val);
|
||||||
}
|
}
|
||||||
public final boolean setMember(Environment env, int key, Value val) {
|
public default boolean setMember(Environment env, int key, Value val) {
|
||||||
return setMember(env, new KeyCache(key), val);
|
return setMember(env, new KeyCache(key), val);
|
||||||
}
|
}
|
||||||
public final boolean setMember(Environment env, double key, Value val) {
|
public default boolean setMember(Environment env, double key, Value val) {
|
||||||
return setMember(env, new KeyCache(key), val);
|
return setMember(env, new KeyCache(key), val);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean setMemberIfExists(Environment env, KeyCache key, Value val) {
|
public default boolean setMemberIfExists(Environment env, KeyCache key, Value val) {
|
||||||
for (Value obj = this; obj != null; obj = obj.getPrototype(env)) {
|
for (Value obj = this; obj != null; obj = obj.getPrototype(env)) {
|
||||||
var member = obj.getOwnMember(env, key);
|
var member = obj.getOwnMember(env, key);
|
||||||
if (member != null) {
|
if (member != null) {
|
||||||
@ -276,20 +275,20 @@ public abstract class Value {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
public final boolean setMemberIfExists(Environment env, Value key, Value val) {
|
public default boolean setMemberIfExists(Environment env, Value key, Value val) {
|
||||||
return setMemberIfExists(env, new KeyCache(key), val);
|
return setMemberIfExists(env, new KeyCache(key), val);
|
||||||
}
|
}
|
||||||
public final boolean setMemberIfExists(Environment env, String key, Value val) {
|
public default boolean setMemberIfExists(Environment env, String key, Value val) {
|
||||||
return setMemberIfExists(env, new KeyCache(key), val);
|
return setMemberIfExists(env, new KeyCache(key), val);
|
||||||
}
|
}
|
||||||
public final boolean setMemberIfExists(Environment env, int key, Value val) {
|
public default boolean setMemberIfExists(Environment env, int key, Value val) {
|
||||||
return setMemberIfExists(env, new KeyCache(key), val);
|
return setMemberIfExists(env, new KeyCache(key), val);
|
||||||
}
|
}
|
||||||
public final boolean setMemberIfExists(Environment env, double key, Value val) {
|
public default boolean setMemberIfExists(Environment env, double key, Value val) {
|
||||||
return setMemberIfExists(env, new KeyCache(key), val);
|
return setMemberIfExists(env, new KeyCache(key), val);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean hasMember(Environment env, KeyCache key, boolean own) {
|
public default boolean hasMember(Environment env, KeyCache key, boolean own) {
|
||||||
for (Value obj = this; obj != null; obj = obj.getPrototype(env)) {
|
for (Value obj = this; obj != null; obj = obj.getPrototype(env)) {
|
||||||
if (obj.getOwnMember(env, key) != null) return true;
|
if (obj.getOwnMember(env, key) != null) return true;
|
||||||
if (own) return false;
|
if (own) return false;
|
||||||
@ -297,37 +296,37 @@ public abstract class Value {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
public final boolean hasMember(Environment env, Value key, boolean own) {
|
public default boolean hasMember(Environment env, Value key, boolean own) {
|
||||||
return hasMember(env, new KeyCache(key), own);
|
return hasMember(env, new KeyCache(key), own);
|
||||||
}
|
}
|
||||||
public final boolean hasMember(Environment env, String key, boolean own) {
|
public default boolean hasMember(Environment env, String key, boolean own) {
|
||||||
return hasMember(env, new KeyCache(key), own);
|
return hasMember(env, new KeyCache(key), own);
|
||||||
}
|
}
|
||||||
public final boolean hasMember(Environment env, int key, boolean own) {
|
public default boolean hasMember(Environment env, int key, boolean own) {
|
||||||
return hasMember(env, new KeyCache(key), own);
|
return hasMember(env, new KeyCache(key), own);
|
||||||
}
|
}
|
||||||
public final boolean hasMember(Environment env, double key, boolean own) {
|
public default boolean hasMember(Environment env, double key, boolean own) {
|
||||||
return hasMember(env, new KeyCache(key), own);
|
return hasMember(env, new KeyCache(key), own);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean deleteMember(Environment env, KeyCache key) {
|
public default boolean deleteMember(Environment env, KeyCache key) {
|
||||||
if (!hasMember(env, key, true)) return true;
|
if (!hasMember(env, key, true)) return true;
|
||||||
return deleteOwnMember(env, key);
|
return deleteOwnMember(env, key);
|
||||||
}
|
}
|
||||||
public final boolean deleteMember(Environment env, Value key) {
|
public default boolean deleteMember(Environment env, Value key) {
|
||||||
return deleteMember(env, new KeyCache(key));
|
return deleteMember(env, new KeyCache(key));
|
||||||
}
|
}
|
||||||
public final boolean deleteMember(Environment env, String key) {
|
public default boolean deleteMember(Environment env, String key) {
|
||||||
return deleteMember(env, new KeyCache(key));
|
return deleteMember(env, new KeyCache(key));
|
||||||
}
|
}
|
||||||
public final boolean deleteMember(Environment env, int key) {
|
public default boolean deleteMember(Environment env, int key) {
|
||||||
return deleteMember(env, new KeyCache(key));
|
return deleteMember(env, new KeyCache(key));
|
||||||
}
|
}
|
||||||
public final boolean deleteMember(Environment env, double key) {
|
public default boolean deleteMember(Environment env, double key) {
|
||||||
return deleteMember(env, new KeyCache(key));
|
return deleteMember(env, new KeyCache(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
public final Set<String> getMembers(Environment env, boolean own, boolean onlyEnumerable) {
|
public default Set<String> getMembers(Environment env, boolean own, boolean onlyEnumerable) {
|
||||||
var res = new LinkedHashSet<String>();
|
var res = new LinkedHashSet<String>();
|
||||||
var protos = new ArrayList<Value>();
|
var protos = new ArrayList<Value>();
|
||||||
|
|
||||||
@ -344,7 +343,7 @@ public abstract class Value {
|
|||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
public final Set<SymbolValue> getSymbolMembers(Environment env, boolean own, boolean onlyEnumerable) {
|
public default Set<SymbolValue> getSymbolMembers(Environment env, boolean own, boolean onlyEnumerable) {
|
||||||
var res = new LinkedHashSet<SymbolValue>();
|
var res = new LinkedHashSet<SymbolValue>();
|
||||||
var protos = new ArrayList<Value>();
|
var protos = new ArrayList<Value>();
|
||||||
|
|
||||||
@ -362,24 +361,24 @@ public abstract class Value {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final Value getMemberPath(Environment env, String ...path) {
|
public default Value getMemberPath(Environment env, String ...path) {
|
||||||
var res = this;
|
var res = this;
|
||||||
for (var key : path) res = res.getMember(env, key);
|
for (var key : path) res = res.getMember(env, key);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
public final Value getMemberPath(Environment env, Value ...path) {
|
public default Value getMemberPath(Environment env, Value ...path) {
|
||||||
var res = this;
|
var res = this;
|
||||||
for (var key : path) res = res.getMember(env, key);
|
for (var key : path) res = res.getMember(env, key);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
public final ObjectValue getMemberDescriptor(Environment env, Value key) {
|
public default ObjectValue getMemberDescriptor(Environment env, Value key) {
|
||||||
var member = getOwnMember(env, new KeyCache(key));
|
var member = getOwnMember(env, new KeyCache(key));
|
||||||
|
|
||||||
if (member != null) return member.descriptor(env, this);
|
if (member != null) return member.descriptor(env, this);
|
||||||
else return null;
|
else return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Iterable<Object> toIterable(Environment env) {
|
public default Iterable<Object> toIterable(Environment env) {
|
||||||
return () -> {
|
return () -> {
|
||||||
if (!(this instanceof FunctionValue)) return Collections.emptyIterator();
|
if (!(this instanceof FunctionValue)) return Collections.emptyIterator();
|
||||||
var func = (FunctionValue)this;
|
var func = (FunctionValue)this;
|
||||||
@ -418,29 +417,29 @@ public abstract class Value {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void callWith(Environment env, Iterable<? extends Value> it) {
|
public default void callWith(Environment env, Iterable<? extends Value> it) {
|
||||||
for (var el : it) {
|
for (var el : it) {
|
||||||
this.apply(env, Value.UNDEFINED, el);
|
this.apply(env, Value.UNDEFINED, el);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void callWithAsync(Environment env, Iterable<? extends Value> it, boolean async) {
|
public default void callWithAsync(Environment env, Iterable<? extends Value> it, boolean async) {
|
||||||
for (var el : it) {
|
for (var el : it) {
|
||||||
env.get(EventLoop.KEY).pushMsg(() -> this.apply(env, Value.UNDEFINED, el), true);
|
env.get(EventLoop.KEY).pushMsg(() -> this.apply(env, Value.UNDEFINED, el), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> toReadableLines(Environment env, HashSet<ObjectValue> passed) {
|
public default List<String> toReadableLines(Environment env, HashSet<ObjectValue> passed) {
|
||||||
return Arrays.asList(toString(env));
|
return Arrays.asList(toString(env));
|
||||||
}
|
}
|
||||||
|
|
||||||
public final String toReadable(Environment ext) {
|
public default String toReadable(Environment ext) {
|
||||||
return String.join("\n", toReadableLines(ext, new HashSet<>()));
|
return String.join("\n", toReadableLines(ext, new HashSet<>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Value global(Environment env) {
|
public static Value global(Environment env) {
|
||||||
return env.initFrom(GLOBAL, () -> new ObjectValue());
|
return env.initFrom(GLOBAL, () -> new ObjectValue());
|
||||||
}
|
}
|
||||||
public static final Map<String, Value> intrinsics(Environment env) {
|
public static Map<String, Value> intrinsics(Environment env) {
|
||||||
return env.initFrom(INTRINSICS, () -> new HashMap<>());
|
return env.initFrom(INTRINSICS, () -> new HashMap<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -457,7 +456,7 @@ public abstract class Value {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final boolean lessOrEqual(Environment env, Value a, Value b) {
|
public static boolean lessOrEqual(Environment env, Value a, Value b) {
|
||||||
a = a.toPrimitive(env);
|
a = a.toPrimitive(env);
|
||||||
b = b.toPrimitive(env);
|
b = b.toPrimitive(env);
|
||||||
|
|
||||||
@ -472,7 +471,7 @@ public abstract class Value {
|
|||||||
else return na.getDouble() <= nb.getDouble();
|
else return na.getDouble() <= nb.getDouble();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static final boolean greaterOrEqual(Environment env, Value a, Value b) {
|
public static boolean greaterOrEqual(Environment env, Value a, Value b) {
|
||||||
a = a.toPrimitive(env);
|
a = a.toPrimitive(env);
|
||||||
b = b.toPrimitive(env);
|
b = b.toPrimitive(env);
|
||||||
|
|
||||||
@ -487,7 +486,7 @@ public abstract class Value {
|
|||||||
else return na.getDouble() >= nb.getDouble();
|
else return na.getDouble() >= nb.getDouble();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static final boolean less(Environment env, Value a, Value b) {
|
public static boolean less(Environment env, Value a, Value b) {
|
||||||
a = a.toPrimitive(env);
|
a = a.toPrimitive(env);
|
||||||
b = b.toPrimitive(env);
|
b = b.toPrimitive(env);
|
||||||
|
|
||||||
@ -502,7 +501,7 @@ public abstract class Value {
|
|||||||
else return na.getDouble() < nb.getDouble();
|
else return na.getDouble() < nb.getDouble();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static final boolean greater(Environment env, Value a, Value b) {
|
public static boolean greater(Environment env, Value a, Value b) {
|
||||||
a = a.toPrimitive(env);
|
a = a.toPrimitive(env);
|
||||||
b = b.toPrimitive(env);
|
b = b.toPrimitive(env);
|
||||||
|
|
||||||
@ -518,7 +517,7 @@ public abstract class Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Value add(Environment env, Value a, Value b) {
|
public static Value add(Environment env, Value a, Value b) {
|
||||||
a = a.toPrimitive(env);
|
a = a.toPrimitive(env);
|
||||||
b = b.toPrimitive(env);
|
b = b.toPrimitive(env);
|
||||||
|
|
||||||
@ -534,21 +533,21 @@ public abstract class Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final NumberValue subtract(Environment env, Value a, Value b) {
|
public static NumberValue subtract(Environment env, Value a, Value b) {
|
||||||
var na = a.toNumber(env);
|
var na = a.toNumber(env);
|
||||||
var nb = b.toNumber(env);
|
var nb = b.toNumber(env);
|
||||||
|
|
||||||
if (na.isInt() && nb.isInt()) return NumberValue.of(na.getInt() - nb.getInt());
|
if (na.isInt() && nb.isInt()) return NumberValue.of(na.getInt() - nb.getInt());
|
||||||
else return NumberValue.of(na.getDouble() - nb.getDouble());
|
else return NumberValue.of(na.getDouble() - nb.getDouble());
|
||||||
}
|
}
|
||||||
public static final NumberValue multiply(Environment env, Value a, Value b) {
|
public static NumberValue multiply(Environment env, Value a, Value b) {
|
||||||
var na = a.toNumber(env);
|
var na = a.toNumber(env);
|
||||||
var nb = b.toNumber(env);
|
var nb = b.toNumber(env);
|
||||||
|
|
||||||
if (na.isInt() && nb.isInt()) return NumberValue.of(na.getInt() * nb.getInt());
|
if (na.isInt() && nb.isInt()) return NumberValue.of(na.getInt() * nb.getInt());
|
||||||
else return NumberValue.of(na.getDouble() * nb.getDouble());
|
else return NumberValue.of(na.getDouble() * nb.getDouble());
|
||||||
}
|
}
|
||||||
public static final NumberValue divide(Environment env, Value a, Value b) {
|
public static NumberValue divide(Environment env, Value a, Value b) {
|
||||||
var na = a.toNumber(env);
|
var na = a.toNumber(env);
|
||||||
var nb = b.toNumber(env);
|
var nb = b.toNumber(env);
|
||||||
|
|
||||||
@ -566,7 +565,7 @@ public abstract class Value {
|
|||||||
}
|
}
|
||||||
else return NumberValue.of(na.getDouble() / nb.getDouble());
|
else return NumberValue.of(na.getDouble() / nb.getDouble());
|
||||||
}
|
}
|
||||||
public static final NumberValue modulo(Environment env, Value a, Value b) {
|
public static NumberValue modulo(Environment env, Value a, Value b) {
|
||||||
var na = a.toNumber(env);
|
var na = a.toNumber(env);
|
||||||
var nb = b.toNumber(env);
|
var nb = b.toNumber(env);
|
||||||
|
|
||||||
@ -579,33 +578,33 @@ public abstract class Value {
|
|||||||
}
|
}
|
||||||
else return NumberValue.of(na.getDouble() % nb.getDouble());
|
else return NumberValue.of(na.getDouble() % nb.getDouble());
|
||||||
}
|
}
|
||||||
public static final NumberValue negative(Environment env, Value a) {
|
public static NumberValue negative(Environment env, Value a) {
|
||||||
var na = a.toNumber(env);
|
var na = a.toNumber(env);
|
||||||
|
|
||||||
if (na.isInt()) return NumberValue.of(-na.getInt());
|
if (na.isInt()) return NumberValue.of(-na.getInt());
|
||||||
else return NumberValue.of(-na.getDouble());
|
else return NumberValue.of(-na.getDouble());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final NumberValue and(Environment env, Value a, Value b) {
|
public static NumberValue and(Environment env, Value a, Value b) {
|
||||||
return NumberValue.of(a.toNumber(env).getInt() & b.toNumber(env).getInt());
|
return NumberValue.of(a.toNumber(env).getInt() & b.toNumber(env).getInt());
|
||||||
}
|
}
|
||||||
public static final NumberValue or(Environment env, Value a, Value b) {
|
public static NumberValue or(Environment env, Value a, Value b) {
|
||||||
return NumberValue.of(a.toNumber(env).getInt() | b.toNumber(env).getInt());
|
return NumberValue.of(a.toNumber(env).getInt() | b.toNumber(env).getInt());
|
||||||
}
|
}
|
||||||
public static final NumberValue xor(Environment env, Value a, Value b) {
|
public static NumberValue xor(Environment env, Value a, Value b) {
|
||||||
return NumberValue.of(a.toNumber(env).getInt() ^ b.toNumber(env).getInt());
|
return NumberValue.of(a.toNumber(env).getInt() ^ b.toNumber(env).getInt());
|
||||||
}
|
}
|
||||||
public static final NumberValue bitwiseNot(Environment env, Value a) {
|
public static NumberValue bitwiseNot(Environment env, Value a) {
|
||||||
return NumberValue.of(~a.toNumber(env).getInt());
|
return NumberValue.of(~a.toNumber(env).getInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final NumberValue shiftLeft(Environment env, Value a, Value b) {
|
public static NumberValue shiftLeft(Environment env, Value a, Value b) {
|
||||||
return NumberValue.of(a.toNumber(env).getInt() << b.toNumber(env).getInt());
|
return NumberValue.of(a.toNumber(env).getInt() << b.toNumber(env).getInt());
|
||||||
}
|
}
|
||||||
public static final NumberValue shiftRight(Environment env, Value a, Value b) {
|
public static NumberValue shiftRight(Environment env, Value a, Value b) {
|
||||||
return NumberValue.of(a.toNumber(env).getInt() >> b.toNumber(env).getInt());
|
return NumberValue.of(a.toNumber(env).getInt() >> b.toNumber(env).getInt());
|
||||||
}
|
}
|
||||||
public static final NumberValue unsignedShiftRight(Environment env, Value a, Value b) {
|
public static NumberValue unsignedShiftRight(Environment env, Value a, Value b) {
|
||||||
long _a = a.toNumber(env).getLong() & 0xFFFFFFFF;
|
long _a = a.toNumber(env).getLong() & 0xFFFFFFFF;
|
||||||
long _b = b.toNumber(env).getLong() & 0xFFFFFFFF;
|
long _b = b.toNumber(env).getLong() & 0xFFFFFFFF;
|
||||||
|
|
||||||
@ -615,7 +614,7 @@ public abstract class Value {
|
|||||||
return NumberValue.of(_a >>> _b);
|
return NumberValue.of(_a >>> _b);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final boolean looseEqual(Environment env, Value a, Value b) {
|
public static boolean looseEqual(Environment env, Value a, Value b) {
|
||||||
// In loose equality, null is equivalent to undefined
|
// In loose equality, null is equivalent to undefined
|
||||||
if (a instanceof VoidValue || b instanceof VoidValue) return a instanceof VoidValue && b instanceof VoidValue;
|
if (a instanceof VoidValue || b instanceof VoidValue) return a instanceof VoidValue && b instanceof VoidValue;
|
||||||
|
|
||||||
@ -637,7 +636,7 @@ public abstract class Value {
|
|||||||
return a.toString(env).equals(b.toString(env));
|
return a.toString(env).equals(b.toString(env));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String errorToReadable(Environment env, RuntimeException err, String prefix) {
|
public static String errorToReadable(Environment env, RuntimeException err, String prefix) {
|
||||||
prefix = prefix == null ? "Uncaught" : "Uncaught " + prefix;
|
prefix = prefix == null ? "Uncaught" : "Uncaught " + prefix;
|
||||||
if (err instanceof EngineException ee) {
|
if (err instanceof EngineException ee) {
|
||||||
if (env == null) env = ee.env;
|
if (env == null) env = ee.env;
|
||||||
|
@ -23,7 +23,7 @@ import me.topchetoeu.j2s.runtime.values.primitives.StringValue;
|
|||||||
import me.topchetoeu.j2s.runtime.values.primitives.SymbolValue;
|
import me.topchetoeu.j2s.runtime.values.primitives.SymbolValue;
|
||||||
import me.topchetoeu.j2s.runtime.values.primitives.numbers.NumberValue;
|
import me.topchetoeu.j2s.runtime.values.primitives.numbers.NumberValue;
|
||||||
|
|
||||||
public class ObjectValue extends Value {
|
public class ObjectValue implements Value {
|
||||||
public static interface PrototypeProvider {
|
public static interface PrototypeProvider {
|
||||||
public ObjectValue get(Environment env);
|
public ObjectValue get(Environment env);
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import me.topchetoeu.j2s.common.Environment;
|
|||||||
import me.topchetoeu.j2s.runtime.values.objects.ObjectValue;
|
import me.topchetoeu.j2s.runtime.values.objects.ObjectValue;
|
||||||
import me.topchetoeu.j2s.runtime.values.primitives.numbers.NumberValue;
|
import me.topchetoeu.j2s.runtime.values.primitives.numbers.NumberValue;
|
||||||
|
|
||||||
public final class BoolValue extends PrimitiveValue {
|
public final class BoolValue implements PrimitiveValue {
|
||||||
public static final BoolValue TRUE = new BoolValue(true);
|
public static final BoolValue TRUE = new BoolValue(true);
|
||||||
public static final BoolValue FALSE = new BoolValue(false);
|
public static final BoolValue FALSE = new BoolValue(false);
|
||||||
|
|
||||||
|
@ -11,30 +11,29 @@ import me.topchetoeu.j2s.runtime.values.Value;
|
|||||||
import me.topchetoeu.j2s.runtime.values.functions.FunctionValue;
|
import me.topchetoeu.j2s.runtime.values.functions.FunctionValue;
|
||||||
import me.topchetoeu.j2s.runtime.values.objects.ObjectValue;
|
import me.topchetoeu.j2s.runtime.values.objects.ObjectValue;
|
||||||
|
|
||||||
public abstract class PrimitiveValue extends Value {
|
public interface PrimitiveValue extends Value {
|
||||||
@Override public boolean defineOwnField(
|
public default boolean defineOwnField(
|
||||||
Environment env, KeyCache key, Value val,
|
Environment env, KeyCache key, Value val,
|
||||||
Boolean writable, Boolean enumerable, Boolean configurable
|
Boolean writable, Boolean enumerable, Boolean configurable
|
||||||
) { return false; }
|
) { return false; }
|
||||||
@Override
|
public default boolean defineOwnProperty(
|
||||||
public boolean defineOwnProperty(
|
|
||||||
Environment env, KeyCache key, Optional<FunctionValue> get, Optional<FunctionValue> set,
|
Environment env, KeyCache key, Optional<FunctionValue> get, Optional<FunctionValue> set,
|
||||||
Boolean enumerable, Boolean configurable
|
Boolean enumerable, Boolean configurable
|
||||||
) { return false; }
|
) { return false; }
|
||||||
@Override public boolean deleteOwnMember(Environment env, KeyCache key) { return true; }
|
public default boolean deleteOwnMember(Environment env, KeyCache key) { return true; }
|
||||||
|
|
||||||
@Override public final boolean isPrimitive() { return true; }
|
public default boolean isPrimitive() { return true; }
|
||||||
@Override public final Value toPrimitive(Environment env) { return this; }
|
public default Value toPrimitive(Environment env) { return this; }
|
||||||
|
|
||||||
@Override public final boolean setPrototype(Environment env, ObjectValue val) { return false; }
|
public default boolean setPrototype(Environment env, ObjectValue val) { return false; }
|
||||||
|
|
||||||
@Override public Member getOwnMember(Environment env, KeyCache key) { return null; }
|
public default Member getOwnMember(Environment env, KeyCache key) { return null; }
|
||||||
@Override public Set<String> getOwnMembers(Environment env, boolean onlyEnumerable) { return new HashSet<>(); }
|
public default Set<String> getOwnMembers(Environment env, boolean onlyEnumerable) { return new HashSet<>(); }
|
||||||
@Override public Set<SymbolValue> getOwnSymbolMembers(Environment env, boolean onlyEnumerable) { return new HashSet<>(); }
|
public default Set<SymbolValue> getOwnSymbolMembers(Environment env, boolean onlyEnumerable) { return new HashSet<>(); }
|
||||||
|
|
||||||
@Override public State getState() { return State.FROZEN; }
|
public default State getState() { return State.FROZEN; }
|
||||||
|
|
||||||
@Override public void preventExtensions() {}
|
public default void preventExtensions() {}
|
||||||
@Override public void seal() {}
|
public default void seal() {}
|
||||||
@Override public void freeze() {}
|
public default void freeze() {}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ import me.topchetoeu.j2s.runtime.values.Member.FieldMember;
|
|||||||
import me.topchetoeu.j2s.runtime.values.objects.ObjectValue;
|
import me.topchetoeu.j2s.runtime.values.objects.ObjectValue;
|
||||||
import me.topchetoeu.j2s.runtime.values.primitives.numbers.NumberValue;
|
import me.topchetoeu.j2s.runtime.values.primitives.numbers.NumberValue;
|
||||||
|
|
||||||
public final class StringValue extends PrimitiveValue {
|
public final class StringValue implements PrimitiveValue {
|
||||||
private static final WeakHashMap<String, StringValue> cache = new WeakHashMap<>();
|
private static final WeakHashMap<String, StringValue> cache = new WeakHashMap<>();
|
||||||
|
|
||||||
public final String value;
|
public final String value;
|
||||||
@ -57,13 +57,13 @@ public final class StringValue extends PrimitiveValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.getOwnMember(env, key);
|
return StringValue.this.getOwnMember(env, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public Set<String> getOwnMembers(Environment env, boolean onlyEnumerable) {
|
@Override public Set<String> getOwnMembers(Environment env, boolean onlyEnumerable) {
|
||||||
var res = new LinkedHashSet<String>();
|
var res = new LinkedHashSet<String>();
|
||||||
|
|
||||||
res.addAll(super.getOwnMembers(env, onlyEnumerable));
|
res.addAll(StringValue.this.getOwnMembers(env, onlyEnumerable));
|
||||||
|
|
||||||
for (var i = 0; i < value.length(); i++) res.add(i + "");
|
for (var i = 0; i < value.length(); i++) res.add(i + "");
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ import me.topchetoeu.j2s.runtime.values.Value;
|
|||||||
import me.topchetoeu.j2s.runtime.values.objects.ObjectValue;
|
import me.topchetoeu.j2s.runtime.values.objects.ObjectValue;
|
||||||
import me.topchetoeu.j2s.runtime.values.primitives.numbers.NumberValue;
|
import me.topchetoeu.j2s.runtime.values.primitives.numbers.NumberValue;
|
||||||
|
|
||||||
public final class SymbolValue extends PrimitiveValue {
|
public final class SymbolValue implements PrimitiveValue {
|
||||||
private static final HashMap<String, SymbolValue> registry = new HashMap<>();
|
private static final HashMap<String, SymbolValue> registry = new HashMap<>();
|
||||||
|
|
||||||
public final String value;
|
public final String value;
|
||||||
|
@ -15,7 +15,7 @@ import me.topchetoeu.j2s.runtime.values.functions.FunctionValue;
|
|||||||
import me.topchetoeu.j2s.runtime.values.objects.ObjectValue;
|
import me.topchetoeu.j2s.runtime.values.objects.ObjectValue;
|
||||||
import me.topchetoeu.j2s.runtime.values.primitives.numbers.NumberValue;
|
import me.topchetoeu.j2s.runtime.values.primitives.numbers.NumberValue;
|
||||||
|
|
||||||
public final class UserValue<T> extends Value {
|
public final class UserValue<T> implements Value {
|
||||||
public final T value;
|
public final T value;
|
||||||
public final ObjectValue prototype;
|
public final ObjectValue prototype;
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ import me.topchetoeu.j2s.runtime.values.Member;
|
|||||||
import me.topchetoeu.j2s.runtime.values.objects.ObjectValue;
|
import me.topchetoeu.j2s.runtime.values.objects.ObjectValue;
|
||||||
import me.topchetoeu.j2s.runtime.values.primitives.numbers.NumberValue;
|
import me.topchetoeu.j2s.runtime.values.primitives.numbers.NumberValue;
|
||||||
|
|
||||||
public final class VoidValue extends PrimitiveValue {
|
public final class VoidValue implements PrimitiveValue {
|
||||||
public final String name;
|
public final String name;
|
||||||
public final String type;
|
public final String type;
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ package me.topchetoeu.j2s.runtime.values.primitives.numbers;
|
|||||||
|
|
||||||
import me.topchetoeu.j2s.common.StringifyUtils;
|
import me.topchetoeu.j2s.common.StringifyUtils;
|
||||||
|
|
||||||
public final class DoubleValue extends NumberValue {
|
public final class DoubleValue implements NumberValue {
|
||||||
public final double value;
|
public final double value;
|
||||||
|
|
||||||
@Override public boolean isInt() {
|
@Override public boolean isInt() {
|
||||||
|
@ -7,7 +7,7 @@ import java.util.List;
|
|||||||
import me.topchetoeu.j2s.common.Environment;
|
import me.topchetoeu.j2s.common.Environment;
|
||||||
import me.topchetoeu.j2s.runtime.values.objects.ObjectValue;
|
import me.topchetoeu.j2s.runtime.values.objects.ObjectValue;
|
||||||
|
|
||||||
public final class IntValue extends NumberValue {
|
public final class IntValue implements NumberValue {
|
||||||
public final long value;
|
public final long value;
|
||||||
|
|
||||||
@Override public boolean isInt() {
|
@Override public boolean isInt() {
|
||||||
|
@ -5,10 +5,10 @@ import me.topchetoeu.j2s.runtime.values.objects.ObjectValue;
|
|||||||
import me.topchetoeu.j2s.runtime.values.primitives.PrimitiveValue;
|
import me.topchetoeu.j2s.runtime.values.primitives.PrimitiveValue;
|
||||||
import me.topchetoeu.j2s.runtime.values.primitives.StringValue;
|
import me.topchetoeu.j2s.runtime.values.primitives.StringValue;
|
||||||
|
|
||||||
public abstract class NumberValue extends PrimitiveValue {
|
public interface NumberValue extends PrimitiveValue {
|
||||||
public static final NumberValue NAN = new DoubleValue(Double.NaN);
|
public static final NumberValue NAN = new DoubleValue(Double.NaN);
|
||||||
|
|
||||||
@Override public final StringValue type() { return StringValue.of("number"); }
|
@Override public default StringValue type() { return StringValue.of("number"); }
|
||||||
|
|
||||||
public abstract double getDouble();
|
public abstract double getDouble();
|
||||||
public abstract int getInt();
|
public abstract int getInt();
|
||||||
@ -21,11 +21,11 @@ public abstract class NumberValue extends PrimitiveValue {
|
|||||||
public abstract String toString();
|
public abstract String toString();
|
||||||
|
|
||||||
|
|
||||||
@Override public final boolean toBoolean() { return getDouble() != 0; }
|
@Override public default boolean toBoolean() { return getDouble() != 0; }
|
||||||
@Override public final NumberValue toNumber(Environment ext) { return this; }
|
@Override public default NumberValue toNumber(Environment ext) { return this; }
|
||||||
@Override public final String toString(Environment ext) { return toString(); }
|
@Override public default String toString(Environment ext) { return toString(); }
|
||||||
|
|
||||||
@Override public final ObjectValue getPrototype(Environment env) {
|
@Override public default ObjectValue getPrototype(Environment env) {
|
||||||
return env.get(NUMBER_PROTO);
|
return env.get(NUMBER_PROTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user