Compare commits
14 Commits
testing
...
eb48507091
| Author | SHA1 | Date | |
|---|---|---|---|
| eb48507091 | |||
| 1410b025c5 | |||
| 5383e3fdf4 | |||
| 2f91528f25 | |||
| f50b365a5a | |||
| b1bf2e9688 | |||
| b355760fda | |||
| d16d6bd809 | |||
| a8ac07e8ab | |||
| 8f9e8f5b25 | |||
| e0fb187a7c | |||
| d15cd17f23 | |||
| f35f908175 | |||
| 3af5f15165 |
@@ -14,7 +14,9 @@
|
|||||||
<h3>Navigation</h3>
|
<h3>Navigation</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li><strong><a href="#core_concepts">Core Concepts</a></strong></li>
|
<li><strong><a href="#core_concepts">Core Concepts</a></strong></li>
|
||||||
<li><strong><a href="#types">Types</a></strong></li>
|
<li><strong><a href="#type_system">Type System</a></strong></li>
|
||||||
|
<li><a href="#value_types">Value Types</a></li>
|
||||||
|
<li><a href="#type_checker">Type Checker</a></li>
|
||||||
<li><strong><a href="#builtins">Built In Functions</a></strong></li>
|
<li><strong><a href="#builtins">Built In Functions</a></strong></li>
|
||||||
<li><a href="#input_string_msg__string">input(string msg) string</a></li>
|
<li><a href="#input_string_msg__string">input(string msg) string</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -44,6 +46,8 @@
|
|||||||
<li>Operators: these make up the actual logic of your program. Operators are thing like <code>+</code>, <code>=</code>, or <code>if</code>. (if and while are operators in Solstice.)</li>
|
<li>Operators: these make up the actual logic of your program. Operators are thing like <code>+</code>, <code>=</code>, or <code>if</code>. (if and while are operators in Solstice.)</li>
|
||||||
<li>Code blocks: this is the collection of values, identifiers, and operators, usually in between <code>{</code> and <code>}</code>.</li>
|
<li>Code blocks: this is the collection of values, identifiers, and operators, usually in between <code>{</code> and <code>}</code>.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<h3>Comments</h3>
|
||||||
|
<p>You can type <code>//</code> to insert a comment into your program. The rest of your line will be commented out.
|
||||||
<h3>puts</h3>
|
<h3>puts</h3>
|
||||||
<p>The <code>puts</code> command in Solstice is used to print out a value. It is not a function, but a built in operator, similar to <code>+</code> or <code>=</code>.</p>
|
<p>The <code>puts</code> command in Solstice is used to print out a value. It is not a function, but a built in operator, similar to <code>+</code> or <code>=</code>.</p>
|
||||||
<p>Use it like this:</p>
|
<p>Use it like this:</p>
|
||||||
@@ -56,9 +60,8 @@ puts "You can print out anything with puts!"</code></pre>
|
|||||||
<pre class="code"><code>x = 5<br>puts x</code></pre>
|
<pre class="code"><code>x = 5<br>puts x</code></pre>
|
||||||
<p>Types are automatically inferred by Solstice.</p>
|
<p>Types are automatically inferred by Solstice.</p>
|
||||||
<h3>Maths</h3>
|
<h3>Maths</h3>
|
||||||
<p>Note: math is currently in beta. Order of Operations is harder to implement than I thought lol</p>
|
|
||||||
<p>You can use <code>+</code> (add), <code>-</code> (subtract), <code>*</code> (multiply), and <code>/</code> (divide) to do math.</p>
|
<p>You can use <code>+</code> (add), <code>-</code> (subtract), <code>*</code> (multiply), and <code>/</code> (divide) to do math.</p>
|
||||||
<p>Math operations take two values on either side, and perform the operation.</p>
|
<p>Math operations take two values on either side, and perform the operation. Order of operations is supported.</p>
|
||||||
<pre class="code"><code>x = 5 + 3<br>y = 10<br>puts x + y</code></pre>
|
<pre class="code"><code>x = 5 + 3<br>y = 10<br>puts x + y</code></pre>
|
||||||
<h3>Control Flow and Equalities</h3>
|
<h3>Control Flow and Equalities</h3>
|
||||||
<p>Solstice supports <code>if</code> and <code>while</code> statements, as well as the <code>==</code>, <code>!=</code>, <code>></code>, <code>>=</code>, <code><</code>, and <code><=</code> operations.</p>
|
<p>Solstice supports <code>if</code> and <code>while</code> statements, as well as the <code>==</code>, <code>!=</code>, <code>></code>, <code>>=</code>, <code><</code>, and <code><=</code> operations.</p>
|
||||||
@@ -72,7 +75,7 @@ if x > 10 {
|
|||||||
if x < 10 {
|
if x < 10 {
|
||||||
puts "x is smaller than 10"
|
puts "x is smaller than 10"
|
||||||
}
|
}
|
||||||
if x == 0 {
|
if x == 10 {
|
||||||
puts "x is 10"
|
puts "x is 10"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,14 +86,24 @@ while number < 10 {
|
|||||||
puts number
|
puts number
|
||||||
}</<code></pre>
|
}</<code></pre>
|
||||||
</code>
|
</code>
|
||||||
|
<h3>Functions</h3>
|
||||||
|
<p><strong>Note:</strong> Functions in Solstice are currently in beta. Type checking for functions is currently experimental, and arguments may not work as intended. Be warned!</p>
|
||||||
|
<p>In Solstice, function definitions have a syntax like this: <pre class="code"><code>def functionName(type arg1, type arg2, type arg3) returnType {<br> // code goes here<br>}</code></pre></p>
|
||||||
|
<p>Your types can be <code>int</code>, <code>double</code>, <code>string</code>, <code>bool</code>, or <code>char</code> (see the "Type System" section for more details)</p>
|
||||||
|
<p>Return a value (which must be the same type as your <code>returnType</code>) with <code>return value</code>.</p>
|
||||||
|
<p>Here's an example function:</p>
|
||||||
|
<pre class="code"><code>def add(int a, int b) int {
|
||||||
|
return a + b
|
||||||
|
}</code></pre>
|
||||||
<h3>Calling Functions</h3>
|
<h3>Calling Functions</h3>
|
||||||
<p>Function calling is done like in most other programming languages, with the syntax <code>function(arg1, arg2, arg3)</code>.</p>
|
<p>Function calling is done like in most other programming languages, with the syntax <code>function(arg1, arg2, arg3)</code>.</p>
|
||||||
<h3>That's it!</h3>
|
<h3>That's it!</h3>
|
||||||
<p>You now know everything you need to know about Solstice to start programming! You can continue reading for more information.</p>
|
<p>You now know everything you need to know about Solstice to start programming! You can continue reading for more information.</p>
|
||||||
</div>
|
</div>
|
||||||
<div id="types">
|
<div id="type_system">
|
||||||
<h2>Types</h2>
|
<h2>Type System</h2>
|
||||||
<p>Solstice's type system is currently a work in progress, but what is so far implemented will be detailed.</p>
|
<p>Solstice's type system is currently a work in progress, but what is so far implemented will be detailed.</p>
|
||||||
|
<div id="value_types">
|
||||||
<h3>Value Types</h3>
|
<h3>Value Types</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>int</code>: Signed 64 bit integer</li>
|
<li><code>int</code>: Signed 64 bit integer</li>
|
||||||
@@ -100,6 +113,26 @@ while number < 10 {
|
|||||||
<li><code>bool</code>: Either true or false</li>
|
<li><code>bool</code>: Either true or false</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="type_checker">
|
||||||
|
<h3>Type Checker</h3>
|
||||||
|
<p>Solstice statically checks types at compile time to ensure your data is used as intended. These are the details of the type checker.</p>
|
||||||
|
<ul>
|
||||||
|
<li>Types of variables when setting with <code>=</code> are autoinferred and cannot be provided by the user. All variables must have a value.</li>
|
||||||
|
<li>When setting a variable with <code>=</code>, it's type must not mutate in any way.</li>
|
||||||
|
<li>Functions must have types annotated. There is no "any" type.</li>
|
||||||
|
<li>When using operators, integers are able to promote to doubles where required. No other types can automatically convert.</li>
|
||||||
|
<li>All equality operators require the same type on both sides of the equality.</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="inline_ground">
|
||||||
|
<h2>Inline Ground</h2>
|
||||||
|
<p>Since Solstice is built atop Ground, you can write Ground code inside Solstice code, usually to wrap a Ground function for the Solstice standard library.</p>
|
||||||
|
<p>Inline Ground is not vetted by the type checker. <strong>Be careful when modifying existing variables with inline ground!</strong> The type checker is not aware of any values created inside inline Ground.</p>
|
||||||
|
<p>If you would like the Solstice type checker to be aware of values created by Ground, initialise a variable with a blank of whatever type is made by Ground.</p>
|
||||||
|
<p>Variable names are the same inside inline Ground as they are in Solstice. Read Ground's syntax guide for an understanding on how it should work <a href="https://chookspace.com/ground/cground/src/branch/master/docs/syntax.md">here</a>.</p>
|
||||||
|
<pre class="code"><code>ground {<br> set &x 5<br> println $x<br>}</code></pre>
|
||||||
|
</div>
|
||||||
<div id="builtins">
|
<div id="builtins">
|
||||||
<h2>Built In Functions</h2>
|
<h2>Built In Functions</h2>
|
||||||
<div id="input_string_msg__string">
|
<div id="input_string_msg__string">
|
||||||
@@ -107,6 +140,16 @@ while number < 10 {
|
|||||||
<p>Gets user input from the console until the next line. The msg is used as a prompt for the user. Returns inputted characters from the console.</p>
|
<p>Gets user input from the console until the next line. The msg is used as a prompt for the user. Returns inputted characters from the console.</p>
|
||||||
<pre class="code"><code>guess = input("What is the password? ")<br>if guess == "password123" {<br> puts "Good job!"<br>}</code></pre>
|
<pre class="code"><code>guess = input("What is the password? ")<br>if guess == "password123" {<br> puts "Good job!"<br>}</code></pre>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="print_string_msg__string">
|
||||||
|
<h3>print(string msg) string</h3>
|
||||||
|
<p>Prints a string to the console.</p>
|
||||||
|
<pre class="code"><code>print("Hello, World!")</code></pre>
|
||||||
|
</div>
|
||||||
|
<div id="println_string_msg__string">
|
||||||
|
<h3>println(string msg) string</h3>
|
||||||
|
<p>Prints a string to the console. Appends a new line afterwards.</p>
|
||||||
|
<pre class="code"><code>println("Hello, World!")</code></pre>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
1
docs/node_modules/.mf/cf.json
generated
vendored
Normal file
1
docs/node_modules/.mf/cf.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"httpProtocol":"HTTP/1.1","clientAcceptEncoding":"gzip, deflate, br","requestPriority":"","edgeRequestKeepAliveStatus":1,"requestHeaderNames":{},"clientTcpRtt":12,"colo":"SYD","asn":9443,"asOrganization":"Vocus","country":"AU","isEUCountry":false,"city":"Sydney","continent":"OC","region":"New South Wales","regionCode":"NSW","timezone":"Australia/Sydney","longitude":"151.20732","latitude":"-33.86785","postalCode":"1001","tlsVersion":"TLSv1.3","tlsCipher":"AEAD-AES256-GCM-SHA384","tlsClientRandom":"daX8oL41wKEGQv5d7pl4Gz+FvxZY9qRPz8AwU1lq8WE=","tlsClientCiphersSha1":"kXrN3VEKDdzz2cPKTQaKzpxVTxQ=","tlsClientExtensionsSha1":"1eY97BUYYO8vDaTfHQywB1pcNdM=","tlsClientExtensionsSha1Le":"u4wtEMFQBY18l3BzHAvORm+KGRw=","tlsExportedAuthenticator":{"clientHandshake":"a677c57d6ea9007a40767d4e57b68c110114325d39d60b2863517e495f5fedb47b6d65db6b0b732420c3a845ebb9b7b7","serverHandshake":"290d01a7b75e9b8739f14abab625c4d18a458ef4c344c21deb141ecffdff506b7c06bd96ce86ac94b6600c255d8d6daa","clientFinished":"0635e92b7ba2caac307410878e7c35778b416890d460bf90703cc6c5ce869e41c1a62fe172c6ceffb734bbc20b41f426","serverFinished":"43843c9f186775a525ccd2c5e0769602e4572abca8075253c01eb26cb908e0c5281c55dbb3a93302a2304a7a45546e73"},"tlsClientHelloLength":"1603","tlsClientAuth":{"certPresented":"0","certVerified":"NONE","certRevoked":"0","certIssuerDN":"","certSubjectDN":"","certIssuerDNRFC2253":"","certSubjectDNRFC2253":"","certIssuerDNLegacy":"","certSubjectDNLegacy":"","certSerial":"","certIssuerSerial":"","certSKI":"","certIssuerSKI":"","certFingerprintSHA1":"","certFingerprintSHA256":"","certNotBefore":"","certNotAfter":""},"verifiedBotCategory":"","botManagement":{"corporateProxy":false,"verifiedBot":false,"jsDetection":{"passed":false},"staticResource":false,"detectionIds":{},"score":99}}
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
<div class="feature-row">
|
<div class="feature-row">
|
||||||
<div class="feature">
|
<div class="feature">
|
||||||
<h3>Small and fast</h3>
|
<h3>Small and fast</h3>
|
||||||
<p>Solstice's compiler is 1216 lines of C++, and compiles code at lightning speed.</p>
|
<p>Solstice's compiler is 1833 lines of C++, and compiles code at lightning speed.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="feature">
|
<div class="feature">
|
||||||
<h3>Built on Ground</h3>
|
<h3>Built on Ground</h3>
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ then
|
|||||||
exit 0;
|
exit 0;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! command -v gmake 2>&1 >/dev/null
|
if ! command -v make 2>&1 >/dev/null
|
||||||
then
|
then
|
||||||
echo "gmake is not installed on your system. Install it with your package manager (or on macOS use xcode-select)"
|
echo "make is not installed on your system. Install it with your package manager (or on macOS use xcode-select)"
|
||||||
exit 0;
|
exit 0;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -20,8 +20,7 @@
|
|||||||
<textarea class="code" id="editor" spellcheck="false" placeholder="Enter Solstice code here..." rows="20">
|
<textarea class="code" id="editor" spellcheck="false" placeholder="Enter Solstice code here..." rows="20">
|
||||||
puts "Hello from Solstice via WebAssembly!"
|
puts "Hello from Solstice via WebAssembly!"
|
||||||
puts "Let's do some math:"
|
puts "Let's do some math:"
|
||||||
puts 10 + 20 + 12
|
puts 10 + 20 + 12</textarea>
|
||||||
</textarea>
|
|
||||||
|
|
||||||
<div id="controls">
|
<div id="controls">
|
||||||
<button id="runBtn" style="font-size: 20px;">Loading WASM...</button>
|
<button id="runBtn" style="font-size: 20px;">Loading WASM...</button>
|
||||||
|
|||||||
@@ -1167,183 +1167,6 @@ function dbg(...args) {
|
|||||||
assert(false, 'Exception thrown, but exception catching is not enabled. Compile with -sNO_DISABLE_EXCEPTION_CATCHING or -sEXCEPTION_CATCHING_ALLOWED=[..] to catch.');
|
assert(false, 'Exception thrown, but exception catching is not enabled. Compile with -sNO_DISABLE_EXCEPTION_CATCHING or -sEXCEPTION_CATCHING_ALLOWED=[..] to catch.');
|
||||||
};
|
};
|
||||||
|
|
||||||
var _abort = () => {
|
|
||||||
abort('native code called abort()');
|
|
||||||
};
|
|
||||||
|
|
||||||
var _emscripten_memcpy_js = (dest, src, num) => HEAPU8.copyWithin(dest, src, src + num);
|
|
||||||
|
|
||||||
var getHeapMax = () =>
|
|
||||||
// Stay one Wasm page short of 4GB: while e.g. Chrome is able to allocate
|
|
||||||
// full 4GB Wasm memories, the size will wrap back to 0 bytes in Wasm side
|
|
||||||
// for any code that deals with heap sizes, which would require special
|
|
||||||
// casing all heap size related code to treat 0 specially.
|
|
||||||
2147483648;
|
|
||||||
|
|
||||||
var growMemory = (size) => {
|
|
||||||
var b = wasmMemory.buffer;
|
|
||||||
var pages = (size - b.byteLength + 65535) / 65536;
|
|
||||||
try {
|
|
||||||
// round size grow request up to wasm page size (fixed 64KB per spec)
|
|
||||||
wasmMemory.grow(pages); // .grow() takes a delta compared to the previous size
|
|
||||||
updateMemoryViews();
|
|
||||||
return 1 /*success*/;
|
|
||||||
} catch(e) {
|
|
||||||
err(`growMemory: Attempted to grow heap from ${b.byteLength} bytes to ${size} bytes, but got error: ${e}`);
|
|
||||||
}
|
|
||||||
// implicit 0 return to save code size (caller will cast "undefined" into 0
|
|
||||||
// anyhow)
|
|
||||||
};
|
|
||||||
var _emscripten_resize_heap = (requestedSize) => {
|
|
||||||
var oldSize = HEAPU8.length;
|
|
||||||
// With CAN_ADDRESS_2GB or MEMORY64, pointers are already unsigned.
|
|
||||||
requestedSize >>>= 0;
|
|
||||||
// With multithreaded builds, races can happen (another thread might increase the size
|
|
||||||
// in between), so return a failure, and let the caller retry.
|
|
||||||
assert(requestedSize > oldSize);
|
|
||||||
|
|
||||||
// Memory resize rules:
|
|
||||||
// 1. Always increase heap size to at least the requested size, rounded up
|
|
||||||
// to next page multiple.
|
|
||||||
// 2a. If MEMORY_GROWTH_LINEAR_STEP == -1, excessively resize the heap
|
|
||||||
// geometrically: increase the heap size according to
|
|
||||||
// MEMORY_GROWTH_GEOMETRIC_STEP factor (default +20%), At most
|
|
||||||
// overreserve by MEMORY_GROWTH_GEOMETRIC_CAP bytes (default 96MB).
|
|
||||||
// 2b. If MEMORY_GROWTH_LINEAR_STEP != -1, excessively resize the heap
|
|
||||||
// linearly: increase the heap size by at least
|
|
||||||
// MEMORY_GROWTH_LINEAR_STEP bytes.
|
|
||||||
// 3. Max size for the heap is capped at 2048MB-WASM_PAGE_SIZE, or by
|
|
||||||
// MAXIMUM_MEMORY, or by ASAN limit, depending on which is smallest
|
|
||||||
// 4. If we were unable to allocate as much memory, it may be due to
|
|
||||||
// over-eager decision to excessively reserve due to (3) above.
|
|
||||||
// Hence if an allocation fails, cut down on the amount of excess
|
|
||||||
// growth, in an attempt to succeed to perform a smaller allocation.
|
|
||||||
|
|
||||||
// A limit is set for how much we can grow. We should not exceed that
|
|
||||||
// (the wasm binary specifies it, so if we tried, we'd fail anyhow).
|
|
||||||
var maxHeapSize = getHeapMax();
|
|
||||||
if (requestedSize > maxHeapSize) {
|
|
||||||
err(`Cannot enlarge memory, requested ${requestedSize} bytes, but the limit is ${maxHeapSize} bytes!`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var alignUp = (x, multiple) => x + (multiple - x % multiple) % multiple;
|
|
||||||
|
|
||||||
// Loop through potential heap size increases. If we attempt a too eager
|
|
||||||
// reservation that fails, cut down on the attempted size and reserve a
|
|
||||||
// smaller bump instead. (max 3 times, chosen somewhat arbitrarily)
|
|
||||||
for (var cutDown = 1; cutDown <= 4; cutDown *= 2) {
|
|
||||||
var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown); // ensure geometric growth
|
|
||||||
// but limit overreserving (default to capping at +96MB overgrowth at most)
|
|
||||||
overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296 );
|
|
||||||
|
|
||||||
var newSize = Math.min(maxHeapSize, alignUp(Math.max(requestedSize, overGrownHeapSize), 65536));
|
|
||||||
|
|
||||||
var replacement = growMemory(newSize);
|
|
||||||
if (replacement) {
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err(`Failed to grow the heap from ${oldSize} bytes to ${newSize} bytes, not enough memory!`);
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
var ENV = {
|
|
||||||
};
|
|
||||||
|
|
||||||
var getExecutableName = () => {
|
|
||||||
return thisProgram || './this.program';
|
|
||||||
};
|
|
||||||
var getEnvStrings = () => {
|
|
||||||
if (!getEnvStrings.strings) {
|
|
||||||
// Default values.
|
|
||||||
// Browser language detection #8751
|
|
||||||
var lang = ((typeof navigator == 'object' && navigator.languages && navigator.languages[0]) || 'C').replace('-', '_') + '.UTF-8';
|
|
||||||
var env = {
|
|
||||||
'USER': 'web_user',
|
|
||||||
'LOGNAME': 'web_user',
|
|
||||||
'PATH': '/',
|
|
||||||
'PWD': '/',
|
|
||||||
'HOME': '/home/web_user',
|
|
||||||
'LANG': lang,
|
|
||||||
'_': getExecutableName()
|
|
||||||
};
|
|
||||||
// Apply the user-provided values, if any.
|
|
||||||
for (var x in ENV) {
|
|
||||||
// x is a key in ENV; if ENV[x] is undefined, that means it was
|
|
||||||
// explicitly set to be so. We allow user code to do that to
|
|
||||||
// force variables with default values to remain unset.
|
|
||||||
if (ENV[x] === undefined) delete env[x];
|
|
||||||
else env[x] = ENV[x];
|
|
||||||
}
|
|
||||||
var strings = [];
|
|
||||||
for (var x in env) {
|
|
||||||
strings.push(`${x}=${env[x]}`);
|
|
||||||
}
|
|
||||||
getEnvStrings.strings = strings;
|
|
||||||
}
|
|
||||||
return getEnvStrings.strings;
|
|
||||||
};
|
|
||||||
|
|
||||||
var stringToAscii = (str, buffer) => {
|
|
||||||
for (var i = 0; i < str.length; ++i) {
|
|
||||||
assert(str.charCodeAt(i) === (str.charCodeAt(i) & 0xff));
|
|
||||||
HEAP8[buffer++] = str.charCodeAt(i);
|
|
||||||
}
|
|
||||||
// Null-terminate the string
|
|
||||||
HEAP8[buffer] = 0;
|
|
||||||
};
|
|
||||||
var _environ_get = (__environ, environ_buf) => {
|
|
||||||
var bufSize = 0;
|
|
||||||
getEnvStrings().forEach((string, i) => {
|
|
||||||
var ptr = environ_buf + bufSize;
|
|
||||||
HEAPU32[(((__environ)+(i*4))>>2)] = ptr;
|
|
||||||
stringToAscii(string, ptr);
|
|
||||||
bufSize += string.length + 1;
|
|
||||||
});
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
var _environ_sizes_get = (penviron_count, penviron_buf_size) => {
|
|
||||||
var strings = getEnvStrings();
|
|
||||||
HEAPU32[((penviron_count)>>2)] = strings.length;
|
|
||||||
var bufSize = 0;
|
|
||||||
strings.forEach((string) => bufSize += string.length + 1);
|
|
||||||
HEAPU32[((penviron_buf_size)>>2)] = bufSize;
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
var runtimeKeepaliveCounter = 0;
|
|
||||||
var keepRuntimeAlive = () => noExitRuntime || runtimeKeepaliveCounter > 0;
|
|
||||||
var _proc_exit = (code) => {
|
|
||||||
EXITSTATUS = code;
|
|
||||||
if (!keepRuntimeAlive()) {
|
|
||||||
Module['onExit']?.(code);
|
|
||||||
ABORT = true;
|
|
||||||
}
|
|
||||||
quit_(code, new ExitStatus(code));
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @suppress {duplicate } */
|
|
||||||
/** @param {boolean|number=} implicit */
|
|
||||||
var exitJS = (status, implicit) => {
|
|
||||||
EXITSTATUS = status;
|
|
||||||
|
|
||||||
checkUnflushedContent();
|
|
||||||
|
|
||||||
// if exit() was called explicitly, warn the user if the runtime isn't actually being shut down
|
|
||||||
if (keepRuntimeAlive() && !implicit) {
|
|
||||||
var msg = `program exited (with status: ${status}), but keepRuntimeAlive() is set (counter=${runtimeKeepaliveCounter}) due to an async operation, so halting execution but not exiting the runtime or preventing further async execution (you can use emscripten_force_exit, if you want to force a true shutdown)`;
|
|
||||||
readyPromiseReject(msg);
|
|
||||||
err(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
_proc_exit(status);
|
|
||||||
};
|
|
||||||
var _exit = exitJS;
|
|
||||||
|
|
||||||
var PATH = {
|
var PATH = {
|
||||||
isAbs:(path) => path.charAt(0) === '/',
|
isAbs:(path) => path.charAt(0) === '/',
|
||||||
splitPath:(filename) => {
|
splitPath:(filename) => {
|
||||||
@@ -4208,6 +4031,367 @@ function dbg(...args) {
|
|||||||
return stream;
|
return stream;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
function ___syscall_faccessat(dirfd, path, amode, flags) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
path = SYSCALLS.getStr(path);
|
||||||
|
assert(flags === 0);
|
||||||
|
path = SYSCALLS.calculateAt(dirfd, path);
|
||||||
|
if (amode & ~7) {
|
||||||
|
// need a valid mode
|
||||||
|
return -28;
|
||||||
|
}
|
||||||
|
var lookup = FS.lookupPath(path, { follow: true });
|
||||||
|
var node = lookup.node;
|
||||||
|
if (!node) {
|
||||||
|
return -44;
|
||||||
|
}
|
||||||
|
var perms = '';
|
||||||
|
if (amode & 4) perms += 'r';
|
||||||
|
if (amode & 2) perms += 'w';
|
||||||
|
if (amode & 1) perms += 'x';
|
||||||
|
if (perms /* otherwise, they've just passed F_OK */ && FS.nodePermissions(node, perms)) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} catch (e) {
|
||||||
|
if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
|
||||||
|
return -e.errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ___syscall_fcntl64(fd, cmd, varargs) {
|
||||||
|
SYSCALLS.varargs = varargs;
|
||||||
|
try {
|
||||||
|
|
||||||
|
var stream = SYSCALLS.getStreamFromFD(fd);
|
||||||
|
switch (cmd) {
|
||||||
|
case 0: {
|
||||||
|
var arg = SYSCALLS.get();
|
||||||
|
if (arg < 0) {
|
||||||
|
return -28;
|
||||||
|
}
|
||||||
|
while (FS.streams[arg]) {
|
||||||
|
arg++;
|
||||||
|
}
|
||||||
|
var newStream;
|
||||||
|
newStream = FS.dupStream(stream, arg);
|
||||||
|
return newStream.fd;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
return 0; // FD_CLOEXEC makes no sense for a single process.
|
||||||
|
case 3:
|
||||||
|
return stream.flags;
|
||||||
|
case 4: {
|
||||||
|
var arg = SYSCALLS.get();
|
||||||
|
stream.flags |= arg;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case 12: {
|
||||||
|
var arg = SYSCALLS.getp();
|
||||||
|
var offset = 0;
|
||||||
|
// We're always unlocked.
|
||||||
|
HEAP16[(((arg)+(offset))>>1)] = 2;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case 13:
|
||||||
|
case 14:
|
||||||
|
return 0; // Pretend that the locking is successful.
|
||||||
|
}
|
||||||
|
return -28;
|
||||||
|
} catch (e) {
|
||||||
|
if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
|
||||||
|
return -e.errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ___syscall_ioctl(fd, op, varargs) {
|
||||||
|
SYSCALLS.varargs = varargs;
|
||||||
|
try {
|
||||||
|
|
||||||
|
var stream = SYSCALLS.getStreamFromFD(fd);
|
||||||
|
switch (op) {
|
||||||
|
case 21509: {
|
||||||
|
if (!stream.tty) return -59;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case 21505: {
|
||||||
|
if (!stream.tty) return -59;
|
||||||
|
if (stream.tty.ops.ioctl_tcgets) {
|
||||||
|
var termios = stream.tty.ops.ioctl_tcgets(stream);
|
||||||
|
var argp = SYSCALLS.getp();
|
||||||
|
HEAP32[((argp)>>2)] = termios.c_iflag || 0;
|
||||||
|
HEAP32[(((argp)+(4))>>2)] = termios.c_oflag || 0;
|
||||||
|
HEAP32[(((argp)+(8))>>2)] = termios.c_cflag || 0;
|
||||||
|
HEAP32[(((argp)+(12))>>2)] = termios.c_lflag || 0;
|
||||||
|
for (var i = 0; i < 32; i++) {
|
||||||
|
HEAP8[(argp + i)+(17)] = termios.c_cc[i] || 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case 21510:
|
||||||
|
case 21511:
|
||||||
|
case 21512: {
|
||||||
|
if (!stream.tty) return -59;
|
||||||
|
return 0; // no-op, not actually adjusting terminal settings
|
||||||
|
}
|
||||||
|
case 21506:
|
||||||
|
case 21507:
|
||||||
|
case 21508: {
|
||||||
|
if (!stream.tty) return -59;
|
||||||
|
if (stream.tty.ops.ioctl_tcsets) {
|
||||||
|
var argp = SYSCALLS.getp();
|
||||||
|
var c_iflag = HEAP32[((argp)>>2)];
|
||||||
|
var c_oflag = HEAP32[(((argp)+(4))>>2)];
|
||||||
|
var c_cflag = HEAP32[(((argp)+(8))>>2)];
|
||||||
|
var c_lflag = HEAP32[(((argp)+(12))>>2)];
|
||||||
|
var c_cc = []
|
||||||
|
for (var i = 0; i < 32; i++) {
|
||||||
|
c_cc.push(HEAP8[(argp + i)+(17)]);
|
||||||
|
}
|
||||||
|
return stream.tty.ops.ioctl_tcsets(stream.tty, op, { c_iflag, c_oflag, c_cflag, c_lflag, c_cc });
|
||||||
|
}
|
||||||
|
return 0; // no-op, not actually adjusting terminal settings
|
||||||
|
}
|
||||||
|
case 21519: {
|
||||||
|
if (!stream.tty) return -59;
|
||||||
|
var argp = SYSCALLS.getp();
|
||||||
|
HEAP32[((argp)>>2)] = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case 21520: {
|
||||||
|
if (!stream.tty) return -59;
|
||||||
|
return -28; // not supported
|
||||||
|
}
|
||||||
|
case 21531: {
|
||||||
|
var argp = SYSCALLS.getp();
|
||||||
|
return FS.ioctl(stream, op, argp);
|
||||||
|
}
|
||||||
|
case 21523: {
|
||||||
|
// TODO: in theory we should write to the winsize struct that gets
|
||||||
|
// passed in, but for now musl doesn't read anything on it
|
||||||
|
if (!stream.tty) return -59;
|
||||||
|
if (stream.tty.ops.ioctl_tiocgwinsz) {
|
||||||
|
var winsize = stream.tty.ops.ioctl_tiocgwinsz(stream.tty);
|
||||||
|
var argp = SYSCALLS.getp();
|
||||||
|
HEAP16[((argp)>>1)] = winsize[0];
|
||||||
|
HEAP16[(((argp)+(2))>>1)] = winsize[1];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case 21524: {
|
||||||
|
// TODO: technically, this ioctl call should change the window size.
|
||||||
|
// but, since emscripten doesn't have any concept of a terminal window
|
||||||
|
// yet, we'll just silently throw it away as we do TIOCGWINSZ
|
||||||
|
if (!stream.tty) return -59;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case 21515: {
|
||||||
|
if (!stream.tty) return -59;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
default: return -28; // not supported
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
|
||||||
|
return -e.errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ___syscall_openat(dirfd, path, flags, varargs) {
|
||||||
|
SYSCALLS.varargs = varargs;
|
||||||
|
try {
|
||||||
|
|
||||||
|
path = SYSCALLS.getStr(path);
|
||||||
|
path = SYSCALLS.calculateAt(dirfd, path);
|
||||||
|
var mode = varargs ? SYSCALLS.get() : 0;
|
||||||
|
return FS.open(path, flags, mode).fd;
|
||||||
|
} catch (e) {
|
||||||
|
if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
|
||||||
|
return -e.errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _abort = () => {
|
||||||
|
abort('native code called abort()');
|
||||||
|
};
|
||||||
|
|
||||||
|
var _emscripten_memcpy_js = (dest, src, num) => HEAPU8.copyWithin(dest, src, src + num);
|
||||||
|
|
||||||
|
var getHeapMax = () =>
|
||||||
|
// Stay one Wasm page short of 4GB: while e.g. Chrome is able to allocate
|
||||||
|
// full 4GB Wasm memories, the size will wrap back to 0 bytes in Wasm side
|
||||||
|
// for any code that deals with heap sizes, which would require special
|
||||||
|
// casing all heap size related code to treat 0 specially.
|
||||||
|
2147483648;
|
||||||
|
|
||||||
|
var growMemory = (size) => {
|
||||||
|
var b = wasmMemory.buffer;
|
||||||
|
var pages = (size - b.byteLength + 65535) / 65536;
|
||||||
|
try {
|
||||||
|
// round size grow request up to wasm page size (fixed 64KB per spec)
|
||||||
|
wasmMemory.grow(pages); // .grow() takes a delta compared to the previous size
|
||||||
|
updateMemoryViews();
|
||||||
|
return 1 /*success*/;
|
||||||
|
} catch(e) {
|
||||||
|
err(`growMemory: Attempted to grow heap from ${b.byteLength} bytes to ${size} bytes, but got error: ${e}`);
|
||||||
|
}
|
||||||
|
// implicit 0 return to save code size (caller will cast "undefined" into 0
|
||||||
|
// anyhow)
|
||||||
|
};
|
||||||
|
var _emscripten_resize_heap = (requestedSize) => {
|
||||||
|
var oldSize = HEAPU8.length;
|
||||||
|
// With CAN_ADDRESS_2GB or MEMORY64, pointers are already unsigned.
|
||||||
|
requestedSize >>>= 0;
|
||||||
|
// With multithreaded builds, races can happen (another thread might increase the size
|
||||||
|
// in between), so return a failure, and let the caller retry.
|
||||||
|
assert(requestedSize > oldSize);
|
||||||
|
|
||||||
|
// Memory resize rules:
|
||||||
|
// 1. Always increase heap size to at least the requested size, rounded up
|
||||||
|
// to next page multiple.
|
||||||
|
// 2a. If MEMORY_GROWTH_LINEAR_STEP == -1, excessively resize the heap
|
||||||
|
// geometrically: increase the heap size according to
|
||||||
|
// MEMORY_GROWTH_GEOMETRIC_STEP factor (default +20%), At most
|
||||||
|
// overreserve by MEMORY_GROWTH_GEOMETRIC_CAP bytes (default 96MB).
|
||||||
|
// 2b. If MEMORY_GROWTH_LINEAR_STEP != -1, excessively resize the heap
|
||||||
|
// linearly: increase the heap size by at least
|
||||||
|
// MEMORY_GROWTH_LINEAR_STEP bytes.
|
||||||
|
// 3. Max size for the heap is capped at 2048MB-WASM_PAGE_SIZE, or by
|
||||||
|
// MAXIMUM_MEMORY, or by ASAN limit, depending on which is smallest
|
||||||
|
// 4. If we were unable to allocate as much memory, it may be due to
|
||||||
|
// over-eager decision to excessively reserve due to (3) above.
|
||||||
|
// Hence if an allocation fails, cut down on the amount of excess
|
||||||
|
// growth, in an attempt to succeed to perform a smaller allocation.
|
||||||
|
|
||||||
|
// A limit is set for how much we can grow. We should not exceed that
|
||||||
|
// (the wasm binary specifies it, so if we tried, we'd fail anyhow).
|
||||||
|
var maxHeapSize = getHeapMax();
|
||||||
|
if (requestedSize > maxHeapSize) {
|
||||||
|
err(`Cannot enlarge memory, requested ${requestedSize} bytes, but the limit is ${maxHeapSize} bytes!`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var alignUp = (x, multiple) => x + (multiple - x % multiple) % multiple;
|
||||||
|
|
||||||
|
// Loop through potential heap size increases. If we attempt a too eager
|
||||||
|
// reservation that fails, cut down on the attempted size and reserve a
|
||||||
|
// smaller bump instead. (max 3 times, chosen somewhat arbitrarily)
|
||||||
|
for (var cutDown = 1; cutDown <= 4; cutDown *= 2) {
|
||||||
|
var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown); // ensure geometric growth
|
||||||
|
// but limit overreserving (default to capping at +96MB overgrowth at most)
|
||||||
|
overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296 );
|
||||||
|
|
||||||
|
var newSize = Math.min(maxHeapSize, alignUp(Math.max(requestedSize, overGrownHeapSize), 65536));
|
||||||
|
|
||||||
|
var replacement = growMemory(newSize);
|
||||||
|
if (replacement) {
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err(`Failed to grow the heap from ${oldSize} bytes to ${newSize} bytes, not enough memory!`);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
var ENV = {
|
||||||
|
};
|
||||||
|
|
||||||
|
var getExecutableName = () => {
|
||||||
|
return thisProgram || './this.program';
|
||||||
|
};
|
||||||
|
var getEnvStrings = () => {
|
||||||
|
if (!getEnvStrings.strings) {
|
||||||
|
// Default values.
|
||||||
|
// Browser language detection #8751
|
||||||
|
var lang = ((typeof navigator == 'object' && navigator.languages && navigator.languages[0]) || 'C').replace('-', '_') + '.UTF-8';
|
||||||
|
var env = {
|
||||||
|
'USER': 'web_user',
|
||||||
|
'LOGNAME': 'web_user',
|
||||||
|
'PATH': '/',
|
||||||
|
'PWD': '/',
|
||||||
|
'HOME': '/home/web_user',
|
||||||
|
'LANG': lang,
|
||||||
|
'_': getExecutableName()
|
||||||
|
};
|
||||||
|
// Apply the user-provided values, if any.
|
||||||
|
for (var x in ENV) {
|
||||||
|
// x is a key in ENV; if ENV[x] is undefined, that means it was
|
||||||
|
// explicitly set to be so. We allow user code to do that to
|
||||||
|
// force variables with default values to remain unset.
|
||||||
|
if (ENV[x] === undefined) delete env[x];
|
||||||
|
else env[x] = ENV[x];
|
||||||
|
}
|
||||||
|
var strings = [];
|
||||||
|
for (var x in env) {
|
||||||
|
strings.push(`${x}=${env[x]}`);
|
||||||
|
}
|
||||||
|
getEnvStrings.strings = strings;
|
||||||
|
}
|
||||||
|
return getEnvStrings.strings;
|
||||||
|
};
|
||||||
|
|
||||||
|
var stringToAscii = (str, buffer) => {
|
||||||
|
for (var i = 0; i < str.length; ++i) {
|
||||||
|
assert(str.charCodeAt(i) === (str.charCodeAt(i) & 0xff));
|
||||||
|
HEAP8[buffer++] = str.charCodeAt(i);
|
||||||
|
}
|
||||||
|
// Null-terminate the string
|
||||||
|
HEAP8[buffer] = 0;
|
||||||
|
};
|
||||||
|
var _environ_get = (__environ, environ_buf) => {
|
||||||
|
var bufSize = 0;
|
||||||
|
getEnvStrings().forEach((string, i) => {
|
||||||
|
var ptr = environ_buf + bufSize;
|
||||||
|
HEAPU32[(((__environ)+(i*4))>>2)] = ptr;
|
||||||
|
stringToAscii(string, ptr);
|
||||||
|
bufSize += string.length + 1;
|
||||||
|
});
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
var _environ_sizes_get = (penviron_count, penviron_buf_size) => {
|
||||||
|
var strings = getEnvStrings();
|
||||||
|
HEAPU32[((penviron_count)>>2)] = strings.length;
|
||||||
|
var bufSize = 0;
|
||||||
|
strings.forEach((string) => bufSize += string.length + 1);
|
||||||
|
HEAPU32[((penviron_buf_size)>>2)] = bufSize;
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var runtimeKeepaliveCounter = 0;
|
||||||
|
var keepRuntimeAlive = () => noExitRuntime || runtimeKeepaliveCounter > 0;
|
||||||
|
var _proc_exit = (code) => {
|
||||||
|
EXITSTATUS = code;
|
||||||
|
if (!keepRuntimeAlive()) {
|
||||||
|
Module['onExit']?.(code);
|
||||||
|
ABORT = true;
|
||||||
|
}
|
||||||
|
quit_(code, new ExitStatus(code));
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @suppress {duplicate } */
|
||||||
|
/** @param {boolean|number=} implicit */
|
||||||
|
var exitJS = (status, implicit) => {
|
||||||
|
EXITSTATUS = status;
|
||||||
|
|
||||||
|
checkUnflushedContent();
|
||||||
|
|
||||||
|
// if exit() was called explicitly, warn the user if the runtime isn't actually being shut down
|
||||||
|
if (keepRuntimeAlive() && !implicit) {
|
||||||
|
var msg = `program exited (with status: ${status}), but keepRuntimeAlive() is set (counter=${runtimeKeepaliveCounter}) due to an async operation, so halting execution but not exiting the runtime or preventing further async execution (you can use emscripten_force_exit, if you want to force a true shutdown)`;
|
||||||
|
readyPromiseReject(msg);
|
||||||
|
err(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
_proc_exit(status);
|
||||||
|
};
|
||||||
|
var _exit = exitJS;
|
||||||
|
|
||||||
function _fd_close(fd) {
|
function _fd_close(fd) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
@@ -4715,6 +4899,14 @@ var wasmImports = {
|
|||||||
/** @export */
|
/** @export */
|
||||||
__cxa_throw: ___cxa_throw,
|
__cxa_throw: ___cxa_throw,
|
||||||
/** @export */
|
/** @export */
|
||||||
|
__syscall_faccessat: ___syscall_faccessat,
|
||||||
|
/** @export */
|
||||||
|
__syscall_fcntl64: ___syscall_fcntl64,
|
||||||
|
/** @export */
|
||||||
|
__syscall_ioctl: ___syscall_ioctl,
|
||||||
|
/** @export */
|
||||||
|
__syscall_openat: ___syscall_openat,
|
||||||
|
/** @export */
|
||||||
abort: _abort,
|
abort: _abort,
|
||||||
/** @export */
|
/** @export */
|
||||||
emscripten_memcpy_js: _emscripten_memcpy_js,
|
emscripten_memcpy_js: _emscripten_memcpy_js,
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user