diff --git a/README.md b/README.md index 676a44f..0eae94b 100644 --- a/README.md +++ b/README.md @@ -1,256 +1,78 @@ -**Stella** is a type checker for Lua. It helps you catch type errors before your code runs, making your Lua code safer and more reliable. +Stella is a type checker for Lua that adds TypeScript-like type safety to your code. It helps catch errors early, ensures your code runs smoothly, and works with your existing Lua code without requiring any changes. +### Installation - - - - - +#### Install Dependencies - - - - -
StellaLua
+##### On Linux or Mac -```lua -type Array = {T} - -function binary_search(arr: Array, target: number): option - local low: number = 1 - local high: number = #arr - - while low <= high do - local mid: number = math.floor((low + high) / 2) - local guess: number = arr[mid] - - if guess == target then - return mid - elseif guess > target then - high = mid - 1 - else - low = mid + 1 - end - end - - return nil -end - -local numbers: Array = {1, 3, 5, 7, 9, 11} -local result: option = binary_search(numbers, 7) -``` - - - -```lua -function binary_search(arr, target) - local low = 1 - local high = #arr - - while low <= high do - local mid = math.floor((low + high) / 2) - local guess = arr[mid] - - if guess == target then - return mid - elseif guess > target then - high = mid - 1 - else - low = mid + 1 - end - end - - return nil -end - -local numbers = {1, 3, 5, 7, 9, 11} -local result = binary_search(numbers, 7) +```sh +# Install Rust if you haven't already. +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh ``` -
- +##### Install Stella +```sh +# Install Stella +cargo install stellla_checker -1. Generics - - - - - - - - - - -
Stella Lua
- -```lua -type fn = function(n: T, b: T): R; - -local do_thing: fn = function (n, b) - local a = n + 10 - return "hei, stella checker :)" -end -``` - - - -```lua -local do_thing = function (n, b) - local a = n + 10 - return "hei, stella checker :)" -end +# Check if Stella is installed correctly +stella --version ``` -
- -2. Function Types - - - - - - - - - - -
Stella Lua
+### Simple exemple! ```lua -type Apply = function(num: T): T; - -type ApplyTwiceType = function(n: number, fn: Apply): T; - -local apply_twice: ApplyTwiceType = function(num, fn) - print(fn) - return fn(fn(num)) -end +type Fn = function(param: T): R -local function inc(n: number): number - return n + 1 -end - -local result = apply_twice(3, inc) -``` +type Array = {T} - +type ProcessListType = function(list: Array, apply_fn: Fn): Array -```lua -local apply_twice = function(num, fn) - print(fn) - return fn(fn(num)) +local process_list: ProcessListType = function(list, apply_fn) + local result = {} + for i = 1, #list do + table.insert(result, apply_fn(list[i])) + end + return result end -local function inc(n) - return n + 1 -end - -local result = apply_twice(3, inc) -``` - -
- -3. optionals - - - - - - - - - - -
Stella Lua
- -```lua -function divide(a: number, b: number): option - if b == 0 then - return nil - end - return a / b +local function increment(n: number): number + return n + 1 end -local result: option = divide(10, 0) -``` - - - -```lua -function divide(a, b) - if b == 0 then - return nil - end - return a / b +local function double(n: number): number + return n * 2 end -local result = divide(10, 0) -``` - -
+local numbers = {1, 2, 3, 4} -4. unions +-- Apply the 'increment' function to each number in the list +local incremented_numbers = process_list(numbers, increment) -- ok :) - - - - +-- Apply the 'double' function to each number in the list +local doubled_numbers = process_list(numbers, double) -- ok :) - - - - -
Stella Lua
-```lua -type Either = union - -function get_value(flag: boolean): Either - if flag then - return 42 - else - return "forty-two" - end -end +--- error +local numbers_error = {1, 2, 3, 4, "hello"} -local value: Either = get_value(true) -``` - - - -```lua -function get_value(flag) - if flag then - return 42 - else - return "forty-two" - end -end +-- ERROR >>> expected `table`, found `table` +-- in `numbers_error` +local incremented_numbers = process_list(numbers_error, increment) -local value = get_value(true) ``` -
- - - - ```sh -cargo build --release +stella check process_list.lua -# Run the type checker -# - -./stella check tests/golden_tests/nested_functions.lua - - -# you can see ast -# -./stella compile tests/golden_tests/nested_functions.lua +# let me know if you have any questions or suggestions :) I hope you have a amazing day! ``` -- [Stella Virtual Machine](https://github.com/yazaldefilimone/stella-compiler) +- [A Quick Guide](./guide.md) + +- [Stella Virtual Machine (maybe coming soon)](https://github.com/yazaldefilimone/stella-compiler) diff --git a/guide.md b/guide.md new file mode 100644 index 0000000..5ff242d --- /dev/null +++ b/guide.md @@ -0,0 +1,169 @@ + + +### A Quick Guide + +Stella is a type checker for Lua that adds TypeScript-like type safety to your code. It helps catch errors early, ensures your code runs smoothly, and works with your existing Lua code without requiring any changes. + +### Installation + +#### Install Dependencies + +##### On Linux or Mac + +```sh +# Install Rust if you haven't already. +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh +``` + +##### Install Stella + +```sh +# Install Stella +cargo install stellla_checker + +# Check if Stella is installed correctly +stella --version +``` + +### Simple exemple! + +Here’s how you can write a simple `"Hello, world!"` in Stella: + +```lua +function main() + return "Hello, world!" +end +``` + +To check it: + +```sh +stella check hello.lua +``` + +Stella checks for any type errors before running your Lua code. + +### Pure Lua + +Stella can run on pure Lua code without type annotations, catching errors and inferring types on the fly. Here’s an example: + +```lua +function binary_search(sorted_array, target_value) + local low_index = 1 + local high_index = #sorted_array + + while low_index <= high_index do + local mid_index = math.floor((low_index + high_index) / 2) + if sorted_array[mid_index] == target_value then + return mid_index + elseif sorted_array[mid_index] < target_value then + low_index = mid_index + 1 + else + high_index = mid_index - 1 + end + end + return nil +end + +local target_index = binary_search({1, 3, 5, 7, 9}, 5) +``` + +Stella will infer the types and warn you if there’s an issue, even without explicit type annotations. + +### Using Generics in Stella + +Stella supports generics, allowing you to create flexible and reusable code. Here’s an example of using generics: + +```lua +type Fn = function(param: T): R + +type Array = {T} + +type ProcessListType = function(list: Array, apply_fn: Fn): Array + +local process_list: ProcessListType = function(list, apply_fn) + local result = {} + for i = 1, #list do + table.insert(result, apply_fn(list[i])) + end + return result +end + +local function increment(n: number): number + return n + 1 +end + +local function double(n: number): number + return n * 2 +end + +local numbers = {1, 2, 3, 4} + +-- Apply the 'increment' function to each number in the list +local incremented_numbers = process_list(numbers, increment) -- ok :) + +-- Apply the 'double' function to each number in the list +local doubled_numbers = process_list(numbers, double) -- ok :) + + +--- error +local numbers_error = {1, 2, 3, 4, "hello"} + +-- ERROR >>> expected `table`, found `table` +-- in `numbers_error` +local incremented_numbers = process_list(numbers_error, increment) + +``` + +### Unions and Option Types + +Stella also supports union and option types, which allow you to represent multiple possible types for a value. This helps in scenarios where a variable might hold different types at runtime. + +**Example with Union Types:** + +```lua +type StringOrNumber = union + +local function process_value(value: StringOrNumber) + if type(value) == "number" then + return value + 1 + else + return value .. " is a string" + end +end + +print(process_value(10)) -- Outputs: 11 +print(process_value("Lua")) -- Outputs: Lua is a string +``` + +**Example with Option Types:** + +```lua + +local function find_value(key: string, data: table): option + return data[key] or nil +end + +local result = find_value("name", { name = "Stella", age = 1 }) +print(result) -- Outputs: Stella + +local missing = find_value("missing", { name = "Stella", age = 1 }) +print(missing) -- Outputs: nil +``` + +### Diagnostics + +Stella helps catch errors such as variable shadowing and type mismatches. Here’s an example: + +```lua +local function add_numbers(a: number, b: number): number + local a = 10 -- WARNING >>> `a` shadows an existing variable + return a + b +end +``` + +Running Stella on this code would give you a warning about shadowing the variable `a`. + +```sh +stella check your_code.lua +``` diff --git a/tests/golden_tests/types/builtin_table.lua b/tests/golden_tests/types/builtin_table.lua index 3bca981..6594ee5 100644 --- a/tests/golden_tests/types/builtin_table.lua +++ b/tests/golden_tests/types/builtin_table.lua @@ -1,6 +1,6 @@ type Table = { - name = string, - age = number, + name: string, + age: number, fn: function(string): string, } diff --git a/tests/playground/algorithms/binart_search_untype.lua b/tests/playground/algorithms/binart_search_untype.lua index 84b6011..acc4b2f 100644 --- a/tests/playground/algorithms/binart_search_untype.lua +++ b/tests/playground/algorithms/binart_search_untype.lua @@ -15,11 +15,4 @@ function binary_search(sorted_array, target_value) return nil end -age = 19 - -local age = 20 - - -age = "Hello, Stella checker :)" - local target_index = binary_search({1, 3, 5, 7, 9}, 5) diff --git a/tests/playground/algorithms/process_list.lua b/tests/playground/algorithms/process_list.lua new file mode 100644 index 0000000..dde68d9 --- /dev/null +++ b/tests/playground/algorithms/process_list.lua @@ -0,0 +1,37 @@ +type Fn = function(param: T): R + +type Array = {T} + +type ProcessListType = function(list: Array, apply_fn: Fn): Array + +local process_list: ProcessListType = function(list, apply_fn) + local result = {} + for i = 1, #list do + table.insert(result, apply_fn(list[i])) + end + return result +end + +local function increment(n: number): number + return n + 1 +end + +local function double(n: number): number + return n * 2 +end + +local numbers = {1, 2, 3, 4} + +-- Apply the 'increment' function to each number in the list +local incremented_numbers = process_list(numbers, increment) -- ok :) + +-- Apply the 'double' function to each number in the list +local doubled_numbers = process_list(numbers, double) -- ok :) + + +--- error +local numbers_error = {1, 2, 3, 4, "hello"} + +-- ERROR >>> expected `table`, found `table` +-- in `numbers_error` +local incremented_numbers = process_list(numbers_error, increment)