Tôi sẽ thứ hai về quan điểm của @EliBendersky liên quan đến việc sử dụng ast.parse thay vì phân tích cú pháp (mà trước đây tôi không biết). Tôi cũng nhiệt liệt khuyên bạn nên xem lại blog của anh ấy. Tôi đã sử dụng ast.parse để làm trình dịch Python-> JavaScript (@ https://bitbucket.org/amirouche/pythonium ). Tôi đã nghĩ ra thiết kế Pythonium bằng cách xem xét phần nào các triển khai khác và tự mình thử chúng. Tôi đã fork Pythonium từ https://github.com/PythonJS/PythonJS mà tôi cũng đã bắt đầu, Nó thực sự là một bản viết lại hoàn chỉnh. Thiết kế tổng thể được lấy cảm hứng từ PyPy và http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-89-1.pdf giấy.
Mọi thứ tôi đã thử, từ đầu đến giải pháp tốt nhất, ngay cả khi có vẻ như tiếp thị bằng Pythonium thì nó thực sự không phải như vậy (đừng ngần ngại cho tôi biết nếu có điều gì đó không đúng với cư dân mạng):
Triển khai ngữ nghĩa Python trong JavaScript cũ bằng cách sử dụng kế thừa nguyên mẫu: AFAIK không thể triển khai đa kế thừa Python bằng hệ thống đối tượng nguyên mẫu JS. Tôi đã cố gắng làm điều đó bằng các thủ thuật khác sau đó (xem getattribute). Theo như tôi biết không có triển khai đa kế thừa Python trong JavaScript, tốt nhất tồn tại là Single inhertance + mixin và tôi không chắc chúng xử lý kế thừa kim cương. Loại tương tự như Skulpt nhưng không có google clojure.
Tôi đã thử với Google clojure, giống như Skulpt (trình biên dịch) thay vì thực sự đọc mã Skulpt #fail. Dù sao vì hệ thống đối tượng dựa trên nguyên mẫu JS vẫn không thể. Việc tạo ràng buộc rất khó khăn, bạn cần phải viết JavaScript và rất nhiều mã soạn sẵn (xem https://github.com/skulpt/skulpt/issues/50 nơi tôi là con ma). Vào thời điểm đó, không có cách nào rõ ràng để tích hợp ràng buộc trong hệ thống xây dựng. Tôi nghĩ rằng Skulpt là một thư viện và bạn chỉ cần đưa các tệp .py của mình vào html để thực thi, không cần nhà phát triển thực hiện giai đoạn biên dịch nào.
Đã thử pyjaco (trình biên dịch) nhưng việc tạo liên kết (gọi mã Javascript từ mã Python) rất khó, có quá nhiều mã biên soạn sẵn để tạo mỗi lần. Bây giờ tôi nghĩ pyjaco là loài gần Pythonium hơn. pyjaco được viết bằng Python (cũng vậy) nhưng rất nhiều được viết bằng JavaScript và nó sử dụng kế thừa nguyên mẫu.
Tôi chưa bao giờ thực sự thành công khi chạy Pajamas #fail và chưa bao giờ cố đọc lại mã #fail. Nhưng trong tâm trí tôi, bộ đồ ngủ đang làm API-> API tranlation (hoặc framework sang framework) chứ không phải dịch từ Python sang JavaScript. Khung JavaScript sử dụng dữ liệu đã có trong trang hoặc dữ liệu từ máy chủ. Mã Python chỉ là "hệ thống ống nước". Sau đó, tôi phát hiện ra rằng bộ đồ ngủ thực sự là một con trăn thật-> js phiên dịch.
Tôi vẫn nghĩ rằng có thể thực hiện dịch API-> API (hoặc framework-> framework) và về cơ bản đó là những gì tôi làm trong Pythonium nhưng ở cấp thấp hơn. Có lẽ Pyjama sử dụng thuật toán tương tự như Pythonium ...
Sau đó, tôi phát hiện ra brython được viết hoàn toàn bằng Javascript như Skulpt, không cần biên dịch và nhiều lông tơ ... mà được viết bằng JavaScript.
Kể từ dòng đầu tiên được viết trong quá trình của dự án này, tôi đã biết về PyPy, thậm chí là phần phụ trợ JavaScript cho PyPy. Đúng vậy, nếu tìm thấy, bạn có thể tạo trực tiếp trình thông dịch Python bằng JavaScript từ PyPy. Mọi người nói, đó là một thảm họa. Tôi đọc không hiểu tại sao. Nhưng tôi nghĩ lý do là ngôn ngữ trung gian mà họ sử dụng để triển khai trình thông dịch, RPython, là một tập con của Python được điều chỉnh để dịch sang C (và có thể là asm). Ira Baxter nói rằng bạn luôn đặt ra các giả định khi xây dựng một thứ gì đó và có lẽ bạn đã tinh chỉnh nó sao cho phù hợp nhất với những gì nó cần làm trong trường hợp bản dịch PyPy: Python-> C. Những giả định đó có thể không phù hợp trong một bối cảnh khác, tệ hơn là chúng có thể suy diễn ra chi phí nếu không nói rằng bản dịch trực tiếp rất có thể sẽ luôn tốt hơn.
Có trình thông dịch được viết bằng Python có vẻ là một ý tưởng (rất) hay. Nhưng tôi quan tâm nhiều hơn đến một trình biên dịch vì lý do hiệu suất, nó thực sự dễ dàng hơn để biên dịch Python sang JavaScript hơn là diễn giải nó.
Tôi bắt đầu PythonJS với ý tưởng tập hợp một tập con Python mà tôi có thể dễ dàng dịch sang JavaScript. Lúc đầu, tôi thậm chí không bận tâm đến việc triển khai hệ thống OO vì kinh nghiệm trong quá khứ. Tập hợp con của Python mà tôi đã đạt được để dịch sang JavaScript là:
- hàm với đầy đủ các tham số ngữ nghĩa cả trong định nghĩa và cách gọi. Đây là phần tôi tự hào nhất.
- while / if / elif / else
- Các loại Python đã được chuyển đổi thành các loại JavaScript (không có bất kỳ loại python nào)
- for có thể lặp lại chỉ trên các mảng Javascript (đối với một trong mảng)
- Truy cập minh bạch vào JavaScript: nếu bạn viết Mảng bằng mã Python, nó sẽ được dịch sang Mảng trong javascript. Đây là thành tựu lớn nhất về khả năng sử dụng so với các đối thủ cạnh tranh.
- Bạn có thể chuyển hàm được định nghĩa trong nguồn Python sang các hàm javascript. Các đối số mặc định sẽ được tính đến.
- Nó bổ sung có chức năng đặc biệt gọi là new được dịch sang JavaScript mới, ví dụ: new (Python) (1, 2, spam, "egg") được dịch thành "new Python (1, 2, spam," egg ").
- "var" được trình dịch tự động xử lý. (phát hiện rất hay từ Brett (cộng tác viên PythonJS).
- từ khóa toàn cầu
- đóng cửa
- lambdas
- danh sách hiểu
- nhập khẩu được hỗ trợ thông qua requestjs
- kế thừa lớp đơn + mixin qua Classjs
Điều này có vẻ như rất nhiều nhưng thực sự rất hẹp so với ngữ nghĩa đầy đủ của Python. Nó thực sự là JavaScript với cú pháp Python.
JS được tạo ra là hoàn hảo tức là. không có chi phí chung, nó không thể được cải thiện về mặt hiệu suất bằng cách chỉnh sửa thêm. Nếu bạn có thể cải thiện mã được tạo, bạn cũng có thể làm điều đó từ tệp nguồn Python. Ngoài ra, trình biên dịch không dựa vào bất kỳ thủ thuật JS nào mà bạn có thể tìm thấy trong .js được viết bởi http://superherojs.com/ , vì vậy nó rất dễ đọc.
Hậu duệ trực tiếp của phần này của PythonJS là chế độ Pythonium Veloce. Bạn có thể tìm thấy toàn bộ cách triển khai @ https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/veloce/veloce.py?at=master 793 SLOC + khoảng 100 SLOC mã được chia sẻ với người dịch khác.
Có thể dịch phiên bản thích nghi của pystone.py ở chế độ Veloce cf. https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pystone/?at=master
Sau khi thiết lập bản dịch Python-> JavaScript cơ bản, tôi đã chọn một đường dẫn khác để dịch Python đầy đủ sang JavaScript. Cách glib thực hiện mã dựa trên lớp hướng đối tượng ngoại trừ ngôn ngữ đích là JS nên bạn có quyền truy cập vào các mảng, các đối tượng giống bản đồ và nhiều thủ thuật khác và tất cả phần đó được viết bằng Python. IIRC không có mã javascript được viết bởi trình dịch Pythonium. Nhận thừa kế đơn lẻ không khó đây là những phần khó khăn khiến Pythonium hoàn toàn tuân thủ với Python:
spam.egg
trong Python luôn được dịch sang getattribute(spam, "egg")
Tôi không nêu cụ thể điều này nhưng tôi nghĩ rằng nó mất rất nhiều thời gian và tôi không chắc mình có thể cải thiện nó với asm.js hoặc bất cứ thứ gì khác.
- thứ tự phân giải phương thức: ngay cả với thuật toán được viết bằng Python, việc dịch nó sang mã tương thích Python Veloce là một nỗ lực lớn.
- getattributre : thuật toán phân giải getattribute thực tế khá phức tạp và nó vẫn không hỗ trợ bộ mô tả dữ liệu
- dựa trên lớp metaclass: Tôi biết nơi cắm mã, nhưng vẫn ...
- cuối cùng không kém phần quan trọng: some_callable (...) luôn được chuyển thành "call (some_callable)". AFAIK trình dịch hoàn toàn không sử dụng suy luận, vì vậy mỗi khi bạn thực hiện một cuộc gọi, bạn cần phải kiểm tra loại đối tượng nào để gọi nó theo cách mà nó được gọi.
Phần này được tính trong https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/runtime.py?at=master Phần này được viết bằng Python tương thích với Python Veloce.
Trình biên dịch tuân thủ thực tế https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/compliant.py?at=master không tạo mã JavaScript trực tiếp và quan trọng nhất là không thực hiện chuyển đổi ast-> ast . Tôi đã thử điều ast-> và ast ngay cả khi đẹp hơn cst cũng không tốt khi làm việc với ngay cả với ast.NodeTransformer và quan trọng hơn là tôi không cần phải làm ast-> ast.
Làm từ python ast sang python ast trong trường hợp của tôi ít nhất có thể là một sự cải thiện hiệu suất vì đôi khi tôi kiểm tra nội dung của một khối trước khi tạo mã được liên kết với nó, ví dụ:
- var / global: để có thể var một cái gì đó, tôi phải biết những gì tôi cần và không nên var. Thay vì tạo khối theo dõi biến nào được tạo trong một khối nhất định và chèn nó lên trên khối chức năng đã tạo, tôi chỉ tìm cách gán biến mới khi nhập khối trước khi thực sự truy cập vào nút con để tạo mã liên kết.
- Năng suất, trình tạo có cú pháp đặc biệt trong JS, vì vậy tôi cần biết hàm Python nào là trình tạo khi tôi muốn viết "var my_generator = function"
Vì vậy, tôi không thực sự truy cập từng nút một lần cho mỗi giai đoạn của bản dịch.
Quá trình tổng thể có thể được mô tả như sau:
Python source code -> Python ast -> Python source code compatible with Veloce mode -> Python ast -> JavaScript source code
Nội trang Python được viết bằng mã Python (!), IIRC có một vài hạn chế liên quan đến các kiểu khởi động, nhưng bạn có quyền truy cập vào mọi thứ có thể dịch Pythonium ở chế độ tuân thủ. Hãy xem tại https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/builtins/?at=master
Có thể hiểu được việc đọc mã JS được tạo từ tuân thủ pythonium nhưng bản đồ nguồn sẽ giúp ích rất nhiều.
Lời khuyên có giá trị mà tôi có thể cung cấp cho bạn dựa trên kinh nghiệm này là những con rắm già:
- đánh giá sâu rộng chủ đề cả trong văn học và các dự án hiện có nguồn đóng hoặc miễn phí. Khi tôi xem xét các dự án hiện có khác nhau, tôi lẽ ra nên cho nó nhiều thời gian và động lực hơn.
- hỏi câu hỏi! Nếu tôi biết trước rằng chương trình phụ trợ PyPy vô dụng vì chi phí cao do không khớp ngữ nghĩa C / Javascript. Tôi có thể đã có ý tưởng Pythonium cách đây 6 tháng có thể là 3 năm trước.
- biết bạn muốn làm gì, có mục tiêu. Đối với dự án này, tôi có các mục tiêu khác nhau: thực hành một chút javascript, tìm hiểu thêm về Python và có thể viết mã Python sẽ chạy trong trình duyệt (hơn thế nữa bên dưới).
- thất bại là kinh nghiệm
- một bước nhỏ là một bước
- khởi đầu nhỏ
- ước mơ lớn
- làm bản demo
- lặp lại
Chỉ với chế độ Python Veloce, tôi rất vui! Nhưng trên đường đi, tôi phát hiện ra rằng những gì tôi thực sự đang tìm kiếm là giải phóng tôi và những người khác khỏi Javascript nhưng quan trọng hơn là có thể tạo ra một cách thoải mái. Điều này dẫn tôi đến Đề án, DSL, Mô hình và cuối cùng là các mô hình miền cụ thể (xem http://dsmforum.org/ ).
Về phản ứng của Ira Baxter:
Các ước tính không hữu ích ở tất cả. Tôi đã dành cho tôi ít hơn 6 tháng thời gian rảnh cho cả PythonJS và Pythonium. Vì vậy, tôi có thể mong đợi nhiều hơn từ toàn thời gian 6 tháng. Tôi nghĩ tất cả chúng ta đều biết 100 năm trong bối cảnh doanh nghiệp có thể có ý nghĩa và không có nghĩa gì cả ...
Khi ai đó nói điều gì đó khó hoặc thường là không thể, tôi trả lời rằng "chỉ mất thời gian để tìm ra giải pháp cho một vấn đề không thể" nói cách khác không có gì là không thể ngoại trừ nếu nó được chứng minh là không thể trong trường hợp này là một bằng chứng toán học ...
Nếu nó không được chứng minh là không thể thì nó sẽ dành chỗ cho trí tưởng tượng:
- tìm một bằng chứng chứng minh điều đó là không thể
và
- Nếu không thể có một vấn đề "thấp kém" có thể có một giải pháp.
hoặc là
- nếu nó không phải là không thể, tìm một giải pháp
Đó không chỉ là suy nghĩ lạc quan. Khi tôi bắt đầu Python-> Javascript, mọi người đều nói rằng điều đó là không thể. PyPy không thể. Kính đeo quá khó. vv ... Tôi nghĩ rằng cuộc cách mạng duy nhất đưa PyPy vượt qua giấy Scheme-> C (đã 25 tuổi) là một số thế hệ JIT tự động (các gợi ý dựa trên được viết trong trình thông dịch RPython mà tôi nghĩ).
Hầu hết những người nói rằng một việc là "khó" hoặc "không thể" đều không cung cấp lý do. C ++ khó phân tích cú pháp? Tôi biết rằng, chúng vẫn là trình phân tích cú pháp C ++ (miễn phí). Cái ác là chi tiết? Tôi biết điều đó. Nói điều đó không thể một mình không có ích gì, Điều tồi tệ hơn là "không hữu ích" là nó làm nản lòng và một số người có ý làm nản lòng người khác. Tôi đã nghe về câu hỏi này qua /programming/22621164/how-to-automatically-generate-a-parser-code-to-code-translator-from-a-corpus .
Điều gì sẽ là sự hoàn hảo cho bạn ? Đó là cách bạn xác định mục tiêu tiếp theo và có thể đạt được mục tiêu tổng thể.
Tôi quan tâm hơn đến việc biết những loại mẫu nào tôi có thể thực thi trên mã để giúp dịch mã dễ dàng hơn (ví dụ: IoC, SOA?) Mã hơn là cách thực hiện dịch.
Tôi thấy không có mẫu nào không thể dịch từ ngôn ngữ này sang ngôn ngữ khác ít nhất là theo cách kém hoàn hảo. Vì có thể dịch từ ngôn ngữ sang ngôn ngữ khác, nên bạn nên nhắm mục tiêu này trước. Vì, tôi nghĩ theo http://en.wikipedia.org/wiki/Graph_isomorphism_problem , bản dịch giữa hai ngôn ngữ máy tính là dạng cây hoặc đẳng cấu DAG. Ngay cả khi chúng ta đã biết rằng cả hai đều hoàn chỉnh, vì vậy ...
Framework-> Framework mà tôi hình dung rõ hơn là API-> Bản dịch API vẫn có thể là thứ mà bạn có thể lưu ý như một cách để cải thiện mã đã tạo. Ví dụ: Prolog dưới dạng cú pháp rất cụ thể nhưng bạn vẫn có thể làm Prolog như tính toán bằng cách mô tả cùng một đồ thị trong Python ... Nếu tôi triển khai một trình dịch Prolog sang Python, tôi sẽ không thực hiện hợp nhất trong Python mà trong thư viện C và đến đưa ra một "cú pháp Python" rất dễ đọc đối với một Pythonist. Cuối cùng, cú pháp chỉ là "bức tranh" mà chúng ta đưa ra một ý nghĩa (đó là lý do tại sao tôi bắt đầu lược đồ). Cái ác nằm ở chi tiết của ngôn ngữ và tôi không nói về cú pháp. Các khái niệm được sử dụng trong ngôn ngữ getattributehook (bạn có thể sống mà không có nó) nhưng các tính năng VM cần thiết như tối ưu hóa đệ quy đuôi có thể khó xử lý. Bạn không quan tâm nếu chương trình ban đầu không sử dụng đệ quy đuôi và ngay cả khi không có đệ quy đuôi trong ngôn ngữ đích, bạn có thể mô phỏng nó bằng cách sử dụng vòng lặp sự kiện / greenlets.
Đối với ngôn ngữ đích và ngôn ngữ nguồn, hãy tìm:
- Ý tưởng lớn và cụ thể
- Những ý tưởng nhỏ và chung được chia sẻ
Từ điều này sẽ xuất hiện:
- Những thứ dễ dịch
- Những thứ khó dịch
Bạn cũng có thể biết những gì sẽ được dịch sang mã nhanh và chậm.
Ngoài ra còn có câu hỏi của stdlib hoặc bất kỳ thư viện nhưng không có câu trả lời rõ ràng, nó phụ thuộc vào mục tiêu của bạn.
Mã tự động hoặc mã được tạo có thể đọc được cũng có các giải pháp ...
Nhắm mục tiêu một nền tảng như PHP dễ dàng hơn nhiều so với nhắm mục tiêu trình duyệt vì bạn có thể cung cấp triển khai C của đường dẫn chậm và / hoặc quan trọng.
Với dự án đầu tiên của bạn là dịch Python sang PHP, ít nhất là đối với tập con PHP3 mà tôi biết, tùy chỉnh veloce.py là lựa chọn tốt nhất của bạn. Nếu bạn có thể triển khai veloce.py cho PHP thì có lẽ bạn sẽ có thể chạy chế độ tuân thủ ... Ngoài ra, nếu bạn có thể dịch PHP sang tập hợp con của PHP, bạn có thể tạo bằng php_veloce.py điều đó có nghĩa là bạn có thể dịch PHP sang tập con của Python mà veloce.py có thể sử dụng, điều đó có nghĩa là bạn có thể dịch PHP sang Javascript. Chỉ nói ...
Bạn cũng có thể xem các thư viện đó:
Ngoài ra, bạn có thể quan tâm đến bài đăng trên blog này (và nhận xét): https://www.rfk.id.au/blog/entry/pypy-js-poc-jit/