From e6201286acc4e610149f81fb16714e200b118431 Mon Sep 17 00:00:00 2001 From: Noratrieb <48135649+Noratrieb@users.noreply.github.com> Date: Thu, 13 Feb 2025 21:58:53 +0100 Subject: [PATCH] init --- index.css | 93 +++++++++++++++++++++++++++++++++++++++++ index.html | 52 +++++++++++++++++++++++ lesson-0.html | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++ lessons.js | 94 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 351 insertions(+) create mode 100644 index.css create mode 100644 index.html create mode 100644 lesson-0.html create mode 100644 lessons.js diff --git a/index.css b/index.css new file mode 100644 index 0000000..624ca75 --- /dev/null +++ b/index.css @@ -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; +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..dfda3b0 --- /dev/null +++ b/index.html @@ -0,0 +1,52 @@ + + + + + + + Womangling + + +
+
+

Learn C++ Itanium Mangling

+ +

+ This website will teach you C++ Itanium Name Mangling. Itanium-style + mangling is used on a lot of platforms, including Linux. +

+

+ Since C++ mangling (the entire ABI) is considered stable today, you + will be able to use this knowledge forever! +

+

+ 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. +

+ +
+
+ + diff --git a/lesson-0.html b/lesson-0.html new file mode 100644 index 0000000..1f14753 --- /dev/null +++ b/lesson-0.html @@ -0,0 +1,112 @@ + + + + + + + Womangling + + +
+
+

Learn C++ Itanium Mangling

+

Lesson 1: Intro and C names

+ + +
+

+ 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. +

+

+ For every exercise, there will be a small quiz. If you complete the + quiz, you can continue +

+
+

To complete the first quiz, press the button below.

+
+ +
+
+
+
+
+

+ 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. +

+

+ To reference this function in C++, we use an + extern "C" block. +

+
+extern "C" {
+  void hello() {}
+}
+          
+

+ Because no mangling is applied to the identifier at all, the symbol + for this function will simply be hello. +

+

+ Similarly, a more complex example would be the following function: +

+
+extern "C" {
+  int main(int argc, char* argv[]) {}
+}
+          
+

+ But once again, the symbol name will simply be + main because no mangling is applied. +

+
+

What is the mangled symbol of the following function?

+
+extern "C" {
+  long long meow(long long argument, long long second) { /* too long */ }
+}
+            
+
+ + +
+
+
+
+
+

meow meow meow!!

+
+
+
+ + + + diff --git a/lessons.js b/lessons.js new file mode 100644 index 0000000..cc37941 --- /dev/null +++ b/lessons.js @@ -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();