Ngôn ngữ BASIC

Dialect BASIC cổ điển của aukimi: kiểu dữ liệu, cấu trúc, hai lối viết tắt, và những quy tắc bẫy mọi người. 2 237 lệnh đứng phía sau.

Trong một câu#

aukimi đi kèm một dialect BASIC cổ điển: một ngôn ngữ đầy đủ, không phải một hệ thống macro đồ chơi, với kiểu số có kiểu tường minh, record, method, tham chiếu, lỗi có cấu trúc, coroutine và tính toán WebGPU. Nó sống trong chế độ viewport TXT của Engine và trong view BASIC của trình biên tập script.

JavaScript vẫn là API script chính thống. BASIC là một frontend tuỳ chọn: cả hai đều biên dịch về cùng một bộ điều phối riêng, nên một chương trình BASIC và một chương trình JavaScript đến cùng một engine y hệt nhau. Không có gì là hạng hai, và không có runtime thứ hai nào cả.

Quy tắc bẫy mọi người#

Một lệnh gọi luôn mang theo dấu ngoặc đơn.

mode = ClipSpaceMode()
SpritePosition(player, 320, 180)

Đây không phải chuyện phong cách. Đó là điều cho phép trình biên dịch phân biệt một lệnh với một biến, và đó là lý do một lỗi chính tả giờ đây bị bắt ngay lúc biên dịch:

Bạn viếtĐiều từng xảy raĐiều xảy ra bây giờ
SpritePositon(1, 10, 20)biên dịch trót lọt, sprite không di chuyển, và lỗi chỉ lộ ra sau đó dưới dạng ... is not definedlỗi biên dịch, kèm gợi ý cách viết gần nhất trong catalogue
Blorp(1, 2)được chuyển nguyên văn vào JavaScript được sinh ralỗi biên dịch
ceci nest pas du basicđược phát ra như một câu lệnhlỗi biên dịch

Một lỗi viết sai từng thể hiện ra như một lỗi của engine. Đo trên bộ ngữ liệu 84 demo, lớp bảo vệ này tạo ra không một dương tính giả nào và tìm thấy hai lỗi âm thầm có thật, SetMusicSystemVolumeGetLightSensorExists, mà catalogue chỉ biết đến dưới tên MusicSystemVolumeLightSensorExists.

Hai lỗ hổng vẫn được để ngỏ một cách có chủ đích: console.log("x")window.x = 1 vẫn qua được. Một lớp bảo vệ cho chúng đã được viết, đo lường, và rút lại: BASIC chạy trong một ngữ cảnh cung cấp những cái tên mà trình biên dịch không thể liệt kê hết, nên việc từ chối một root không xác định sẽ loại bỏ luôn cả những chương trình hợp lệ. Một dương tính giả ở đó còn tệ hơn lỗ hổng.

Điều bất ngờ phổ biến nhất:

Print(...)vẽ lên màn hình, và một chương trình gọi nó ở mỗi khung hình
Console(...)ghi vào console của trình biên tập, và không làm gì khác
Debug(...)cùng một lệnh dưới cái tên của PureBasic, để giữ trí nhớ cơ bắp
ConsoleWarning, ConsoleError, ClearConsolephần còn lại của log

Print trong một vòng lặp khung hình sẽ nhấn chìm bất kỳ lỗi thật nào trong console, đó là lý do hai lệnh này tách biệt thay vì một lệnh có thêm một cờ.

Kiểu dữ liệu#

Các kiểu số là thật, và chúng hoạt động giống hệt nhau trên mọi target: trình biên tập, bản xuất HTML và bản build Bevy/native.

  • Số nguyên có dấu và không dấu 8, 16, 32 và 64-bit, với phép ép kiểu tất định, DIV số nguyên, và tràn số kiểu wrap-around.
  • float32 và float64.
  • Các ký hiệu cổ điển vẫn hoạt động: name$ là một chuỗi, speed# là một float.

OPTION EXPLICIT là tuỳ chọn bật, và các biến ngầm định kiểu cổ điển vẫn là mặc định để các chương trình được nhập từ nơi khác vẫn chạy được. Bật nó lên là điều kiện tiên quyết cho hai tính năng không thể an toàn nếu thiếu nó, kiểu số tường minh và tham chiếu, bởi một phép gán viết sai chính tả mà âm thầm tạo ra một biến mới sẽ vô hiệu hoá cả hai.

Cấu trúc#

Record#

TYPE khai báo một record. Chúng lồng nhau tuỳ ý, và có ngữ nghĩa giá trị: gán một record sẽ deep-copy nó, bao gồm cả mảng và collection lồng bên trong.

Method#

METHOD gắn một hàm vào một instance, với SELF bên trong nó, New để khởi tạo và Delete để huỷ. Các bản deep copy vẫn an toàn với method.

Tham chiếu#

REFBYREF là cùng một thứ dưới hai cách viết, và cả hai đều cho một tham số đọc/ghi sống động, cho một scalar, một record, một field đơn lẻ, một mảng, một con trỏ danh sách hay một entry của map. Tham chiếu truyền tiếp qua các lệnh gọi, và ép kiểu về kích thước cố định tại biên.

Handle#

@target lấy một tham chiếu hạng nhất. HANDLEPOINTER là các dạng có kiểu, với đọc, ghi, kiểm tra hiệu lực và giải phóng đều được kiểm tra, và một handle trỏ đến một record đã bị xoá sẽ bị vô hiệu hoá thay vì bị bỏ lửng.

Kiểm soát và an toàn#

Lỗi có cấu trúc: TRY / CATCH / FINALLY, lồng được, với THROW, RETHROW được bảo vệ, và bắt được cả dạng có cấu trúc lẫn dạng chuỗi.

Biên dịch có điều kiện: #IF / #ELSEIF / #ELSE / #ENDIF, lồng được, với cờ tính năng và các profile tường minh cho editor, HTML, Bevy, native/wasm và debug/release. Nó được xử lý trước các include, trên mọi target.

Hàm giàu tính năng: giá trị mặc định, OPTIONAL, một PARAMARRAY (hay ...) ở cuối, overload an toàn theo số lượng tham số, ép kiểu giá trị trả về, và record cùng mảng trả về đều được nhân bản.

Chương trình nhiều file#

#INCLUDE, #INSERTIncludeFile biến một chương trình thành nhiều file. Trình biên tập tạo và nhập các module dự án, tự hoàn thành đường dẫn include, giữ đồ thị phụ thuộc, và mọi runtime target đều được kết nối cho việc này.

Coroutine, và thứ bị cố tình bỏ ra ngoài#

Các task hợp tác được đánh dấu bằng nhãn, với handle có kiểu, trạng thái kết quả và lỗi, huỷ được tại các điểm yield, và có thể await một task đơn lẻ hay một nhóm. Chúng chia sẻ chung bộ lập lịch của game trên mọi target.

Thread với bộ nhớ chia sẻ bị loại trừ một cách có chủ đích. Không phải "chưa có" mà là bị loại trừ. Một bộ lập lịch hợp tác mà bạn có thể suy luận được còn hơn một cuộc đua dữ liệu mà bạn không thể tái hiện lại.

Tính toán WebGPU#

Storage buffer có kiểu f32 / i32 / u32, pipeline WGSL thô, dispatch theo thứ tự khung hình và đọc lại memblock, tính toán GPU thật từ BASIC.

⚠️ Chỉ dành cho Engine. Target HTML báo lỗi năng lực tường minh, và target Bevy báo sự không tương thích trước khi build thay vì tạo ra một binary lỗi ngay ở lần dispatch đầu tiên.

Hai lối viết tắt cho cùng một vấn đề#

597 trong số các lệnh có tên Set/Get<Object><Property>: Sprite 66, Tween 58, Text 32, Edit 29. Tên đối tượng nằm bên trong tên hàm và id của nó là tham số đầu tiên của mọi dòng. Cả hai lối viết tắt dưới đây đều loại bỏ sự lặp lại đó, và không cái nào là một API mới: trình biên dịch dựng lại tên lệnh thật và tra nó trong catalogue.

WITH <family>, bên trong một block#

WITH SPRITE s
  \position 100, 200      ` SpritePosition(s, 100, 200)
  \size 64, 64            ` SpriteSize(s, 64, 64)
  x# = \x                 ` SpriteX(s)
ENDWITH

Ở đầu một câu lệnh \prop sẽ ghi; ở bất kỳ vị trí nào khác nó đọc. Vị trí quyết định, nên không có ký hiệu thứ hai nào cần học thêm. WITH hero, một token duy nhất, vẫn là block record; WITH SPRITE s chọn một family trong catalogue.

s.position(...), ở mọi nơi khác#

s = CreateSprite(img)     ` the family is DEDUCED from the creation command
s.position(100, 200)      ` SpritePosition(s, 100, 200)
s.visible = 1             ` SpriteVisible(s, 1)
x# = s.x                  ` SpriteX(s)

Family đến từ Create<F> / Load<F> / Clone<F>, hoặc từ một khai báo tường minh s AS Sprite khi id đến từ nơi khác. Chỉ những biến có family đã biết mới được viết lại: record giữ nguyên field của chúng, list giữ nguyên method của chúng, SELF.field không bị đụng đến.

⚠️ Một tham số có kiểu không được nhận diện. FUNCTION move(s AS Sprite) không cho s một family, lượt quét chỉ đọc các khai báo và phép gán ở cấp câu lệnh. Ghi rõ ở đây vì đây là một giới hạn thật, không phải một lỗi cần bạn đi tìm.

⚠️ Catalogue bỏ động từ trên các property, và giữ nó trên lifecycle. SpritePosition ghi, SpriteX đọc, và không cái nào mang Set hay Get: 4 lệnh trong toàn bộ catalogue bắt đầu bằng Set, và không lệnh nào bắt đầu bằng Get. Động từ chỉ sống sót ở nơi có gì đó được tạo ra hoặc kết thúc: CreateSprite, LoadImage, DeleteSprite.

Điều đó đáng biết vì một lỗi chính tả là một lỗi biên dịch, và Set… chính là lỗi chính tả mà mọi người thường mắc phải. Catalogue là nguồn tham chiếu duy nhất, và tài liệu tham khảo được sinh ra từ chính nó.

Nội suy chuỗi, tuỳ chọn bật#

Print($"score: {points}")        ` "score: " + Str(points)

{{}} viết ra dấu ngoặc nhọn theo nghĩa đen.

⚠️ Tiền tố $ là bắt buộc, và nó không phải là trang trí. Nội suy mọi chuỗi ký tự sẽ làm hỏng JSON viết tay, thứ mà world API dùng thường xuyên:

CreateTerrain("island", "{\"preset\":\"island\",\"size\":256}")

Ở đó dấu ngoặc nhọn là dữ liệu, không phải chỗ trống cần điền. Một chuỗi không có tiền tố được giữ nguyên bất kể nó chứa gì.

Đặt tên là hiển thị#

Một chương trình cổ điển tạo ra hàng trăm đối tượng. Chỉ những cái được ĐẶT TÊN mới vào Scene Graph, SpriteName(id, "player") và những lệnh tương tự là thứ đưa một đối tượng vào cây nơi phần còn lại của Engine có thể thấy nó. LightNameParticlesName làm điều tương tự cho một ánh sáng và một emitter.

Bài hướng dẫn Đặt tên cho những gì chương trình bạn tạo ra đi qua điều này: cùng một scene, một lần với cây trống rỗng và một lần với ba mục trong đó.

Catalogue lệnh#

2 237 lệnh, 2 550 overload công khai, 43 danh mục. Những cái lớn nhất:

3D286Studio106File61
Core200Input95Memblock43
Tweening149Input-Raw943D Particles41
3D Physics144Multiplayer91World40
Sprite135Text68Particles38
Platform1112D Physics66Sound37

cộng thêm JSON (36), Image (35), Skeleton (34), XML (34), Music (29), Preference (27), Extras (21), HTTP (21), String (21), Math (19), Regular Expression (19), Video (18), Dictionary (17), Benchmarking (15), Compute (14), Date (13), Maths (12), Time (12), StringBuilder (9), Compression (7), Font (8), Error (4), Array (3), Cipher (2), Sort (2).

StudioCompute là những bổ sung riêng của Aukimi cho dialect cổ điển: các lệnh console, đặt tên đối tượng, và pipeline WebGPU.

Tài liệu tham khảo lệnh đầy đủ liệt kê tất cả, kèm mọi tham số và mọi overload, với công cụ tìm kiếm riêng, được sinh ra từ cùng một catalogue mà trang này đếm, nên nó không thể bị tụt lại phía sau. Panel API của chính trình biên tập cũng đọc catalogue đó.

Trang này viết về ngôn ngữ; trang kia viết về các lệnh.

Giới hạn và các lỗi thường gặp#

  • Dấu ngoặc đơn không phải là tuỳ chọn trên một lệnh. Dạng PureBasic trần trụi (Debug "x") bị từ chối, vì nó mở lại sự mập mờ biến/lệnh mà lớp bảo vệ biên dịch phụ thuộc vào.
  • Một hàm người dùng thắng một lệnh trong catalogue cùng tên, và một biến có thể chia sẻ tên với một lệnh trong một khai báo có kiểu, ở vế trái của một phép gán, hoặc làm root của một đường dẫn.
  • Biến và hàm người dùng không phân biệt hoa thường, và không gian ký hiệu của chúng thật sự tách biệt với catalogue.
  • Print không phải là log. Xem ở trên; đó là lỗi làm đầy một console.
  • Compute không xuất ra được. Hãy viết lối dự phòng trước khi bạn dựa vào nó.