This commit is contained in:
nora 2025-02-13 21:58:53 +01:00
commit e6201286ac
4 changed files with 351 additions and 0 deletions

93
index.css Normal file
View file

@ -0,0 +1,93 @@
* {
box-sizing: border-box;
}
html {
--color-primary: rebeccapurple;
--color-white: white;
--color-error: red;
}
.main {
width: 100vw;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.content {
max-width: 50rem;
}
.center {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.start-button {
width: 300px;
height: 100px;
font-size: 3rem;
}
.lessons-list {
list-style: none;
padding: 0;
display: flex;
flex-direction: column;
gap: 10px;
}
.step {
padding-bottom: 20px;
border-bottom: 1px solid black;
margin-bottom: 20px;
}
.code {
padding-left: 30px;
}
.hidden {
display: none;
}
form[data-challenge] > .error {
margin-top: 10px;
color: var(--color-error);
}
.quiz-section {
border: 2px var(--color-primary) solid;
border-radius: 5px;
padding: 10px;
}
.submit-challenge {
height: 2.5rem;
background-color: var(--color-primary);
color: var(--color-white);
font-weight: bold;
border: none;
padding: 0px 10px;
cursor: pointer;
&:hover {
background-color: color-mix(in oklab, var(--color-primary), white 15%);
}
&:disabled {
background-color: color-mix(in oklab, var(--color-primary), grey 80%);
cursor: initial;
}
}
.quiz-input {
height: 2.5rem;
font-size: 1rem;
}

52
index.html Normal file
View file

@ -0,0 +1,52 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="index.css" />
<title>Womangling</title>
</head>
<body>
<main class="main">
<div class="content">
<h1>Learn C++ Itanium Mangling</h1>
<noscript>
<p>
Warning: You have JavaScript disabled While the content is still
viewable, interactive exercises will not work. Consider enabling
JavaScript for this website.
</p>
</noscript>
<p>
This website will teach you C++ Itanium Name Mangling. Itanium-style
mangling is used on a lot of platforms, including Linux.
</p>
<p>
Since C++ mangling (the entire ABI) is considered stable today, you
will be able to use this knowledge forever!
</p>
<p>
This website consists of many lessons, each teaching you something new
about C++ Itanium Mangling. There will be many interactive quizzes at
each step to test your knowledge.
</p>
<div class="center">
<ol class="lessons-list">
<li class="lesson-list-item">
<a href="/lesson-0.html">C names</a>
</li>
<li class="lesson-list-item">
<a href="/lesson.html?lesson=1">Arguments and Return Types</a>
</li>
<li class="lesson-list-item">
<a href="/lesson.html?lesson=2">More Integers</a>
</li>
<li class="lesson-list-item">
<a href="/lesson.html?lesson=3">Namespaces</a>
</li>
</ol>
</div>
</div>
</main>
</body>
</html>

112
lesson-0.html Normal file
View file

@ -0,0 +1,112 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="index.css" />
<title>Womangling</title>
</head>
<body>
<main class="main">
<div class="content" id="content-area">
<h1>Learn C++ Itanium Mangling</h1>
<h2>Lesson 1: Intro and C names</h2>
<noscript>
<p>
Warning: You have JavaScript disabled While the content is still
viewable, interactive exercises will not work. Consider enabling
JavaScript for this website.
</p>
</noscript>
<section data-step="0" class="step">
<p>
Welcome to the interactive Itanium C++ mangling learning website! In
this course you will learn everything there is to know about Itanium
C++ Mangling, especially the things you've never wanted to know.
</p>
<p>
For every exercise, there will be a small quiz. If you complete the
quiz, you can continue
</p>
<div class="quiz-section">
<p>To complete the first quiz, press the button below.</p>
<form data-challenge="1">
<button
data-challenge-submit="1"
class="submit-challenge"
type="submit"
>
Complete first challenge!
</button>
<div class="error"></div>
</form>
</div>
</section>
<section data-step="1" class="step">
<p>
Congrats, you just completed your first challenge! Good job. So,
let's start with the mangling. Before diving too deep into the
innards of Itanium Mangling, let's get more familiar with the way
this works by mangling something trivial: a C function. C functions
are traditionally not mangled (*this is not always fully true on all
platforms). The simplest possible C function takes no arguments and
returns no value. For C it doesn't actually matter what the
parameters or return value are, since there is no mangling.
</p>
<p>
To reference this function in C++, we use an
<code>extern "C"</code> block.
</p>
<pre class="code">
extern "C" {
void hello() {}
}
</pre>
<p>
Because no mangling is applied to the identifier at all, the symbol
for this function will simply be <code>hello</code>.
</p>
<p>
Similarly, a more complex example would be the following function:
</p>
<pre class="code">
extern "C" {
int main(int argc, char* argv[]) {}
}
</pre>
<p>
But once again, the symbol name will simply be
<code>main</code> because no mangling is applied.
</p>
<div class="quiz-section">
<p>What is the mangled symbol of the following function?</p>
<pre class="code">
extern "C" {
long long meow(long long argument, long long second) { /* too long */ }
}
</pre>
<form data-challenge="2" data-answer="meow">
<input class="quiz-input" />
<button
data-challenge-submit="2"
class="submit-challenge"
type="submit"
>
Answer
</button>
<div class="error"></div>
</form>
</div>
</section>
<section data-step="2" class="step">
<p>meow meow meow!!</p>
</section>
</div>
</main>
<script>
window.LESSON = 0;
</script>
<script type="module" src="./lessons.js"></script>
</body>
</html>

94
lessons.js Normal file
View file

@ -0,0 +1,94 @@
let step = 0;
const parseIntThrow = (s) => {
const i = parseInt(s, 10);
if (Number.isNaN(i)) {
throw new Error(`Cannot parse integer for ${s}`);
}
return i;
};
const setShowHiddenSteps = () => {
const elements = document.querySelectorAll("[data-step]");
for (const element of elements) {
const sectionStep = parseIntThrow(element.dataset.step);
if (sectionStep > step) {
element.classList.add("hidden");
} else {
element.classList.remove("hidden");
}
}
};
const rerender = () => {
setShowHiddenSteps();
const buttonElements = document.querySelectorAll(
"button[data-challenge-submit]"
);
for (const element of buttonElements) {
const elemStep = parseIntThrow(element.dataset.challengeSubmit);
element.disabled = elemStep <= step;
}
};
const setStep = (newStep) => {
if (newStep > step) {
step = newStep;
rerender();
}
};
const initButtons = () => {
const formElements = document.querySelectorAll("form[data-challenge]");
for (const element of formElements) {
const step = parseIntThrow(element.dataset.challenge);
const error = element.querySelector(".error");
if (!error) {
alert(`The step ${step} is missing an error div!`);
}
element.addEventListener("submit", (e) => {
e.preventDefault(e);
error.innerText = "";
const answer = element.dataset.answer;
if (!answer) {
setStep(step);
return;
}
const input = e.target[0];
const value = input.value;
if (value === answer) {
setStep(step);
return;
}
// Wrong answer :(
const incorrectTries = parseIntThrow(error.dataset.errors ?? "0");
const messages = [
"This is not the right answer, please try again.",
"This is still not the right answer, please try again.",
`This is still not the right answer, please try again. Tip: The answer is ${answer.length} characters long`,
`The right answer was: '${answer}'. Enter it to finish this step.`,
];
if (incorrectTries >= messages.length) {
input.value = answer;
setStep(step); // just give up and finish lol
return;
}
error.innerText = messages[incorrectTries];
error.dataset.errors = incorrectTries + 1;
});
}
};
const init = () => {
initButtons();
rerender();
};
init();