Difference between revisions of "pas2js/ru"

From Lazarus wiki
Jump to navigationJump to search
Line 158: Line 158:
 
= Supported syntax elements =
 
= Supported syntax elements =
  
Basically, [[Delphi]] 7 syntax is supported.  
+
В основном, поддерживается синтаксис [[Delphi]] 7. Это включает RTTI.
This includes RTTI.
+
Более подробный список можно найти в источниках файла [https://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/utils/pas2js/docs/translation.html?view=co translation.html].
A more detailed list can be found in the [https://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/utils/pas2js/docs/translation.html?view=co translation.html].file in the sources.
 
  
*[[Mode_Delphi|Delphi]] and [[Mode_ObjFPC|ObjFPC]] mode
+
*режим [[Mode_Delphi|Delphi]] и [[Mode_ObjFPC|ObjFPC]]
*[[Program]], [[Unit]]s, namespaces
+
*[[Program]], [[Unit]]s, пространства имен
*unit initialization, but not finalization
+
*инициализация модуля, но не финализация
 
*[[Var]], [[Const]], [[Type]]
 
*[[Var]], [[Const]], [[Type]]
 
*string (unicodestring), char (widechar), [[Boolean]], [[Double]], [[Byte]], [[Shortint]], [[Word]], [[Smallint]], longword, [[Longint]], nativeint(int53), nativeuint(int52), currency
 
*string (unicodestring), char (widechar), [[Boolean]], [[Double]], [[Byte]], [[Shortint]], [[Word]], [[Smallint]], longword, [[Longint]], nativeint(int53), nativeuint(int52), currency
 
*resourcestrings
 
*resourcestrings
*[[Pointer]] (as a reference to a class, array, record, pointer of record, interface, but no pointer arithmetic)
+
*[[Pointer]] (как ссылка на класс, массив, запись, указатель записи, интерфейс, но без арифметики указателя)
*[[Record]] (but no variant records)
+
*[[Record]] (но не variant records)
*[[Function]]s, [[Procedure]]s, nested, anonymous functions
+
*[[Function]]s, [[Procedure]]s, вложенные, анонимные функции
*function types, of object, reference to (closures)
+
*типы функций: of object, reference to (закрытые)
*function arguments: default, const, var, out
+
*аргументы функций: default, const, var, out
 
*[[If]]-then-else
 
*[[If]]-then-else
 
*[[For]]-do
 
*[[For]]-do
Line 186: Line 185:
 
*class type, visibility, virtual, override, abstract, overload, properties, class properties, class var, class const, constructor, destructor
 
*class type, visibility, virtual, override, abstract, overload, properties, class properties, class var, class const, constructor, destructor
 
*class-of
 
*class-of
*nested classes
+
*вложенные классы
*interfaces: CORBA, COM, delegations, method resolution, reference counting, TVirtualInterface
+
*интерфейсы: CORBA, COM, delegations, method resolution, reference counting, TVirtualInterface
*external classes, vars, const
+
*внешние классы, переменные, константы
*Enumeration for..in..do
+
*Энумератор for..in..do
*Type alias, e.g. type TTranslateString = type string;
+
*Псевдоним типа, например, type TTranslateString = type string;
 
*RTTI
 
*RTTI
*asm block for embedding JavaScript directly
+
*asm блок для встраивания в JavaScript напрямую
*compiler directives (e.g. $ifdef, $if, $define, $modeswitch, $R+)
+
*директивы компилятора (e.g. $ifdef, $if, $define, $modeswitch, $R+)
*compile time and run time range checking
+
*проверка времени компиляции и времени выполнения
  
There are some constructs that are naturally not supported and will never be supported:
+
Есть некоторые конструкции, которые естественно не поддерживаются и никогда не будут поддерживаться:
*Anything involving memory pointers and pointer arithmetic.
+
*Все, что связано с указателями памяти и арифметикой указателей.
 
*Variant records
 
*Variant records
  
Details about supported elements and the conversion from Pascal to JavaScript: [https://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/utils/pas2js/docs/translation.html?view=co translation].
+
Подробно о поддерживаемых элементах и переходе с Pascal на JavaScript: [https://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/utils/pas2js/docs/translation.html?view=co translation].
  
 
= Planned language features =
 
= Planned language features =

Revision as of 23:13, 23 February 2019

Template:Translate

Pas2js: что это?

Компилятор

Pas2js - это транспилер(транскомпилятор) [кода] Pascal в JavaScript. Он парсит Object Pascal и выдает JavaScript. JavaScript в настоящее время имеет уровень ECMAScript 5 и должен запускаться в любом браузере или в Node.js (цель "nodejs"). Доступен в 3 формах:

  • как библиотека
  • как программа командной строки
  • как веб-сервер

Он транскомпилирует [код] из фактических исходников Pascal, у него нет промежуточных файлов .ppu. Это означает, что все исходники должны быть всегда доступны.

Через определения внешних классов компилятор может использовать классы JavaScript:

  • Все классы, доступные во время выполнения JavaScript и в браузере, доступны через модули импорта (сравнимо с модулями windows или unix для собственного компилятора).
  • Для Node.js доступна базовая поддержка среды выполнения nodejs.
  • Доступен модуль импорта для jQuery (libjquery)

RTL

Для работы сгенерированного кода требуется небольшой файл JavaScript: rtl.js. Он определяет объект RTL. Этот объект запустит код Object Pascal, если вы включите вызов rtl.run() на странице HTML.

<script type="application/javascript">
  rtl.run()
</script>

pas2js может автоматически включить этот файл в сгенерированный вывод, например так:

pas2js -Jc -Jirtl.js -Tbrowser hello.pas

Для nodejs компилятор вставит вызов rtl.run() автоматически в конец сгенерированного файла Javascript.

Существует базовый Object Pascal RTL, также доступны несколько модулей из пакетов FPC.

  • system
  • sysutils
  • Math
  • strutils
  • rtlconst
  • classes
  • contnrs
  • DB (да, TDataset)
  • fpcunit testsuite
  • custapp
  • restconnection
  • js (системные объекты javascript)
  • web (объекты, предоставляемые браузером)
  • libjquery (JQuery также доступен)
  • nodejs (среда выполнения базового узла)
  • typinfo
  • objpas
  • browserconsole (поддержка writeln)
  • dateutils
  • browserapp
  • nodejsapp

Где его взять

Компилятор pas2js и RTL - естественно - с открытым исходным кодом и могут быть загружены и использованы свободно.

Снапшоты

Снапшоты содержат двоичные файлы для Windows (32 и 64-разрядная версия), Linux (64-разрядная версия) и MacOS.

Снапшоты загружены в

Каждая версия имеет каталог с номером версии. Список изменений можно найти на странице журнала изменений Pas2JS Version Changes

SVN

svn co https://svn.freepascal.org/svn/projects/pas2js/trunk pas2js

Вам нужен FPC 3.0.4 или старше, чтобы скомпилировать его.

Перейдите в каталог и соберите его с помощью:

make clean all

Это создаст compiler/utils/pas2js/pas2js (Windows: compiler\utils\pas2js\pas2js.exe)

Как использовать pas2js

Аргументы командной строки в основном остаются такими же, как аргументы командной строки FPC. Сообщения об ошибках также в том же формате.

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

Что касается компилятора FPC, поддерживается файл конфигурации, который имеет тот же синтаксис, что и файл конфигурации FPC. Обратите внимание, что снапшоты и версия svn уже содержат файл pas2js.cfg по умолчанию с путями поиска модулей (-Fu) для rtl и fcl.

По сути, команда такая же, как и в любой командной строке FPC. Единственное, что отличается - это цель: '-Tbrowser' или '-Tnodeejs'

Вот полный список аргументов командной строки: аргументы командной строки.

для браузера

Рассмотрим классику:

program hello;

begin
  Writeln('Hello, world!');
end.

Да, writeln поддерживается. Вот как это скомпилировать:

pas2js -Jc -Jirtl.js -Tbrowser hello.pas

После успешной компиляции код можно запустить в браузере, открыв в браузере html-файл со следующим содержимым:

<html>
  <head>
    <meta charset="utf-8"/>
    <script type="application/javascript" src="hello.js"></script>
  </head>
  <body>
    <script type="application/javascript">
     rtl.run();
    </script>
  </body>
</html>

Необходимые файлы:

  • hello.html
  • hello.js

Независимо от того, открыт ли hello.html двойным щелчком по нему в проводнике или помещен на сервер и открыт с помощью URL, это не имеет значения.

Вывод отображается в консоли веб-разработчика браузера. Включив модуль browserconsole, это будет видно на странице браузера:

program hello;

uses browserconsole;

begin
  Writeln('Hello, world!');
end.

для NodeJS

pas2js -Tnodejs hello.pas

После успешной компиляции код можно запустить на узле с помощью следующей команды.

nodejs hello.js
Light bulb  Примечание: в MacOS это "node hello.js"

Supported syntax elements

В основном, поддерживается синтаксис Delphi 7. Это включает RTTI. Более подробный список можно найти в источниках файла translation.html.

  • режим Delphi и ObjFPC
  • Program, Units, пространства имен
  • инициализация модуля, но не финализация
  • Var, Const, Type
  • string (unicodestring), char (widechar), Boolean, Double, Byte, Shortint, Word, Smallint, longword, Longint, nativeint(int53), nativeuint(int52), currency
  • resourcestrings
  • Pointer (как ссылка на класс, массив, запись, указатель записи, интерфейс, но без арифметики указателя)
  • Record (но не variant records)
  • Functions, Procedures, вложенные, анонимные функции
  • типы функций: of object, reference to (закрытые)
  • аргументы функций: default, const, var, out
  • If-then-else
  • For-do
  • Repeat-until
  • While-do
  • With-do
  • try-finally
  • try-except
  • enums
  • sets
  • arrays static, dynamic, open, multi dimensionals
  • String like array operations: a:=[1,2,3]+[1,1];
  • class type, visibility, virtual, override, abstract, overload, properties, class properties, class var, class const, constructor, destructor
  • class-of
  • вложенные классы
  • интерфейсы: CORBA, COM, delegations, method resolution, reference counting, TVirtualInterface
  • внешние классы, переменные, константы
  • Энумератор for..in..do
  • Псевдоним типа, например, type TTranslateString = type string;
  • RTTI
  • asm блок для встраивания в JavaScript напрямую
  • директивы компилятора (e.g. $ifdef, $if, $define, $modeswitch, $R+)
  • проверка времени компиляции и времени выполнения

Есть некоторые конструкции, которые естественно не поддерживаются и никогда не будут поддерживаться:

  • Все, что связано с указателями памяти и арифметикой указателей.
  • Variant records

Подробно о поддерживаемых элементах и переходе с Pascal на JavaScript: translation.

Planned language features

Basically, the idea is to get the pas2js transpiler up to the same level as FPC or Delphi. That means the following needs to be added:

  • Advanced records
  • Runtime checks: Overflow -Co, $Q
  • Generics
  • Type helpers
  • Array of const

Needless to say, anything requiring direct memory access is not going to be supported.

Other not implemented features

  • Attributes
  • Enums with custom values
  • Global properties
  • Futures
  • Helpers for types, classes, records
  • Inline
  • Library
  • Objects
  • Operator overloading
  • Pointer arithmetic
  • Resources
  • RTTI extended, $RTTI
  • Variant records
  • Variants

Lazarus integration of pas2js

Lazarus understands the concept of external classes as used by pas2js, so code completion will work.

Since Lazarus 1.9 the IDE can use pas2js.exe as a normal compiler.

The integration is described here: lazarus pas2js integration. It is still under construction, but deep integration with lazarus is planned.

Importing Javascript classes

To import a javascript class, one writes a normal class definition that mimics the Javascript class. It is possible to use properties. Many examples can be found in the JS, web, nodejs and libjquery units.

Here is a simple example:

  TJSFunction = class external name 'Function'(TJSObject)
  private
    Flength: NativeInt external name 'length';
    Fprototyp: TJSFunction external name 'prototyp';
  public
    name: String;
    property prototyp: TJSFunction read Fprototyp;
    property length: NativeInt read Flength;
    function apply(thisArg: TJSObject; const ArgArray: TJSValueDynArray): JSValue; varargs;
    function bind(thisArg: TJSObject): JSValue; varargs;
    function call(thisArg: TJSObject): JSValue; varargs;
  end;

This declares the TJSFunction object : in Javascript, functions are objects.

  • The "external name 'Function'" means that you declare a Javascript class where the Javascript name of the class is 'Function'.
  • The (TJSObject) means it descends from TJSObject also an external class. There does not need to be an ancestor type.
  • Fields are declared just as in Pascal.
  • To declare read-only fields, a trick can be used: declare the field using an external name "thename" modifier, and declare a read-only property with the same name.
    (see the length declaration)
  • Varargs can be used to indicate that a function accepts any number of arguments.
  • JSValue can be used to indicate an unknown type.
    It is more or less equivalent to a Variant.

Create simple JS objects with the new function

Some JS-framework functions expect an JS object as parameter. Here is how to do that in Pascal using the new function from unit JS:

// JavaScript:
DoIt({name:"Fred", id:3, size:4.3});
// Pascal;
DoIt(new(['name','Fred', 'id',3, 'size',4.3]));

You can nest it to create sub objects:

// JavaScript:
DoIt({name:"Fred", size:{width:3,height:2}});
// Pascal;
DoIt(new(['name','Fred', 'size',new(['width',3, 'height',2])]));

You can use TJSArray._of to create JS arrays on the fly:

// JavaScript:
DoIt({numbers:[1,2,3]});
// Pascal;
DoIt(new(['numbers',TJSArray._of(1,2,3)]));

Debugging

The generated Javascript source code is of course visible and debuggable in the browser.

Moreover, the transpiler can generate a source map, which means that you will be able to see and debug the Pascal code in the browser. (not everything will work, but many things do. This depends on the browser too.)

A source map can be generated using the command-line parameter

-Jm

The easiest is to include the Pascal sources in the source map

-Jminclude

You can tell the compiler to store all file names relative to a local base directory:

-Jmbasedir=DirName

And you can store an URL in the map, so the browser will use URL/above-relative-file-name to get the source:

-Jmsourceroot=URL

Bugs

Please report bugs in the FPC bugtracker with category pas2js: http://bugs.freepascal.org

Examples

Lazarus Widgetset

The ultimate goal is of course to have the LCL running in the web. Discussions on this topic are delegated to a separate page. pas2js_widgetsets

FAQ

Why is a simple hello world program so big?

This is mainly due to the used rtl.js. The rtl.js contains code for Pascal modules, classes, RTTI, sets, range checks, etc and is written with big WebApps in mind, not for scripts with a few lines of code.

  1. You can use a Javascript minifier to reduce the created Javascript
  2. You can create your own minified rtl.js by removing all functions you don't need. Eventually this will be done automatically by pas2js.

Why are asm blocks bad?

Asm blocks are useful for things you cannot do with pas2js. But there are some downsides: pas2js does not parse the JS. Neither does it check the syntax, nor does it know what Pascal identifiers the code is referencing. That means any identifier only accessed by the asm block will be removed by the pas2js' optimizer.

Therefore always try to do it in Pascal. Remember you can typecast values to JSValue, objects to TJSObject, arrays to TJSArray, strings to TJSString, etc to use almost all JS features.

Why not parse asm blocks?

Any compiletime JS parser can only do a syntax check and parse only simple JS. But since simple JS can be better written in Pascal, it is somewhat pointless and has therefore low priority.