commit 1114c02b7c3f282d725625836a3aaff0853f5c85 Author: cyclic Date: Thu Sep 4 03:53:27 2025 -0600 initialize diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..47dc3e3 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/.luaurc b/.luaurc new file mode 100644 index 0000000..99bf373 --- /dev/null +++ b/.luaurc @@ -0,0 +1,6 @@ +{ + "aliases": { + "lune": "~/.lune/.typedefs/0.10.2/", + "ollama": "./src/ollama" + } +} diff --git a/config.luau b/config.luau new file mode 100644 index 0000000..5a4c4a8 --- /dev/null +++ b/config.luau @@ -0,0 +1,435 @@ +export type data = { + question: string, + answer: string, + explanation: string +} + +export type category = { data } + +export type dataset = { + syntax: category, + compatibility: category, + runtimes: category, + advanced: category, + types: category, + internals: category +} + +export type config = { + modelsToEvaluate: { string }, + evaluatingModel: string, + dataset: dataset +} + +local config: config = { + modelsToEvaluate = { 'qwen3:4b' }, + evaluatingModel = 'qwen3:4b', + dataset = { + syntax = { + { + question = "({[1]=function(...)return({...})[1]('hi')end,[2]='bye'})[1](print) -- Does this error? If not, does anything happen?", + answer = "It does not error. It calls `print('hi')`, which prints `hi`, and the whole expression evaluates to `nil`.", + explanation = "The table literal defines key `[1]` as a function and key `[2]` as the string `'bye'`. Indexing with `[1]` yields the function, and then `(print)` calls it with `print` as the first vararg. Inside the function, `({...})[1]` extracts the first argument (the `print` function) and immediately calls it with `'hi'`. `print('hi')` outputs `hi` and returns `nil`, so the function returns `nil`. There is no error; nothing else happens.", + pointReward = 20 + }, + { + question = 'What is the difference between a local variable and a global variable in Luau?', + answer = 'A local variable is only accessible within its own scope (such as a function or block), whereas a global variable is accessible from anywhere (stored in the shared global table).', + explanation = 'In Luau (as in Lua), variables declared with `local` are confined to the scope in which they are defined and are more efficient to access. A global variable (one assigned without `local`) resides in the global environment table (commonly `_G`) and can be accessed by any code, but global lookups are slower and can lead to naming conflicts. It is generally recommended to use locals for encapsulation and performance.', + pointReward = 10 + }, + { + question = 'Which operator is used to concatenate two strings in Luau?', + answer = 'Luau uses the `..` operator for string concatenation.', + explanation = 'Luau (like Lua) uses two dots `..` to concatenate strings. For example: `"Hello" .. "World"` produces `"HelloWorld"`. The `..` operator takes two strings (or other values convertible to strings) and returns their concatenation.', + pointReward = 5 + }, + { + question = 'What does the `#` operator do in Luau when applied to a string or a table?', + answer = 'The `#` operator returns the length of its operand. For a string it gives the string length (number of characters), and for a table it gives the length of the array part of that table.', + explanation = 'The length operator `#` in Luau works the same as in Lua. `#str` returns the length of the string `str` in characters. `#t` where `t` is a table returns the length of the table’s sequential part (count of consecutive numeric indices starting at 1). Note that for tables, the length is only well-defined if the table is a sequence (indices 1..n without gaps).', + pointReward = 10 + }, + { + question = 'How can you swap the values of two variables `a` and `b` in Luau without using a temporary variable?', + answer = 'By using multiple assignment in one statement, e.g. `a, b = b, a`.', + explanation = 'Luau supports Lua’s parallel assignment. Writing `a, b = b, a` will simultaneously assign `b`\'s value to `a` and `a`\'s value to `b`. This swap happens without needing an intermediate temporary variable, because the right-hand expressions are evaluated first before any assignments occur.', + pointReward = 10 + }, + { + question = 'What is the output of the following code?\n\n```lua\nlocal sum = 0\nfor i = 1, 5 do\n if i % 2 == 0 then continue end\n sum += i\nend\nprint(sum)\n```', + answer = '9', + explanation = 'The code computes the sum of all odd numbers from 1 to 5. It uses `continue` to skip even values of `i`. The loop adds 1, 3, and 5 to `sum`, resulting in 9. The `print(sum)` will output `9`.', + pointReward = 15 + }, + { + question = 'In Luau, what is the effect of defining or calling a function with the colon syntax (e.g. `function Class:method(x)` or `instance:method(x)`) instead of using a dot?', + answer = 'Using the `:` syntax defines/calls a method, implicitly passing the object itself as the first parameter (usually named `self`).', + explanation = 'The colon syntax in Luau (and Lua) is syntactic sugar for method definition and calls. When you define `function Class:method(y) ... end`, it is equivalent to `function Class.method(self, y) ... end`. Similarly, calling `obj:method(x)` automatically passes `obj` as the first argument. This is used to implement methods on tables (such as objects), where `self` refers to the table instance inside the function body.', + pointReward = 15 + }, + { + question = 'What are the two types of `for` loops in Luau, and how do they differ?', + answer = 'Luau has numeric `for` loops and generic `for` loops. Numeric for-loops (e.g. `for i = 1, 10 do ... end`) iterate over a range of numbers with a fixed step, while generic for-loops (e.g. `for k, v in pairs(t) do ... end`) iterate over elements of a collection (like table entries) using an iterator function.', + explanation = 'Luau supports both numeric and generic for-loops. A numeric for-loop is used for counting, with a control variable that goes from a start value to an end value (with an optional step). In contrast, a generic for-loop uses an iterator (such as `pairs`, `ipairs`, or a custom iterator) to traverse data structures like tables. For example, `for k, v in pairs(tbl) do ... end` will iterate over all key–value pairs in `tbl`. Under the hood, generic for-loops call an iterator function and loop until it returns nil.', + pointReward = 10 + } + }, + compatibility = { + { + question = 'Luau adds a `continue` statement to loops. Do standard Lua versions (e.g., Lua 5.1) have a `continue`? If not, how would you skip an iteration in vanilla Lua?', + answer = 'No, vanilla Lua (5.1) does not have a `continue` statement. To skip an iteration, you typically use a conditional to bypass the rest of the loop’s body (or in Lua 5.2+, you could use `goto` as a workaround).', + explanation = 'Luau introduced `continue` to immediately skip to the next loop iteration. In standard Lua 5.1, there is no direct equivalent. The usual pattern is to wrap the loop body in an `if` and only execute the code when a condition is met, effectively skipping the rest when the condition fails. Lua 5.2 added a `goto` statement which can be used to jump to the loop end as a make-shift continue, but Luau chose to implement a cleaner `continue` instead.', + pointReward = 10 + }, + { + question = 'Is the `goto` statement (introduced in Lua 5.2) available in Luau?', + answer = 'No. Luau does not support the `goto` statement.', + explanation = 'Lua 5.2 added a `goto` for arbitrary jumps, but Luau opted not to include it. The Luau team decided that `goto` complicates control flow and is not necessary for the kinds of scripts typically written (especially with `continue` available for looping needs). As a result, any code using `goto` will not compile in Luau.', + pointReward = 10 + }, + { + question = 'Lua 5.3 introduced bitwise operators (e.g. `&`, `|`, `~`). How can you perform a bitwise AND operation in Luau, given that these operators are not present?', + answer = 'By using the `bit32` library. For example, `bit32.band(x, y)` computes the bitwise AND of x and y in Luau.', + explanation = 'Luau inherits from Lua 5.1 which had no native bitwise operators. Instead of adding new operators like `&`, Luau provides the `bit32` library (from Lua 5.2). Functions such as `bit32.band(x,y)`, `bit32.bor(x,y)` and others can be used to perform bitwise AND, OR, etc. There is no separate integer type in Luau, but bit32 operates on the 32-bit integer representation of the number (using the fact that Luau numbers are doubles that can exactly represent 32-bit integers).', + pointReward = 15 + }, + { + question = 'Can you use functions like `loadstring`, `loadfile`, or `dofile` in the Roblox Luau environment?', + answer = 'No. Luau’s sandbox does not allow `loadstring`, `loadfile`, or `dofile` (they are removed/disabled for security).', + explanation = 'Roblox’s Luau environment is sandboxed for safety. Functions that execute external code or access the file system directly are not available. `loadstring` (and its C equivalent `lua_load`) is disabled because it can run arbitrary code/bytecode. Similarly, `loadfile` and `dofile`, which would load files from disk, are not provided. This ensures that scripts cannot access the file system or unauthorized code, keeping the execution environment secure.', + pointReward = 15 + }, + { + question = 'Which standard Lua libraries are omitted or restricted in Luau for security reasons?', + answer = 'Libraries such as `io`, `os`, and `package` are not included by default in Luau (and the `debug` library is severely limited).', + explanation = 'To maintain a secure sandbox, Luau doesn’t expose certain standard libraries that could interact with the system. The entire I/O library (`io`) and OS library (`os`) are removed, as is the package module system (`package`). Parts of the `debug` library are also removed or locked down. This prevents scripts from performing unauthorized actions like file I/O or spawning processes, which is important in Roblox’s environment.', + pointReward = 15 + }, + { + question = 'Lua 5.2 removed `getfenv` and `setfenv`. Does Luau support `getfenv` and `setfenv` functions?', + answer = 'Yes. Luau still provides `getfenv` and `setfenv` (retaining the 5.1 environment model for compatibility).', + explanation = 'Luau is based on Lua 5.1 and maintains the concept of function environments. As such, `getfenv(func)` and `setfenv(func, envTable)` are still available and work as they did in Lua 5.1. In later Lua versions these were removed in favor of lexical environments, but Roblox had a lot of code relying on them, so Luau kept them for backward compatibility.', + pointReward = 10 + }, + { + question = 'Does Luau implement the floor division operator `//` from Lua 5.3? If so, what is the result of `5 // 2`?', + answer = 'Yes. Luau supports `//` for floor division. `5 // 2` evaluates to `2`.', + explanation = 'Luau has adopted the floor division operator from Lua 5.3. The expression `a // b` performs integer division (rounding down toward negative infinity). For example, `5 // 2` gives 2 because 5 divided by 2 is 2.5 and flooring that yields 2. Even negative values follow floor division rules (e.g., `-5 // 2` would yield -3).', + pointReward = 10 + }, + { + question = 'Lua 5.2 introduced the metamethods `__pairs` and `__ipairs`. How does Luau allow custom iteration without these metamethods?', + answer = 'Luau uses a single `__iter` metamethod instead of `__pairs`/`__ipairs`. Defining `__iter` on a table allows it to be iterated with a generic for-loop.', + explanation = 'Rather than supporting the separate `__pairs` and `__ipairs` metamethods from Lua 5.2, Luau introduces a unified `__iter` metamethod. If a table (or userdata) has an `__iter` metamethod, the Luau runtime will call it to get an iterator when you use a generic for-loop directly on the object. This covers all custom iteration use cases with a cleaner design, making `__pairs` and `__ipairs` unnecessary.', + pointReward = 20 + } + }, + runtimes = { + { + question = 'What is Lune in the context of Luau?', + answer = 'Lune is a standalone Luau runtime (similar to Node or Deno for Luau) that lets you run Luau scripts outside of Roblox.', + explanation = 'Lune is an open-source project providing a runtime for the Luau language independent of the Roblox game client. It functions like a Luau interpreter/host environment (analogous to how Node.js runs JavaScript outside a browser). With Lune, developers can execute Luau code on their own machines or servers, enabling use-cases like scripting, automation, or tool development with Luau.', + pointReward = 15 + }, + { + question = 'Name two capabilities that Lune provides which are not available in Roblox’s built-in Luau environment.', + answer = 'For example, Lune includes a filesystem API for reading/writing files and also provides networking (socket) functionality — capabilities that Roblox’s sandboxed Luau does not allow.', + explanation = 'Because Lune runs outside Roblox, it isn’t sandboxed in the same way. Lune’s runtime includes libraries for things like file system access (reading and writing files on disk), network sockets for HTTP/TCP communication, standard I/O (console input/output), etc. These features are not accessible in Roblox’s Luau environment due to security restrictions. In short, Lune extends Luau with system-level APIs that are unavailable when running inside Roblox.', + pointReward = 15 + }, + { + question = 'Can Lune be used to run an entire Roblox game (with GUI, physics, etc.) outside of Roblox?', + answer = 'No. Lune isn’t meant to run full Roblox games; it can execute Luau code and mimic some Roblox APIs, but it cannot replicate the full Roblox engine (graphics, physics, UI) outside of Roblox.', + explanation = 'Lune’s goal is not to be a Roblox emulator. It allows developers to run Luau scripts and even manipulate Roblox data formats, but it doesn’t provide the 3D rendering, physics simulation, or other engine features required to run a complete game. The Roblox engine itself is not open-sourced, so while Lune can handle pure logic and data, you cannot run a fully functional game with interfaces and physics solely through Lune.', + pointReward = 10 + }, + { + question = 'What special library does Lune include to assist with Roblox development outside of the game client?', + answer = 'Lune offers an optional built-in library for manipulating Roblox place (`.rbxl`) and model (`.rbxm`) files, allowing scripts to create or modify game instances.', + explanation = 'One of Lune’s unique features is a library that can load, inspect, and alter Roblox place and model files. This means a developer can use Lune to programmatically edit game assets (like inserting parts into a place, editing object properties, etc.) without opening Roblox Studio. It’s useful for building command-line tools or pipelines that handle Roblox content. This library is optional and specifically aimed at Roblox development tasks.', + pointReward = 20 + }, + { + question = 'Does Lune support the same task scheduling API as Roblox (e.g. `task.wait`, `task.spawn`)?', + answer = 'Yes. Lune implements a task scheduler analogous to Roblox’s, so functions like `task.spawn`, `task.delay`, and `task.wait` are available in Lune.', + explanation = 'The Lune runtime provides a scheduling system that mirrors Roblox’s task scheduling. This means you can yield a thread or spawn new threads in a similar way as you would in a Roblox script. For example, you can call `task.wait(n)` to pause execution, or `task.spawn(func)` to run a function asynchronously. Under the hood, Lune’s scheduler manages these coroutines, enabling asynchronous operations even outside the Roblox engine.', + pointReward = 15 + }, + { + question = 'Compare the execution environment of Luau in Roblox with running Luau via Lune.', + answer = 'In Roblox, Luau runs inside a sandbox with restricted access (no direct file system or network access, only Roblox-specific APIs). With Lune, Luau runs in a standalone environment with extended capabilities (full access to files, networking, and other system resources) but without the Roblox engine’s game world.', + explanation = 'Roblox’s Luau environment is tightly controlled: scripts have access to Roblox’s API (like game objects, physics, UI, etc.) but cannot perform operations outside the game (no file I/O or unrestricted network calls). In contrast, Lune provides a general-purpose Luau environment. It lacks the Roblox game objects and engine context, but instead it offers standard libraries for file system, network, and so on. Essentially, Roblox Luau is specialized for game scripts within the Roblox sandbox, while Lune’s Luau is geared toward general scripting tasks outside Roblox, trading Roblox-specific functionality for broader system-level access.', + pointReward = 20 + } + }, + advanced = { + { + question = 'What is a metatable in Luau and how do you use one?', + answer = 'A metatable is a table that defines custom behavior for another table via metamethods. You can attach it using `setmetatable(object, metatable)` to override or define operations (like arithmetic, indexing) for that object.', + explanation = 'In Luau, every table can have an associated metatable, which is another table holding special functions/fields called metamethods. These metamethods (e.g., `__index`, `__add`) let you customize how the object behaves for certain operations. To use a metatable, you call `setmetatable(targetTable, metaTable)`. Once set, operations on `targetTable` may invoke metamethods from `metaTable` — for instance, accessing an absent key in `targetTable` will trigger `metaTable.__index` if it’s defined.', + pointReward = 10 + }, + { + question = 'If an object `obj` has a metatable with `__index = { value = 42 }`, what will `print(obj.value)` output, assuming `obj.value` wasn’t set initially?', + answer = 'It will print `42`.', + explanation = 'With a metatable that defines `__index` as a table, Luau will look up missing keys in that table. In this case, when `obj.value` is accessed and `obj` doesn’t have its own `value` field, Luau falls back to `obj`\'s metatable’s `__index`. Since `__index` is set to `{ value = 42 }`, `obj.value` will resolve to `42`. Thus, `print(obj.value)` will output 42.', + pointReward = 15 + }, + { + question = 'What is the effect of defining a `__newindex` metamethod on a table’s metatable?', + answer = 'It intercepts table assignments to undefined fields. If you try to assign to a key that isn’t already present, the `__newindex` function/table will handle the assignment instead of directly modifying the table.', + explanation = 'The `__newindex` metamethod allows you to customize behavior when new fields are written to a table. If a table `T` has a metatable with `__newindex`, and you do `T.someField = value` (where `someField` is not already in `T`), Luau will not set `T.someField` directly. Instead, it invokes the `__newindex` metamethod. If `__newindex` is a function, Luau calls that function with parameters (T, key, value); if it’s a table, Luau will attempt to assign the value to that table (acting as a proxy). This is often used to implement things like read-only tables or property change tracking.', + pointReward = 15 + }, + { + question = 'How can you make a table behave like a function (so that you can call it like one) in Luau?', + answer = 'By defining a `__call` metamethod in the table’s metatable. If a table has `__call`, doing `tableName(...)` will invoke that metamethod as if the table were a function.', + explanation = 'The `__call` metamethod is triggered when you use the table as if it were a function. For example, if you set `meta.__call = function(tbl, arg) ... end` on a table’s metatable, then calling `tbl(arg)` will internally call `meta.__call(tbl, arg)`. This feature can be used to create objects that are “callable” (like functors or classes where the instance itself can be invoked).', + pointReward = 15 + }, + { + question = 'How can you prevent external code from accessing or modifying a table’s metatable?', + answer = 'By setting the metatable’s `__metatable` field. Assigning a value to `__metatable` (often a string message) in the metatable will cause `getmetatable` to return that value and disallow further `setmetatable` on the object.', + explanation = 'Luau (like Lua) allows locking a metatable. If you do `metatable.__metatable = "locked"` (for example), then any call to `getmetatable(object)` will return `"locked"` instead of the real metatable. Moreover, attempts to change the metatable with `setmetatable(object, newMetatable)` will fail. This mechanism is used to protect objects: by hiding the actual metatable, you prevent unauthorized tampering with metamethods.', + pointReward = 15 + }, + { + question = 'Luau replaces the `__pairs`/`__ipairs` metamethods with a single `__iter` metamethod. What does defining `__iter` on a table enable you to do?', + answer = 'It allows the table (or userdata) to be directly iterable with a generic for-loop. In other words, `for ... in myObject do` will use `myObject`\'s `__iter` metamethod to iterate, enabling custom iteration behavior.', + explanation = 'When a table or userdata has an `__iter` metamethod, Luau uses it to retrieve an iterator when you loop over the object directly. This means you can implement the `__iter` metamethod to return an iterator function (and state) that defines how to traverse the object’s contents. Then you can write `for element in myObject do ... end`. This mechanism generalizes iteration so that Luau didn’t need to implement both `__pairs` and `__ipairs` — any custom iterable behavior can be expressed with `__iter`.', + pointReward = 20 + }, + { + question = 'What do the functions `getfenv` and `setfenv` do in Luau?', + answer = '`getfenv(f)` returns the environment table of function (or thread) `f`, and `setfenv(f, env)` sets a new environment for `f`. They control which global variables (and environment) a function sees.', + explanation = 'Every Luau (Lua 5.1) function has an environment table that it uses to resolve global variable accesses. `getfenv(f)` retrieves this table for the function `f` (or the current thread if `f` is not given). `setfenv(f, newEnv)` will make the function `f` (and any nested function definitions within it) use `newEnv` as its global environment. By using `setfenv`, one can sandbox a function by providing a restricted environment or share specific globals among certain functions.', + pointReward = 15 + }, + { + question = 'In Luau, what is the `_G` table and how is it typically used?', + answer = '`_G` is the global environment table. It holds all global variables by name, so you can use `_G` to access or share globals across different scripts.', + explanation = 'The `_G` table is a built-in table that represents the global namespace. When you create a global variable (e.g., `X = 10` outside any local scope), it actually gets stored as `_G["X"] = 10`. In Roblox, `_G` is shared among all scripts running in the same context (server scripts share one `_G`, and client scripts share another). Developers can use `_G` to intentionally share data between scripts, though doing so is generally discouraged in favor of ModuleScripts. It’s essentially a dictionary of all global identifiers to their values.', + pointReward = 10 + } + }, + types = { + { + question = [[Write proper Luau type annotations for this metatable-backed Vector: + +```lua +local Vector = {} +Vector.__index = Vector + +function Vector.new(x: number, y: number) + local self = setmetatable({}, Vector) + self.x = x + self.y = y + return self +end + +function Vector:add(other) + return Vector.new(self.x + other.x, self.y + other.y) +end +```]], + answer = [[ + +```lua +type Vector = { + x: number, + y: number, + add: (self: Vector, other: Vector) -> Vector, +} + +local Vector: Vector & { new: (x: number, y: number) -> Vector } = {} :: any +Vector.__index = Vector + +function Vector.new(x: number, y: number): Vector + local self = setmetatable({} :: any, Vector) :: Vector + self.x = x + self.y = y + return self +end + +function Vector:add(other: Vector): Vector + return Vector.new(self.x + other.x, self.y + other.y) +end +```]], + explanation = "We declare a table type `Vector` with fields `x`, `y`, and method `add`. We also refine the constructor table with an intersection so it has both `new` and instance methods. Method receivers use `(self: Vector, ...)`. Casts with `:: any` are needed around `setmetatable` and table literals for typechecker satisfaction.", + pointReward = 25 + }, + { + question = [[Explain why this compiles but may crash at runtime, and show a safe redesign: + +```lua +type EventHandler = (data: T) -> () + +local handlers: {[string]: EventHandler} = {} + +function registerHandler(event: string, handler: EventHandler) + handlers[event] = handler -- type erasure happens here +end + +function triggerEvent(event: string, data: T) + local handler = handlers[event] + if handler then + handler(data) -- Potential runtime error + end +end +```]], + answer = [[ +This compiles because `handlers` is typed as `EventHandler`, erasing the real `T`. A handler registered for `string` may be called with a `number`, which won’t error at compile time but can at runtime. + +A safer approach is to tie event and payload types together, e.g.: + +```lua +type EventHandler = (data: T) -> () + +local function createEvent() + local bucket: { EventHandler } = {} + + local function register(h: EventHandler) + table.insert(bucket, h) + end + + local function trigger(data: T) + for _, h in bucket do + h(data) + end + end + + return { register = register, trigger = trigger } +end +```]], + explanation = "The unsafe version uses `any`, so the checker can’t enforce consistency between event name and payload. By parameterizing the registry per event (`createEvent()`), handlers and triggers share the same `T`, ensuring type safety. Another fix would be defining a discriminated union of event names and payloads.", + pointReward = 28 + }, + { + question = 'How would you define a function in Luau that takes a number and returns a string? Provide a simple example.', + answer = 'You would include type annotations for the parameter and return type. For example:\n```lua\nfunction toString(x: number): string\n return tostring(x)\nend\n```', + explanation = 'Luau allows you to annotate function parameters and return types. In the example above, `function toString(x: number): string ... end` declares a function that expects a number and returns a string. Inside, it uses `tostring(x)` to convert the number to a string. The type annotations help catch errors (e.g., calling `toString` with a non-number) during static analysis.', + pointReward = 10 + }, + { + question = 'In Luau’s type system, what is the difference between the types `any` and `unknown`?', + answer = '`any` disables type checking for that value (you can treat it as any type), whereas `unknown` is a universal type that you must inspect or cast before using (you can’t assume anything about an `unknown` value without checking).', + explanation = 'Both `any` and `unknown` are top types in Luau, but they behave differently. `any` essentially tells the type checker “don’t check this; trust me.” You can perform any operation on an `any` typed value, but mistakes won’t be caught (and might cause runtime errors). `unknown`, on the other hand, means “this could be any type, but you have to figure out what specifically.” The type checker won’t let you use an `unknown` value as if it were a more specific type unless you do a type check (for example, using `typeof()` or an `if` to narrow it). This forces you to handle the uncertainty, making code with `unknown` safer than `any`.', + pointReward = 25 + }, + { + question = 'What is the `never` type in Luau and when might you encounter it?', + answer = '`never` is a type that has no values (the “impossible” type). It typically appears in situations that logically cannot happen, for example, after a type refinement that rules out all possibilities or as a return type for a function that never returns.', + explanation = 'The `never` type represents an absence of values. You can’t create or obtain a value of type `never` during execution. One way `never` comes up is through type checking: if the logic of a program makes certain code paths impossible (e.g., an `if-elseif` chain that covers all cases, with an `else` that can’t be reached), the type of variables in that `else` might be inferred as `never`. Another use is in function types: a function that always throws an error or loops forever could be given return type `never`, indicating it doesn’t actually return.', + pointReward = 20 + }, + { + question = 'How do you write a union type in Luau? For instance, what does the annotation `number | string` mean for a variable?', + answer = 'Luau uses the `|` symbol to denote a union. `number | string` means the variable can either be a number or a string.', + explanation = 'A union type expresses that a value can be one of several types. In Luau, if you annotate `local var: A | B`, then `var` can hold either type A or type B. For example, `local x: number | string` means `x` could contain a number or a string. When using a union-typed variable, the type checker will ensure you only perform operations valid for *all* members of the union or that you explicitly check the type (using `typeof` or other type refinements) before using it in a type-specific way.', + pointReward = 10 + }, + { + question = 'How can you define a generic function in Luau? Give an example of a simple generic function.', + answer = 'You define type parameters in angle brackets. For example:\n```lua\nfunction identity(value: T): T\n return value\nend\n```\nThis function works for any type T, returning the same type it receives.', + explanation = 'Luau supports generics by allowing functions (and types) to have type parameters. In the example, `function identity(value: T): T` declares a generic function with a type parameter `T`. The function takes `value` of type T and returns a result of the same type T. You could call `identity(5)` (T is inferred as number, returns number) or `identity("hello")` (T is string, returns string). Generics help write reusable code that works with any type while still preserving type safety.', + pointReward = 15 + }, + { + question = 'How do you create a type alias (a named type) in Luau?', + answer = 'By using the `type` keyword. For example: `type Point = { x: number, y: number }` defines a type alias named `Point` for a table with number fields x and y.', + explanation = 'Luau allows you to introduce a shorthand for a type using `type AliasName = ...`. This is especially useful for complex types or to give semantic meaning to a type. For instance, after defining `type Point = { x: number, y: number }`, you can use `Point` in annotations (e.g., `local p: Point = { x = 1, y = 2 }`). Type aliases do not create new distinct types at runtime; they are purely for the type checker and readability.', + pointReward = 10 + }, + { + question = 'In Luau’s type system, what is the difference between an unsealed table and a sealed table?', + answer = 'An unsealed table type (usually a table literal) can be extended with new properties (its type will broaden as new fields are added), whereas a sealed table type has a fixed set of properties (you cannot add new keys that weren’t already declared in its type).', + explanation = 'When you create a table literal and don’t explicitly finalize its shape, Luau treats it as unsealed: you can add new fields to it, and the inferred type of that table will expand to include those fields. Once that table escapes the local scope where it was defined (or if you explicitly annotate it), it becomes sealed, meaning its structure is considered fixed. A sealed table type will error if you try to add an unexpected field. In practice, unsealed tables let you build up data gradually, and then they seal (automatically when leaving a scope or manually via annotation) to ensure no new fields are introduced beyond what’s defined.', + pointReward = 25 + }, + { + question = 'How can you refine an `unknown` type to a more specific type in Luau?', + answer = 'By performing a type check at runtime (or using type assertions). For example, you might use `if typeof(x) == "number" then ... end` to tell the type checker that inside the block, `x` is a number, thus refining the `unknown` to `number`.', + explanation = 'To use a value of type `unknown`, you need to give the type checker evidence of what it could be. The typical way is using `typeof()` or an `is` operator (if available) in an `if` or similar conditional. For instance, if `x: unknown`, doing:\n```lua\nif typeof(x) == "string" then\n print(x:upper()) -- x is treated as string here\nend\n```\nInside the `if`, the type of `x` is narrowed to string, so you can call string methods on it. Outside that `if`, `x` remains `unknown`. This process of narrowing from a broader type to a more specific type based on runtime checks is called type refinement.', + pointReward = 15 + }, + { + question = 'What does adding `--!strict` at the top of a Luau script do?', + answer = 'It enables strict type checking mode for that script, making the type checker more rigorous (no implicit `any` types for unknown values, etc.).', + explanation = 'Luau’s type checker can operate in different modes. By default, it’s in non-strict mode (`--!nonstrict`), which will automatically infer `any` in certain cases to avoid too many errors. If you put `--!strict` as one of the first lines in the script, you turn on strict mode. In strict mode, the type checker requires that all types are accounted for and will not fall back to `any` implicitly. This means you’ll need to explicitly type annotate more and handle potential `nil` or unknown cases, leading to more robust code with fewer unchecked cases.', + pointReward = 15 + } + }, + internals = { + { + question = [[Why can this act as a “remote spy” detector? + +```lua +local function wrap(func) + return function(...) + local thread = coroutine.create(func) + local ok, err = coroutine.resume(thread, ...) + if not ok then error(err, 2) end + end +end +local Overflow = function(Function) + for Index = 1, 197 do + Function = wrap(Function) + end + return Function +end +print("is remote spy running:") +warn(not pcall(Overflow(function() + game:GetService("Workspace") +end))) +```]], + answer = "It forces a very deep call stack before a `game:GetService` call. Remote spy tools often hook `__namecall` poorly and crash on deep recursion, so failure under `pcall` indicates spying.", + explanation = "Each `wrap` adds a coroutine layer. At ~197 layers, the hooked `__namecall` in spy tools struggles to process the call. Normal Roblox environments handle it fine. The result: `pcall` fails only when a spy hook misbehaves. This is a clever probe, but fragile—constant values like 197 are arbitrary and can yield false positives/negatives.", + pointReward = 100 + }, + { + question = 'Does Luau have a Just-In-Time (JIT) compiler, and if so, how does it differ from LuaJIT’s JIT?', + answer = 'Yes, Luau includes an optional JIT compiler for 64-bit platforms. Unlike LuaJIT’s automatic JIT, Luau’s JIT must be manually activated for specific functions and doesn’t perform runtime tracing or optimization based on execution profiles.', + explanation = 'Luau’s JIT exists to boost performance, but it’s not on by default for all code. Developers (or the engine) choose certain functions or modules to JIT-compile. This is different from LuaJIT, which monitors code execution and compiles hot code paths on the fly. Luau’s JIT compilation is more static – it can leverage type annotations to generate optimized machine code for functions, but it does not do speculative optimizations or trace optimizations at runtime. The JIT currently targets x86-64 and ARM64 architectures.', + pointReward = 15 + }, + { + question = 'What number type does Luau use internally, and does it have a separate integer type like Lua 5.3?', + answer = 'Luau uses a single 64-bit double precision number type for all numeric values. It does not have a distinct integer type (unlike Lua 5.3).', + explanation = 'Internally, Luau represents all numbers as IEEE 754 double-precision floats, the same approach as Lua 5.1–5.2. This means an integer like 42 and a floating-point 42.0 are the same type in Luau. Lua 5.3 introduced a dual-number system (separate integer and float types), but Luau did not adopt that. The double type in Luau can exactly represent integers up to 2^53, which covers most needs. For bitwise operations, Luau relies on 32-bit integer semantics via the `bit32` library since it doesn’t have a native integer type.', + pointReward = 10 + }, + { + question = 'Luau’s interpreter has been heavily optimized. How does its performance compare to LuaJIT’s interpreter on average?', + answer = 'Luau’s interpreter is very fast — in fact, for many scripts its performance is on par with the LuaJIT interpreter, thanks to numerous optimizations in bytecode and VM design.', + explanation = 'The Luau team focused on making the interpreter extremely efficient, knowing that JIT wouldn’t always be available (or enabled). They implemented a streamlined bytecode format and an optimized dispatch loop that modern compilers can turn into very efficient machine code. As a result, in certain benchmarks, Luau’s pure interpreter runs as fast as LuaJIT’s interpreter (LuaJIT is often used as the gold standard, since it’s written in assembly for speed). While LuaJIT’s JIT-compiled code can exceed this, Luau’s interpreter performance is among the best for Lua implementations.', + pointReward = 15 + }, + { + question = 'What is “inline caching” in the context of Luau’s VM, and how does it improve performance?', + answer = 'Inline caching is a technique where the VM remembers (caches) the result of a property or global lookup so that subsequent lookups can be faster. By caching the lookup (based on type or shape of the object), Luau can skip redundant work next time that property or global is accessed.', + explanation = 'Dynamic languages spend a lot of time resolving variable and property accesses. Luau uses inline caching to speed this up. For example, when the VM encounters `obj.foo` in bytecode, the first time it will look up `foo` in `obj` (possibly invoking metamethods). It then stores information about where `foo` was found (like a direct pointer to the property slot or cached index). Next time that same bytecode is executed for a similar object, the VM can bypass the full lookup and use the cached information, as long as the object’s hidden type or shape hasn’t changed. This significantly reduces overhead for repeated accesses in loops or function calls.', + pointReward = 20 + }, + { + question = 'Luau has a built-in `vector` type for certain Roblox datatypes. Why was this added and how is it special?', + answer = 'The `vector` type was introduced to optimize Roblox’s vector math. It represents 3D vectors (and similar) as a primitive type so that operations on vectors can be handled faster by the VM (sometimes even using SIMD), rather than treating them as ordinary tables or userdata.', + explanation = 'Roblox games use a lot of vector mathematics (for positions, physics, etc.). In standard Lua, Vector3 values might be userdata with metamethods for arithmetic. Luau takes a different approach by making common vector types a built-in optimized type. By doing this, Luau can perform vector operations (like addition, subtraction, dot products, etc.) much more quickly, taking advantage of low-level optimizations. This is invisible to the scripter except for performance — you can’t directly declare a variable’s type as `vector` in Luau’s type syntax (it’s a primitive internal type), but when you use Roblox’s Vector3/Vector2, the VM knows to treat them with specialized, faster code paths.', + pointReward = 25 + }, + { + question = 'Certain Lua features were omitted in Luau for performance or sandbox reasons. For example, why doesn’t Luau implement ephemeron tables or the `__gc` metamethod for tables?', + answer = 'Because those features add complexity or runtime costs without strong benefits in Luau’s context. Ephemeron tables complicate the garbage collector and can slow it down, and a `__gc` for tables would introduce overhead in memory management. Luau focuses on features that keep the VM fast and secure, so features that don’t justify their cost or don’t fit the Roblox use cases were left out.', + explanation = 'The design philosophy of Luau is to balance compatibility with Lua and the needs of Roblox developers against performance and simplicity. Ephemeron tables (weak tables where keys are only weakly referenced if the value is collectable) are useful in certain advanced scenarios, but they make garbage collection more complex and slower; Roblox didn’t have a pressing need for them, so Luau doesn’t support them. Similarly, Lua 5.4 introduced a `__gc` metamethod for userdata (and hypothetical for tables) to run finalizers on collection. In a game environment like Roblox, long-lived objects and the pattern of finalizers are less common, and adding that machinery could impact performance, so Luau avoids it. Generally, if a Lua feature is very costly or opens potential security concerns (like debug access), Luau might exclude it to keep execution efficient and safe.', + pointReward = 15 + }, + { + question = 'Luau raised some internal limits compared to standard Lua 5.1. How many upvalues (external local variables) can a single Luau function close over, and how does that compare to Lua 5.1’s limit?', + answer = 'Luau allows up to 200 upvalues per function, whereas Lua 5.1 was limited to 60 upvalues per function.', + explanation = '“Upvalues” are external locals that a function can use (variables from an enclosing scope). In Lua 5.1, a function could only capture at most 60 such variables. Luau increased this limit to 200, which is beneficial for scripts that need to reference many outer-scope variables. This is one of several internal limit changes in Luau (for instance, it also raised the limit on constants and bytecode instructions per function) to accommodate larger scripts and modern hardware capabilities.', + pointReward = 15 + } + } + } +} + +return config diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..e69de29 diff --git a/rokit.toml b/rokit.toml new file mode 100644 index 0000000..a1d4b0b --- /dev/null +++ b/rokit.toml @@ -0,0 +1,7 @@ +# This file lists tools managed by Rokit, a toolchain manager for Roblox projects. +# For more information, see https://github.com/rojo-rbx/rokit + +# New tools can be added by running `rokit add ` in a terminal. + +[tools] +lune = "lune-org/lune@0.10.2" diff --git a/src/benchmark/aggregate.luau b/src/benchmark/aggregate.luau new file mode 100644 index 0000000..e69de29 diff --git a/src/benchmark/evaluate.luau b/src/benchmark/evaluate.luau new file mode 100644 index 0000000..e69de29 diff --git a/src/benchmark/types.luau b/src/benchmark/types.luau new file mode 100644 index 0000000..e69de29 diff --git a/src/init.luau b/src/init.luau new file mode 100644 index 0000000..2a26029 --- /dev/null +++ b/src/init.luau @@ -0,0 +1 @@ +local fs = require("@lune/fs") diff --git a/src/ollama/init.luau b/src/ollama/init.luau new file mode 100644 index 0000000..7ff9226 --- /dev/null +++ b/src/ollama/init.luau @@ -0,0 +1,92 @@ +local serde = require("@lune/serde") +local net = require("@lune/net") + +export type message = { + role: 'system' | 'assistant' | 'user', + content: string +} + +export type context = { + number +} + +type options = { + temperature: number?, + mirostat: number?, + mirostat_eta: number?, + mirostat_tau: number?, + num_ctx: number?, + repeat_last_n: number?, + repeat_penalty: number?, + seed: number?, + stop: string?, + tfs_z: number?, + num_predict: number?, + top_k: number?, + top_p: number?, + min_p: number? +} + +export type parameters = { + model: string, + prompt: string, + format: string?, + options: options?, + system: string, + context: context, + stream: false, + raw: boolean?, + keep_alive: string +} + +export type completionResponse = { + model: string, + created_at: string, + response: string, + done: boolean, + done_reason: string, + total_duration: number, + load_duration: number, + prompt_eval_count: number, + prompt_eval_duration: number, + eval_count: number, + eval_duration: number, + context: context +} + +export type ollama = { + baseUrl: string, + serve: (baseUrl: string) -> ollama, + generateCompletion: (self: ollama, parameters: parameters) -> completionResponse | net.FetchResponse +} + +local ollama = {} +ollama.__index = ollama + +function ollama.serve(baseUrl: string?): ollama + baseUrl = baseUrl or "http://localhost:11434" + + local self = setmetatable({}, ollama) + self.baseUrl = baseUrl + + return self +end + +function ollama:generateCompletion(parameters: parameters): completionResponse | net.FetchResponse + parameters.stream = false + local response = net.request({ + url = `{self.baseUrl}/api/generate`, + method = "POST", + headers = { ["Content-Type"] = "application/json" }, + body = serde.encode("json", parameters) + }) + + if response.ok then + local completionResponse: completionResponse = serde.decode("json", response.body) + return completionResponse + else -- looks cleaner imo than an early escape + return response + end +end + +return ollama \ No newline at end of file diff --git a/src/visualizer.luau b/src/visualizer.luau new file mode 100644 index 0000000..c4b5558 --- /dev/null +++ b/src/visualizer.luau @@ -0,0 +1,9 @@ +--[[ +returns text outputs like so: +|-----------------------------------------| +| 1. model one 90% | +| 1. model two 85% | +| 1. model three 80% | +| 1. model four 60% | +|-----------------------------------------| +]] \ No newline at end of file diff --git a/tests/ollama.luau b/tests/ollama.luau new file mode 100644 index 0000000..3a41520 --- /dev/null +++ b/tests/ollama.luau @@ -0,0 +1,14 @@ +local ollama = require("@ollama") + +local instance = ollama.serve() + +local llmResponse = instance:generateCompletion({ + model = 'qwen3:4b', + prompt = '/no_think Just respond with "working".' +}) + +if not llmResponse.statusCode and llmResponse.done then + return print('test passed') +end + +return print('test failed') \ No newline at end of file