Творим дичь с помощью инструментов веб-разработки
Или что будет если заставить очень опытного разработчика заниматься не своим делом. Думаю после этой статьи термин «overqualified» заиграет для вас новыми красками.
Наш волшебный дикий веб
Что первым делом приходит в голову, когда говорят о «веб-разработке»? Наверное анальная контузия и фистинг кулаком создание сайтов или веб-приложений?
Лендинги, сайты-визитки, интернет-магазины или веб-порталыв ад.
Самые продвинутые вспомнят про PWA и какой-нибудь React Native с Flutter — весь возможный предел для полета фантазии обычного разработчика.
главное что отделяет человека разумного от великих свершений (кроме денег) это его фантазия — поскольку нельзя сделать только то, что невозможно вообразить.
Поэтому сейчас мы снова будем расширять ваше сознание — в превентивных мерах и как обычно дрелью и дыроколом подручными средствами.
Перед вами шесть проектов отборнейшей дичи — реализующих самые безумные идеи с помощью вполне обыденных инструментов веб-разработчика.
Пожалуйста не пытайтесь рассказывать о таком на интервью в обычных компаниях — с высокой долей вероятности вас навсегда внесут в «черные списки» как #бнутого.
Дичь первая: HTMLang
Не могу пропустить столь жизнеутверждающее описание от автора этого замечательного проекта:
They were laughing that HTML was not a real programming language... WHO"S LAUGHING NOW!!11
Да, это именно то что вы подумали — кто-то будучи сильно не в себе взял синтаксис HTML и слепил на его основе полноценный язык программирования.
Нет, это не шутка — это п#здец.
Вот так выглядит реализация знаменитого FizzBuzz:
<!DOCTYPE html> <html> <head> <title>FizzBuzz</title> </head> <body> <h3>Look into the DevTools Console</h3> <htmlang style="display: none;"> <call target="console.log"><s>Generating FizzBuzz...</s></call> <for><v>i</v> <n>1</n> <n>100</n> <cond> <when> <eq> <mod> <v>i</v> <n>15</n> </mod> <n>0</n> </eq> <call target="console.log"> <s>FizzBuzz</s> </call> </when> <when> <eq> <mod> <v>i</v> <n>3</n> </mod> <n>0</n> </eq> <call target="console.log"> <s>Fizz</s> </call> </when> <when> <eq> <mod> <v>i</v> <n>5</n> </mod> <n>0</n> </eq> <call target="console.log"> <s>Buzz</s> </call> </when> <else> <call target="console.log"><v>i</v></call> </else> </cond> </for> </htmlang> <script src="./HTMLang.js"></script> </body> </html>
Кто там рассказывал на парах про «декларативный язык разметки» и «общую неполноценность», ась?
HTML (от англ. HyperText Markup Language — «язык гипертекстовой разметки») — стандартизированный язык гипертекстовой разметки документов для просмотра веб-страниц в браузере.
А автор тем временем будет дико гогоча писать в консоль тегами HTML:
<call target="console.log"> <s>FizzBuzz</s> </call>
Все потому что не надо нанимать системных программистов, прошедших полноценное обучение по дисциплинам CS (вроде курса по разработке компиляторов) для работы заштатным говночистом в обычном корпоративном проекте — может случиться неприятность:
в самый интересный момент окажется что половина работы реализована на чем-то таком интересном.
А сотворивший это «великий гуру» внезапно пропал, выключив телефон и переехал в поисках истины в солнечную Караганду Канаду.
Хотя это далеко не последняя психическая травма, которую сегодня нанесет вам моя статья — ведь мы едем дальше, к следующему #банутому проекту!
Дичь вторая: HTML-as-programming-language
Нехорошие мысли о набивании кода х#ем по клавиатуре терзают очень многих опытных разработчиков, поэтому та же самая идея проекта «полноценной разработки на HTML» не дает покоя и автору этого проекта.
Но только он зашел в этом процессе сильно дальше предыдущего.
Как вам например функция на чистом HTML:
<def multiplyFunction returns=int> <!-- You can create functions --> <param a type=int/> <param b type=int/> <return>a * b</return> </def> <def main> <var result type=int> <!-- Create variables --> <multiplyFunction> <!-- and store the result of the function in the variable --> <param>5</param> <param>6</param> </multiplyFunction> </var> </def>
Известная библейская фраза «многие знания — многие печали» — как раз про этот проект, я бы очень хотел все это забыть и никогда о подобном не знать.
Лучше порно с дельфинами чем такой п#здец, ей богу.
Но к сожалению уже слишком поздно, поэтому делюсь откровениями:
Да, вы все правильно поняли — это самый настоящий компилятор из HTML в нативный бинарник.
А сейчас вам совсем поплохеет:
To write code for Adruino/AVR microcontrollers, (Arduino UNO for example) you need to put a DOCTYPE tag in your HTML file.
<!DOCTYPE avr/atmega328p>
Да, это была оригинальная задумка автора — разработка для микроконтроллеров на HTML, я ничего не додумываю.
К слову — именно по этой причине и нужна была небольшая магия с #include <stdio.h> на скриншоте выше — компилятор предназначен для микроконтроллеров и не добавляет в генерируемый код на С стандартный для обычной ОС заголовок.
К сожалению у меня не оказалось под рукой такого девайса, так что полноценную работу и весь пайплайн проверить не смог.
To compile your AVR/Arduino code:
htmlc my-code.html -compile
To upload your code to an arduino or other AVR microcontroller:
htmlc my-code.html -upload
Но если среди читателей найдутся отбитые наглухо смелые люди, которые смогут это запустить — с радостью почитаю о впечатлениях.
А мы тем временем переходим к следующему замечательному проекту.
Дичь третья: ass-js
Таким названием и не менее характерным логотипом:
(‿*‿)
Assembler.js
авторы как бы честно намекают на суть:
Assembler implemented in JavaScript
Полагаю вы еще никогда не устанавливали компилятор ассемблера с помощью npm?
Ну что же, все когда-нибудь бывает в первый раз:
npm i ass-js
Поздравляю с очередным лишениеммозговойдевственности.
А так выглядит классический «Hello, world»:
import {X64} from '../src/index'; const asm = X64(); asm.code(_ => { _('db', 'Hello World!\n'); _('mov', ['rax', 1]); // 0x48, 0xC7, 0xC0, 0x01, 0x00, 0x00, 0x00 _('mov', ['rdi', 1]); _('lea', ['rsi', _('rip').disp(-34)]); _('mov', ['rdx', 13]); _('syscall'); _('ret'); }); console.log(asm.toString());
Только не показывайте любимому преподу с курса по ассемблеру — дедушке станет плохо.
Есть даже отдельный туториал по разбору этого «Hello world», где по шагам разобрано как оно работает.
Еще нашелся замечательный вопрос к автору:
I was looking at your project and I couldn't figure out a reason as to why I would (and what, rather) implement with this.
Который как бы намекает на уровень треша и угара в этом проекте.
Но едем дальше — к следующему отбитому проекту.
Дичь четвертая: ts2c
Тут все более-менее просто и очевидно (для дичи):
Produces readable C89 code from JS/TS code.
Все кроме смысла существования этого замечательного проекта — понятно и очевидно.
Как-то так выглядит весь пайплайн:
Если вам вдруг будет нужен транспилер из Typescript в чистый Си — берите и пользуйтесь, благо проект очень даже рабочий:
npm install -g ts2c
Работает кстати и из браузера:
<script src="https://unpkg.com/typescript"></script> <script src="ts2c.bundle.js"></script> <script> var cCode = ts2c.transpile("console.log('Hello world!')"); alert(cCode); </script>
Есть даже онлайн версия:
Несмотря на то что автор честно пишет о куче недоработок:
Work in progress: it works, but only about 70% of ES3 specification is currently supported: statements and expressions - 95%, built-in objects - 17%.
Скажу что это самый работоспособный проект из серии, все остальное буквально рассыпается в руках.
Рассыпается и валится и наш следующий поциент.
Дичь пятая: nerd
Как легко и быстро понять что исследуемый проект — трешевое, нерабочее и глючное говно?
По описанию, обещающему бесконечные ништяки:
Javascript's God Mode. No VM. No Bytecode. No GC. Just native binaries.
Отсылка к чему-то божественному в описании технического проекта это вообще практически диагноз, можно отбраковывать только по одному этому признаку — врядли ошибетесь.
Как нетрудно догадаться, вместо нормального JavaScript тут что-то свое:
NerdLang is a substract of JS with some additions, focus on efficiency.
И это «свое» скажем так застряло в далеком прошлом:
Supporting EcmaScript 3 standard
Чтобы вы понимали, 3я редакция этого стандарта вышла в далеком 2000м году. А сам проект пытается в который раз «натянуть сову на глобус» и залезть именно туда, где последовательно обосрались все крупные корпрорации уровня Google:
Nerd is a JavaScript native compiler aiming to make JavaScript universal, Nerd is able to compile native apps for Windows, Mac, Linux, iOS, Android, Raspberry, STM32 and more.
Пайплайн (он же на титульном скриншоте) выглядит вот так:
Автор настолько #бнут суров, что запихал инстукции сборки и линковки модуля работы с сокетами в package.json:
{ .. "version": "0.0.1", "nerd": { "env": ["std"], "read_only": [], "lib": { "win32": [ "-D_WIN32_WINNT=0x0600", "-Wno-narrowing", "-D_GNU_SOURCE", "-I{__EXTERN__}/libuv/include/", "-I{__EXTERN__}/libuv/src/", "-D_CRT_SECURE_NO_DEPRECATE", "-D_CRT_NONSTDC_NO_DEPRECATE", "{__EXTERN__}/libuv/src/*.h", "{__EXTERN__}/libuv/src/*.c", "{__EXTERN__}/libuv/src/win/*.h", "{__EXTERN__}/libuv/src/win/*.c", "-I {__MODULE__}/httplib/uWS/", "-I {__MODULE__}/httplib/uSockets/", "{__MODULE__}/httplib/uSockets/*.c", "{__MODULE__}/httplib/uSockets/crypto/*.c", "{__MODULE__}/httplib/uSockets/eventing/*.c", "-DLIBUS_NO_SSL", "-DUWS_NO_ZLIB", "-fpermissive", "-w", "-lm", "-ladvapi32", "-liphlpapi", "-lpsapi", "-lshell32", "-luser32 ", "-luserenv", "-lwsock32", "-lws2_32" ] } } }
Я слегка оху#л когда это увидел не рискнул адаптировать такое для сборки под Linux, так что вы останетесь без примера запуска HTTP-сервера на этой йобе.
Дичь шестая: lemon
Наконец последний на сегодня проект, который по сравнению с предыдущими является можно сказать нормальным и даже применимым:
Lemon is a framework for building Javascript runtime software, built on the Chrome V8 Javascript Engine.
Мне он понравился своей какой-то запредельной простотой (по сравнению со всеми остальными проектами) и легкостью встраивания.
Специально показываю скрипт сборки целиком:
CXX = g++ V8 = engine/lib/v8 define INCLUDE $(V8)/include engine/Core.cpp engine/Environment.cpp engine/Lemon.cpp engine/StaticHelpers.cpp engine/ObjectCreator.cpp endef define APP app/*.cpp endef define LIB $(V8)/out/x64.release/obj/ endef define OBJ v8_monolith endef export INCLUDE export APP export LIB export OBJ build: $(CXX) -I $INCLUDE $APP -L $LIB -l $OBJ -std=c++0x -pthread -o lemon
Настолько простую сборку V8 вижу впервые в жизни, честно.
Оно действительно собирается одной командой:
Ниже показано как выглядит двойной «Hello, world», в котором есть как часть на JavaScript так и часть на C++ — я немного подумав объединил два примера из документации в один.
version(); console.log("Превед из JS"); helloworld();
#ifndef APP #define APP #include "../engine/Lemon.hpp" using v8::Context; class App : public Lemon { public: void Start(int argc, char* argv[]); void SetupEnvironment(); }; #endif
#include "App.hpp" using namespace v8; static void Log(const FunctionCallbackInfo<Value>& args) { HandleScope scope(args.GetIsolate()); String::Utf8Value str(args.GetIsolate(), args[0]); const char* cstr = StaticHelpers::ToCString(str); fprintf(stdout, "%s", cstr); fprintf(stdout, "\n"); fflush(stdout); } static void HelloWorld(const FunctionCallbackInfo<Value>& args) { printf("Превед из C++ \n"); } void App::SetupEnvironment() { this->CreateGlobalMethod("helloworld", HelloWorld); } void App::Start(int argc, char* argv[]) { for (int i = 1; i < argc; ++i) { // Get filename of the javascript file to run const char* filename = argv[i]; // Create a new context for executing javascript code Local<Context> context = this->CreateLocalContext(); // Enter the new context Context::Scope contextscope(context); this->CreateGlobalObject("console") .SetPropertyMethod("log", Log) .Register(); // Run the javascript file this->RunJsFromFile(filename); } }
Чудны дела твои Господи, коль даже перебирая запредельную дичь есть шанс найти столь мощный проект.
Почему я так радуюсь?
Потому что это самый настоящий V8, не самопальное поделие по мотивам, а именно то самый движок, который используется в браузере Chrome — со всеми оптимизациями и наворотами.
А значит при определенных усилиях, у вас будет работать практически любой JavaScript код — в вашем рантайме, без всяких жирных Node.js и всего геммороя с линковкой и версиями.
Словом — берите на вооружение, пригодится.
Одной строкой
Конечно же интересных проектов в области творения дичи куда больше чем я смогу описать, поэтому ниже небольшая подборка того что я нашел, счел интересным но не смог или не успел запустить.
Compile javascript to LLVM IR, x86 assembly and self interpreting
К сожалению оказался прибит гвоздями к MacOS, ни нормально собрать ни прогнать тесты под Linux не удалось.
Интересен тем что в одном проекте собран и интерпретатор и компилятор, причем в нативный бинарник.
JavaScript Assembler x86-16
Генерирует com-файлы времен DOS, под эмулятором Dosbox не завелись.
Duktape - embeddable Javascript engine with a focus on portability and compact footprint
Более продвинутый и известный аналог Lemon, не успел посмотреть.
clang ported to js
Сломанная и сильно устаревшая сборка, но сам проект — очень крутой, тк это полноценный компилятор Clang, вытащенный в веб.
Вот тут есть рабочая онлайн версия.
LLVM compiled to JavaScript using Emscripten
Сломанная и устаревшая сборка, нереально запустить.
Она же в готовом виде онлайн.
Compile JS into LLVM IR - JavaScript Static Analysis Tool
Вот тут находится статья про этот проект, но мне собрать не удалось.
A toy js -> c++ compiler written in coffeescript. Uses escodegen to write c++ and tern to figure out types.
Устаревшая и сломанная сборка.
Compiled implementation of Javascript, targeting C (for fun)
Половина тестов сломана, но сама сборка проходит - не стал детально изучать.
Letter is a compiler project built in TypeScript using LLVM node bindings.
Очень интересный, но к сожалению устаревший проект — требует устаревший 13й LLVM и старую же версию Node.js.
Подружить с новыми версиями LLVM и Node не удалось.
A tiny C compiler written purely in JavaScript.
Еще один интересный, но неработающий проект — сам компилятор отработал, но ассемблерный код отказался собираться.