Skip to content

Adopted Features

These features have been adopted from previous implementations of KSP compilers, namely Nils Liberg's original SublimeKSP plugin and its fork by nojanath. To make migration from sKSP to cksp easier and ensure compatibility with existing code bases as quickly as possible, I have implemented what I consider to be the most important and commonly used features into cksp.

SublimeKSP Features cksp v0.0.7
Imports relative import paths imports from project root via "./" imports only supported in global scope Learn More
Pragma different syntax, functionality and #pragma options temporary workaround for SublimeKSP compatibility Learn More
Number Formats (hexadecimal, binary, scientific) Learn More
for-loops for-each loops break and continue Learn More
Automatic Type Casting Learn More
Variable Persistence Shorthand Learn More
Single-quoted Strings Learn More
f-strings single-quoted and double-quoted are supported Learn More
String Array Improvements Learn More
Automatic Array Size Learn More
Array Concatenation concat not yet implemented (planned with + operator)
Families Learn More
Constant Blocks Learn More
Inlined Functions typed parameters premature return statements callable in conditions different parameter passing behavior Learn More
Task Functions different syntax normal functions can be used, since local variables are thread-safe
Function Overriding not (yet) supported for methods and in namespaces
Properties can be emulated with defines, or objects and methods Learn More
Macros Learn More
Define Macros Learn More
Iterate Macros Learn More
Iterate Post Macros not supported
Literate Macros Learn More
Literate Post Macros not supported
Built-in Defines additional built-in define __CKSP_VER__ which denotes the compiler version
Automatic Number Incrementer Learn More
Multidimensional Arrays wildcard notation * new num_elements functionality new search and sort functionality Learn More
UI Arrays Learn More
Lists list blocks, lists of lists and referencing lists are supported list_add() and declare list controlIds[] not supported
Structs different syntax dynamic allocation methods operator overloading Learn More
UI Control Parameter Shorthand Learn More
UI Control Property Functions Learn More
Creator Tools NCKP Support Learn More
Combine Duplicate Callbacks supported via #pragma combine_callbacks(true) Learn More

Pragma Directives

Pragma directives are special instructions for the compiler that can be placed anywhere in the code. In SublimeKSP, the output path can be set using {#pragma save_compile_source path/to/file.txt}. Since cksp uses a different syntax, there is a temporary workaround, so that both compilers can be used interchangeably. Read more about this here.


Shorthand for Setting and Getting UI Control Parameters

A shorthand is available for setting and getting UI control parameters, replacing the need for set_control_par() and get_control_par(). The syntax is as follows:

ui_control -> param := value // Setting a value
message(ui_control -> param) // Getting a value

Here, param refers to the suffix of the control parameter, such as hide for $CONTROL_PAR_HIDE or pos_x for $CONTROL_PAR_POS_X. ui_control can either be id of the UI control (returned by get_ui_id()) or its actual name.


Variable Persistence Shorthand

Three keywords can be used to streamline the declaration of variable persistence.

  • pers: Equivalent to make_persistent() in the next line.
  • read: Equivalent to make_persistent() and then read_persistent_var() in the subsequent two lines.
  • instpers: Equivalent to make_instr_persistent() in the next line.
1
2
3
declare pers var
declare pers array[10]
declare read ui_slider sli_volume (0, 100)

Functions for Setting UI Control Properties

These functions set the most commonly used properties of each ui control type. The number of parameters is optional, but the order must be maintained. At least two parameters must be provided. Each command takes an optional number of arguments. set_bounds(control, x, y, width, height) works with any ui control type. The first argument always specifies the control to be used, which can either be the literal name of the UI variable or its UI ID.

set_bounds(control, x, y, width, height)
set_slider_properties(slider, default, picture, mouse-behaviour)
set_button_properties(button, text, picture, text_alignment, font-type, textpos-y)
set_knob_properties(knob, text, default)
set_label_properties(label, text, picture, text_alignment, font-type, textpos-y)
set_level_meter_properties(level-meter, bg-color, off-color, on-color, overload-color)
set_menu_properties(menu, picture, font-type, text_alignment, textpos-y)
set_switch_properties(switch, text, picture, text_alignment, font-type, textpos-y)
set_table_properties(table, bar-color, zero-line-color)
set_text_edit_properties(text_edit, text, picture, text_alignment, font-type, textpos-y)
set_value_edit_properties(value_edit, text, font-type, textpos-y, show-arrows)
set_waveform_properties(waveform, bar-color, zero-line-color, bg-color, bg-alpha, wave-color, wave-cursor-color, slicemarkers-color, wf-vis-mode)
set_wavetable2d_properties(wavetable, wt-zone, bg-color, bg-alpha, wave-color, wave-alpha, wave-end-color, wave-end-alpha)
set_wavetable3d_properties(wavetable, wt-zone, bg-color, bg-alpha, wavetable-color, wavetable-alpha, wavetable-end-color, wavetable-end-alpha, parallax-x, parallax-y)

Multidimensional Arrays

Arrays can be created with multiple dimensions and can consist of integers, strings, or ui_controls. Accessing the raw array is achieved by prefixing the multidimensional version with an underscore: _array[0]. Each array also includes built-in constants for the number of elements in each dimension, denoted as <array-name>.SIZE_D1, <array-name>.SIZE_D2, etc.

Initialization of multidimensional arrays follows the same pattern as regular arrays, regardless of the number of dimensions.

1
2
3
declare coordinates[3, 2] := (1, 0, 1, 1, -1, 0, 0, -1) /* 2D array 3 x, y coordinates */
message(coordinates[0, 1])      // message(0)
message(coordinates.SIZE_D1)    // message(3)

NCKP Support

The syntax import_nckp(<file_path>) can be used to load performance_view files created with CT Creator, providing variable checking capabilities.


Define Macros

Define macros allow for the creation of constants that are replaced in the code by the preprocessor during compile time, thus substituting declare const expressions.

define NUM_CONST := 10*3
declare another_array[NUM_CONST]

Furthermore, they function as text replacements and can mimic not only numerical literals but also other syntax features.

define POINT(x, y) := x, y
declare unit_circle[4,2] := (POINT(1,0), POINT(1,1), POINT(-1,0), POINT(-1,-1))

However, since they are simply substituted by the preprocessor, it is best practice to use parentheses when dealing with arithmetic expressions in define macros to maintain operator precedence if needed.

define ARITHM(a, b) := (a + b)
declare d := 2 * ARITHM(SOME_CONST, 4)   // declare d := 2 * (SOME_CONST + 4)

Macros

Macros are function-like code blocks that are evaluated and inlined at compile time by the preprocessor and perform complete text replacement, similar to define macros. However, unlike define macros, they can encompass multiple lines of code. Additionally, macro parameters enclosed in # can replace text within the macro body, including within strings. Macros can not be nested.

1
2
3
4
5
6
7
8
macro declare_button(#name#, #text#, #picture#)
    declare read ui_button btn_#name#
    set_button_properties(btn_#name#, #text#, #picture#)
end macro

on init
    declare_button(click_me, "Click Me")
end on

Iterate Macros

With this command, one can execute a macro a specified number of times. The iteration range is set similar to a for-loop. If the range is set invalidly (e.g., minimum value larger than maximum), the macro will not be iterated.

on init
    define ROW_SIZE := 20
    declare read ui_button btn_row[ROW_SIZE]
end on 

macro ui_button_callback(#n#)
    on ui_control(btn_row#n#)
        message(#n#)
    end on
end macro

iterate_macro(ui_button_callback) := 0 to ROW_SIZE - 1

There's a shorthand for iterating a one-line macro. Simply put the line you wish to repeat in the brackets of the iterate_macro() command, using #n# to indicate where numbers should be substituted. At least one such token must be present to use this functionality.

define ROW_SIZE := 20
iterate_macro(message(#n#)) := 0 to ROW_SIZE - 1

Literate Macros

A related function to iterate_macro() is literate_macro(), which iterates with a list of literal strings instead of numbers. These strings call a macro multiple times, each time using a different string as the argument.

To use, create a macro with one argument, where the argument is a text replacement. The function expects a list of comma-separated strings. There's a shorthand for one-line macros, using #l# as the token instead of #n#. However, #n# can still be used in one-line literate macros to use the ordinal number of the literal as an argument.

1
2
3
4
5
6
define SLIDER_NAMES := volume, pan, tune

on init
    literate_macro(declare read ui_slider sli_#l# (0, 100)) on SLIDER_NAMES
    literate_macro(message(#l# & #n#)) on "s1", "s2", "s3"
end on

UI Arrays

UI arrays allow for easy access to multiple UI controls through an array structure where the size of the array indicates the number of controls to be declared. Access the UI ID of each element with <array_name>[<idx>]. UI arrays can be multidimensional, in which case accessing the raw variable names or the single dimension version requires prefixing the name with an underscore.

1
2
3
4
5
6
define ROW_SIZE := 20
declare ui_button btn_row[ROW_SIZE]
for idx, btn_id in pairs(btn_row)
    set_button_properties(btn_id, "Button Number: " & idx)
    set_bounds(btn_id, idx * 50, 10, 45, 25)
end for

Families

With the Family feature, variables can be organized into families for better clarity. Variables within a family are referenced as <family>.<variable>. After declaration, variables must always be referred to using their fully qualified name. Nesting families is also supported.

on init
    family preset
        declare const NUM := 100
        declare current
        declare ids[preset.NUM]    
    end family
end on

on ui_control(value_edit)
    preset.current := search(preset.ids, value_edit)
end on

Constant Blocks

A Constant Block is similar to the concept of enums in other languages. This enables the creation of a set of integer constants within a defined block. The constants' values can be set automatically, with the default being 0 for the first constant and subsequent constants being incremented.

1
2
3
4
5
6
7
8
9
const colors
    WHITE := 0x9FFFFFF
    BLACK := 0x9000000
    BLUE  := 0x90000FF
end const

message(colors.SIZE) // Indicates the number of elements in colors.
message(colors.BLACK)
message(colors[0]) 

Automatic Number Incrementer

This is a preprocessor directive allowing for automatic incrementation of a number by a specified amount on each new line. The syntax to initiate the incrementer is START_INC(<var>, <start>, <step>), with the incrementer being concluded by END_INC. The incrementation will be inserted during compile time.

1
2
3
4
5
6
7
on init
    START_INC(X, 0, 1)
        message(X)          // message(0)
        message(X)          // message(1)
        message(X & X)      // message(2 & 2)
    END_INC
end on

Basic For Loops

Basic for-loops are supported with an iterator that must be declared beforehand. Additionally, the step keyword can be used to define the step size, and to and downto can be used to specify ascending or descending iteration.

declare local i
for i := 0 to 6
    message(i)
end for

for i := 0 to 6 step 2
    message(i)
end for

for i := 6 downto 0
    message(i)
end for

Automatic Type Casting

Variable prefixes are optional. The type of a variable is inferred by the compiler. If the type cannot be inferred, Integer is used as the default type.

1
2
3
4
declare int_variable := 3
declare string_variable := "string"
declare real_variable := 2.3
declare string_array[1] := ("string")