Творим дичь с помощью инструментов веб-разработки

в 21:59, , рубрики: c++, transpiler, Компиляторы, Си

Или что бывает если заставить очень опытного разработчика заниматься не своим делом. Думаю после этой статьи термин «overqualified» заиграет для вас новыми красками.

От авторов, запихнувших веб‑сервер на визитку и локализующих корпоративные приложения на клингонский — держим марку!

Пять минут вдумчивого изучения этого скриншота могут привести к нервному срыву, я предупредил.
Пять минут вдумчивого изучения этого скриншота могут привести к нервному срыву, я предупредил.

Наш волшебный дикий веб

Что первым делом приходит в голову, когда говорят о «веб-разработке»? Наверное создание сайтов или веб-приложений?

Лендинги, сайты-визитки, интернет-магазины или какие-нибудь веб-порталы в ад.

Самые продвинутые из читателей наверное вспомнят PWA или какой-нибудь React Native с Flutter — предел полета фантазии обычного разработчика.

Что плохо:

главное что отделяет человека от великих свершений это его фантазия — точно нельзя сделать только то, что невозможно вообразить.

Поэтому сейчас мы будем расширять ваше воображение — в превентивных мерах, дрелью и дыроколом подручными средствами.

Перед вами шесть проектов отборнейшей дичи — реализующих самые безумные идеи с помощью вполне обыденных инструментов современного веб-разработчика.

Пожалуйста не пытайтесь рассказывать о таком на интервью в обычных компаниях — пожалейте интервьюера и его нежную психику.

Автор когда‑то давно (когда еще ходил по собеседованиям) довел одного интервьюера до нервного срыва, просто в деталях рассказав как на самом деле работает загрузка больших файлов через форму со стороны сервера — про HTTP 100 Continue, разбор MIME и прочие радости.

Люди тогда были сильно крепче головой чем сейчас, в нынешних реалиях могут и побить прямо на интервью.

Дичь первая: 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>

Не представляю что будет если самому Джоэлу выдать его же знаменитый «FizzBuzz» в такой реализации — есть шанс что старый сишный программист впадет в рекурсию.

Кстати кто там рассказывал на лекциях про «декларативный язык разметки» и «общую неполноценность»?

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, правда?

Замечательный пайплайн с вызовом компилятора HTML, правда?

Да, вы все правильно поняли — это самый настоящий компилятор из HTML в нативный ELF64 бинарник.

А сейчас вам совсем поплохеет:

To write code for Adruino/AVR microcontrollers, (Arduino UNO for example) you need to put a DOCTYPE tag in your HTML file.

For example:

<!DOCTYPE avr/atmega328p>

Да, это была оригинальная задумка автора — разработка для микроконтроллеров на HTML, я ничего не додумываю.

Увидев такой вот DOCTYPE, один знакомый веб-разработчик навсегда бросил пить.

К слову, небольшая магия с #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 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.

Собственно все кроме смысла существования этого замечательного проекта — понятно и очевидно. Как-то так выглядит весь пайплайн:

Творим дичь с помощью инструментов веб-разработки - 5

Если вам вдруг будет нужен транспилер из 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>

Есть даже онлайн версия:

Творим дичь с помощью инструментов веб-разработки - 6

Несмотря на то что автор честно пишет о куче недоработок:

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.

Отсылка к чему-то божественному в описании технического проекта это вообще практически 100% диагноз, можно отбраковывать только по одному этому признаку — врядли ошибетесь.

Как нетрудно догадаться, вместо нормального 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.

Разумеется я не мог пройти мимо такого, поэтому всю эту дичь собрал и запустил, хотя и пришлось немного исправлять скрипты сборки.

Пайплайн (присутствует на титульном скриншоте) выглядит вот так:

Творим дичь с помощью инструментов веб-разработки - 7

Автор настолько суров, что запихал инстукции сборки и линковки модуля работы с сокетами в 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"
		]
    }
  }
}

Увидев вот такой package.json, знакомый веб-разработчик (другой) решил навсегда уйти из профессии и теперь пасет коз в горах Кавказа.

Ну а я всего лишь не рискнул адаптировать такое для сборки под 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 " class="formula inline">$INCLUDE $$APP -L $$LIB -l $$OBJ -std=c++0x -pthread -o lemon

И.. это все.

Настолько простую сборку V8 вижу впервые в жизни, честно.

Оно действительно собирается одной командой:

Творим дичь с помощью инструментов веб-разработки - 8

Ниже показано как выглядит двойной «Hello, world», в котором есть как часть на JavaScript так и часть на C++ — немного подумав объединил два примера из документации в один.

App.js:

version();
console.log("Превед из JS");
helloworld();

App.hpp:

#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

App.cpp:

#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, не самопал с реализацией ECMAScript «в переводе Гоблина», а именно тот самый движок, который используется в браузере Chrome — со всеми оптимизациями и наворотами.

А значит при определенных усилиях, у вас будет работать практически любой JavaScript код — в вашем нативном приложении, без всяких жирных Node.js и всех проблем с линковкой и версиями.

Словом берите на вооружение, пригодится.

Одной строкой

Конечно же интересных проектов в области творения дичи куда больше чем хватит сил описать, поэтому ниже небольшая подборка найденного и интересного, но неработающего.

js-ziju

Compile javascript to LLVM IR, x86 assembly and self interpreting

К сожалению оказался прибит гвоздями к определенной версии MacOS, ни нормально собрать ни прогнать тесты под Linux не удалось. Интересен тем что в одном проекте собран и интерпретатор и компилятор, причем в нативный бинарник.

JS-ASM

JavaScript Assembler x86-16

Генерирует готовые COM-файлы времен DOS, но под эмулятором Dosbox они работать отказались.

Duktape

Duktape — embeddable Javascript engine with a focus on portability and compact footprint

Более продвинутый и известный аналог Lemon, который я нашел слишком поздно и не успел посмотреть.

clangor

«clang ported to js» — можно сразу в цитаты добавлять.

Сломанная и сильно устаревшая сборка, но сам проект — очень крутой, поскольку это полноценный компилятор Clang, вытащенный в веб.

Вот тут есть онлайн версия.

llvm.js

LLVM compiled to JavaScript using Emscripten

Снова сломанная и устаревшая сборка, починить за разумное время не получилось.

Она же в готовом виде онлайн.

jssat

Compile JS into LLVM IR - JavaScript Static Analysis Tool

Вот тут находится статья про этот проект, но мне собрать так и не удалось.

js2cpp

A toy js -> c++ compiler written in coffeescript. Uses escodegen to write c++ and tern to figure out types.

Опять сильно устаревшая и сломанная сборка.

js-to-c

Compiled implementation of Javascript, targeting C (for fun)

Половина тестов сломана, но сама сборка проходит — не стал детально изучать.

Letter

Letter is a compiler project built in TypeScript using LLVM node bindings.

Очень интересный, но к сожалению устаревший проект — требует 13й LLVM и старую же версию Node.js.

Подружить с новыми версиями LLVM и Node не удалось.

CaptCC

A tiny C compiler written purely in JavaScript.

Еще один интересный, но неработающий проект — сам компилятор отработал, но ассемблерный код отказался собираться.

Эпилог

Все описанные в этой статье проекты приведены в первую очередь для расширения границ вашего воображения — просто чтобы вы знали что так тоже бывает.

Пожалуйста не пытайтесь такое внедрять и использовать в рельном проекте, если не имеете за плечами серьезного опыта и/или профильного обучения по CS.

Либо умеете быстро бегать и имеете запасное гражданство.

Куда более вольная версия данной статьи доступна в нашем блоге.

0x08 Software

Мы небольшая команда ветеранов ИТ‑индустрии, создаем и дорабатываем самое разнообразное программное обеспечение, наш софт автоматизирует бизнес‑процессы на трех континентах, в самых разных отраслях и условиях.

Оживляем давно умершеечиним никогда не работавшее и создаем невозможное — затем рассказываем об этом в своих статьях.

Автор: Alex Chernyshev

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js