Files
ioccc/2024/maffiodo/index.html
T

1587 lines
69 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<!-- START: two lines up starts content from: inc/top.default.html -->
<!-- END: this line ends content from: inc/top.default.html -->
<!-- START: this line starts content from: inc/head.default.html -->
<head>
<link rel="stylesheet" href="../../ioccc.css">
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@100..900&display=swap" rel="stylesheet">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>2024/maffiodo - Prize in creative interpretation</title>
<link rel="icon" type="image/x-icon" href="../../favicon.ico">
<meta name="description" content="2024 IOCCC entry maffiodo - Prize in creative interpretation">
<meta name="keywords" content="IOCCC, 2024, IOCCC 2024, IOCCC entry, maffiodo, Prize in creative interpretation">
</head>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<!-- !!! DO NOT MODIFY THIS FILE - This file is generated by a tool !!! -->
<!-- !!! DO NOT MODIFY THIS FILE - This file is generated by a tool !!! -->
<!-- !!! DO NOT MODIFY THIS FILE - This file is generated by a tool !!! -->
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<!-- END: this line ends content from: inc/head.default.html -->
<!-- -->
<!-- This web page was formed via the tool: unspecified -->
<!-- The main section of this web page came from JSON and other data files -->
<!-- -->
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<!-- The main section of this web page was generated via the tool: unspecified -->
<!-- The main section of this web page was generated via the tool: unspecified -->
<!-- The main section of this web page was generated via the tool: unspecified -->
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<!-- Markdown content was converted into HTML via the tool: bin/md2html.sh -->
<!-- START: this line starts content from: inc/body.default.html -->
<body>
<!-- END: this line ends content from: inc/body.default.html -->
<!-- START: this line starts content from: inc/topbar.default.html -->
<div class="theader">
<nav class="topbar">
<div class="container">
<div class="logo">
<a href="../../index.html" class="logo-link">
IOCCC
</a>
</div>
<div class="topbar-items">
<div class="item">
<span class="item-header">
Entries
</span>
<div class="sub-item">
<div class="outfit-font">
<a href="../../years.html" class="sub-item-link">
Winning entries
</a>
</div>
<div class="outfit-font">
<a href="../../authors.html" class="sub-item-link">
Winning authors
</a>
</div>
<div class="outfit-font">
<a href="../../location.html" class="sub-item-link">
Location of authors
</a>
</div>
<div class="outfit-font">
<a href="../../bugs.html" class="sub-item-link">
Bugs and (mis)features
</a>
</div>
<div class="outfit-font">
<a href="../../faq.html#fix_an_entry" class="sub-item-link">
Fixing entries
</a>
</div>
<div class="outfit-font">
<a href="../../faq.html#fix_author" class="sub-item-link">
Updating author info
</a>
</div>
</div>
</div>
<div class="item">
<span class="item-header">
Status
</span>
<div class="sub-item">
<div class="outfit-font">
<a href="../../news.html" class="sub-item-link">
News
</a>
</div>
<div class="outfit-font">
<a href="../../status.html" class="sub-item-link">
Contest status
</a>
</div>
<div class="outfit-font">
<a href="../../next/rules.html" class="sub-item-link">
IOCCC rules
</a>
</div>
<div class="outfit-font">
<a href="../../next/guidelines.html" class="sub-item-link">
IOCCC guidelines
</a>
</div>
<div class="outfit-font">
<a href="../../markdown.html" class="sub-item-link">
Markdown guidelines
</a>
</div>
<div class="outfit-font">
<a href="../../SECURITY.html" class="sub-item-link">
Security policy
</a>
</div>
</div>
</div>
<div class="item">
<span class="item-header">
FAQ
</span>
<div class="sub-item">
<div class="outfit-font">
<a href="../../faq.html" class="sub-item-link">
Frequently asked questions
</a>
</div>
<div class="outfit-font">
<a href="../../quick-start.html#enter" class="sub-item-link">
Enter the IOCCC
</a>
</div>
<div class="outfit-font">
<a href="../../faq.html#compiling" class="sub-item-link">
Compiling entries
</a>
</div>
<div class="outfit-font">
<a href="../../faq.html#running_entries" class="sub-item-link">
Running entries
</a>
</div>
<div class="outfit-font">
<a href="../../faq.html#help" class="sub-item-link">
How to help
</a>
</div>
</div>
</div>
<div class="item">
<span class="item-header">
About
</span>
<div class="sub-item">
<div class="outfit-font">
<a href="../../index.html" class="sub-item-link">
Home page
</a>
</div>
<div class="outfit-font">
<a href="../../social.html" class="sub-item-link">
IOCCC social media
</a>
</div>
<div class="outfit-font">
<a href="../../about.html" class="sub-item-link">
About the IOCCC
</a>
</div>
<div class="outfit-font">
<a href="../../judges.html" class="sub-item-link">
The judges
</a>
</div>
<div class="outfit-font">
<a href="../../thanks-for-help.html" class="sub-item-link">
Thanks for the help
</a>
</div>
<div class="outfit-font">
<a href="../../contact.html" class="sub-item-link">
Contact us
</a>
</div>
</div>
</div>
</div>
</div>
</nav>
<div class="header-mobile-menu">
<noscript>
<a href="../../nojs-menu.html" class="topbar-js-label">
Please Enable JavaScript
</a>
</noscript>
<button id="header-open-menu-button" class="topbar-mobile-menu">
<img
src="../../png/hamburger-icon-open.png"
alt="hamburger style menu icon - open state"
width=48
height=48>
</button>
<button id="header-close-menu-button" class="hide-content">
<img
src="../../png/hamburger-icon-closed.png"
alt="hamburger style menu icon - closed state"
width=48
height=48>
</button>
<div id="mobile-menu-panel" class="hide-content">
<div class="mobile-menu-container">
<div class="mobile-menu-wrapper">
<div class="mobile-menu-item">
Entries
</div>
<div class="mobile-submenu-wrapper">
<a class="mobile-submenu-item" href="../../years.html">
Winning entries
</a>
<a class="mobile-submenu-item" href="../../authors.html">
Winning authors
</a>
<a class="mobile-submenu-item" href="../../location.html">
Location of authors
</a>
<a class="mobile-submenu-item" href="../../bugs.html">
Bugs and (mis)features
</a>
<a class="mobile-submenu-item" href="../../faq.html#fix_an_entry">
Fixing entries
</a>
<a class="mobile-submenu-item" href="../../faq.html#fix_author">
Updating author info
</a>
<a class="mobile-submenu-item" href="../../thanks-for-help.html">
Thanks for the help
</a>
</div>
</div>
<div class="mobile-menu-wrapper">
<div class="mobile-menu-item">
Status
</div>
<div class="mobile-submenu-wrapper">
<a class="mobile-submenu-item" href="../../news.html">
News
</a>
<a class="mobile-submenu-item" href="../../status.html">
Contest status
</a>
<a class="mobile-submenu-item" href="../../next/rules.html">
IOCCC rules
</a>
<a class="mobile-submenu-item" href="../../next/guidelines.html">
IOCCC guidelines
</a>
<a class="mobile-submenu-item" href="../../markdown.html">
Markdown guidelines
</a>
<a class="mobile-submenu-item" href="../../SECURITY.html">
Security policy
</a>
</div>
</div>
<div class="mobile-menu-wrapper">
<div class="mobile-menu-item">
FAQ
</div>
<div class="mobile-submenu-wrapper">
<a class="mobile-submenu-item" href="../../faq.html">
Frequently asked questions
</a>
<a class="mobile-submenu-item" href="../../quick-start.html#enter">
Enter the IOCCC
</a>
<a class="mobile-submenu-item" href="../../faq.html#compiling">
Compiling entries
</a>
<a class="mobile-submenu-item" href="../../faq.html#running_entries">
Running entries
</a>
<a class="mobile-submenu-item" href="../../faq.html#help">
How to help
</a>
</div>
</div>
<div class="mobile-menu-wrapper">
<div class="mobile-menu-item">
About
</div>
<div class="mobile-submenu-wrapper">
<a class="mobile-submenu-item" href="../../index.html">
Home page
</a>
<a class="mobile-submenu-item" href="../../social.html">
IOCCC social media
</a>
<a class="mobile-submenu-item" href="../../about.html">
About the IOCCC
</a>
<a class="mobile-submenu-item" href="../../judges.html">
The judges
</a>
<a class="mobile-submenu-item" href="../../contact.html">
Contact us
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
var headerOpenMenuButton = document.getElementById("header-open-menu-button");
var headerCloseMenuButton = document.getElementById("header-close-menu-button");
var mobileMenuPanel = document.getElementById("mobile-menu-panel");
headerOpenMenuButton.addEventListener("click", () => {
headerOpenMenuButton.classList.remove("topbar-mobile-menu");
headerOpenMenuButton.classList.add("hide-content");
headerCloseMenuButton.classList.remove("hide-content");
headerCloseMenuButton.classList.add("topbar-mobile-menu");
mobileMenuPanel.classList.remove("hide-content");
mobileMenuPanel.classList.add("topbar-mobile-panel");
});
headerCloseMenuButton.addEventListener("click", () => {
headerCloseMenuButton.classList.remove("topbar-mobile-menu");
headerCloseMenuButton.classList.add("hide-content");
mobileMenuPanel.classList.add("hide-content");
mobileMenuPanel.classList.remove("topbar-mobile-panel");
headerOpenMenuButton.classList.add("topbar-mobile-menu");
headerOpenMenuButton.classList.remove("hide-content");
});
</script>
<!-- END: this line ends content from: inc/topbar.default.html -->
<!-- START: this line starts content from: inc/header.default.html -->
<div class="header">
<a href="../../2011/zucker/index.html">
<img src="../../png/ioccc.png"
alt="IOCCC image by Matt Zucker"
width=300
height=110>
</a>
<h1>The International Obfuscated C Code Contest</h1>
<h2>2024/maffiodo - Prize in creative interpretation</h2>
<h3>Jav*script interpreter</h3>
</div>
<!-- END: this line ends content from: inc/header.default.html -->
<!-- START: this line starts content from: inc/navbar.mid.html -->
<div class="navbar">
<a class="Left" href="../kurdyukov4/index.html">&larr; 2024/kurdyukov4</a>
<a class="Left" href="../index.html">&uarr; 2024 &uarr;</a>
<a class="Left" href="../mills/index.html">2024/mills &rarr;</a>
<a class="Right" href="https://github.com/ioccc-src/winner/blob/master/2024/maffiodo/prog.c">C code</a>
<a class="Right" href="https://github.com/ioccc-src/winner/blob/master/2024/maffiodo/Makefile">Makefile</a>
<a class="Right" href="#inventory">Inventory</a>
<a class="Right" href="https://validator.w3.org/nu/?doc=#">&#x2713;</a>
</div>
<!-- END: this line ends content from: inc/navbar.mid.html -->
<!-- START: this line starts content from: inc/before-content.default.html -->
<div class="content" id="content">
<!-- END: this line ends content from: inc/before-content.default.html -->
<!-- START: this line starts content for HTML phase 20 by: bin/output-index-author.sh via bin/md2html.sh -->
<!-- START: this line starts content generated by: bin/output-index-author.sh -->
<h2 id="author">Author:</h2>
<ul>
<li>Name: <a href="../../authors.html#Sandro_Maffiodo">Sandro Maffiodo</a><br>
Location: <a href="../../location.html#IT">IT</a> - <em>Italian Republic</em> (<em>Italy</em>)</li>
</ul>
<!-- END: next line ends content generated by: bin/output-index-author.sh -->
<!-- END: this line ends content for HTML phase 20 by: bin/output-index-author.sh via bin/md2html.sh -->
<!-- START: this line starts content for HTML phase 21 by: bin/pandoc-wrapper.sh via bin/md2html.sh -->
<!-- BEFORE: 1st line of markdown file: 2024/maffiodo/README.md -->
<h2 id="to-build">To build:</h2>
<pre><code> make all</code></pre>
<h2 id="to-use">To use:</h2>
<pre><code> ./prog &lt; script.js</code></pre>
<h2 id="try">Try:</h2>
<pre><code> ./try.sh</code></pre>
<h2 id="judges-remarks">Judges’ remarks:</h2>
<p>This is the latest entry into the IOCCC compendium of programming language tools.</p>
<p>One example is regrettably missing: a quine.
Can you write one in the implemented subset of the language?</p>
<h2 id="authors-remarks">Author’s remarks:</h2>
<h3 id="javscript">Jav*script !!</h3>
<h4 id="whats-this">What’s this?</h4>
<p>Jav*script interpreter with Object, Array, String, Number, Functions and
Garbage Collector. Batteries are not included.</p>
<h4 id="run-forrest-run">Run Forrest, run</h4>
<p>If you want to execute some tests run one of these shell commands (these are
also included inside try.sh script):</p>
<pre><code> cat test.js string.js | ./prog
cat test.js array.js | ./prog
cat test.js math.js | ./prog
cat test.js utils.js | ./prog
cat utils.js verify.js | ./prog</code></pre>
<h3 id="remarks">Remarks</h3>
<p>This interpreter has been tested on</p>
<ul>
<li>Ubuntu 24.10 64bit x86</li>
<li>MacOS Sequoia M3 CPU</li>
</ul>
<p>Disabled warnings via Makefile:</p>
<ul>
<li><strong>Wno-implicit-int</strong> to reduce the number of tokens, lower than 2503</li>
<li><strong>Wno-incompatible-pointer-types</strong> for sprintf and strlen alias function
pointers</li>
<li><strong>Wno-return-type</strong> for functions that does not return a value (99% of times
are the same functions that uses implicit int as return type but do not use
any return statement)</li>
<li><strong>Wno-deprecated-non-prototype</strong> because on clang some function pointers like
strdup(char<em>) is aliased as (</em>)() without any explicit parameter. On gcc this
is not a problem but on MacOS clang this is needed to suppress a warning</li>
<li><strong>Wno-deprecated-declarations</strong> (probably not needed) on clang sprintf is
deprecated because is always better to use snprintf. This warning need to be
disabled because snprintf requires more tokens</li>
<li><strong>Wno-parentheses</strong> for “if (j = 0)” cases where assignment is made inside
conditional expressions, to reduce the total number of tokens used</li>
<li><strong>Wno-unused-variable</strong> because some of the variables are not used but assigned</li>
<li><strong>Wno-misleading-indentation</strong> because compiler can sometimes doubt the correct
indentation; wrong indentation can sometimes be an indicator of possible
errors, not in this case!</li>
<li><strong>Wno-strict-prototypes</strong> for clang, related to implicit-int for functions
declared without a full prototype</li>
</ul>
<p>Included files via Makefile (to reduce number of tokens, lower than 5006/2):</p>
<ul>
<li>include stdio.h</li>
<li>include string.h</li>
<li>include stdlib.h</li>
<li>include ctype.h</li>
</ul>
<h3 id="features">Features</h3>
<p>Supported and unsupported features (everything else that is not listed is
probably unsupported, but who knows…):</p>
<ul>
<li>supported binary operators (in execution priority order from lower to higher);
<pre>, = == != & &= && | |= || > >= >> < <= << - -= + += * \*= / /= % %= [ ( .</pre>
this is not standard so keep in mind that the standard one can be found
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_precedence">here</a>
and the order of execution in this interpreter is slightly different.</li>
<li>binary operator x() call functions. Ah, yes, the interpreter support both
native and interpreted functions; inside this (light) obfuscated version of
the program, only 1 native function has been included (print), to demonstrate
this feature; The interpreter support infinite native functions, as global
functions or (in theory) as Object property.</li>
<li>operator x[y] can be used to access Object properties dynamically using String
or Numbers as y index.</li>
<li>operator x.y works like x[y] but requires that y is an identifier</li>
<li>supported unary operators: ~ ! - +</li>
<li>support infinite nested Objects and Arrays</li>
<li>+String does not convert the given String to a Number</li>
<li>multiple unary operators cannot be chained without parenthesis</li>
<li>Object properties lookup is implemented with O(N) complexity, using a linked
list instead of a dictionary or map</li>
<li>UNICODE strings are not supported. Use ASCII like if we were in 1963</li>
<li>Function can be used as anonymous callback inside function calls (for example
in Array.filter, see <strong>Useful things</strong> chapter)</li>
<li>literal String can include a limited set of escape codes: \n \” \’
or escape code with hexadecimal notation \x00..\xFF. Please note that only
ASCII characters are supported so escape codes cannot exceed two hexadecimal
characters. For example this string:</li>
</ul>
<pre><code> &quot;abc\\xffabc&quot;</code></pre>
<p>need to be break into two substrings to prevent “ffabc” to be parsed as a
as a single character escape code:</p>
<pre><code> &quot;abc\\xff&quot; + &quot;abc&quot;</code></pre>
<ul>
<li>postfix and prefix ++ – are not supported. Use</li>
</ul>
<pre><code> x += 1; x -= 1;</code></pre>
<ul>
<li>only <strong>if else while return</strong> and <strong>break</strong> statement control operations are
supported. Use <strong>while</strong> instead of <strong>for</strong></li>
<li>Number are implemented using <strong>double</strong> as internal data type. To save some
RAM, is possible to change this to use <strong>float</strong> instead but the code need
to be changed manually (there is no define or typedef for this data type).</li>
<li>operators with 3 or more characters length (like === or !== or &gt;&gt;=) are not
implemented</li>
<li>support infinite nested <em>small</em> statements (without {}) and <em>‘fat’</em> statements
(with {})</li>
<li>String concatenation with + and += is supported. Concatenated string does not
has a maximum length limit but literal strings are limited to 99 characters
(you can change this limit inside the code)</li>
<li>comparison of Object Number and String is implemented similar to the ECMA 1
specification but not fully implemented. See <strong>Equality</strong> chapter</li>
<li>does not support full Object or Array literal declaration, only the shortest
one with {} for Object and [] for Array</li>
<li>does not support Object Prototype. Object Array Number Function and String
does not have any default methods. Only “length” property is supported and is
reserved for internal use</li>
<li><strong>var</strong> is supported but <strong>let</strong> is not</li>
<li><strong>var</strong> works well only with one variable at a time. If you declare multiple
variables on the same <em>var</em> line (using comma) only the first one will be
declared correctly in local scope, overriding any existing previous variable
with the same ID. If multiple variables are declared on the same <em>var</em> line,
the next variables (after the first one) will be linked with existing
variables that has the same ID.</li>
<li><strong>var</strong> is also optional but, when is not used, all undeclared variables will
be declared automatically in local scope (and collected after current
statement ends)</li>
<li><strong>only</strong> single line comments are supported</li>
<li>multi line comments are not supported. Use only single line comments</li>
<li>any unary operator on String value will convert String to Number</li>
<li>NaN is not implemented so invalid number conversion will generate a 0 Number</li>
<li>division by zero is not handled</li>
<li>there is no error handling, so if something goes wrong, interpreter will
crash. If some of the unsupported language features are used, parser will
continue to parse what it can understand (wrongly)</li>
<li>expressions must <em>always</em> terminate with a semicolon; otherwise, unexpected
behavior will definitely happen inside the parser</li>
<li><strong>length</strong> property is a reserved property name so cannot be declared in any
Object</li>
<li>identifier does not include $ character, only alphanumeric characters and
the underscore character. Identifier maximum length is 99 character but you
can increment that by changing one constant in the beginning of the file</li>
<li><strong>delete</strong> is not implemented. You can add any property to an Object but you
cannot remove them! This can be managed by creating new Object or Array
without the property to be removed</li>
<li><strong>true</strong> and <strong>false</strong> does not exists but can be declared as variables, like
this:</li>
</ul>
<pre><code> var true = 1;
var false = 0;</code></pre>
<ul>
<li><strong>length</strong> will return the number of properties inside an Object. This is
also true for Array (see <strong>Strange(r) Things</strong> chapter)</li>
<li><strong>length</strong> on String variables (or literal) return the number of characters
in the string</li>
<li>there is no slice or splice in String and Array (but these feature can be
partially implemented in plain JavaScript – see <strong>Useful things</strong> chapter)</li>
<li>there is no Date RegEx or Math (but some of Math methods can be implemented
in plain JavaScript)</li>
<li>subscript operation like</li>
</ul>
<pre><code> x[1]</code></pre>
<p>return the property 1 of the object x or returns the character at position 1
if x is a String
- subscript operation like</p>
<pre><code> x[&quot;abc&quot;]</code></pre>
<p>always declare a new property “abc” also when the Object x does not contains
“abc”. Normally in ECMA, if a property does not exists, undefined is returned
and, if the property is assigned, a new property is created to hold a new
value. This is not true in this mini nano tiny puppy ugly interpreter
- null and undefined are not implemented but can be declared like this:</p>
<pre><code> var null = {};
var undefined = {};</code></pre>
<p>but something different will happen when you perform some comparisons:</p>
<ul>
<li><p>null == 0 will be equal to 1</p></li>
<li><p>undefined == 0 will be equal to 1</p></li>
<li><p>undefined == null will be equal to 0</p></li>
<li><p>null == {} will be false (correctly)</p></li>
<li><p>… some other edge cases, can you spot them?</p></li>
<li><p>there is no <code>typeof</code> nor <code>instanceof</code>. You need to know the types of your
variables or track its type inside other data structures.</p></li>
<li><p><code>this</code> is missing. Inside Function you need to remember <code>this</code>.</p></li>
<li><p>Function declaration is supported ONLY inside expression and not as a
standalone declarator, so instead of this:</p></li>
</ul>
<pre><code> function x() {}</code></pre>
<p>write this:</p>
<pre><code> var x = function () {};</code></pre>
<p>and please look at the final semicolon! It is very important because every
expression need to terminate with that and without that strange parsing
things will happen (also probably some segmentation fault).
Functions need to be unnamed by itself.
Functions can be used as callback inside other function calls but read the
following limitation…
- there is no closure mechanism so, if your function work on some variables
outside of the function scope, be warned, something strange will happen. If
possible use a <em>pure functional</em> approach.
- <strong>function</strong> named parameters are not supported, for example:</p>
<pre><code> function (a, b, c) { return a+b; }</code></pre>
<p>need to be rewritten as:</p>
<pre><code> function () { return arguments[0] + arguments[1]; }</code></pre>
<p>using <strong>arguments</strong> array. Another solution is to map arguments to new local
variables using <strong>var</strong>, for example:</p>
<pre><code> function () {
var a = arguments[0];
var b = arguments[1];
return a+b;
}</code></pre>
<ul>
<li><strong>arguments</strong> array cannot be used directly for nested function calls, so
instead of this:</li>
</ul>
<pre><code> var foo = function () {
print(arguments[0] + &#39; &#39; + arguments[1]);
};</code></pre>
<p>you need to write that:</p>
<pre><code> var foo = function () {
var string = arguments[0] + &#39; &#39; + arguments[1];
print(string); //&lt;-- here, inside parenthesis, arguments cannot be used and
// will cause a missmatch between the current arguments and
// the new one allocated for print Function
};</code></pre>
<p>because internally <strong>arguments</strong> array will be re-declared locally, with a
stack based approach, for the next function call and can cause some variable
resolving mismatch. This is a little annoying but is also better to always
remap each arguments value to a dedicated local variable.
- early exit inside logical expression is not implemented so this code will not
be interrupted before the execution of the <code>foo2</code> function:</p>
<pre><code> if (0 &amp;&amp; foo2(123)) { print(&quot;hello\n&quot;); }</code></pre>
<p>and this is clearly not standard (in ECMA, Yes you can)
- accessing properties on literal String or Number is not supported; For
example this code will not work</p>
<pre><code> &#39;abc&#39;.x = 1;</code></pre>
<p>and this can cause a crash, like in many other unsupported features
- when statement execution is off (for example inside an else {} statement to be
NOT executed) the code is partially interpreted to obtain intermediate results
that will be not used and will be freed by the next GC call. Some memory is
wasted in the process.
- recursive object structure like this:</p>
<pre><code> var obj = {};
obj.x = 32;
obj[&quot;yy&quot;] = &#39;hello&#39;;
obj.recursive = obj;</code></pre>
<p>is not supported and will cause an infinite loop inside GC. Recursive
structures need to be handled with some kind of data <em>sentinel values</em>.
- maximum size of input source code is 65536 bytes but you can change the buffer
size inside main function (change 1&lt;&lt;16 constant)</p>
<p>Parsing errors are not handled so “garbage in garbage out” (but garbage is also
collected if no errors are found, ah ah).</p>
<h4 id="equality">Equality</h4>
<p>Loose equality is implemented similarly as described in
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Equality_comparisons_and_sameness#:~:text=is%20logged%0A%7D-,Loose%20equality%20using%20%3D%3D,-Loose%20equality%20is">this docs</a>
From that doc, the following paragraph is slightly different (point 2 is
missing becouse some of the required features are not present in the
interpreter):</p>
<p>Loose equality is symmetric: A == B always has identical semantics to B == A
for any values of A and B (except for the order of applied conversions). The
behavior for performing loose equality using == is as follows:</p>
<ol type="1">
<li>If the operands have the same type, they are compared as follows:</li>
</ol>
<ul>
<li>Object: return 1 only if both operands reference the same object.</li>
<li>String: return 1 only if both operands have the same characters in the same
order.</li>
<li>Number: return 1 only if both operands have the same value. +0 and -0 are
treated as the same value. NaN is not supported</li>
</ul>
<ol start="3" type="1">
<li>If one of the operands is an object and the other is a primitive, convert
the object to a primitive.</li>
<li>At this step, both operands are converted to primitives (one of String and
Number. The rest of the conversion is done case-by-case.</li>
</ol>
<ul>
<li>If they are of the same type, compare them using step 1.</li>
<li>Number to String: convert the string to a number. Conversion failure
results in 0 (not NaN), which will NOT guarantee the equality to be false.</li>
</ul>
<p>This logic has been implemented in this (light) obfuscated code:</p>
<pre><code> if (_ == y-&gt;m) {
if (_ &amp; 4) U = x != y;
else if (_ &amp; 1) goto O;
else goto Q;
} else if ((_ | y-&gt;m) == 2) {
Q: U = A(Q(x)-&gt;f, Q(y)-&gt;f);
} else {
O: U = V - X;
}
// U == 0 mean true loose equality</code></pre>
<p><em>NOTE: the (light) obfuscated code can be slightly different from the final
one, due to final refinements on the obfuscation process.</em></p>
<h4 id="garbage-collection">Garbage Collection</h4>
<p>Garbage Collection is implemented with these two functions (in pseudocode):</p>
<pre><code> // x=item z=terminal y=mark_value
mark(x, z, y, next)
if x and x != z
if value(x) not already marked
mark(value(x), 0, y, 0)
mark(props(value(x)), 0, y, 1)
mark(props(x), 0, y, 1)
mark x = y
if next
mark(next(x), z, y, 1)
// z=terminal, stop when z is reached
gc(z)
// all values from head to z are marked to 1
mark(all, z, 1, 1)
// all values connected to props are marked to 0
mark(props, 0, 0, 1)
foreach x in all
if x marked and x not retained
if type(x) == String
freeString(x)
free(x)
else
mark x = 0</code></pre>
<p>It is <em>clear and quite obvious</em> that this is a classical <strong>mark &amp; sweep</strong>
process that marks all the local values (from a given heap starting point) and
release all values that are not referenced from any heap variable (recursively,
also for any values referenced from infinite nested objects properties).</p>
<p>Unfortunately, this implementation does not support recursive Object structures
where the properties tree includes the root node itself or any other parent node.
I was not able to include this in the compressed program, without exceed the
tokens limitation.</p>
<p>The following chart show the length of the two global linked lists (for
variables and values) while executing the internal tests in C (see <strong>Internal
tests</strong> chapter):</p>
<figure>
<img src="gc.png" alt="Garbage Collector actions inside internal tests" />
<figcaption aria-hidden="true">Garbage Collector actions inside internal tests</figcaption>
</figure>
<h4 id="values-and-variables">Values and variables</h4>
<p>The interpreter uses the same struct to hold values and variables. The same
struct (c) is also used to store a linked list for global variables and a linked
list for all properties contained inside a variable.</p>
<p>Using the same struct has been useful to strip down the code for a lesser number
of tokens.</p>
<p>This is a semi obfuscated struct that holds variables or values (NOTE: obfuscated
symbols can be slightly different from the final obfuscated ones):</p>
<pre><code> typedef struct c*d;
struct c{
union{
char*e;
double n;
} ;
char *f, //{id} set if var is a property
g, // used in gc (mark)
h, // used in gc (retain)
l; // type (1 = number, 2 = string, 4 = object)
d d, // when this is a value, is one of the variables that use this value
x, // when this is an variable this point to the variable value
b, // next value or variable in the list (linked list)
m, // object properties head (linked list of props)
(*q)(); // native function, used then type is 2 and this is a function
int r; // array length / properties length
} ;</code></pre>
<p>This struct is huge! It uses 72 bytes on 64bit X86 architecture. This struct is
big to fit all the useful data inside it and also something else that is
needed to compress the code. In theory can be much smaller but the final code
will uses more tokens (I have tried multiple times to implement this interpreter
but this is the only solution that I’ve found to match the 2503 limitation.. with
the previous limit of 2053 was really hard to stay under the limits – for me!).
Keep in mind also that on 64bit X86 architecture each pointer cost 8 bytes…</p>
<p>The interpreter uses a large amount of RAM, creating many temporary values
objects that are not really necessary but are needed to compress the code.</p>
<p>Global variables linked list is stored inside a global pointer, and all
temporary values are stored inside another pointer. Garbage Collector work to
free a subset of unused values not pointed from current global variables list.</p>
<h4 id="native-functions">Native functions</h4>
<p>The only native function included inside the obfuscated program is <strong>print</strong>,
that prints out the first parameter that receive, as a String (by converting it
to a String if is not a String type); its native code is inside the bb function:</p>
<pre><code> e bb(e u) {
printf(&quot;%s&quot;, Q(u-&gt;x-&gt;q-&gt;x));
return E(0);
}</code></pre>
<p>This native function is declared in global scope using this code, inside main
function:</p>
<pre><code> c(g, &quot;print&quot;);
e x = G(&amp;q);
x-&gt;m = 2;
x-&gt;x-&gt;r = bb;</code></pre>
<p>And the same sequence of calls over c() and G() can be iterated to declare
additional native functions inside the global context of the interpreter.</p>
<p>If you want you can declare other native functions. Each native function receive
a parameter of type <em>e</em> (pointer to struct c) that is the value of the temporary
<strong>arguments</strong> array. Each native function MUST return a new value using <em>E()</em>
function otherwise the interpreter will crash.</p>
<p>I’m sure that will be a little hard to add new native functions writing directly
them in this (light) obfuscated format, but in theory this is not impossible…</p>
<p>For example, this is a new <em>keys</em> native function that can returns an array of
all properties contained inside an object, given the target Object as first
parameter (like the Object.keys standard method):</p>
<pre><code> e be(e u) {
int y = 0; // index for properties declared in output Array
e h = u-&gt;x-&gt;q-&gt;x-&gt;q, // get first argument only
x = E(4), // declare a new value with type 4 = Object (Array!)
l;
// loop for each properties inside arg
while (h) {
c(g, &quot;%d&quot;, y++); // format N=y for output Array index property
l = G(&amp;x-&gt;q); // declare a new property N=y inside x
x-&gt;u++; // increment number of properties in x
l-&gt;x-&gt;m = 2; // type of new property value is 2 = String
l-&gt;x-&gt;f = D(h-&gt;g); // duplicate ID of the arg Object property
h = h-&gt;b; // jump on the next property of arg Object
}
return x;
}</code></pre>
<p>These (light) obfuscated functions and variables are used in the previous
examples:</p>
<pre><code> c // sprintf alias
g // char[] array used for F and G functions
D // strdup
E(T) // allocate a new value of type T
F(props) // find property f[] inside props linked list
G(&amp;props) // declare property f[] inside props linked list</code></pre>
<p>Also, just for fun, the following <strong>exec</strong> native function can be used to
expose <strong>popen</strong> inside the interpreter, to exec any arbitrary shell subprocess
commands:</p>
<pre><code> e bc(e u) {
FILE *bd = popen(Q(u-&gt;x-&gt;q-&gt;x)-&gt;f, &quot;r&quot;);
e x = E(2);
x-&gt;f = D(&quot;&quot;);
while (fgets(g, 99, bd) != 0) {
char *d = malloc(w(x-&gt;f) + w(g) + 1);
c(d, &quot;%s%s&quot;, x-&gt;f, g);
free(x-&gt;f);
x-&gt;f = d;
}
pclose(bd);
return x;
}</code></pre>
<p>Unfortunately <strong>keys</strong> and <strong>exec</strong> functions were not included in the obfuscated
<em>prog.c</em> program, due to tokens limitations.</p>
<h3 id="stranger-things">Strange(r) Things</h3>
<p>The following things comes from the <em>Upside Down</em>…
Strange things can happen or can be found when using this interpreter:</p>
<ul>
<li>Array are implemented as Object and <strong>length</strong> property of Array values are
implemented assuming that Array values have a list of properties that are
numerical indexes and there are not <em>holes</em> inside the list of all indexes.
For example this array is ok:</li>
</ul>
<pre><code> var x = [];
x[0] = 1;
x[1] = &#39;hello&#39;;
x[2] = &quot;From\tUpside\tDown&quot;;</code></pre>
<p>and its length is 3. The following one is instead a NOT-OK Array that contains
<em>holes</em> inside its own indexes:</p>
<pre><code> var y = [];
y[0] = &#39;I have&#39;;
y[2] = &quot;one hole&quot;;</code></pre>
<p>and its length is computed as 2 instead of 3
- Object has <strong>length</strong> property and the object length is equal to the number
of properties declared inside the Object (not standard)
- functions are implemented as String, so you can do strange(r) things like this:</p>
<pre><code> var x = &quot;{ print(&#39;x&#39;); }&quot;;
x();</code></pre>
<p>this also mean that you can implement an eval function that can evaluate
dynamic generated code using this trick:</p>
<pre><code> var eval = function() {
arguments[0]();
}</code></pre>
<p>this technique can also work if you create a dynamic string (like normally is
done while using eval). Please note that the given string need to include an
outer statement ({}) otherwise the execution will be interrupted after the
first expression or short statement. See <strong>utils.js</strong> or <strong>verify.js</strong> for
some real examples.
- 0.1 + 0.2 does compute 0.3 correctly. Node.js returns 0.30000000000000004
instead
- <strong>var</strong> can be used multiple times like this:</p>
<pre><code> var var var var a = 1;</code></pre>
<p>and this will work like var has been typed one time. Can you find out where
this has been allowed inside the source code? (hint: goto)
- many other unknown strange things can happen in Hawkins, Indiana…</p>
<h3 id="useful-things">Useful Things</h3>
<p>Console prototype is not implemented but console.log can be implemented using
only native <strong>print</strong> function. The following is an example of Console
implementation (found also inside console.js file):</p>
<pre><code> var console = {};
console.log = function () {
var i = 0;
while (i &lt; arguments.length) {
var arg = &quot;&quot; + arguments[i];
print(arg);
i += 1;
if (i == arguments.length) {
break;
}
print(&#39; &#39;);
}
print(&#39;\n&#39;);
};</code></pre>
<p>You can use this with cat when testing the interpreter:</p>
<pre><code> cat console.js fibo.js | ./prog</code></pre>
<p>Other standard functions can be implement slightly different from the ECMA
standard library original ones but still something useful can be achieved:</p>
<pre><code> var String = {};
// slice(string, from, to)
String.slice = function () {
if (arguments.length &lt; 2) {
return &quot;&quot;;
}
var s = arguments[0];
var from = arguments[1];
var to = -1;
if (arguments.length &gt; 2) {
to = arguments[2];
} else {
to = s.length;
}
var o = &quot;&quot;;
var i = from;
while (i &lt; to) {
o += s[i];
i += 1;
}
return o;
}</code></pre>
<p>see <em>string.js</em> for additional String methods implemented using only the few
features present in this little mini voodoo interpreter.</p>
<p>If you need both <strong>Console</strong> and <strong>String</strong> utils, use cat:</p>
<pre><code> cat console.js string.js YOUR_SCRIPT.js | ./prog</code></pre>
<p>Where YOUR_SCRIPT.js is some script that you can create, not included in this
package. If you want to try out some other scripts bundled with this package,
see <strong>Run Forrest, run</strong> chapter.</p>
<p>The following list includes a summary of all of my examples for standard JS
features implemented using this interpreter. These methods are not fully
implemented and each method work slightly differently from the one that exists
inside the ECMA standard:</p>
<pre><code> // string.js
String.slice(s, start, end);
String.split(s, singleCharSeparator);
String.charAt(s, index);
String.charCodeAt(s, index);
String.startsWith(s, prefix);
String.fromCharCode(asciiCode);
String.trimStart(s);
String.trimEnd(s);
String.trim(s);
// array.js
Array.at(array, index);
Array.join(array, separator);
Array.push(array, item1 ... itemN);
Array.pop(array); // return { new: NEW_ARRAY, removed: REMOVED_ITEM }
Array.concat(array1, array2);
Array.slice(array, start, end);
Array.toString(array);
Array.filter(array, callback);
// math.js
Math.E;
Math.e;
Math.LN2;
Math.LN10;
Math.LOG2E;
Math.LOG10E;
Math.phi;
Math.PI;
Math.pi;
Math.SQRT1_2;
Math.SQRT2;
Math.tau;
Math.sign(x);
Math.abs(x);
// console.js
console.log(...);
// utils.js
eval(string);</code></pre>
<p><em>NOTE: each file includes some unit tests that can be enabled manually inside
each file by setting a test variable equal to 1 or by prepending the test.js
script before the source file (see <strong>Run Forrest, run</strong> chapter)</em></p>
<p><em>NOTE(2): take a look at Array.filter! The interpreter support function callbacks</em></p>
<h3 id="internal-tests">Internal tests</h3>
<p>The following tests has been made in the original not-obfuscated code development.
Without these tests, the implementation of the interpreter would have been
impossible or at least exhausting.</p>
<p><em>NOTE: some tests uses additional native functions like exec and keys that has
been stripped down in the final (light) obfuscated version of the code</em></p>
<h4 id="tests-functions">Tests functions</h4>
<pre><code> /**
* Test a single JS Expression evaluation.
* return value MUST be equal to type
* return value, if type=1 (Number) MUST be equal to res
* return value, if type=2 (String) MUST be equal to sres
*/
void etest_base(char *src, char type, double res, char *sres);
// same as etest_base but assume that return type MUST be 1 (Number)
void etest(char *src, double res);
/**
* Test a JS Statement
* return value MUST be equal to type
* return value, if type=1 (Number) MUST be equal to res
* return value, if type=2 (String) MUST be equal to sres
*/
void stest_base(char *src, char type, double res, char *sres);
// same as stest_base but assume that return type MUST be 1 (Number)
void stest(char *src, double res);</code></pre>
<h4 id="verify-single-expressions-correctness">Verify single Expressions correctness</h4>
<pre><code> spf(id, &quot;x&quot;); decl(&amp;props); // declare x variable
etest_base(&quot;;&quot;, 0, 0, 0);
etest_base(&quot;; 2; 3&quot;, 0, 0, 0);
etest(&quot;2*(2+3)-1&quot;, 9);
etest_base(&quot;&#39;&#39; + 32&quot;, 2, 0, &quot;32&quot;);
etest_base(&quot;\&quot;\&quot; + 32&quot;, 2, 0, &quot;32&quot;);
etest(&quot;x + 32&quot;, 32);
etest(&quot;x = 3&quot;, 3);
etest(&quot;x&quot;, 3);
etest(&quot;var y = 11&quot;, 11);
etest(&quot;var y = 11, z = 22&quot;, 22);
etest_base(&quot;var foo = function () { 2; }&quot;, 2, 0, &quot;{ 2; }&quot;);
etest_base(&quot;&#39; 1 2 \\n 23 \\&#39; &#39;&quot;, 2, 0, &quot; 1 2 \n 23 \&#39; &quot;);
etest(&quot; &#39;hello&#39; == &#39;hello&#39;; &quot;, 1);
etest(&quot; &#39;hello&#39; == &#39;hello2&#39;; &quot;, 0);
etest(&quot; &#39;hello&#39; != &#39;hello2&#39;; &quot;, 1);
etest(&quot; &#39;32&#39; == 32; &quot;, 1);
etest(&quot; &#39;32&#39; == 33; &quot;, 0);
etest(&quot; &#39;32&#39; &lt;= 33; &quot;, 1);
etest(&quot; &#39;32&#39; &lt;= 2; &quot;, 0);
etest(&quot; &#39;2&#39; &gt;= 32; &quot;, 0);
etest(&quot; &#39;32&#39; &gt;= 2; &quot;, 1);
etest(&quot; 32 == 32; &quot;, 1);
etest(&quot; 32 &gt;= 0; &quot;, 1);
etest(&quot; 0 &lt;= 32; &quot;, 1);
etest(&quot; 1+4 &amp;&amp; 3-3; &quot;, 0);
etest(&quot; 1+4 || 3-3; &quot;, 1);
etest(&quot; 1&lt;&lt;3; &quot;, 8);
etest(&quot; 8&gt;&gt;3; &quot;, 1);
etest(&quot; -6; &quot;, -6);
etest(&quot; +&#39;6&#39;; &quot;, 6);
etest(&quot; ~&#39;6&#39;; &quot;, -7);
etest(&quot; !&#39;6&#39;; &quot;, 0);
etest(&quot; !&#39;0&#39;; &quot;, 1);
etest(&quot; !(1 &amp;&amp; 2); &quot;, 0);
etest(&quot; 0.1 + 0.2 == 0.3; &quot;, 1); // OMG
etest(&quot; &#39;hello&#39;.length; &quot;, 5);
etest(&quot; [].length; &quot;, 0);
etest(&quot; {}.length; &quot;, 0); // Stranger Things in Hawkins, Indiana
etest_base(&quot;obj = {}&quot;, 4, 0, 0);
etest(&quot;obj.abc = 32&quot;, 32);
etest(&quot;obj[0] = 2; &quot;, 2);
etest(&quot;obj[0]; &quot;, 2);
etest_base(&quot;obj[1] = {}; &quot;, 4, 0, 0);
etest(&quot;obj[1].temp = 123; &quot;, 123);
etest(&quot;obj[1].temp; &quot;, 123);
etest_base(&quot;print(1); &quot;, 0, 0, 0);
etest_base(&quot;print(3*9); &quot;, 0, 0, 0);
etest_base(&quot;print(&#39;22&#39;); &quot;, 0, 0, 0);
etest_base(&quot;&#39;abc&#39;[0];&quot;, 2, 0, &quot;a&quot;);
etest_base(&quot;&#39;1+2&#39;();&quot;, 1, 3, 0);
etest(&quot;0 || &#39;hello&#39;&quot;, 0);
etest(&quot;0 || &#39;1hello&#39;&quot;, 1);
etest_base(&quot;print(123);&quot;, 0, 0, 0);</code></pre>
<h4 id="verify-statement-correctness">Verify Statement correctness</h4>
<pre><code> stest(&quot;; 2; 3&quot;, 3);
stest(&quot;{ { 1; }; }; 2; {{3;}}&quot;, 3);
stest(&quot;{ { return 1; } } 2; 3&quot;, 1);
stest_base(&quot;var strt = &#39;&#39; + 32&quot;, 2, 0, &quot;32&quot;);
stest_base(&quot;var strt = \&quot;\&quot; + 32&quot;, 2, 0, &quot;32&quot;);
stest(&quot;var foo = function () { var w = 2 * 3; }; foo(1, 2, 3)&quot;, 6);
stest(&quot;var foo = function () { \
arguments[1] * arguments[2] * arguments[0]; \
}; foo(10, 2, 3)&quot;, 60);
stest(&quot;var x = 2 + 3, y; \
if (x == 5) { \
7; \
} else { \
2; \
}&quot;, 7);
stest(&quot;var x = 2 + 3, y; \
if (x == 3) { \
7; \
} else { \
2; \
}&quot;, 2);
stest(&quot;var x = 2 + 3, y; \
if (x == 5) \
7; \
else \
2; \
&quot;, 7);
stest(&quot;var x = 2 + 3, y; \
if (x == 3) \
7; \
else \
2; \
&quot;, 2);
stest(&quot;var x = 2 + 3, y; \
if (x == 5) \
y = 7; \
else \
y = 3; \
y;&quot;, 7);
stest(&quot;var x = 2 + 3, y; \
if (x == 3) \
y = 7; \
else \
y = 3; \
y;&quot;, 3);
stest(&quot;var cnt = 0; \
while (cnt &lt; 10) { cnt = cnt + 1; break; } \
cnt&quot;, 1);
stest(&quot;var cnt = 0; \
while (cnt &lt; 10) { if (1) { break; } cnt = cnt + 1; } \
cnt&quot;, 0);
stest(&quot;var cnt = 0, x = 0; \
while (x &lt; 4) { \
var y = 0; \
while (y &lt; 4) { \
if ((y == 2) &amp;&amp; (x == 2)) \
break; \
cnt = cnt + 1; \
y += 1; \
} \
if ((y == 2) &amp;&amp; (x == 2)) \
break; \
x += 1; \
}\
cnt&quot;, 10);
stest(&quot;var cnt = 0; while (cnt &lt; 10) { cnt = cnt + 1; } cnt&quot;, 10);
stest(&quot;var o2 = {}, l2 = 1; o2.l2 = 33; o2.l2&quot;, 33);
stest(&quot;var o2 = {}, l2 = 1; o2.l2 = 31; l2&quot;, 1);
stest(&quot;var w2 = 1; w2 += 3&quot;, 4);
stest(&quot;var true = 1, false = 0; 1 == true &amp;&amp; !1 == false&quot;, 1);
stest(&quot;var s = 1; ~s; s&quot;, 1);
stest_base(&quot;var s = &#39;1&#39;; ~s; s&quot;, 2, 0, &quot;1&quot;);
stest(&quot; \n\
var number = 10, \n\
n1 = 0, \n\
n2 = 1, \n\
i = 0, \n\
nextTerm; \n\
var console = {}; \n\
console.log = print; \n\
console.log(&#39;fibonacci series:&#39;); \n\
while (i &lt;= number) { \n\
console.log(n1); \n\
nextTerm = n1 + n2; \n\
n1 = n2; \n\
n2 = nextTerm; \n\
i += 1; \n\
} \n\
n1; \n\
&quot;, 89);
stest(&quot; \n\
var x = 32, y = 10; \n\
var console = {}; \n\
console.log = function () { \n\
var i = 0; \n\
while (i &lt; arguments.length) { \n\
var arg = \&quot;\&quot; + arguments[i]; \n\
print(arg); \n\
i += 1; \n\
if (i == arguments.length) { \n\
break; \n\
} \n\
print(&#39; &#39;); \n\
} \n\
print(&#39;\\n&#39;); \n\
}; \n\
console.log(&#39;test 123&#39;, {}, x+y, []); \n\
0; \n\
&quot;, 0);
stest(&quot; \n\
var x = {}; \n\
x.a = 32; \n\
x.b = 1; \n\
x.prova = \&quot;abc\&quot;; \n\
var y = keys(x); \n\
var z = y.length; \n\
while (z) { \n\
z -= 1; \n\
print(y[z]); \n\
} \n\
0;&quot;, 0);
stest(&quot;var null = {}; var nullx = null; null == nullx;&quot;, 1);
stest(&quot;var null = {}; null == {};&quot;, 0);
stest(&quot;var null = {}; null == 0;&quot;, 1);
stest(&quot;var undefined = {}; undefined == 0;&quot;, 1);
stest(&quot;var undefined = {}, null = {}; undefined == null;&quot;, 0);
stest_base(&quot;exec(&#39;echo -n 123&#39;);&quot;, 2, 0, &quot;123&quot;);
stest(&quot; \n\
var recobj = {}; \n\
{ \n\
var o1 = {}; \n\
var o2 = {}; \n\
recobj.x = o1; \n\
recobj.y = o2; \n\
o1.x = 3; \n\
o2.o1 = o1; \n\
o1 = 0; \n\
o2 = 0; \n\
} \n\
recobj.y.o1.x;&quot;, 3);
stest_base(&quot; \n\
var String = {}; \n\
// slice(string, from, to) \n\
String.slice = function () { \n\
if (arguments.length &lt; 2) { \n\
return &#39;&#39;; \n\
} \n\
var s = arguments[0]; \n\
var from = arguments[1]; \n\
var to; \n\
if (arguments.length &gt; 2) { \n\
to = arguments[2]; \n\
} else { \n\
to = s.length; \n\
} \n\
var o = &#39;&#39;; \n\
var i = from; \n\
while (i &lt; to) { \n\
o += s[i]; \n\
i += 1; \n\
} \n\
return o; \n\
}; \n\
var test = &#39;hello world!&#39;; \n\
//print(String.slice(test, 1) + &#39;\\n&#39;); \n\
print(String.slice(test, 1, 5) + &#39;\\n&#39;);\n\
String.slice(test, 1, 5);&quot;, 2, 0, &quot;ello&quot;);
stest_base(&quot; \n\
// split(string, singleCharSeparator) \n\
var String = {}; \n\
String.split = function () { \n\
var o = []; \n\
var s = arguments[0]; \n\
var delimiter = arguments[1]; \n\
var start = 0; \n\
var i = 0; \n\
var oindex = 0; \n\
while (i &lt; s.length) { \n\
if (s[i] == delimiter) { \n\
o[oindex] = String.slice(s, start, i); \n\
start = i + 1; \n\
oindex += 1; \n\
} \n\
i += 1; \n\
} \n\
if (start &lt; s.length) { \n\
o[oindex] = String.slice(s, start); \n\
} \n\
return o; \n\
}; \n\
// slice(string, from, to) \n\
String.slice = function () { \n\
if (arguments.length &lt; 2) { \n\
return &#39;&#39;; \n\
} \n\
var s = arguments[0]; \n\
var from = arguments[1]; \n\
var to; \n\
if (arguments.length &gt; 2) { \n\
to = arguments[2]; \n\
} else { \n\
to = s.length; \n\
} \n\
var o = &#39;&#39;; \n\
var i = from; \n\
while (i &lt; to) { \n\
o += s[i]; \n\
i += 1; \n\
} \n\
return o; \n\
}; \n\
var test2 = &#39;abc, d, e f&#39;; \n\
var splitted = String.split(test2, &#39;,&#39;); \n\
print(splitted.length + &#39;\n&#39;); \n\
print(splitted[0] + &#39;\n&#39;); \n\
print(splitted[1] + &#39;\n&#39;); \n\
print(splitted[2] + &#39;\n&#39;); \n\
splitted[0];&quot;, 2, 0, &quot;abc&quot;);
stest(&quot; \n\
var _cm = {}; // map from character to ASCII code \n\
_cm[&#39;\\x0&#39;] = 0; _cm[&#39;\\x1&#39;] = 1; _cm[&#39;\\x2&#39;] = 2; \n\
_cm[&#39;\\x3&#39;] = 3; _cm[&#39;\\x4&#39;] = 4; _cm[&#39;\\x5&#39;] = 5; \n\
_cm[&#39;\\x6&#39;] = 6; _cm[&#39;\\x7&#39;] = 7; _cm[&#39;\\x8&#39;] = 8; \n\
_cm[&#39;\\x9&#39;] = 9; _cm[&#39;\\xa&#39;] = 10; _cm[&#39;\\xb&#39;] = 11; \n\
_cm[&#39;\\xc&#39;] = 12; _cm[&#39;\\xd&#39;] = 13; _cm[&#39;\\xe&#39;] = 14; \n\
_cm[&#39;\\xf&#39;] = 15; _cm[&#39;\\x10&#39;] = 16; _cm[&#39;\\x11&#39;] = 17; \n\
_cm[&#39;\\x12&#39;] = 18; _cm[&#39;\\x13&#39;] = 19; _cm[&#39;\\x14&#39;] = 20; \n\
_cm[&#39;\\x15&#39;] = 21; _cm[&#39;\\x16&#39;] = 22; _cm[&#39;\\x17&#39;] = 23; \n\
_cm[&#39;\\x18&#39;] = 24; _cm[&#39;\\x19&#39;] = 25; _cm[&#39;\\x1a&#39;] = 26; \n\
_cm.length&quot;, 27);
stest_base(&quot; \n\
var stest = function () { return arguments[0] + &#39;_1&#39;; }; \n\
var s = &#39;abc&#39;; \n\
s = stest(s); \n\
s = stest(s); \n\
s;&quot;, 2, 0, &quot;abc_1_1&quot;);
stest(&quot; \
var test = function () { \
var x = arguments[0]; \
if (x &lt; 0) \
return 2; \
return 3; \
}; \
var t1 = test(-32); \
t1;&quot;, 2);
stest_base(&quot; \n\
var stest = function () { \n\
var o = arguments[0] + &#39;_&#39;; \n\
var i = 0; \n\
while (i &lt; 2) { \n\
o += i; \n\
i += 1; \n\
} \n\
return o; \n\
}; \n\
var s = &#39;abc&#39;; \n\
s = stest(s); \n\
s = stest(s); \n\
s;&quot;, 2, 0, &quot;abc_01_01&quot;);
stest_base(&quot; \
var test = function () { \
var x = arguments[0]; \
var o = &#39;x&#39;; \
if (x &gt; 0) { \
o += 2; \
} else { \
o += 3; \
} \
return o; \
}; \
var t1 = test(-32); \
t1;&quot;, 2, 0, &quot;x3&quot;);
stest(&quot; \
var atmp = []; \
atmp[0] = 10; \
atmp[1] = 20; \
atmp[0 + 1];&quot;, 20);</code></pre>
<p>Some of these tests has also been ported in plain JavaScript; take a look inside
the <strong>verify.js</strong> script. These tests uses <strong>eval()</strong> function to execute a test
source code string and verify its execution results. These other tests can be
executed with this command:</p>
<pre><code> cat utils.js verify.js | ./prog</code></pre>
<h3 id="f.a.q">F.A.Q</h3>
<p>These are frequently asked questions that can be asked when trying to use this
little mambo jumbo interpreter:</p>
<ul>
<li>why? because why not</li>
<li>if program crash, check if you are calling some function that is not declared
or has been misspelled. There are no safety check about this</li>
<li>if program loop indefinitely, check if your function assignments includes a
final ; after }. This is required</li>
<li>what is the meaning of life and everything? 42 or sometimes 2503</li>
<li>if program do not do what you want, check the supported features because the
parser can easily misunderstand what you are giving as input text; for example
you can type <strong>let</strong> instead of <strong>var</strong> and, without any errors raised,
everything will go terribly wrong</li>
<li>can this interpreter be used on real production environment? of course not</li>
<li>what is the memory limit of this interpreter? there is no limits</li>
<li>what happen if an object contains a reference to itself (object with a
recursive structure)? An infinite loop is triggered because the Garbage
Collector cannot recognize this kind of structure</li>
</ul>
<h3 id="final-thoughts">Final Thoughts</h3>
<p>I’ve tried multiple time to rewrite this interpreter and compress the final
obfuscated source code to match the previous IOCCC limit but without success.</p>
<p>The increased limitation of tokens from 2053 to 2503 has made possible to use
this iteration of the interpreter without continue to retry to rewrite that to
compress the final source code. Probably with more iterations the 2053 limit
should be reached, who knows.</p>
<p>The most tricky part in the development process has been to find out a minimal
bare bones subset of JavaScript features, small enough to allow to build some
other standard features on top of the bare bones interpreter.</p>
<p>In many tests I’ve tried to include the Object.keys features (to obtain the
list of property keys inside a given Object) but, in all of my attempts, the
limitation on tokens count was exceeded. With Object.keys would have been
possible to build up also Object.values and other Object methods. Also the lack
of prefix/postfix ++ and – it’s a pity… Damn it!
May be without the Garbage Collector some other features should be packed into
the program but it’s too late to change that.</p>
<p>Have fun!</p>
<!--
Copyright © 1984-2025 by Landon Curt Noll and Leonid A. Broukhis. All Rights Reserved.
You are free to share and adapt this file under the terms of this license:
Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
For more information, see:
https://creativecommons.org/licenses/by-sa/4.0/
-->
<!-- AFTER: last line of markdown file: 2024/maffiodo/README.md -->
<!-- END: this line ends content for HTML phase 21 by: bin/pandoc-wrapper.sh via bin/md2html.sh -->
<!-- START: this line starts content for HTML phase 22 by: bin/output-index-inventory.sh via bin/md2html.sh -->
<!-- START: this line starts content generated by: bin/output-index-inventory.sh -->
<div id="inventory">
<h1 id="inventory-for-2024maffiodo">Inventory for 2024/maffiodo</h1>
</div>
<h2 id="primary-files">Primary files</h2>
<ul>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/maffiodo/prog.c">prog.c</a> - entry source code</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/maffiodo/Makefile">Makefile</a> - entry Makefile</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/maffiodo/prog.orig.c">prog.orig.c</a> - original source code</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/maffiodo/array.js">array.js</a> - javascript array test</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/maffiodo/console.js">console.js</a> - javascript console implementation</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/maffiodo/fibo.js">fibo.js</a> - javascript fibonacci test</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/maffiodo/gc.png">gc.png</a> - garbage Collector actions inside internal tests</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/maffiodo/math.js">math.js</a> - javascript math test</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/maffiodo/string.js">string.js</a> - javascript forrest test</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/maffiodo/test.js">test.js</a> - javascript test setup</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/maffiodo/try.sh">try.sh</a> - script to try entry</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/maffiodo/utils.js">utils.js</a> - javascript utility test</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/maffiodo/verify.js">verify.js</a> - verify javascript test execution</li>
</ul>
<h2 id="secondary-files">Secondary files</h2>
<ul>
<li><a href="2024_maffiodo.tar.bz2">2024_maffiodo.tar.bz2</a> - download entry tarball</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/maffiodo/README.md">README.md</a> - markdown source for this web page</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/maffiodo/.entry.json">.entry.json</a> - entry summary and manifest in JSON</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/maffiodo/.gitignore">.gitignore</a> - list of files that should not be committed under git</li>
<li><a href=".path">.path</a> - directory path from top level directory</li>
<li><a href="index.html">index.html</a> - this web page</li>
</ul>
<hr style="width:10%;text-align:left;margin-left:0">
<h4>
Jump to: <a href="#">top</a>
</h4>
<!-- END: next line ends content generated by: bin/output-index-inventory.sh -->
<!-- END: this line ends content for HTML phase 22 by: bin/output-index-inventory.sh via bin/md2html.sh -->
<!-- START: this line starts content from: inc/after-content.default.html -->
</div>
<!-- END: this line ends content from: inc/after-content.default.html -->
<!-- START: this line starts content from: inc/footer.inventory.html -->
<!--
Copyright © 1984-2025 by Landon Curt Noll. All Rights Reserved.
You are free to share and adapt this file under the terms of this license:
Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
For more information, see:
https://creativecommons.org/licenses/by-sa/4.0/
-->
<div class="footer">
<div id="copyright"><h3>Copyright &copy; 1984-2025 by Landon Curt Noll:
<a href="https://creativecommons.org/faq/#what-does-some-rights-reserved-mean"
target="_blank"
rel="license noopener noreferrer">Some Rights Reserved</a></h3>
<p>
This work is <b>licensed by Landon Curt Noll</b> under
<b><a href="https://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1"
target="_blank"
rel="license noopener noreferrer"
style="display:inline-block;">CC BY-SA 4.0</a></b>.
<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;"
src="../../png/cc.png"
alt="cc inside circle symbol">
<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;"
src="../../png/by.png"
alt="person inside circle symbol">
<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;"
src="../../png/sa.png"
alt="arrow looping back on itself inside circle symbol"><br>
You should <b>carefully review</b> the
<b><a href="https://creativecommons.org/licenses/by-sa/4.0/legalcode.en"
target="_blank"
rel="license noopener noreferrer">CC BY-SA 4.0 LEGAL CODE</a></b>
before using the licensed material.<br>
You may wish to review the
<b><a href="../../license.html"
target="_blank"
rel="license noopener noreferrer">highlights of some of the key features and terms</a></b>
of <b>CC BY-SA 4.0</b>.<br>
</p>
</div>
<div id="coda"><h3>Coda</h3>
<p>
<a href="https://validator.w3.org/nu/?doc=#" rel="nofollow">Nu HTML check this web page</a><br>
<a href="#top">Jump to top</a> <a href="#content">Jump to Content</a> <a href="#inventory">Jump to Inventory</a><br>
</p>
</div>
</div>
<!-- END: this line ends content from: inc/footer.inventory.html -->
<!-- START: this line starts content from: inc/bottom.default.html -->
</body>
</html>
<!-- END: this line ends content from: inc/bottom.default.html -->