Pull to refresh

Транспилятор PAS2JS из Паскаля в JavaScript: несовместимости с Delphi и пути обхода

Reading time3 min
Views7.9K

В наше время в кармане обычного человека лежит мощный персональный компьютер, о котором 10-20 лет назад можно было только мечтать. И если у вас километры отлаженного Windows-кода и отлично работающие приложения и утилиты, написанные на Delphi, вы наверняка хотели бы задействовать это богатство для мобильной разработки. А также опыт, накопленный за время программирования под Windows. PAS2JS поможет вам совместить два мира: разработку под Windows и создание Web-приложений и Node.js модулей.


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


Почему просто не изучить JavaScript и писать Web-приложения на нём?


Я изучил язык JavaScript в достаточной мере. Но во-первых, программирование для Web — это больше чем просто знание языка. Во-вторых, возможность писать один код под разные платформы бесценна. Можно отладить модули приложения в Delphi IDE, используя его мощный отладчик и редактор, и затем, добавив необходимую обвязку, получить готовое работающее приложение для сайта. А когда вы исправите ошибку или добавите новую функциональность в приложение для Windows, достаточно будет только перекомпилировать JavaScript-модули в PAS2JS.


Нужно заметить, что пока PAS2JS поддерживает не все возможности языка Delphi, они указаны на сайте. Также некоторые фрагменты, казалось бы, простого кода PAS2JS не может транспилировать в JavaScript.


Трудности перевода


Итак, свежий пакет PAS2JS скачан с FTP, пробуем перекомпилировать простой «Привет, мир», и сразу же остановка на:


uses
  System.SysUtils;

Error: can't find unit "System.SysUtils"

Готовые пакеты PAS2JS, которые можно найти в папке packages, частично дублируют системные юниты Delphi. Но у них нет префикса в имени. Решение простое: удаляем префикс «System.» из названия юнита. Программа в Delphi компилируется (если нет — проверьте наличие префикса «System» в Unit Scope Names, в меню Delphi Project | Options | Delphi Compiler).


Приведение типа в константах


PAS2JS не поддерживает приведение типа в константных выражениях:


const
  CODE_A = Word('a');

Error: Constant expression expected

В случае перечислимых типов можно попробовать поменять так, это проходит:


const
  CODE_A = Ord('a');

Также PAS2JS не понимает встроенные функции языка Lo и Hi. В определении констант их можно заменить так:


const
  LO_BYTE = $1234 and $FF; // Lo($1234);
  HI_BYTE = $1234 shr 8;// Hi($1234);

Символы и строки ANSI


Я надеюсь, вы уже перешли на Unicode-строки в своих Delphi-проектах? Если же вы оставили часть строк в формате ANSI в целях экономии памяти, они в JavaScript не сконвертируются: PAS2JS не знает типы AnsiChar, AnsiString, Utf8String и RawByteString. Рассмотрите возможность заменить их на Unicode-типы, либо на Byte и Array of Byte.


Вот пример замены AnsiChar на Byte:


// Было
procedure TestAnsiCharAndByte1;
const
  SMALL_ENG_LETTERS = ['a'..'z'];
  CAPITAL_ENG_LETTERS = ['A'..'Z'];
var
  ch: AnsiChar;
  engs: set of AnsiChar;
begin
  engs := SMALL_ENG_LETTERS + CAPITAL_ENG_LETTERS;
  ch := 'Z';
  if ch in engs then
    Writeln('It''s an English letter');
end;

// Стало
procedure TestAnsiCharAndByte2;
const
  SMALL_ENG_LETTERS = [Ord('a')..Ord('z')];
  CAPITAL_ENG_LETTERS = [Ord('A')..Ord('Z')];
var
  ch: Byte;
  engs: set of Byte;
begin
  engs := SMALL_ENG_LETTERS + CAPITAL_ENG_LETTERS;
  ch := Ord('Z');
  if ch in engs then
    Writeln('It''s an English letter');
end;

Неуживчивая буква ó


Как курьёз: в польском языке есть буква ó — O kreskowane, Unicode #$00F3. По каким-то причинам PAS2JS её невзлюбил, и в некоторых случаях не может воспринять строку, если в неё входит эта буква:


var
  s: string;
begin
  s := #$00F3'abdef'; // Компилируется
  s := 'abdef'#$017C; // Компилируется
  s := #$00F3'abdef'#$017C; // Error: Illegal character
  s := #$00F3; s := s + 'abdef'#$017C; // Так снова компилируется
end;

Оператор Case


Внезапная неожиданность подстерегла в операторе case, в котором PAS2JS отказался принимать русские буквы в качестве вариантов выбора:


  ch := 'Я';
  case ch of
    'А': Writeln('Это "А"'); // Error: Incompatible types: got "Char" expected "Char" (???)
    'Б'..'Я': Writeln('Это другая русская буква'); // Error: char expected, but string found
  end;

Помогло определение констант для нужных русских букв:


const
  ckbA = #$410; // А
  ckbB = #$411; // Б
  ckbYa = #$42F; // Я
var
  ch: Char;
begin
  ch := 'Я';
  case ch of
    ckbA: Writeln('Это "А"');
    ckbB..ckbYa: Writeln('Это другая русская буква');
  end;

Выводы


Мне удалось скомпилировать для Web небольшой проект Delphi, внеся сравнительно небольшие изменения в исходный текст программы, а на сэкономленное время я написал эту статью. Тестирование показало, что обе версии программы: для Windows и для Web, работают абсолютно одинаково. Это несомненно успех: теперь я могу развивать этот проект, дорабатывая программу на Delphi, и транспилируя её в JavaScript с помощью PAS2JS.


Что касается выявленных небольших недочётов, я уверен они будут быстро устранены. Поскольку проект PAS2JS — открытый и свободный, активно развиваемый силами сообщества Free Pascal.

Only registered users can participate in poll. Log in, please.
Если Вы программируете на Delphi/Pascal, пишете ли Вы также под Web и mobile?
21.82% Нет, не пишу для Web и mobile и не планирую12
50.91% Да, но только использую другие языки и средства разработки (Java, JavaScript, PHP и проч.)28
21.82% Да, пишу либо готов попробовать Delphi/Pascal для мобильной и/или Web-разработки12
5.45% Другое (напишите в комментарии)3
55 users voted. 31 users abstained.
Tags:
Hubs:
+18
Comments17

Articles

Change theme settings