From 8d860a7a86826908ae9d0dec84fb9fbef4f6760a Mon Sep 17 00:00:00 2001 From: Bartek Zbytniewski Date: Thu, 17 Apr 2025 19:59:33 +0200 Subject: [PATCH 1/9] custom Syntax Highlighting for Sublime Text --- syntax/CurlyWASM.sublime-syntax | 231 ++++++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+) create mode 100644 syntax/CurlyWASM.sublime-syntax diff --git a/syntax/CurlyWASM.sublime-syntax b/syntax/CurlyWASM.sublime-syntax new file mode 100644 index 0000000..7d61646 --- /dev/null +++ b/syntax/CurlyWASM.sublime-syntax @@ -0,0 +1,231 @@ +%YAML 1.2 +--- +# ========================================================== +# http://www.sublimetext.com/docs/syntax.html +# created by: zbyti & various AI +# ========================================================== +# For best results, use with Rust-themed color schemes like: +# - "RustEnhanced" +# - "Atomized" +# - "Solarized Rust" +# ========================================================== +name: CurlyWASM +file_extensions: [cwa] +scope: source.curlywasm + +contexts: + main: + # Comments + - match: /\* + scope: comment.block.curlywasm + push: block_comment + - match: // + scope: comment.line.curlywasm + push: line_comment + + # Module system + - match: \b(import|include|export)\b + scope: keyword.control.import.curlywasm + + # Declarations and definitions + - match: \b(fn)\b + scope: keyword.declaration.function.curlywasm + + - match: \b(const)\b + scope: storage.modifier.const.curlywasm + + - match: \b(global|mut|let|lazy|inline)\b + scope: storage.modifier.curlywasm + + # Control flow + - match: \b(return|if|else|loop|block|branch|branch_if|break)\b + scope: keyword.control.flow.curlywasm + + # Type conversion + - match: \b(as)\b + scope: keyword.operator.type.curlywasm + + # WASM memory access operators + - match: \b(load|load8_s|store)\b + scope: keyword.operator.memory.curlywasm + + # API functions + - match: \b(sin|cos|tan|asin|acos|atan|atan2|pow|log|fmod|random|randomf|randomSeed|cls|setPixel|getPixel|hline|rectangle|circle|line|time|isButtonPressed|isButtonTriggered|printChar|printString|printInt|setTextColor|setBackgroundColor|setCursorPosition|rectangleOutline|circleOutline|exp|playNote|sndGes|blitSprite|grabSprite)\b + scope: support.function.curlywasm + + # Built-in functions + - match: \b(sqrt|min|max|ceil|floor|trunc|nearest|abs|copysign|select|trunc_sat_f32_u)\b + scope: support.function.curlywasm + + # Data blocks - Match 'data {' together and push context + - match: \b(data)\s*(\{) + captures: + 1: storage.type.data.curlywasm + 2: punctuation.section.block.begin.curlywasm + push: data_content + + # Base types + - match: \b(i8|i16|i32|i64|f32|f64)\b + scope: storage.type.primitive.curlywasm + + # Memory access operators + - match: (\?|\$|\!) + scope: keyword.operator.memory.curlywasm + + # Operators + - match: (->) + scope: keyword.operator.arrow.curlywasm + + # Assignment operators + - match: (=|:=|\+=|-=|\*=|/=|%=|&=|\|=|\^=|#/=) + scope: keyword.operator.assignment.curlywasm + + # Arithmetic operators + - match: (\+|-|\*|/|%|#/|#%) + scope: keyword.operator.arithmetic.curlywasm + + # Bitwise operators + - match: (\&|\||\^|<<|>>|#>>) + scope: keyword.operator.bitwise.curlywasm + + # Comparison operators + - match: (<|>|<=|>=|#<|#<=|#>|#>=|==|!=) + scope: keyword.operator.comparison.curlywasm + + # Other operators + - match: (<\|) + scope: keyword.operator.misc.curlywasm + + # Numeric literals + - match: \b(0x[0-9a-fA-F]+)\b + scope: constant.numeric.hex.curlywasm + + - match: '\b\d+(_f)\b' + scope: constant.numeric.float.curlywasm + + - match: \b([0-9]+\.[0-9]+)\b + scope: constant.numeric.float.curlywasm + + - match: \b([0-9]+)\b + scope: constant.numeric.integer.curlywasm + + # String literals + - match: \" + scope: punctuation.definition.string.begin.curlywasm + push: double_quoted_string + - match: \' + scope: punctuation.definition.string.begin.curlywasm + push: single_quoted_string + + # Function calls + - match: \b([a-zA-Z_][a-zA-Z0-9_]*)\s*\( + captures: + 1: entity.name.function.call.curlywasm + + # Function declarations + - match: \bfn\s+([a-zA-Z_][a-zA-Z0-9_]*)\b + captures: + 1: entity.name.function.declaration.curlywasm + + # Constants (Upper case convention) + - match: \b([A-Z_][A-Z0-9_]*)\b + scope: constant.other.curlywasm + + # Variables (Lower case convention) + - match: \b([a-z_][a-zA-Z0-9_]*)\b + scope: variable.other.curlywasm + + # Punctuation + - match: \{ + scope: punctuation.section.block.begin.curlywasm + - match: \} + scope: punctuation.section.block.end.curlywasm + - match: \( + scope: punctuation.section.group.begin.curlywasm + - match: \) + scope: punctuation.section.group.end.curlywasm + - match: \[ + scope: punctuation.section.brackets.begin.curlywasm + - match: \] + scope: punctuation.section.brackets.end.curlywasm + - match: ; + scope: punctuation.terminator.curlywasm + - match: \, + scope: punctuation.separator.curlywasm + - match: ':' + scope: punctuation.separator.type.curlywasm + + # Context for /* ... */ block comments + block_comment: + - meta_scope: comment.block.curlywasm + - match: \*/ + scope: punctuation.definition.comment.end.curlywasm + pop: true + + # Context for // ... line comments + line_comment: + - meta_scope: comment.line.double-slash.curlywasm + - match: $ # Pop at the end of the line + pop: true + + # Context for "..." strings + double_quoted_string: + - meta_scope: string.quoted.double.curlywasm + - match: \" + scope: punctuation.definition.string.end.curlywasm + pop: true + - match: \\. # Escape sequences + scope: constant.character.escape.curlywasm + + # Context for '...' strings + single_quoted_string: + - meta_scope: string.quoted.single.curlywasm + - match: \' + scope: punctuation.definition.string.end.curlywasm + pop: true + - match: \\. # Escape sequences + scope: constant.character.escape.curlywasm + + # Context for the content inside data { ... } + data_content: + - meta_scope: meta.data.content.curlywasm + # Match the closing brace to pop the context + - match: \} + scope: punctuation.section.block.end.curlywasm + pop: true + # Include rules for literals within the data block + - include: literals + # Specific types/keywords allowed inside data blocks + - match: \b(i8|i16|i32|i64|f32|f64)\b + scope: storage.type.primitive.curlywasm + - match: \b(file)\b + scope: keyword.control.curlywasm + # Punctuation inside data blocks + - match: \( + scope: punctuation.section.group.begin.curlywasm + - match: \) + scope: punctuation.section.group.end.curlywasm + - match: \, + scope: punctuation.separator.curlywasm + # Potentially allow comments inside data blocks + - include: block_comment + - include: line_comment + + # Reusable patterns for literals (used via include) + literals: + # Numeric literals + - match: \b(0x[0-9a-fA-F]+)\b + scope: constant.numeric.hex.curlywasm + - match: '\b\d+(_f)\b' + scope: constant.numeric.float.curlywasm + - match: \b([0-9]+\.[0-9]+)\b + scope: constant.numeric.float.curlywasm + - match: \b([0-9]+)\b + scope: constant.numeric.integer.curlywasm + # String literals + - match: \" + scope: punctuation.definition.string.begin.curlywasm + push: double_quoted_string + - match: \' + scope: punctuation.definition.string.begin.curlywasm + push: single_quoted_string From 44566ce1a380480a80fce000c3e5f5d2b155676a Mon Sep 17 00:00:00 2001 From: Bartek Zbytniewski Date: Thu, 17 Apr 2025 20:03:42 +0200 Subject: [PATCH 2/9] new commented examples --- examples/curlywas/cube_wireframe.cwa | 254 +++++++++++++++++++++++++++ examples/curlywas/plasma.cwa | 51 ++++++ examples/curlywas/plasma_chars.cwa | 168 ++++++++++++++++++ 3 files changed, 473 insertions(+) create mode 100644 examples/curlywas/cube_wireframe.cwa create mode 100644 examples/curlywas/plasma.cwa create mode 100644 examples/curlywas/plasma_chars.cwa diff --git a/examples/curlywas/cube_wireframe.cwa b/examples/curlywas/cube_wireframe.cwa new file mode 100644 index 0000000..a7b9de8 --- /dev/null +++ b/examples/curlywas/cube_wireframe.cwa @@ -0,0 +1,254 @@ +/* + This program renders a rotating 3D wireframe cube on a 2D screen using the MicroW8 platform. + + code : zbyti + date : 2025.04.15 + platform : MicroW8 0.4.1 + + https://exoticorn.github.io/microw8/ + https://exoticorn.github.io/microw8/docs/ + + https://github.com/exoticorn/microw8 + https://github.com/exoticorn/curlywas + + https://developer.mozilla.org/en-US/docs/WebAssembly + + https://en.wikipedia.org/wiki/Rotation_matrix +*/ + +//----------------------------------------------------------------------------- +// MicroW8 API +//----------------------------------------------------------------------------- + +//include "../include/microw8-api.cwa" + +// Import memory allocation: 4 pages (64KB) of memory (256KB total) +import "env.memory" memory(4); + +// Import MicroW8 API functions for graphics and math operations +import "env.cls" fn cls(i32); // Clears the screen +import "env.time" fn time() -> f32; // Returns the current time as a float for animation +import "env.sin" fn sin(f32) -> f32; // Computes the sine of an angle (in radians) +import "env.cos" fn cos(f32) -> f32; // Computes the cosine of an angle (in radians) +import "env.line" fn line(f32, f32, f32, f32, i32); // Draws a line between two 2D points with a color + +// Define the starting address for user memory +const USER_MEM = 0x14000; + +//----------------------------------------------------------------------------- +// CONSTANTS +//----------------------------------------------------------------------------- + +// Screen and rendering constants +const CENTER_X = 320.0 / 2.0; // X-coordinate of the screen center (320px width) +const CENTER_Y = 240.0 / 2.0; // Y-coordinate of the screen center (240px height) +const ROTATE_SPEED = 0.5; // Speed at which the cube rotates +const PI = 3.14159265; // Mathematical constant Pi for angle conversions +const RADIAN = PI / 180.0; // Conversion factor from degrees to radians +const SCALE = 65.0; // Scaling factor to adjust the size of the cube on screen +const PERSPECTIVE = SCALE * 0.5; // Perspective factor +const LINE_COLOR = 0xBF; // Color value for drawing the cube's edges (hexadecimal) + +// Memory layout for vertex data +const V_BASE = USER_MEM; // Base vertices stored as 8-bit integers (i8) +const V_ROT = V_BASE + (3 * 8); // Rotated vertices stored as 32-bit floats (f32), offset after V_BASE + +// Offsets for accessing X, Y, Z coordinates in memory (in bytes) +const X = 0; // Offset for X coordinate +const Y = 4; // Offset for Y coordinate +const Z = 8; // Offset for Z coordinate + +// Memory offsets for each rotated vertex (8 vertices, 3 floats each, 12 bytes per vertex) +const VA = V_ROT + (0 * 3 * 4); // Vertex A (front-top-left) +const VB = V_ROT + (1 * 3 * 4); // Vertex B (front-top-right) +const VC = V_ROT + (2 * 3 * 4); // Vertex C (front-bottom-right) +const VD = V_ROT + (3 * 3 * 4); // Vertex D (front-bottom-left) +const VE = V_ROT + (4 * 3 * 4); // Vertex E (back-top-left) +const VF = V_ROT + (5 * 3 * 4); // Vertex F (back-top-right) +const VG = V_ROT + (6 * 3 * 4); // Vertex G (back-bottom-right) +const VH = V_ROT + (7 * 3 * 4); // Vertex H (back-bottom-left) + +//----------------------------------------------------------------------------- +// Function to rotate the cube around X, Y, and Z axes based on time +//----------------------------------------------------------------------------- + +fn rotate() { + // Calculate the rotation angle using the current time for continuous animation + let angle = time() * ROTATE_SPEED; + + // Precompute sine and cosine values once for efficiency + let sn = sin(angle); + let cs = cos(angle); + + let calc = 0; + loop calc { // Iterate over all 8 vertices + // Calculate memory offset for current vertex (12 bytes per vertex: 4 bytes each for X, Y, Z) + let v = calc * 12; + let inline vX = v + X; + let inline vY = v + Y; + let inline vZ = v + Z; + + // Load original vertex coordinates from V_BASE (stored as i8, converted to f32) + let x = i32.load8_s(V_BASE+(calc * 3 + 0)) as f32; // X coordinate + let y = i32.load8_s(V_BASE+(calc * 3 + 1)) as f32; // Y coordinate + let z = i32.load8_s(V_BASE+(calc * 3 + 2)) as f32; // Z coordinate + + // Rotate around Z-axis: updates X and Y, Z stays the same + (vX)$V_ROT = x * cs - y * sn; + (vY)$V_ROT = x * sn + y * cs; + (vZ)$V_ROT = z; + + // Rotate around Y-axis: updates X and Z, Y stays the same + x = (vX)$V_ROT; + z = (vZ)$V_ROT; + (vX)$V_ROT = x * cs + z * sn; + (vZ)$V_ROT = z * cs - x * sn; + + // Rotate around X-axis: updates Y and Z, X stays the same + y = (vY)$V_ROT; + z = (vZ)$V_ROT; + (vY)$V_ROT = y * cs - z * sn; + (vZ)$V_ROT = y * sn + z * cs; + + // Move to the next vertex until all 8 are processed + branch_if (calc +:= 1) < 8: calc; + } +} + +//----------------------------------------------------------------------------- +// Function to project 3D vertices to 2D screen space and draw the cube's edges +//----------------------------------------------------------------------------- + +fn drawLines() { + let scale = 0; + loop scale { // Scale and center each vertex for 2D projection + // Calculate memory offset for current vertex (12 bytes per vertex: 4 bytes each for X, Y, Z) + let v = scale * 12; + let inline vX = v + X; + let inline vY = v + Y; + + // Load Z coordinate of current vertex (from rotated vertex data) + let inline z = (v + Z)$V_ROT; + + // Calculate perspective factor: + // - When z=0 (midpoint), factor=1.0 (no scaling) + // - Positive z (farther away) → factor<1.0 (objects appear smaller) + // - Negative z (closer) → factor>1.0 (objects appear larger) + let lazy factor = PERSPECTIVE / (PERSPECTIVE + z) * SCALE; + + // Apply perspective projection, scaling and shift to center for X and Y coordinats: + // 1. Multiply by perspective factor + // 2. Apply global scaling (SCALE constant) + // 3. Center on screen (CENTER_X, CENTER_Y) + (vX)$V_ROT = (vX)$V_ROT * factor + CENTER_X; // X + (vY)$V_ROT = (vY)$V_ROT * factor + CENTER_Y; // Y + + // Continue until all 8 vertices are scaled + branch_if (scale +:= 1) < 8: scale; + } + + // Draw the front face of the cube (vertices A-B-C-D) + line(VA$X, VA$Y, VB$X, VB$Y, LINE_COLOR); + line(VB$X, VB$Y, VC$X, VC$Y, LINE_COLOR); + line(VC$X, VC$Y, VD$X, VD$Y, LINE_COLOR); + line(VD$X, VD$Y, VA$X, VA$Y, LINE_COLOR); + + // Draw the back face of the cube (vertices E-F-G-H) + line(VE$X, VE$Y, VF$X, VF$Y, LINE_COLOR); + line(VF$X, VF$Y, VG$X, VG$Y, LINE_COLOR); + line(VG$X, VG$Y, VH$X, VH$Y, LINE_COLOR); + line(VH$X, VH$Y, VE$X, VE$Y, LINE_COLOR); + + // Draw edges connecting front and back faces + line(VA$X, VA$Y, VE$X, VE$Y, LINE_COLOR); + line(VB$X, VB$Y, VF$X, VF$Y, LINE_COLOR); + line(VC$X, VC$Y, VG$X, VG$Y, LINE_COLOR); + line(VD$X, VD$Y, VH$X, VH$Y, LINE_COLOR); +} + +//----------------------------------------------------------------------------- +// Entry point for INIT type function, starts first +//----------------------------------------------------------------------------- + +/* +export fn start() { + let init = 0; + loop init { + // Calculate memory offset for current vertex (12 bytes per vertex: 4 bytes each for X, Y, Z) + let v = init * 12; + + (v + X)$V_ROT = i32.load8_s(V_BASE+(init * 3) + 0) as f32; + (v + Y)$V_ROT = i32.load8_s(V_BASE+(init * 3) + 1) as f32; + (v + Z)$V_ROT = i32.load8_s(V_BASE+(init * 3) + 2) as f32; + branch_if (init +:= 1) < 8: init; + } +} +*/ + +//----------------------------------------------------------------------------- +// Main update function called every frame to refresh the screen +//----------------------------------------------------------------------------- + +export fn upd() { + cls(0); // Clear the screen with color 0 (black) + rotate(); // Perform cube rotation calculations + drawLines(); // Draw the rotated cube on the screen +} + +//----------------------------------------------------------------------------- +// DATA +//----------------------------------------------------------------------------- + +/* + Initial vertex data for the cube (8 vertices, each with X, Y, Z as 8-bit signed integers) + Each vertex represents a corner of a unit cube centered at the origin + + F - front, B - back, L - left, R - right, U - up, D - down +*/ +data V_BASE { // 3 * 8 -> 3 bytes per vertex * 8 vertices = 24 bytes + i8( + // X Y Z + -1, -1, 1, // FLU Vertex A + 1, -1, 1, // FRU Vertex B + 1, 1, 1, // FRD Vertex C + -1, 1, 1, // FLD Vertex D + -1, -1, -1, // BLU Vertex E + 1, -1, -1, // BRU Vertex F + 1, 1, -1, // BRD Vertex G + -1, 1, -1 // BLD Vertex H + ) +} + +//----------------------------------------------------------------------------- + +/* + Storage for rotated vertex data (8 vertices, each with X, Y, Z as 32-bit signed floats) + Initialized to zero and updated during rotation +*/ +data V_ROT { // 4 * 3 * 8 -> 12 bytes per vertex * 8 vertices = 96 bytes + f32( + // X Y Z + 0.0, 0.0, 0.0, // VA -> Vertex A + 0.0, 0.0, 0.0, // VB -> Vertex B + 0.0, 0.0, 0.0, // VC -> Vertex C + 0.0, 0.0, 0.0, // VD -> Vertex D + 0.0, 0.0, 0.0, // VE -> Vertex E + 0.0, 0.0, 0.0, // VF -> Vertex F + 0.0, 0.0, 0.0, // VG -> Vertex G + 0.0, 0.0, 0.0 // VH -> Vertex H + ) +} + +//----------------------------------------------------------------------------- +// SNIPPETS +//----------------------------------------------------------------------------- + +/* + let tmp: f32; + tmp = -123.0; + f32.store(tmp, V_ROT); + tmp = f32.load(V_ROT); + printInt(tmp as i32); +*/ + +//----------------------------------------------------------------------------- diff --git a/examples/curlywas/plasma.cwa b/examples/curlywas/plasma.cwa new file mode 100644 index 0000000..4db0350 --- /dev/null +++ b/examples/curlywas/plasma.cwa @@ -0,0 +1,51 @@ +/* + Plasma effect (sizecoding) + + Combines sine waves to create a 2D pixel pattern with intensity-based colors. + + code : zbyti & Grok 3 + date : 2025.04.17 + platform : MicroW8 0.4.1 +*/ + +include "../include/microw8-api.cwa" + +// Constants for color, math, and screen dimensions +const BASE_COLOR = 0xF0; // Base color value for pixel coloring +const PI = 3.14159265; // Mathematical constant π +const RAD = PI / 180.0; // Conversion factor from degrees to radians +const SCR_X = 320; // Screen width in pixels +const SCR_Y = 240; // Screen height in pixels +const SCR_SIZE = SCR_X * SCR_Y; // Screen size in bytes + +// Global variables to track animation phases +global mut phaseX = 0; // Phase offset for X-axis wave animation +global mut phaseY = 0; // Phase offset for Y-axis wave animation + +// Update function called each frame to render the plasma effect +export fn upd() { + let i = 0; + loop i { + // Calculate pixel coordinates from linear index + let lazy x = i % SCR_X; // X-coordinate (column) + let lazy y = i / SCR_X; // Y-coordinate (row) + + // Compute three sine waves with different frequencies and phases + let inline val1 = sin(RAD * 2.25 * (x + phaseX) as f32); // Wave along X-axis + let inline val2 = sin(RAD * 3.25 * (y + phaseY) as f32); // Wave along Y-axis + let inline val3 = sin(RAD * 1.25 * (x + y + phaseX) as f32); // Diagonal wave + + // Combine waves, scale to color range, and convert to integer + let inline c = BASE_COLOR + ((val1 + val2 + val3) * 4.75) as i32; + + // Set pixel color based on computed intensity + setPixel(x, y, c); + + // Continue loop until all pixels are processed + branch_if (i +:= 1) < (SCR_SIZE): i; + } + + // Update phase offsets for animation (different speeds for dynamic effect) + phaseX += 1; // Increment X-phase for horizontal wave movement + phaseY += 2; // Increment Y-phase for vertical wave movement +} \ No newline at end of file diff --git a/examples/curlywas/plasma_chars.cwa b/examples/curlywas/plasma_chars.cwa new file mode 100644 index 0000000..f2f1e5e --- /dev/null +++ b/examples/curlywas/plasma_chars.cwa @@ -0,0 +1,168 @@ +/* + Plasma effect (chars) + + Combines sine waves to create a 2D pattern, maps to custom characters, + and renders to the 40x30 character grid with intensity-based colors. + + code : zbyti (conversion & optimizations) + original : https://github.com/tebe6502/Mad-Pascal/blob/origin/samples/a8/demoeffects/plasma_2.pas + date : 2025.04.16 + platform : MicroW8 0.4.1 +*/ + +include "../include/microw8-api.cwa" + +//----------------------------------------------------------------------------- +// Constants defining memory layout, screen dimensions, and effect parameters +//----------------------------------------------------------------------------- + +const MEM_END = 0x40000; + +const CUSTOM_FONT = FONT + 0x100; +const CHARS = 0x20; +const BASE_COLOR = 0xF0; + +const PI = 3.14159265; +const RAD = PI / 180.0; + +const SCR_X = 320; +const SCR_Y = 240; +const SCR_W = SCR_X / 8; // 40 +const SCR_H = SCR_Y / 8; // 30 +const SCR_SIZE = SCR_X * SCR_Y; + +const SIN_TABLE_SIZE = 128; // Number of entries in the sine lookup table +const SIN_TABLE_MASK = SIN_TABLE_SIZE - 1; + +const SIN_TABLE = MEM_END - SIN_TABLE_SIZE; // Memory address for sine table +const ROW_BUFFER = SIN_TABLE - SCR_W; // Memory address for precomputed row buffer + +//----------------------------------------------------------------------------- +// Global variables to track animation state +//----------------------------------------------------------------------------- + +global mut phaseA = 1; // Phase offset for the first sine wave, controls animation +global mut phaseB = 5; // Phase offset for the second sine wave, controls animation + +//----------------------------------------------------------------------------- + +/* + Logs a value to the console (STDOUT) with a prefix for debugging purposes + + Args: + prefix : 4-character identifier (i32) to label the output + log : Integer value to log (i32) + + Prints to console and returns to screen output +*/ +fn console(prefix: i32, log: i32) { + printChar('\6'); // Switch output to console + printChar(prefix); // Print the prefix + printInt(log); // Print the integer value + printChar('\n\4'); // Print newline and switch back to screen output +} + +//------------------------------------- + +/* + Fills a sine table with precomputed values for fast lookups + + Args: + adr : Memory address where the sine table is stored + size : Number of entries in the table + + Computes: sin(i * 180/size * radians) * 255 for i = 0 to size-1, scaled to 0-255 +*/ +fn fillSin(adr: i32, size: i32) { + let i = 0; + let inline f = 180.00 / size as f32 * RAD; + loop i { + (adr+i)?0 = (sin(f * i as f32) * 255.0) as i32; + branch_if (i +:= 1) < size: i; + } +} + +//----------------------------------------------------------------------------- + +/* + Initialization function called when the program starts +*/ +export fn start() { + // Populate the sine table with values for fast wave calculations + fillSin(SIN_TABLE, SIN_TABLE_SIZE); +} + +//------------------------------------- + +/* + Update function called each frame to render the plasma effect +*/ +export fn upd() { + let pA = phaseA; // Local copy of phaseA to avoid modifying global during frame + let pB = phaseB; // Local copy of phaseB for the same reason + + let i = 0; + loop i { + // Wrap phase values to stay within sine table bounds using bitwise AND + pA &= SIN_TABLE_MASK; + pB &= SIN_TABLE_MASK; + + // Combine two sine waves and store in row buffer + i?ROW_BUFFER = pA?SIN_TABLE + pB?SIN_TABLE; + + pA += 3; // Shift phase for first sine wave (controls wave speed) + pB += 7; // Shift phase for second sine wave (different speed for variety) + + branch_if (i +:= 1) < SCR_W: i; + } + + i = 0; + loop i { + let j = 0; + loop j { + // Combine wave values from row buffer for current position + // Use bitwise AND to clamp to 0-255, then scale to 0-15 for character index + let c = ((j?ROW_BUFFER + i?ROW_BUFFER) & 255) >> 4; + + // Set text color based on intensity (base color + scaled value) + setTextColor(BASE_COLOR + c); + // Draw custom character corresponding to intensity + printChar(CHARS + c); + + branch_if (j +:= 1) < SCR_W: j; + } + branch_if (i +:= 1) < SCR_H: i; + } + + // Update global phase offsets for the next frame to animate the pattern + phaseA += 0; // Increment phaseA to shift the pattern (+/- speed move) + phaseB += 1; // Increment phaseB to shift the pattern (+/- right/left move) +} + +//----------------------------------------------------------------------------- + +/* + Custom font data defining 16 characters (8x8 pixels each) + Each character represents a different intensity level for the plasma effect + Pixels range from empty (0x00) to nearly full (0xFE or 0x7F) to simulate gradients +*/ +data CUSTOM_FONT { + i8( + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, + 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, + 0x00, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x00, + 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, + 0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x00, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x00, + 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + ) +} From 5e54716007df076432ed976d185036fd95299de0 Mon Sep 17 00:00:00 2001 From: Bartek Zbytniewski Date: Thu, 17 Apr 2025 21:27:42 +0200 Subject: [PATCH 3/9] add constant.numeric.float.curlywasm _f for hex --- syntax/CurlyWASM.sublime-syntax | 3 +++ 1 file changed, 3 insertions(+) diff --git a/syntax/CurlyWASM.sublime-syntax b/syntax/CurlyWASM.sublime-syntax index 7d61646..0c2619f 100644 --- a/syntax/CurlyWASM.sublime-syntax +++ b/syntax/CurlyWASM.sublime-syntax @@ -103,6 +103,9 @@ contexts: - match: '\b\d+(_f)\b' scope: constant.numeric.float.curlywasm + - match: \b0x[0-9a-fA-F]+_f\b + scope: constant.numeric.float.curlywasm + - match: \b([0-9]+\.[0-9]+)\b scope: constant.numeric.float.curlywasm From 14e31d02fc3e59db9664c9a36a5530c1e68ed4e9 Mon Sep 17 00:00:00 2001 From: Bartek Zbytniewski Date: Thu, 17 Apr 2025 22:11:40 +0200 Subject: [PATCH 4/9] expanded syntax with start() & upd() functions --- syntax/CurlyWASM.sublime-syntax | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/syntax/CurlyWASM.sublime-syntax b/syntax/CurlyWASM.sublime-syntax index 0c2619f..2d49d5c 100644 --- a/syntax/CurlyWASM.sublime-syntax +++ b/syntax/CurlyWASM.sublime-syntax @@ -54,7 +54,7 @@ contexts: scope: support.function.curlywasm # Built-in functions - - match: \b(sqrt|min|max|ceil|floor|trunc|nearest|abs|copysign|select|trunc_sat_f32_u)\b + - match: \b(start|upd|sqrt|min|max|ceil|floor|trunc|nearest|abs|copysign|select|trunc_sat_f32_u)\b scope: support.function.curlywasm # Data blocks - Match 'data {' together and push context From 3c4fd20d7051fe370d91383c89499844422f65d5 Mon Sep 17 00:00:00 2001 From: Bartek Zbytniewski Date: Fri, 18 Apr 2025 19:45:16 +0200 Subject: [PATCH 5/9] sublime text autocompletion --- syntax/CurlyWASM.sublime-completions | 543 +++++++++++++++++++++++++++ syntax/CurlyWASM.sublime-syntax | 4 +- 2 files changed, 545 insertions(+), 2 deletions(-) create mode 100644 syntax/CurlyWASM.sublime-completions diff --git a/syntax/CurlyWASM.sublime-completions b/syntax/CurlyWASM.sublime-completions new file mode 100644 index 0000000..4be26c5 --- /dev/null +++ b/syntax/CurlyWASM.sublime-completions @@ -0,0 +1,543 @@ +{ + "scope": "source.curlywasm", + "completions": [ + // Keywords + { + "trigger": "if", + "contents": "if (${1:condition}) { ${2:block} }", + "details": "if (condition) { block }", + "kind": "keyword" + }, + { + "trigger": "else", + "contents": "else { ${1:block} }", + "details": "else { block }", + "kind": "keyword" + }, + { + "trigger": "loop", + "contents": "loop ${1:label} { ${2:block} }", + "details": "loop label { block }", + "kind": "keyword" + }, + { + "trigger": "fn", + "contents": "fn ${1:name}(${2:params}) ${3:-> ${4:return_type}} { ${5:block} }", + "details": "fn name(params) [-> return_type] { block }", + "kind": "keyword" + }, + { + "trigger": "let", + "contents": "let ${1:variable}${2:: ${3:type}} = ${4:value};", + "details": "let variable[: type] = value;", + "kind": "keyword" + }, + { + "trigger": "const", + "contents": "const ${1:name}${2:: ${3:type}} = ${4:value};", + "details": "const name[: type] = value;", + "kind": "keyword" + }, + { + "trigger": "branch_if", + "contents": "branch_if (${1:condition}): ${2:label};", + "details": "branch_if (condition): label;", + "kind": "keyword" + }, + { + "trigger": "global", + "contents": "global mut ${1:name}${2:: ${3:type}} = ${4:value};", + "details": "global mut name[: type] = value;", + "kind": "keyword" + }, + { + "trigger": "import", + "contents": "import \"${1:module.name}\" ${2:|memory(min_pages)|global var_name: type|fn fun_name(param_types) [-> return_type]};", + "details": "import \"module.name\" memory(min_pages); import \"module.name\" global var_name: type; import \"module.name\" fn fun_name(param_types) [-> return_type];", + "kind": "keyword" + }, + { + "trigger": "include", + "contents": "include \"${1:path}\"", + "details": "include \"path\"", + "kind": "keyword" + }, + { + "trigger": "export", + "contents": "export fn ${1:name}(${2:params}) ${3:-> ${4:return_type}} { ${5:block} }", + "details": "export fn name(params) [-> return_type] { block }", + "kind": "keyword" + }, + { + "trigger": "return", + "contents": "return${1: expression}", + "details": "return [expression]", + "kind": "keyword" + }, + { + "trigger": "block", + "contents": "block ${1:label} { ${2:block} }", + "details": "block label { block }", + "kind": "keyword" + }, + { + "trigger": "branch", + "contents": "branch ${1:label};", + "details": "branch label;", + "kind": "keyword" + }, + { + "trigger": "data", + "contents": "data ${1:address} { ${2:content} }", + "details": "data address { content }", + "kind": "keyword" + }, + { + "trigger": "mut", + "contents": "mut", + "details": "Mutable variable modifier", + "kind": "storage.modifier" + }, + { + "trigger": "lazy", + "contents": "lazy", + "details": "Lazy variable modifier", + "kind": "storage.modifier" + }, + { + "trigger": "inline", + "contents": "inline", + "details": "Inline variable modifier", + "kind": "storage.modifier" + }, + { + "trigger": "break", + "contents": "break;", + "details": "Break from block or loop", + "kind": "keyword" + }, + + // Operators + { + "trigger": "as", + "contents": "as", + "details": "Type cast", + "kind": "keyword.operator.type" + }, + { + "trigger": "?", + "contents": "?", + "details": "Load byte", + "kind": "keyword.operator.memory" + }, + { + "trigger": "!", + "contents": "!", + "details": "Load word", + "kind": "keyword.operator.memory" + }, + { + "trigger": "$", + "contents": "$", + "details": "Load float", + "kind": "keyword.operator.memory" + }, + { + "trigger": "<|", + "contents": "<|", + "details": "Take first (sequencing operator)", + "kind": "keyword.operator.misc" + }, + + // Memory access intrinsic functions (i32 and f32 only) + { + "trigger": "i32.load", + "contents": "i32.load(${1:base}, ${2:offset}${3:, ${4:align}})", + "details": "i32.load(base: i32, offset: i32 = 0, align: i32 = 2) -> i32: Load 32-bit word", + "kind": "support.function" + }, + { + "trigger": "i32.load8_u", + "contents": "i32.load8_u(${1:base}, ${2:offset}${3:, ${4:align}})", + "details": "i32.load8_u(base: i32, offset: i32 = 0, align: i32 = 0) -> i32: Load 8-bit unsigned", + "kind": "support.function" + }, + { + "trigger": "i32.load8_s", + "contents": "i32.load8_s(${1:base}, ${2:offset}${3:, ${4:align}})", + "details": "i32.load8_s(base: i32, offset: i32 = 0, align: i32 = 0) -> i32: Load 8-bit signed", + "kind": "support.function" + }, + { + "trigger": "i32.load16_u", + "contents": "i32.load16_u(${1:base}, ${2:offset}${3:, ${4:align}})", + "details": "i32.load16_u(base: i32, offset: i32 = 0, align: i32 = 1) -> i32: Load 16-bit unsigned", + "kind": "support.function" + }, + { + "trigger": "i32.load16_s", + "contents": "i32.load16_s(${1:base}, ${2:offset}${3:, ${4:align}})", + "details": "i32.load16_s(base: i32, offset: i32 = 0, align: i32 = 1) -> i32: Load 16-bit signed", + "kind": "support.function" + }, + { + "trigger": "i32.store", + "contents": "i32.store(${1:value}, ${2:base}, ${3:offset}${4:, ${5:align}});", + "details": "i32.store(value: i32, base: i32, offset: i32 = 0, align: i32 = 2): Store 32-bit word", + "kind": "support.function" + }, + { + "trigger": "i32.store8", + "contents": "i32.store8(${1:value}, ${2:base}, ${3:offset}${4:, ${5:align}});", + "details": "i32.store8(value: i32, base: i32, offset: i32 = 0, align: i32 = 0): Store 8-bit", + "kind": "support.function" + }, + { + "trigger": "i32.store16", + "contents": "i32.store16(${1:value}, ${2:base}, ${3:offset}${4:, ${5:align}});", + "details": "i32.store16(value: i32, base: i32, offset: i32 = 0, align: i32 = 1): Store 16-bit", + "kind": "support.function" + }, + { + "trigger": "f32.load", + "contents": "f32.load(${1:base}, ${2:offset}${3:, ${4:align}})", + "details": "f32.load(base: i32, offset: i32 = 0, align: i32 = 2) -> f32: Load 32-bit float", + "kind": "support.function" + }, + { + "trigger": "f32.store", + "contents": "f32.store(${1:value}, ${2:base}, ${3:offset}${4:, ${5:align}});", + "details": "f32.store(value: f32, base: i32, offset: i32 = 0, align: i32 = 2): Store 32-bit float", + "kind": "support.function" + }, + + + // API functions + { + "trigger": "sin", + "contents": "sin(${1:x})", + "details": "sin(x: f32) -> f32: Returns the sine of x (radians)", + "kind": "support.function" + }, + { + "trigger": "cos", + "contents": "cos(${1:x})", + "details": "cos(x: f32) -> f32: Returns the cosine of x (radians)", + "kind": "support.function" + }, + { + "trigger": "tan", + "contents": "tan(${1:x})", + "details": "tan(x: f32) -> f32: Returns the tangent of x (radians)", + "kind": "support.function" + }, + { + "trigger": "asin", + "contents": "asin(${1:x})", + "details": "asin(x: f32) -> f32: Returns the arcsine of x (radians)", + "kind": "support.function" + }, + { + "trigger": "acos", + "contents": "acos(${1:x})", + "details": "acos(x: f32) -> f32: Returns the arccosine of x (radians)", + "kind": "support.function" + }, + { + "trigger": "atan", + "contents": "atan(${1:x})", + "details": "atan(x: f32) -> f32: Returns the arctangent of x (radians)", + "kind": "support.function" + }, + { + "trigger": "atan2", + "contents": "atan2(${1:y}, ${2:x})", + "details": "atan2(y: f32, x: f32) -> f32: Returns the angle in radians of the point (x, y)", + "kind": "support.function" + }, + { + "trigger": "pow", + "contents": "pow(${1:x}, ${2:y})", + "details": "pow(x: f32, y: f32) -> f32: Returns x raised to the power of y", + "kind": "support.function" + }, + { + "trigger": "log", + "contents": "log(${1:x})", + "details": "log(x: f32) -> f32: Returns the natural logarithm of x", + "kind": "support.function" + }, + { + "trigger": "fmod", + "contents": "fmod(${1:x}, ${2:y})", + "details": "fmod(x: f32, y: f32) -> f32: Returns the remainder of x/y", + "kind": "support.function" + }, + { + "trigger": "random", + "contents": "random()", + "details": "random() -> i32: Returns a random 32-bit integer", + "kind": "support.function" + }, + { + "trigger": "randomf", + "contents": "randomf()", + "details": "randomf() -> f32: Returns a random float [0, 1)", + "kind": "support.function" + }, + { + "trigger": "randomSeed", + "contents": "randomSeed(${1:seed});", + "details": "randomSeed(seed: i32): Seeds the random number generator", + "kind": "support.function" + }, + { + "trigger": "cls", + "contents": "cls(${1:color});", + "details": "cls(color: i32): Clears the screen with the given color, resets cursor to 0,0, disables graphics mode", + "kind": "support.function" + }, + { + "trigger": "setPixel", + "contents": "setPixel(${1:x}, ${2:y}, ${3:color});", + "details": "setPixel(x: i32, y: i32, color: i32): Sets the pixel at (x, y) to color", + "kind": "support.function" + }, + { + "trigger": "getPixel", + "contents": "getPixel(${1:x}, ${2:y})", + "details": "getPixel(x: i32, y: i32) -> i32: Gets the color of the pixel at (x, y) (returns 0 if out of bounds)", + "kind": "support.function" + }, + { + "trigger": "hline", + "contents": "hline(${1:left}, ${2:right}, ${3:y}, ${4:color});", + "details": "hline(left: i32, right: i32, y: i32, color: i32): Fills the horizontal line [left, right), y", + "kind": "support.function" + }, + { + "trigger": "rectangle", + "contents": "rectangle(${1:x}, ${2:y}, ${3:width}, ${4:height}, ${5:color});", + "details": "rectangle(x: f32, y: f32, w: f32, h: f32, color: i32): Fills the rectangle x,y - x+w,y+h", + "kind": "support.function" + }, + { + "trigger": "circle", + "contents": "circle(${1:cx}, ${2:cy}, ${3:radius}, ${4:color});", + "details": "circle(cx: f32, cy: f32, radius: f32, color: i32): Fills the circle at cx, cy with radius", + "kind": "support.function" + }, + { + "trigger": "line", + "contents": "line(${1:x1}, ${2:y1}, ${3:x2}, ${4:y2}, ${5:color});", + "details": "line(x1: f32, y1: f32, x2: f32, y2: f32, color: i32): Draws a line from x1,y1 to x2,y2", + "kind": "support.function" + }, + { + "trigger": "time", + "contents": "time()", + "details": "time() -> f32: Returns the current time in seconds", + "kind": "support.function" + }, + { + "trigger": "isButtonPressed", + "contents": "isButtonPressed(${1:button})", + "details": "isButtonPressed(button: i32) -> bool: Checks if a button is pressed this frame (returns i32)", + "kind": "support.function" + }, + { + "trigger": "isButtonTriggered", + "contents": "isButtonTriggered(${1:button})", + "details": "isButtonTriggered(button: i32) -> bool: Checks if a button is newly pressed this frame (returns i32)", + "kind": "support.function" + }, + { + "trigger": "printChar", + "contents": "printChar(${1:char});", + "details": "printChar(char: i32): Prints the character in the lower 8 bits", + "kind": "support.function" + }, + { + "trigger": "printString", + "contents": "printString(${1:ptr});", + "details": "printString(ptr: i32): Prints the zero-terminated string at memory address ptr", + "kind": "support.function" + }, + { + "trigger": "printInt", + "contents": "printInt(${1:value});", + "details": "printInt(value: i32): Prints an integer as a signed decimal number", + "kind": "support.function" + }, + { + "trigger": "setTextColor", + "contents": "setTextColor(${1:color});", + "details": "setTextColor(color: i32): Sets the text color", + "kind": "support.function" + }, + { + "trigger": "setBackgroundColor", + "contents": "setBackgroundColor(${1:color});", + "details": "setBackgroundColor(color: i32): Sets the background color", + "kind": "support.function" + }, + { + "trigger": "setCursorPosition", + "contents": "setCursorPosition(${1:x}, ${2:y});", + "details": "setCursorPosition(x: i32, y: i32): Sets the cursor position (character or pixel coords depending on mode)", + "kind": "support.function" + }, + { + "trigger": "rectangleOutline", + "contents": "rectangleOutline(${1:x}, ${2:y}, ${3:width}, ${4:height}, ${5:color});", + "details": "rectangleOutline(x: f32, y: f32, w: f32, h: f32, color: i32): Draws a rectangle outline", + "kind": "support.function" + }, + { + "trigger": "circleOutline", + "contents": "circleOutline(${1:cx}, ${2:cy}, ${3:radius}, ${4:color});", + "details": "circleOutline(cx: f32, cy: f32, radius: f32, color: i32): Draws a circle outline", + "kind": "support.function" + }, + { + "trigger": "exp", + "contents": "exp(${1:x})", + "details": "exp(x: f32) -> f32: Returns e raised to the power of x", + "kind": "support.function" + }, + { + "trigger": "playNote", + "contents": "playNote(${1:channel}, ${2:note}${3:, ${4:duration}${5:, ${6:volume}}});", + "details": "playNote(channel: i32, note: i32): Triggers a note on the given channel (note 0 stops, 128-255 triggers attack+release)", + "kind": "support.function" + }, + { + "trigger": "sndGes", + "contents": "sndGes(${1:sampleIndex})", + "details": "sndGes(sampleIndex: i32) -> f32: Sound generator function (uses 32 bytes at 0x50 by default)", + "kind": "support.function" + }, + { + "trigger": "blitSprite", + "contents": "blitSprite(${1:spriteData}, ${2:size}, ${3:x}, ${4:y}, ${5:control});", + "details": "blitSprite(spriteData: i32, size: i32, x: i32, y: i32, control: i32): Copies sprite data to screen", + "kind": "support.function" + }, + { + "trigger": "grabSprite", + "contents": "grabSprite(${1:spriteData}, ${2:size}, ${3:x}, ${4:y}, ${5:control});", + "details": "grabSprite(spriteData: i32, size: i32, x: i32, y: i32, control: i32): Copies screen data to sprite", + "kind": "support.function" + }, + + // Built-in functions (or commonly used intrinsics) + { + "trigger": "start", + "contents": "export fn start() {\n\t${1:// Your start code here}\n}", + "details": "export fn start(): Called once after module is loaded", + "kind": "support.function" + }, + { + "trigger": "upd", + "contents": "export fn upd() {\n\t${1:// Your update code here}\n}", + "details": "export fn upd(): Called once per frame", + "kind": "support.function" + }, + { + "trigger": "sqrt", + "contents": "sqrt(${1:x})", + "details": "sqrt(x: f32) -> f32: Returns the square root of x", + "kind": "support.function" + }, + { + "trigger": "min", + "contents": "min(${1:x}, ${2:y})", + "details": "min(x: f32, y: f32) -> f32: Returns the minimum of x and y", + "kind": "support.function" + }, + { + "trigger": "max", + "contents": "max(${1:x}, ${2:y})", + "details": "max(x: f32, y: f32) -> f32: Returns the maximum of x and y", + "kind": "support.function" + }, + { + "trigger": "ceil", + "contents": "ceil(${1:x})", + "details": "ceil(x: f32) -> f32: Returns the smallest integer >= x", + "kind": "support.function" + }, + { + "trigger": "floor", + "contents": "floor(${1:x})", + "details": "floor(x: f32) -> f32: Returns the largest integer <= x", + "kind": "support.function" + }, + { + "trigger": "trunc", + "contents": "trunc(${1:x})", + "details": "trunc(x: f32) -> f32: Returns the nearest integer to x toward zero", + "kind": "support.function" + }, + { + "trigger": "nearest", + "contents": "nearest(${1:x})", + "details": "nearest(x: f32) -> f32: Returns the nearest integer to x (round to nearest, ties to even)", + "kind": "support.function" + }, + { + "trigger": "abs", + "contents": "abs(${1:x})", + "details": "abs(x: f32) -> f32: Returns the absolute value of x", + "kind": "support.function" + }, + { + "trigger": "copysign", + "contents": "copysign(${1:x}, ${2:y})", + "details": "copysign(x: f32, y: f32) -> f32: Returns x with the sign of y", + "kind": "support.function" + }, + { + "trigger": "select", + "contents": "select(${1:a}, ${2:b}, ${3:c})", + "details": "select(a: f32, b: f32, c: f32) -> f32: Selects b if a is non-zero, otherwise selects c (equivalent to a != 0 ? b : c)", + "kind": "support.function" + }, + { + "trigger": "i32.clz", + "contents": "i32.clz(${1:value})", + "details": "i32.clz(value: i32) -> i32: Count Leading Zeros", + "kind": "support.function" + }, + { + "trigger": "i32.ctz", + "contents": "i32.ctz(${1:value})", + "details": "i32.ctz(value: i32) -> i32: Count Trailing Zeros", + "kind": "support.function" + }, + { + "trigger": "i32.popcnt", + "contents": "i32.popcnt(${1:value})", + "details": "i32.popcnt(value: i32) -> i32: Population Count (number of set bits)", + "kind": "support.function" + }, + { + "trigger": "i32.bswap", + "contents": "i32.bswap(${1:value})", + "details": "i32.bswap(value: i32) -> i32: Byte Swap", + "kind": "support.function" + }, + { + "trigger": "i32.trunc_sat_f32_u", + "contents": "i32.trunc_sat_f32_u(${1:value})", + "details": "i32.trunc_sat_f32_u(value: f32) -> i32: Truncate f32 to i32 unsigned, saturating", + "kind": "support.function" + }, + { + "trigger": "i32.trunc_sat_f32_s", + "contents": "i32.trunc_sat_f32_s(${1:value})", + "details": "i32.trunc_sat_f32_s(value: f32) -> i32: Truncate f32 to i32 signed, saturating", + "kind": "support.function" + } + ] +} diff --git a/syntax/CurlyWASM.sublime-syntax b/syntax/CurlyWASM.sublime-syntax index 2d49d5c..23cb115 100644 --- a/syntax/CurlyWASM.sublime-syntax +++ b/syntax/CurlyWASM.sublime-syntax @@ -46,7 +46,7 @@ contexts: scope: keyword.operator.type.curlywasm # WASM memory access operators - - match: \b(load|load8_s|store)\b + - match: \b(load|store)\b scope: keyword.operator.memory.curlywasm # API functions @@ -54,7 +54,7 @@ contexts: scope: support.function.curlywasm # Built-in functions - - match: \b(start|upd|sqrt|min|max|ceil|floor|trunc|nearest|abs|copysign|select|trunc_sat_f32_u)\b + - match: \b(start|upd|sqrt|min|max|ceil|floor|trunc|nearest|abs|copysign|select)\b scope: support.function.curlywasm # Data blocks - Match 'data {' together and push context From 3ca10fc85a1609bc6fd0665031d6e7122f22a24e Mon Sep 17 00:00:00 2001 From: Bartek Zbytniewski Date: Fri, 18 Apr 2025 20:43:44 +0200 Subject: [PATCH 6/9] syntax & autocomplete refactor --- syntax/CurlyWASM.sublime-completions | 22 +++++----------------- syntax/CurlyWASM.sublime-syntax | 2 +- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/syntax/CurlyWASM.sublime-completions b/syntax/CurlyWASM.sublime-completions index 4be26c5..7ec5882 100644 --- a/syntax/CurlyWASM.sublime-completions +++ b/syntax/CurlyWASM.sublime-completions @@ -4,25 +4,25 @@ // Keywords { "trigger": "if", - "contents": "if (${1:condition}) { ${2:block} }", + "contents": "if (${1:condition}) {\n\t${2:// Your start code here}\n}", "details": "if (condition) { block }", "kind": "keyword" }, { "trigger": "else", - "contents": "else { ${1:block} }", + "contents": "else {\n\t${1:// Your start code here}\n}", "details": "else { block }", "kind": "keyword" }, { "trigger": "loop", - "contents": "loop ${1:label} { ${2:block} }", + "contents": "loop ${1:label} {\n\t${2:// Your start code here}\n}", "details": "loop label { block }", "kind": "keyword" }, { "trigger": "fn", - "contents": "fn ${1:name}(${2:params}) ${3:-> ${4:return_type}} { ${5:block} }", + "contents": "fn ${1:name}(${2:params}) {\n\t${3:// Your start code here}\n}", "details": "fn name(params) [-> return_type] { block }", "kind": "keyword" }, @@ -74,12 +74,6 @@ "details": "return [expression]", "kind": "keyword" }, - { - "trigger": "block", - "contents": "block ${1:label} { ${2:block} }", - "details": "block label { block }", - "kind": "keyword" - }, { "trigger": "branch", "contents": "branch ${1:label};", @@ -88,7 +82,7 @@ }, { "trigger": "data", - "contents": "data ${1:address} { ${2:content} }", + "contents": "data ${1:address} {\n\t${2:content}\n}", "details": "data address { content }", "kind": "keyword" }, @@ -110,12 +104,6 @@ "details": "Inline variable modifier", "kind": "storage.modifier" }, - { - "trigger": "break", - "contents": "break;", - "details": "Break from block or loop", - "kind": "keyword" - }, // Operators { diff --git a/syntax/CurlyWASM.sublime-syntax b/syntax/CurlyWASM.sublime-syntax index 23cb115..03179df 100644 --- a/syntax/CurlyWASM.sublime-syntax +++ b/syntax/CurlyWASM.sublime-syntax @@ -38,7 +38,7 @@ contexts: scope: storage.modifier.curlywasm # Control flow - - match: \b(return|if|else|loop|block|branch|branch_if|break)\b + - match: \b(return|if|else|loop|branch|branch_if)\b scope: keyword.control.flow.curlywasm # Type conversion From e14db77f26b1ec62ca9d7243e3fb391b4c3ce069 Mon Sep 17 00:00:00 2001 From: Bartek Zbytniewski Date: Sun, 20 Apr 2025 10:53:26 +0200 Subject: [PATCH 7/9] more Sublime Text fetures --- .../CurlyWASM.sublime-completions | 252 +++++++++++++++++- .../CurlyWASM.sublime-syntax | 2 +- syntax/SublimeText/data-block.sublime-snippet | 11 + syntax/SublimeText/fn-export.sublime-snippet | 9 + syntax/SublimeText/if-else.sublime-snippet | 11 + syntax/SublimeText/let-inline.sublime-snippet | 7 + syntax/SublimeText/let-lazy.sublime-snippet | 7 + .../loop-branch_if.sublime-snippet | 11 + 8 files changed, 300 insertions(+), 10 deletions(-) rename syntax/{ => SublimeText}/CurlyWASM.sublime-completions (73%) rename syntax/{ => SublimeText}/CurlyWASM.sublime-syntax (99%) create mode 100644 syntax/SublimeText/data-block.sublime-snippet create mode 100644 syntax/SublimeText/fn-export.sublime-snippet create mode 100644 syntax/SublimeText/if-else.sublime-snippet create mode 100644 syntax/SublimeText/let-inline.sublime-snippet create mode 100644 syntax/SublimeText/let-lazy.sublime-snippet create mode 100644 syntax/SublimeText/loop-branch_if.sublime-snippet diff --git a/syntax/CurlyWASM.sublime-completions b/syntax/SublimeText/CurlyWASM.sublime-completions similarity index 73% rename from syntax/CurlyWASM.sublime-completions rename to syntax/SublimeText/CurlyWASM.sublime-completions index 7ec5882..b906b56 100644 --- a/syntax/CurlyWASM.sublime-completions +++ b/syntax/SublimeText/CurlyWASM.sublime-completions @@ -28,13 +28,13 @@ }, { "trigger": "let", - "contents": "let ${1:variable}${2:: ${3:type}} = ${4:value};", + "contents": "let ${1:variable} = ${2:value};", "details": "let variable[: type] = value;", "kind": "keyword" }, { "trigger": "const", - "contents": "const ${1:name}${2:: ${3:type}} = ${4:value};", + "contents": "const ${1:name} = ${2:value};", "details": "const name[: type] = value;", "kind": "keyword" }, @@ -46,7 +46,7 @@ }, { "trigger": "global", - "contents": "global mut ${1:name}${2:: ${3:type}} = ${4:value};", + "contents": "global mut ${1:name} = ${2:value};", "details": "global mut name[: type] = value;", "kind": "keyword" }, @@ -69,9 +69,9 @@ "kind": "keyword" }, { - "trigger": "return", - "contents": "return${1: expression}", - "details": "return [expression]", + "trigger": "block", + "contents": "block ${1:label} { ${2:block} }", + "details": "block label { block }", "kind": "keyword" }, { @@ -82,7 +82,7 @@ }, { "trigger": "data", - "contents": "data ${1:address} {\n\t${2:content}\n}", + "contents": "data ${1:address} {\n\t${2:type}(\n\t\t${3:values}\n\t)\n}", "details": "data address { content }", "kind": "keyword" }, @@ -199,7 +199,6 @@ "kind": "support.function" }, - // API functions { "trigger": "sin", @@ -526,6 +525,241 @@ "contents": "i32.trunc_sat_f32_s(${1:value})", "details": "i32.trunc_sat_f32_s(value: f32) -> i32: Truncate f32 to i32 signed, saturating", "kind": "support.function" + }, + // Added Constants + { + "trigger": "TIME_MS", + "contents": "TIME_MS", + "details": "0x40 Time since module start in ms", + "kind": "constant" + }, + { + "trigger": "GAMEPAD", + "contents": "GAMEPAD", + "details": "0x44 Gamepad state", + "kind": "constant" + }, + { + "trigger": "FRAMEBUFFER", + "contents": "FRAMEBUFFER", + "details": "0x78 Frame buffer address", + "kind": "constant" + }, + { + "trigger": "PALETTE", + "contents": "PALETTE", + "details": "0x13000 Palette address", + "kind": "constant" + }, + { + "trigger": "FONT", + "contents": "FONT", + "details": "0x13400 Font address", + "kind": "constant" + }, + { + "trigger": "USER_MEM", + "contents": "USER_MEM", + "details": "0x14000 Start of general user memory", + "kind": "constant" + }, + { + "trigger": "BUTTON_UP", + "contents": "BUTTON_UP", + "details": "0x00 Gamepad button Up", + "kind": "constant" + }, + { + "trigger": "BUTTON_DOWN", + "contents": "BUTTON_DOWN", + "details": "0x01 Gamepad button Down", + "kind": "constant" + }, + { + "trigger": "BUTTON_LEFT", + "contents": "BUTTON_LEFT", + "details": "0x02 Gamepad button Left", + "kind": "constant" + }, + { + "trigger": "BUTTON_RIGHT", + "contents": "BUTTON_RIGHT", + "details": "0x03 Gamepad button Right", + "kind": "constant" + }, + { + "trigger": "BUTTON_A", + "contents": "BUTTON_A", + "details": "0x04 Gamepad button A (Z on keyboard)", + "kind": "constant" + }, + { + "trigger": "BUTTON_B", + "contents": "BUTTON_B", + "details": "0x05 Gamepad button B (X on keyboard)", + "kind": "constant" + }, + { + "trigger": "BUTTON_X", + "contents": "BUTTON_X", + "details": "0x06 Gamepad button X (A on keyboard)", + "kind": "constant" + }, + { + "trigger": "BUTTON_Y", + "contents": "BUTTON_Y", + "details": "0x07 Gamepad button Y (S on keyboard)", + "kind": "constant" + }, + { + "trigger": "PI", + "contents": "PI", + "details": "Mathematical constant π", + "kind": "constant" + }, + { + "trigger": "RAD", + "contents": "RAD", + "details": "One radian value", + "kind": "constant" + }, + { + "trigger": "SCR_X", + "contents": "SCR_X", + "details": "Screen width in pixels", + "kind": "constant" + }, + { + "trigger": "SCR_Y", + "contents": "SCR_Y", + "details": "Screen height in pixels", + "kind": "constant" + }, + { + "trigger": "SCR_W", + "contents": "SCR_W", + "details": "Screen width in chars (40)", + "kind": "constant" + }, + { + "trigger": "SCR_H", + "contents": "SCR_H", + "details": "Screen height in chars (30)", + "kind": "constant" + }, + { + "trigger": "CENTER_X", + "contents": "CENTER_X", + "details": "X-coordinate of the screen center (160)", + "kind": "constant" + }, + { + "trigger": "CENTER_Y", + "contents": "CENTER_Y", + "details": "Y-coordinate of the screen center (120)", + "kind": "constant" + }, + { + "trigger": "SCR_SIZE", + "contents": "SCR_SIZE", + "details": "Total screen size in pixels (76800)", + "kind": "constant" + }, + { + "trigger": "MEM_END", + "contents": "MEM_END", + "details": "End of available memory", + "kind": "constant" + }, + { + "trigger": "CUSTOM_FONT", + "contents": "CUSTOM_FONT", + "details": "Address for a custom font", + "kind": "constant" + }, + { + "trigger": "COLOR_BLACK", + "contents": "COLOR_BLACK", + "details": "0x00 Black", + "kind": "constant" + }, + { + "trigger": "COLOR_DARK_BLUE", + "contents": "COLOR_DARK_BLUE", + "details": "0x17 Dark Blue", + "kind": "constant" + }, + { + "trigger": "COLOR_DARK_PURPLE", + "contents": "COLOR_DARK_PURPLE", + "details": "0x27 Dark Purple", + "kind": "constant" + }, + { + "trigger": "COLOR_CYAN", + "contents": "COLOR_CYAN", + "details": "0x37 Cyan", + "kind": "constant" + }, + { + "trigger": "COLOR_BRIGHT_RED", + "contents": "COLOR_BRIGHT_RED", + "details": "0x47 Bright Red", + "kind": "constant" + }, + { + "trigger": "COLOR_MAGENTA", + "contents": "COLOR_MAGENTA", + "details": "0x57 Magenta", + "kind": "constant" + }, + { + "trigger": "COLOR_ORANGE", + "contents": "COLOR_ORANGE", + "details": "0x58 Orange", + "kind": "constant" + }, + { + "trigger": "COLOR_BRIGHT_YELLOW", + "contents": "COLOR_BRIGHT_YELLOW", + "details": "0x67 Bright Yellow", + "kind": "constant" + }, + { + "trigger": "COLOR_MEDIUM_GREY", + "contents": "COLOR_MEDIUM_GREY", + "details": "0x78 Medium Grey", + "kind": "constant" + }, + { + "trigger": "COLOR_LIGHT_GREY", + "contents": "COLOR_LIGHT_GREY", + "details": "0x7C Light Grey", + "kind": "constant" + }, + { + "trigger": "COLOR_WHITE", + "contents": "COLOR_WHITE", + "details": "0xF8 White", + "kind": "constant" + }, + { + "trigger": "COLOR_BRIGHT_GREEN", + "contents": "COLOR_BRIGHT_GREEN", + "details": "0x87 Bright Green", + "kind": "constant" + }, + { + "trigger": "COLOR_BROWN", + "contents": "COLOR_BROWN", + "details": "0xD4 Brown", + "kind": "constant" + }, + { + "trigger": "COLOR_DARK_GREY", + "contents": "COLOR_DARK_GREY", + "details": "0xE1 Dark Grey", + "kind": "constant" } ] -} +} \ No newline at end of file diff --git a/syntax/CurlyWASM.sublime-syntax b/syntax/SublimeText/CurlyWASM.sublime-syntax similarity index 99% rename from syntax/CurlyWASM.sublime-syntax rename to syntax/SublimeText/CurlyWASM.sublime-syntax index 03179df..2a522bc 100644 --- a/syntax/CurlyWASM.sublime-syntax +++ b/syntax/SublimeText/CurlyWASM.sublime-syntax @@ -38,7 +38,7 @@ contexts: scope: storage.modifier.curlywasm # Control flow - - match: \b(return|if|else|loop|branch|branch_if)\b + - match: \b(if|else|block|loop|branch|branch_if)\b scope: keyword.control.flow.curlywasm # Type conversion diff --git a/syntax/SublimeText/data-block.sublime-snippet b/syntax/SublimeText/data-block.sublime-snippet new file mode 100644 index 0000000..ef8a8ed --- /dev/null +++ b/syntax/SublimeText/data-block.sublime-snippet @@ -0,0 +1,11 @@ + + + datatype + Data block definition + diff --git a/syntax/SublimeText/fn-export.sublime-snippet b/syntax/SublimeText/fn-export.sublime-snippet new file mode 100644 index 0000000..18b9c0d --- /dev/null +++ b/syntax/SublimeText/fn-export.sublime-snippet @@ -0,0 +1,9 @@ + + ${3:return_type} { + ${4:// Function body} +} +]]> + fnexport + Exported function definition + diff --git a/syntax/SublimeText/if-else.sublime-snippet b/syntax/SublimeText/if-else.sublime-snippet new file mode 100644 index 0000000..6526b0e --- /dev/null +++ b/syntax/SublimeText/if-else.sublime-snippet @@ -0,0 +1,11 @@ + + + ifelse + If-else statement + diff --git a/syntax/SublimeText/let-inline.sublime-snippet b/syntax/SublimeText/let-inline.sublime-snippet new file mode 100644 index 0000000..cfdee88 --- /dev/null +++ b/syntax/SublimeText/let-inline.sublime-snippet @@ -0,0 +1,7 @@ + + + letinline + Lazy variable declaration + diff --git a/syntax/SublimeText/let-lazy.sublime-snippet b/syntax/SublimeText/let-lazy.sublime-snippet new file mode 100644 index 0000000..acaa041 --- /dev/null +++ b/syntax/SublimeText/let-lazy.sublime-snippet @@ -0,0 +1,7 @@ + + + letlazy + Lazy variable declaration + diff --git a/syntax/SublimeText/loop-branch_if.sublime-snippet b/syntax/SublimeText/loop-branch_if.sublime-snippet new file mode 100644 index 0000000..b46014d --- /dev/null +++ b/syntax/SublimeText/loop-branch_if.sublime-snippet @@ -0,0 +1,11 @@ + + + loopbr + Loop with branch_if + From ede0484e9bdf6be052def42105acc17014dacbc2 Mon Sep 17 00:00:00 2001 From: Bartek Zbytniewski Date: Sun, 20 Apr 2025 13:09:38 +0200 Subject: [PATCH 8/9] Sublime Text refactor --- .../SublimeText/CurlyWASM.sublime-completions | 18 +++++++++++++++--- syntax/SublimeText/if-else.sublime-snippet | 2 +- .../SublimeText/loop-branch_if.sublime-snippet | 2 +- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/syntax/SublimeText/CurlyWASM.sublime-completions b/syntax/SublimeText/CurlyWASM.sublime-completions index b906b56..677ef8b 100644 --- a/syntax/SublimeText/CurlyWASM.sublime-completions +++ b/syntax/SublimeText/CurlyWASM.sublime-completions @@ -4,7 +4,7 @@ // Keywords { "trigger": "if", - "contents": "if (${1:condition}) {\n\t${2:// Your start code here}\n}", + "contents": "if ${1:condition} {\n\t${2:// Your start code here}\n}", "details": "if (condition) { block }", "kind": "keyword" }, @@ -40,7 +40,7 @@ }, { "trigger": "branch_if", - "contents": "branch_if (${1:condition}): ${2:label};", + "contents": "branch_if ${1:condition}: ${2:label};", "details": "branch_if (condition): label;", "kind": "keyword" }, @@ -62,6 +62,18 @@ "details": "include \"path\"", "kind": "keyword" }, + { + "trigger": "api", + "contents": "include \"../include/microw8-api.cwa\"", + "details": "include \"path\"", + "kind": "keyword" + }, + { + "trigger": "common", + "contents": "include \"../include/common.cwa\"", + "details": "include \"path\"", + "kind": "keyword" + }, { "trigger": "export", "contents": "export fn ${1:name}(${2:params}) ${3:-> ${4:return_type}} { ${5:block} }", @@ -70,7 +82,7 @@ }, { "trigger": "block", - "contents": "block ${1:label} { ${2:block} }", + "contents": "block ${1:label} {\n\t${2://content}\n}", "details": "block label { block }", "kind": "keyword" }, diff --git a/syntax/SublimeText/if-else.sublime-snippet b/syntax/SublimeText/if-else.sublime-snippet index 6526b0e..7688126 100644 --- a/syntax/SublimeText/if-else.sublime-snippet +++ b/syntax/SublimeText/if-else.sublime-snippet @@ -1,6 +1,6 @@ loopbr From 9208c0e652068a97dd6b1313473c00ac178d45eb Mon Sep 17 00:00:00 2001 From: Bartek Zbytniewski Date: Mon, 21 Apr 2025 20:18:17 +0200 Subject: [PATCH 9/9] new completions --- syntax/SublimeText/CurlyWASM.sublime-completions | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/syntax/SublimeText/CurlyWASM.sublime-completions b/syntax/SublimeText/CurlyWASM.sublime-completions index 677ef8b..bd3901f 100644 --- a/syntax/SublimeText/CurlyWASM.sublime-completions +++ b/syntax/SublimeText/CurlyWASM.sublime-completions @@ -442,6 +442,18 @@ "details": "export fn upd(): Called once per frame", "kind": "support.function" }, + { + "trigger": "memory.fill", + "contents": "memory.fill(${1:dest}, ${2:value}, ${3:size});", + "details": "memory.fill(dest: i32, value: i32, size: i32): Fills a memory area", + "kind": "support.function" + }, + { + "trigger": "memory.copy", + "contents": "memory.copy(${1:dest}, ${2:src}, ${3:size});", + "details": "memory.copy(dest: i32, src: i32, size: i32): Copies a memory block", + "kind": "support.function" + }, { "trigger": "sqrt", "contents": "sqrt(${1:x})",