mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
Merge pull request #172 from Gipson62/v1-docs
docs: spelling mistakes correction
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
|
|
||||||
|
|
||||||
# drive_system.h
|
# drive_system.h
|
||||||
|
|
||||||
When accessing the file system through Toy (such as with the runner library), it's best practice to utilize the drive system - this system (tries to) prevent malicious accessing of files outside of the designated folders. It does this by causing an error when a script tries to access a parent directory.
|
When accessing the file system through Toy (such as with the runner library), it's best practice to utilize the drive system - this system (tries to) prevent malicious accessing of files outside the designated folders. It does this by causing an error when a script tries to access a parent directory.
|
||||||
|
|
||||||
To use the drive system, first you must designate specific folders which can be accessed, like so:
|
To use the drive system, first you must designate specific folders which can be accessed, like so:
|
||||||
|
|
||||||
@@ -9,19 +10,19 @@ To use the drive system, first you must designate specific folders which can be
|
|||||||
#include "drive_system.h"
|
#include "drive_system.h"
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
//the drive system uses a LiteralDictionary, which must be initialized with this
|
//the drive system uses a LiteralDictionary, which must be initialized with this
|
||||||
Toy_initDriveSystem();
|
Toy_initDriveSystem();
|
||||||
|
|
||||||
Toy_setDrivePath("scripts", "assets/scripts");
|
Toy_setDrivePath("scripts", "assets/scripts");
|
||||||
Toy_setDrivePath("sprites", "assets/sprites");
|
Toy_setDrivePath("sprites", "assets/sprites");
|
||||||
Toy_setDrivePath("fonts", "assets/fonts");
|
Toy_setDrivePath("fonts", "assets/fonts");
|
||||||
|
|
||||||
//TODO: do you stuff here
|
//TODO: do you stuff here
|
||||||
|
|
||||||
//clean up the drive dictionary when you're done
|
//clean up the drive dictionary when you're done
|
||||||
Toy_freeDriveSystem();
|
Toy_freeDriveSystem();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -43,7 +44,7 @@ This function cleans up after the drive system is no longer needed.
|
|||||||
|
|
||||||
### void Toy_setDrivePath(char* drive, char* path)
|
### void Toy_setDrivePath(char* drive, char* path)
|
||||||
|
|
||||||
This function sets a key-value pair in the drive system. It uses C strings, since its intended to be called directly from `main()`.
|
This function sets a key-value pair in the drive system. It uses C strings, since it is intended to be called directly from `main()`.
|
||||||
|
|
||||||
### Toy_Literal Toy_getDrivePathLiteral(Toy_Interpreter* interpreter, Toy_Literal* drivePathLiteral)
|
### Toy_Literal Toy_getDrivePathLiteral(Toy_Interpreter* interpreter, Toy_Literal* drivePathLiteral)
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
|
|
||||||
|
|
||||||
# repl_tools.h
|
# repl_tools.h
|
||||||
|
|
||||||
This header provides a number of tools for compiling and running Toy, and is used primarily by the repl. However, it can also be modified and used by any host program with a little effort.
|
This header provides a number of tools for compiling and running Toy, and is used primarily by the REPL. However, it can also be modified and used by any host program with a little effort.
|
||||||
|
|
||||||
This is not a core part of Toy or a library, and as such `repl_tools.h` and `repl_tools.c` can both be found in the `repl/` folder.
|
This is not a core part of Toy or a library, and as such `repl_tools.h` and `repl_tools.c` can both be found in the `repl/` folder.
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
|
|
||||||
|
|
||||||
# toy_common.h
|
# toy_common.h
|
||||||
|
|
||||||
This file is generally included in most header files within Toy, as it is where the TOY_API macro is defined. It also has some utilities intended for use only by the repl.
|
This file is generally included in most header files within Toy, as it is where the TOY_API macro is defined. It also has some utilities intended for use only by the REPL.
|
||||||
|
|
||||||
## Defined Macros
|
## Defined Macros
|
||||||
|
|
||||||
@@ -11,7 +12,7 @@ This definition of this macro is platform-dependant, and used to enable cross-pl
|
|||||||
|
|
||||||
### TOY_VERSION_MAJOR
|
### TOY_VERSION_MAJOR
|
||||||
|
|
||||||
The current major version of Toy. This value is embedded into the bytecode, and the interpreter will refuse to run bytecode with a major version that does not match it’s own version.
|
The current major version of Toy. This value is embedded into the bytecode, and the interpreter will refuse to run bytecode with a major version that does not match its own version.
|
||||||
|
|
||||||
This value MUST fit into an unsigned char.
|
This value MUST fit into an unsigned char.
|
||||||
|
|
||||||
@@ -33,4 +34,4 @@ The current build version of Toy. This value is embedded into the bytecode.
|
|||||||
|
|
||||||
This evaluates to a c-string, which contains build information such as compilation date and time of the interpreter. When in verbose mode, the compiler will display a warning if the build version of the bytecode does not match the build version of the interpreter.
|
This evaluates to a c-string, which contains build information such as compilation date and time of the interpreter. When in verbose mode, the compiler will display a warning if the build version of the bytecode does not match the build version of the interpreter.
|
||||||
|
|
||||||
This macro may also be used to store additonal information about forks of the Toy codebase.
|
This macro may also be used to store additional information about forks of the Toy codebase.
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ During the collation step, everything from the core program’s execution instru
|
|||||||
|
|
||||||
## Define Functions
|
## Define Functions
|
||||||
|
|
||||||
Executing the following functions out-of-order causes undefiend behaviour.
|
Executing the following functions out-of-order causes undefined behaviour.
|
||||||
|
|
||||||
### void Toy_initCompiler(Toy_Compiler* compiler)
|
### void Toy_initCompiler(Toy_Compiler* compiler)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
|
|
||||||
|
|
||||||
# toy.h - A Toy Programming Language
|
# toy.h - A Toy Programming Language
|
||||||
|
|
||||||
If you're looking how to use Toy directly, try https://toylang.com/
|
If you're looking how to use Toy directly, try https://toylang.com/
|
||||||
@@ -50,7 +51,7 @@ You probably won't use these directly, but they're a good learning opportunity.
|
|||||||
|
|
||||||
`Toy_Scope` holds the variables of a specific scope within Toy - be it a script, a function, a block, etc. Scopes are also where the type system lives at runtime. They use identifier literals as keys, exclusively.
|
`Toy_Scope` holds the variables of a specific scope within Toy - be it a script, a function, a block, etc. Scopes are also where the type system lives at runtime. They use identifier literals as keys, exclusively.
|
||||||
|
|
||||||
`Toy_RefString` is a utility class that wraps traditional C strings, making them less memory intensive and faster to copy and move. In reality, since strings are considered immutable, multiple variables can point to the same string to save memory, and you can just create a new one of these vars pointing to the original rather than copying entirely for a speed boost. This module has it's own memory allocator system that is plugged into the main memory allocator.
|
`Toy_RefString` is a utility class that wraps traditional C strings, making them less memory intensive and faster to copy and move. In reality, since strings are considered immutable, multiple variables can point to the same string to save memory, and you can just create a new one of these vars pointing to the original rather than copying entirely for a speed boost. This module has its own memory allocator system that is plugged into the main memory allocator.
|
||||||
|
|
||||||
`Toy_RefFunction` acts similarly to `Toy_RefString`, but instead operates on function bytecode.
|
`Toy_RefFunction` acts similarly to `Toy_RefString`, but instead operates on function bytecode.
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ This header defines the interpreter structure, which is the beating heart of Toy
|
|||||||
|
|
||||||
`Toy_Interpreter` is a stack-based, bytecode-driven interpreter with a number of customisation options, including "hooks"; native C functions wrapped in `Toy_Literal` instances, injected into the interpreter in order to give the Toy scripts access to libraries via the `import` keyword. The hooks, when invoked this way, can then inject further native functions into the interpreter's current scope. Exactly which hooks are made available varies by host program, but `standard` is the most commonly included one.
|
`Toy_Interpreter` is a stack-based, bytecode-driven interpreter with a number of customisation options, including "hooks"; native C functions wrapped in `Toy_Literal` instances, injected into the interpreter in order to give the Toy scripts access to libraries via the `import` keyword. The hooks, when invoked this way, can then inject further native functions into the interpreter's current scope. Exactly which hooks are made available varies by host program, but `standard` is the most commonly included one.
|
||||||
|
|
||||||
Another useful customisation feature is the ability to redicrect output from the `print` and `assert` keywords, as well as any internal errors that occur. This can allow you to add in a logging system, or even hook the `print` statement up to some kind of HUD.
|
Another useful customisation feature is the ability to redirect output from the `print` and `assert` keywords, as well as any internal errors that occur. This can allow you to add in a logging system, or even hook the `print` statement up to some kind of HUD.
|
||||||
|
|
||||||
## Defined Interfaces
|
## Defined Interfaces
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ The identifier of the library (its name) is passed in as a `Toy_Literal`, as is
|
|||||||
import standard as std;
|
import standard as std;
|
||||||
```
|
```
|
||||||
|
|
||||||
Conventionally, when an alias is given, all of the functions should instead be inserted into a `Toy_LiteralDictionary` which is then inserted into the scope with the alias as its identifier.
|
Conventionally, when an alias is given, all the functions should instead be inserted into a `Toy_LiteralDictionary` which is then inserted into the scope with the alias as its identifier.
|
||||||
|
|
||||||
## Defined Functions
|
## Defined Functions
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ This function takes a `Toy_Interpreter` and `bytecode` (as well as the `length`
|
|||||||
|
|
||||||
If the given bytecode's embedded version is not compatible with the current interpreter, then this function will refuse to execute.
|
If the given bytecode's embedded version is not compatible with the current interpreter, then this function will refuse to execute.
|
||||||
|
|
||||||
Re-using a `Toy_Interpreter` instance without first resetting it is possible (that's how the repl works), however doing so may have unintended consequences if the scripts are not intended to be used in such a way. Any variables declared will persist.
|
Re-using a `Toy_Interpreter` instance without first resetting it is possible (that's how the REPL works), however doing so may have unintended consequences if the scripts are not intended to be used in such a way. Any variables declared will persist.
|
||||||
|
|
||||||
### void Toy_resetInterpreter(Toy_Interpreter* interpreter)
|
### void Toy_resetInterpreter(Toy_Interpreter* interpreter)
|
||||||
|
|
||||||
@@ -60,11 +60,11 @@ This function frees any scopes that the scripts have built up, and generates a n
|
|||||||
|
|
||||||
### void Toy_freeInterpreter(Toy_Interpreter* interpreter)
|
### void Toy_freeInterpreter(Toy_Interpreter* interpreter)
|
||||||
|
|
||||||
This function frees a `Toy_Interpreter`, clearing all of the memory used within. That interpreter is no longer valid for use, and must be re-initialized.
|
This function frees a `Toy_Interpreter`, clearing all the memory used within. That interpreter is no longer valid for use, and must be re-initialized.
|
||||||
|
|
||||||
### bool Toy_injectNativeFn(Toy_Interpreter* interpreter, const char* name, Toy_NativeFn func)
|
### bool Toy_injectNativeFn(Toy_Interpreter* interpreter, const char* name, Toy_NativeFn func)
|
||||||
|
|
||||||
This function will inject the given native function `func` into the `Toy_Interpreter`'s current scope, with the identifer as `name`. Both the name and function will be converted into literals internally before being stored. It will return true on success, otherwise it will return false.
|
This function will inject the given native function `func` into the `Toy_Interpreter`'s current scope, with the identifier as `name`. Both the name and function will be converted into literals internally before being stored. It will return true on success, otherwise it will return false.
|
||||||
|
|
||||||
The primary use of this function is within hooks.
|
The primary use of this function is within hooks.
|
||||||
|
|
||||||
@@ -86,12 +86,12 @@ This utility function will find a `Toy_literal` within the `Toy_Interpreter`'s s
|
|||||||
|
|
||||||
### bool Toy_parseIdentifierToValue(Toy_Interpreter* interpreter, Toy_Literal* literalPtr)
|
### bool Toy_parseIdentifierToValue(Toy_Interpreter* interpreter, Toy_Literal* literalPtr)
|
||||||
|
|
||||||
Sometimes, native functions will receive `Toy_Literal` identifiers instead of the values - the correct values can be retreived from the given interpreter's scope using the following pattern:
|
Sometimes, native functions will receive `Toy_Literal` identifiers instead of the values - the correct values can be retrieved from the given interpreter's scope using the following pattern:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
Toy_Literal foobarIdn = foobar;
|
Toy_Literal foobarIdn = foobar;
|
||||||
if (TOY_IS_IDENTIFIER(foobar) && Toy_parseIdentifierToValue(interpreter, &foobar)) {
|
if (TOY_IS_IDENTIFIER(foobar) && Toy_parseIdentifierToValue(interpreter, &foobar)) {
|
||||||
freeLiteral(foobarIdn); //remember to free the identifier
|
freeLiteral(foobarIdn); //remember to free the identifier
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -101,11 +101,11 @@ This function sets the function called by the `print` keyword. By default, the f
|
|||||||
|
|
||||||
```c
|
```c
|
||||||
static void printWrapper(const char* output) {
|
static void printWrapper(const char* output) {
|
||||||
printf("%s\n", output);
|
printf("%s\n", output);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: The above is a very minor lie - in reality there are some preprocessor directives to allow the repl's `-n` flag to work.
|
Note: The above is a very minor lie - in reality, there are some preprocessor directives to allow the REPL's `-n` flag to work.
|
||||||
|
|
||||||
### void Toy_setInterpreterAssert(Toy_Interpreter* interpreter, Toy_PrintFn assertOutput)
|
### void Toy_setInterpreterAssert(Toy_Interpreter* interpreter, Toy_PrintFn assertOutput)
|
||||||
|
|
||||||
@@ -113,7 +113,7 @@ This function sets the function called by the `assert` keyword on failure. By de
|
|||||||
|
|
||||||
```c
|
```c
|
||||||
static void assertWrapper(const char* output) {
|
static void assertWrapper(const char* output) {
|
||||||
fprintf(stderr, "Assertion failure: %s\n", output);
|
fprintf(stderr, "Assertion failure: %s\n", output);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -123,6 +123,6 @@ This function sets the function called when an error occurs within the interpret
|
|||||||
|
|
||||||
```c
|
```c
|
||||||
static void errorWrapper(const char* output) {
|
static void errorWrapper(const char* output) {
|
||||||
fprintf(stderr, "%s", output); //no newline
|
fprintf(stderr, "%s", output); //no newline
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -23,6 +23,6 @@ Private functions are not intended for general use.
|
|||||||
|
|
||||||
### void Toy_private_setComments(Toy_Lexer* lexer, bool enabled)
|
### void Toy_private_setComments(Toy_Lexer* lexer, bool enabled)
|
||||||
|
|
||||||
This function sets whether comments are allowed within source code. By default, comments are allowed, and are only disabled in the repl.
|
This function sets whether comments are allowed within source code. By default, comments are allowed, and are only disabled in the REPL.
|
||||||
|
|
||||||
Private functions are not intended for general use.
|
Private functions are not intended for general use.
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
|
|
||||||
|
|
||||||
# literal_array.h
|
# literal_array.h
|
||||||
|
|
||||||
This header defines the array structure, which manages a series of `Toy_Literal` instances in sequential memory. The array does not take ownership of given literals, instead it makes an internal copy.
|
This header defines the array structure, which manages a series of `Toy_Literal` instances in sequential memory. The array does not take ownership of given literals, instead it makes an internal copy.
|
||||||
|
|
||||||
The array type is one of two fundemental data structures used throughout Toy - the other is the dictionary.
|
The array type is one of two fundamental data structures used throughout Toy - the other is the dictionary.
|
||||||
|
|
||||||
## Defined Functions
|
## Defined Functions
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
|
|
||||||
|
|
||||||
# toy_literal_dictionary.h
|
# toy_literal_dictionary.h
|
||||||
|
|
||||||
This header defines the dictionary structure (as well as the private entry structure), which manages a series of `Toy_Literal` instances stored in a key-value hash map. The dictionary does not take ownership of given literals, instead it makes an internal copy.
|
This header defines the dictionary structure (as well as the private entry structure), which manages a series of `Toy_Literal` instances stored in a key-value hash map. The dictionary does not take ownership of given literals, instead it makes an internal copy.
|
||||||
|
|
||||||
The dictionary type is one of two fundemental data structures used throughout Toy - the other is the array.
|
The dictionary type is one of two fundamental data structures used throughout Toy - the other is the array.
|
||||||
|
|
||||||
## Defined Macros
|
## Defined Macros
|
||||||
|
|
||||||
### TOY_DICTIONARY_MAX_LOAD
|
### TOY_DICTIONARY_MAX_LOAD
|
||||||
|
|
||||||
If the contents of a dictionary exceeds this percentage of it's capacity, then a new buffer is created, the old contents are copied over one-by-one, and the original buffer is freed.
|
If the contents of a dictionary exceeds this percentage of its capacity, then a new buffer is created, the old contents are copied over one-by-one, and the original buffer is freed.
|
||||||
|
|
||||||
Since this process can be memory and time intensive, a configurable macro is used to allow for fine-grained control across the lang.
|
Since this process can be memory and time intensive, a configurable macro is used to allow for fine-grained control across the language.
|
||||||
|
|
||||||
The current default value is `0.75`, representing 75% capacity.
|
The current default value is `0.75`, representing 75% capacity.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
|
|
||||||
|
|
||||||
# toy_literal.h
|
# toy_literal.h
|
||||||
|
|
||||||
This header defines the literal structure, which is used extensively throughout Toy to represent values of some kind.
|
This header defines the literal structure, which is used extensively throughout Toy to represent values of some kind.
|
||||||
@@ -65,7 +66,7 @@ The following macros are used to cast a literal to a specific C type to be used.
|
|||||||
|
|
||||||
The following macros are used to create a new literal, with the given `value` as it's internal value.
|
The following macros are used to create a new literal, with the given `value` as it's internal value.
|
||||||
|
|
||||||
* `TOY_TO_NULL_LITERAL` - does not need parantheses
|
* `TOY_TO_NULL_LITERAL` - does not need parentheses
|
||||||
* `TOY_TO_BOOLEAN_LITERAL(value)`
|
* `TOY_TO_BOOLEAN_LITERAL(value)`
|
||||||
* `TOY_TO_INTEGER_LITERAL(value)`
|
* `TOY_TO_INTEGER_LITERAL(value)`
|
||||||
* `TOY_TO_FLOAT_LITERAL(value)`
|
* `TOY_TO_FLOAT_LITERAL(value)`
|
||||||
@@ -85,9 +86,9 @@ The following macros are utilities used throughout Toy's internals, and are avai
|
|||||||
|
|
||||||
### TOY_IS_TRUTHY(x)
|
### TOY_IS_TRUTHY(x)
|
||||||
|
|
||||||
Returns true of the literal `x` is truthy, otherwise it returns false.
|
Returns true if the literal `x` is truthy, otherwise it returns false.
|
||||||
|
|
||||||
Currently, every value is considered truthy except `false`, which is falsy and `null`, which is neither true or false.
|
Currently, every value is considered truthy except `false`, which is falsy and `null`, which is neither true nor false.
|
||||||
|
|
||||||
### TOY_AS_FUNCTION_BYTECODE_LENGTH(lit)
|
### TOY_AS_FUNCTION_BYTECODE_LENGTH(lit)
|
||||||
|
|
||||||
@@ -107,9 +108,9 @@ This macro is only valid on `TOY_LITERAL_IDENTIFIER`.
|
|||||||
|
|
||||||
### TOY_TYPE_PUSH_SUBTYPE(lit, subtype)
|
### TOY_TYPE_PUSH_SUBTYPE(lit, subtype)
|
||||||
|
|
||||||
When building a complex type, such as the type of an array or dictionary, you may need to specify inner types. Use this to push a `subtype`. calling `Toy_freeLiteral()` on the outermost type should clean up all inner types, as expected.
|
When building a complex type, such as the type of an array or dictionary, you may need to specify inner types. Use this to push a `subtype`. Calling `Toy_freeLiteral()` on the outermost type should clean up all inner types, as expected.
|
||||||
|
|
||||||
This macro returns the index of the newly pushed value within it's parent.
|
This macro returns the index of the newly pushed value within its parent.
|
||||||
|
|
||||||
This macro is only valid on `TOY_LITERAL_TYPE`, for both `type` and `subtype`.
|
This macro is only valid on `TOY_LITERAL_TYPE`, for both `type` and `subtype`.
|
||||||
|
|
||||||
@@ -135,7 +136,7 @@ This function returns a copy of the given literal. Literals should never be copi
|
|||||||
|
|
||||||
This checks to see if two given literals are equal.
|
This checks to see if two given literals are equal.
|
||||||
|
|
||||||
When an integer and a float are compared, the integer is cooerced into a float for the duration of the call.
|
When an integer and a float are compared, the integer is coerced into a float for the duration of the call.
|
||||||
|
|
||||||
Arrays or dictionaries are equal only if their keys and values all equal. Likewise, types only equal if all subtypes are equal, in order.
|
Arrays or dictionaries are equal only if their keys and values all equal. Likewise, types only equal if all subtypes are equal, in order.
|
||||||
|
|
||||||
@@ -145,7 +146,7 @@ Functions and opaques are never equal to anything, while values with the type `T
|
|||||||
|
|
||||||
This finds the hash of a literal, for various purposes. Different hashing algorithms are used for different types, and some types can't be hashed at all.
|
This finds the hash of a literal, for various purposes. Different hashing algorithms are used for different types, and some types can't be hashed at all.
|
||||||
|
|
||||||
types that can't be hashed are
|
Types that can't be hashed are
|
||||||
|
|
||||||
* all kinds of functions
|
* all kinds of functions
|
||||||
* type
|
* type
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
|
|
||||||
|
|
||||||
# toy_memory.h
|
# toy_memory.h
|
||||||
|
|
||||||
This header defines all of the memory management utilities. Any and all heap-based memory management goes through these utilities.
|
This header defines all the memory management utilities. Any and all heap-based memory management goes through these utilities.
|
||||||
|
|
||||||
A default memory allocator function is used internally, but it can be overwritten for diagnostic and platform related purposes.
|
A default memory allocator function is used internally, but it can be overwritten for diagnostic and platform related purposes.
|
||||||
|
|
||||||
@@ -45,7 +46,7 @@ Any and all memory allocator functions should:
|
|||||||
|
|
||||||
* Take a `pointer` to a previously allocated block of memory, or `NULL`
|
* Take a `pointer` to a previously allocated block of memory, or `NULL`
|
||||||
* Take the `oldSize`, which is the previous size of the `pointer` allocated, in bytes (`oldSize` can be 0)
|
* Take the `oldSize`, which is the previous size of the `pointer` allocated, in bytes (`oldSize` can be 0)
|
||||||
* Take the `newSize`, which is the new size of the buffer to be allocaated, in bytes (`newSize` can be 0)
|
* Take the `newSize`, which is the new size of the buffer to be allocated, in bytes (`newSize` can be 0)
|
||||||
* Return the newly allocated buffer, or `NULL` if `newSize` is zero
|
* Return the newly allocated buffer, or `NULL` if `newSize` is zero
|
||||||
* Return `NULL` on error
|
* Return `NULL` on error
|
||||||
|
|
||||||
|
|||||||
@@ -67,6 +67,6 @@ This function should be called repeatedly until it returns `NULL`, indicating th
|
|||||||
|
|
||||||
### void Toy_freeASTNode(Toy_ASTNode* node)
|
### void Toy_freeASTNode(Toy_ASTNode* node)
|
||||||
|
|
||||||
This function cleans up any valid instance of `Toy_ASTNode` pointer passed to it. It is most commonly used to clean up the values returned by `Toy_scanParser`, after they have been passsed to `Toy_writeCompiler`, or when the node is an error node.
|
This function cleans up any valid instance of `Toy_ASTNode` pointer passed to it. It is most commonly used to clean up the values returned by `Toy_scanParser`, after they have been passed to `Toy_writeCompiler`, or when the node is an error node.
|
||||||
|
|
||||||
Note: this function is *actually* defined in toy_ast_node.h, but documented here, because this is where it matters most.
|
Note: this function is *actually* defined in toy_ast_node.h, but documented here, because this is where it matters most.
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
|
|
||||||
|
|
||||||
# toy_reffunction.h
|
# toy_reffunction.h
|
||||||
|
|
||||||
This header defines the Toy_RefFunction structure, as well as all of the related utilities.
|
This header defines the Toy_RefFunction structure, as well as all the related utilities.
|
||||||
|
|
||||||
See [Toy_RefString](toy_refstring_h.md) for more information about the reference pattern.
|
See [Toy_RefString](toy_refstring_h.md) for more information about the reference pattern.
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
|
|
||||||
|
|
||||||
# toy_refstring.h
|
# toy_refstring.h
|
||||||
|
|
||||||
This header defines the structure `Toy_RefString`, as well as all of the related utilities.
|
This header defines the structure `Toy_RefString`, as well as all the related utilities.
|
||||||
|
|
||||||
[refstring](https://github.com/Ratstail91/refstring) is a stand-alone utility written to reduce the amount of memory manipulation used within Toy. It was independantly written and tested, before being incorporated into Toy proper. As such it has it's own memory management API, which by default is tied into Toy's [core memory API](toy_memory_h.md).
|
[refstring](https://github.com/Ratstail91/refstring) is a stand-alone utility written to reduce the amount of memory manipulation used within Toy. It was independently written and tested, before being incorporated into Toy proper. As such, it has its own memory management API, which by default is tied into Toy's [core memory API](toy_memory_h.md).
|
||||||
|
|
||||||
Instances of `Toy_RefString` are reference counted - that is, rather than copying an existing string in memory, a pointer to the refstring is returned, and the internal reference counter is increased by 1. When the pointer is no longer needed, `Toy_DeleteRefString` can be called; this will decrement the internal reference counter by 1, and only free it when it reaches 0. This has multiple benefits, when used correctly:
|
Instances of `Toy_RefString` are reference counted - that is, rather than copying an existing string in memory, a pointer to the refstring is returned, and the internal reference counter is increased by 1. When the pointer is no longer needed, `Toy_DeleteRefString` can be called; this will decrement the internal reference counter by 1, and only free it when it reaches 0. This has multiple benefits, when used correctly:
|
||||||
|
|
||||||
@@ -62,8 +63,8 @@ This function exposes the interal cstring of `refString`. Only use this function
|
|||||||
|
|
||||||
### bool Toy_equalsRefString(Toy_RefString* lhs, Toy_RefString* rhs)
|
### bool Toy_equalsRefString(Toy_RefString* lhs, Toy_RefString* rhs)
|
||||||
|
|
||||||
This function returns true when the two refstrings are either the same refstring, or contain the same value. Otherwise it returns false.
|
This function returns true when the two refstrings are either the same refstring, or contain the same value. Otherwise, it returns false.
|
||||||
|
|
||||||
### bool Toy_equalsRefStringCString(Toy_RefString* lhs, char* cstring)
|
### bool Toy_equalsRefStringCString(Toy_RefString* lhs, char* cstring)
|
||||||
|
|
||||||
This function returns true when the `refString` contains the same value as the `cstring`. Otherwise it returns false.
|
This function returns true when the `refString` contains the same value as the `cstring`. Otherwise, it returns false.
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
|
|
||||||
|
|
||||||
# toy_scope.h
|
# toy_scope.h
|
||||||
|
|
||||||
This header defines the scope structure, which stores all of the variables used within a given block of code.
|
This header defines the scope structure, which stores all the variables used within a given block of code.
|
||||||
|
|
||||||
Scopes are arranged into a linked list of ancestors, each of which is reference counted. When a scope is popped off the end of the chain, every ancestor scope has it's reference counter reduced by 1 and, if any reach 0, they are freed.
|
Scopes are arranged into a linked list of ancestors, each of which is reference counted. When a scope is popped off the end of the chain, every ancestor scope has its reference counter reduced by 1 and, if any reach 0, they are freed.
|
||||||
|
|
||||||
This is also where Toy's type system lives.
|
This is also where Toy's type system lives.
|
||||||
|
|
||||||
@@ -15,7 +16,7 @@ This function creates a new `Toy_scope` with `scope` as it's ancestor, and retur
|
|||||||
|
|
||||||
### Toy_Scope* Toy_popScope(Toy_Scope* scope)
|
### Toy_Scope* Toy_popScope(Toy_Scope* scope)
|
||||||
|
|
||||||
This function frees the given `scope`, and returns it's ancestor.
|
This function frees the given `scope`, and returns its ancestor.
|
||||||
|
|
||||||
### Toy_Scope* Toy_copyScope(Toy_Scope* original)
|
### Toy_Scope* Toy_copyScope(Toy_Scope* original)
|
||||||
|
|
||||||
@@ -35,7 +36,7 @@ This function checks to see if a given variable with the name `key` has been pre
|
|||||||
|
|
||||||
### bool Toy_setScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal value, bool constCheck)
|
### bool Toy_setScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal value, bool constCheck)
|
||||||
|
|
||||||
This function sets an existing variable named `key` to the value of `value`. This function fails if `constCheck` is true and the given key's type has the constaant flag set. It also fails if the given key doesn't exist.
|
This function sets an existing variable named `key` to the value of `value`. This function fails if `constCheck` is true and the given key's type has the constant flag set. It also fails if the given key doesn't exist.
|
||||||
|
|
||||||
This function returns true on success, otherwise it returns false.
|
This function returns true on success, otherwise it returns false.
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
# Building Toy
|
# Building Toy
|
||||||
|
|
||||||
This tutorial assumes you're using git, GCC, and make.
|
This tutorial assumes you're using git, GCC, and make.
|
||||||
@@ -10,22 +11,22 @@ Toy's makefile uses the exported variable `TOY_OUTDIR` to define where the outpu
|
|||||||
export TOY_OUTDIR = out
|
export TOY_OUTDIR = out
|
||||||
```
|
```
|
||||||
|
|
||||||
Next, you'll want to run make the from within Toy's `source`, assuming the output directory has been created. There are two options for building Toy - `library` (default) or `static`; the former will create a shared library (and a .dll file on windows), while the latter will create a static library.
|
Next, you'll want to run make the from within Toy's `source`, assuming the output directory has been created. There are two options for building Toy - `library` (default) or `static`; the former will create a shared library (and a .dll file on Windows), while the latter will create a static library.
|
||||||
|
|
||||||
```make
|
```make
|
||||||
toy: $(OUTDIR)
|
toy: $(OUTDIR)
|
||||||
$(MAKE) -C Toy/source
|
$(MAKE) -C Toy/source
|
||||||
|
|
||||||
$(OUTDIR):
|
$(OUTDIR):
|
||||||
mkdir $(OUTDIR)
|
mkdir $(OUTDIR)
|
||||||
```
|
```
|
||||||
|
|
||||||
Finally, link against the outputted library, with the source directory as the location of the header files.
|
Finally, link against the outputted library, with the source directory as the location of the header files.
|
||||||
|
|
||||||
```make
|
```make
|
||||||
all: $(OBJ) toy
|
all: $(OBJ) toy
|
||||||
$(CC) $(CFLAGS) -o $(OUT) $(OBJ) -L$(TOY_OUTDIR) -ltoy
|
$(CC) $(CFLAGS) -o $(OUT) $(OBJ) -L$(TOY_OUTDIR) -ltoy
|
||||||
```
|
```
|
||||||
|
|
||||||
These snippets of makefile are only an example - the repository has a more fully featured set of makefiles which can also produce a usable repl program.
|
These snippets of makefile are only an example - the repository has a more fully featured set of makefiles which can also produce a usable REPL program.
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
# Compiling Toy
|
# Compiling Toy
|
||||||
|
|
||||||
This tutorial is a sub-section of [Embedding Toy](deep-dive/embedding-toy) that has been spun off into it's own page for the sake of brevity/sanity. It's recommended that you read the main article first.
|
This tutorial is a subsection of [Embedding Toy](deep-dive/embedding-toy) that has been spun off into its own page for the sake of brevity/sanity. It's recommended that you read the main article first.
|
||||||
|
|
||||||
The exact phases outlined here are entirely implementation-dependent - that is, they aren't required, and are simply how the canonical implementation of Toy works.
|
The exact phases outlined here are entirely implementation-dependent - that is, they aren't required, and are simply how the canonical implementation of Toy works.
|
||||||
|
|
||||||
@@ -69,7 +70,7 @@ Toy_freeCompiler(&compiler);
|
|||||||
|
|
||||||
The writing step is the process in which AST nodes are compressed into bytecode instructions, while literal values are extracted and placed aside in a cache (usually in a compressed, intermediate state).
|
The writing step is the process in which AST nodes are compressed into bytecode instructions, while literal values are extracted and placed aside in a cache (usually in a compressed, intermediate state).
|
||||||
|
|
||||||
The collation phase, however is when the bytecode instructions, along with the now flattened intermediate literals and function bodies are combined. The bytecode header specified in [Developing Toy](deep-dive/developing-toy) is placed at the beginning of this blob of bytes during this step.
|
The collation phase, however, is when the bytecode instructions, along with the now flattened intermediate literals and function bodies are combined. The bytecode header specified in [Developing Toy](deep-dive/developing-toy) is placed at the beginning of this blob of bytes during this step.
|
||||||
|
|
||||||
The Toy bytecode (abbreviated to `tb`), along with the `size` variable indicating the size of the bytecode, are the result of the compilation. This bytecode can be saved into a file for later consumption by the host at runtime - you must ensure that any bytecode files have the `.tb` extension.
|
The Toy bytecode (abbreviated to `tb`), along with the `size` variable indicating the size of the bytecode, are the result of the compilation. This bytecode can be saved into a file for later consumption by the host at runtime - you must ensure that any bytecode files have the `.tb` extension.
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Here you'll find some of the implementation details.
|
|||||||
|
|
||||||
# Bytecode
|
# Bytecode
|
||||||
|
|
||||||
The output of Toy's compiler, and the input of the interpreter, is known as "bytecode". Here, I've attempted to fully document the layout of the canonical bytecode's structure, but since this was written after most of this was implemented, there may be small discrepencies present.
|
The output of Toy's compiler, and the input of the interpreter, is known as "bytecode". Here, I've attempted to fully document the layout of the canonical bytecode's structure, but since this was written after most of this was implemented, there may be small discrepancies present.
|
||||||
|
|
||||||
There are four main sections of the bytecode:
|
There are four main sections of the bytecode:
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ The header consists of four values:
|
|||||||
* TOY_VERSION_PATCH
|
* TOY_VERSION_PATCH
|
||||||
* TOY_VERSION_BUILD
|
* TOY_VERSION_BUILD
|
||||||
|
|
||||||
The first three are single unsigned bytes, embedded at the beginning of the bytecode in sequence. These represent the major, minor and patch versions of the language. The fourth value is a null-terminated c-string of unspecified data, which is *intended* but not required to specify the time that the langauge's compiler was itself compiled. The build string can hold arbitrary data, such as the current maintainer's name, current fork of the language, or other versioning info.
|
The first three are single unsigned bytes, embedded at the beginning of the bytecode in sequence. These represent the major, minor and patch versions of the language. The fourth value is a null-terminated c-string of unspecified data, which is *intended* but not required to specify the time that the language's compiler was itself compiled. The build string can hold arbitrary data, such as the current maintainer's name, current fork of the language, or other versioning info.
|
||||||
|
|
||||||
There are some strict rules when interpreting these values (mimicking, but not conforming to [semver.org](https://semver.org/)):
|
There are some strict rules when interpreting these values (mimicking, but not conforming to [semver.org](https://semver.org/)):
|
||||||
|
|
||||||
@@ -43,33 +43,34 @@ The latest version information can be found in [toy_common.h](https://github.com
|
|||||||
|
|
||||||
In Toy, a "Literal" is a value of some kind, be it an integer, or a dictionary, or even a variable name. Rather than embedding the same literal (potentially) many times within the bytecode, the "Literal Cache" was devised to act as an immutable, indexable repository of any literals needed. When bytecode is first loaded into the interpreter, the first thing that happens (after the header is parsed) is the reconstruction of the literal cache. The internal function `readInterpreterSections()` is responsible for this step.
|
In Toy, a "Literal" is a value of some kind, be it an integer, or a dictionary, or even a variable name. Rather than embedding the same literal (potentially) many times within the bytecode, the "Literal Cache" was devised to act as an immutable, indexable repository of any literals needed. When bytecode is first loaded into the interpreter, the first thing that happens (after the header is parsed) is the reconstruction of the literal cache. The internal function `readInterpreterSections()` is responsible for this step.
|
||||||
|
|
||||||
The first `unsigned short` to be read from this section is `literalCount`, which defines the number of literals which are to be read. Once all literals have been read out of this section, the opcode `TOY_OP_SECTION_END` is expected to be consumed. Some preprocessor macros can also enable or disable debug printing functionality within the repl.
|
The first `unsigned short` to be read from this section is `literalCount`, which defines the number of literals which are to be read. Once all literals have been read out of this section, the opcode `TOY_OP_SECTION_END` is expected to be consumed. Some preprocessor macros can also enable or disable debug printing functionality within the REPL.
|
||||||
|
|
||||||
The list of valid literal types are:
|
The list of valid literal types are:
|
||||||
|
|
||||||
|
|
||||||
### TOY_LITERAL_NULL
|
### TOY_LITERAL_NULL
|
||||||
|
|
||||||
This literal is simply inserted into the literal cache when encountered.
|
This literal is simply inserted into the literal cache when encountered.
|
||||||
|
|
||||||
### TOY_LITERAL_BOOLEAN
|
### TOY_LITERAL_BOOLEAN
|
||||||
|
|
||||||
This literal specifies that the next byte is it's value, either true or false.
|
This literal specifies that the next byte is its value, either true or false.
|
||||||
|
|
||||||
### TOY_LITERAL_INTEGER
|
### TOY_LITERAL_INTEGER
|
||||||
|
|
||||||
This literal specifies that the next 4 bytes are it's value, interpreted as a 32-bit integer.
|
This literal specifies that the next 4 bytes are its value, interpreted as a 32-bit integer.
|
||||||
|
|
||||||
### TOY_LITERAL_FLOAT
|
### TOY_LITERAL_FLOAT
|
||||||
|
|
||||||
This literal specifies that the next 4 bytes are it's value, interpreted as a 32-bit floating point integer.
|
This literal specifies that the next 4 bytes are its value, interpreted as a 32-bit floating point integer.
|
||||||
|
|
||||||
### TOY_LITERAL_STRING
|
### TOY_LITERAL_STRING
|
||||||
|
|
||||||
This literal specifies that the next collection of null terminated bytes are it's value, interpreted as a null-terminated string.
|
This literal specifies that the next collection of null terminated bytes are its value, interpreted as a null-terminated string.
|
||||||
|
|
||||||
### TOY_LITERAL_ARRAY_INTERMEDIATE
|
### TOY_LITERAL_ARRAY_INTERMEDIATE
|
||||||
|
|
||||||
`TOY_LITERAL_ARRAY_INTERMEDIATE` specifies that the literal to be read is a flattened `LiteralArray`. A "flattened" compound literal does not actually store it's contents, only references to it's contents' positions within the literal cache.
|
`TOY_LITERAL_ARRAY_INTERMEDIATE` specifies that the literal to be read is a flattened `LiteralArray`. A "flattened" compound literal does not actually store its contents, only references to its contents' positions within the literal cache.
|
||||||
|
|
||||||
To read this array, you must first read an `unsigned short` which specifies the size, then read that many additional `unsigned shorts`, which are indices. Finally, the original `LiteralArray` can be reconstructed using those indices, in order.
|
To read this array, you must first read an `unsigned short` which specifies the size, then read that many additional `unsigned shorts`, which are indices. Finally, the original `LiteralArray` can be reconstructed using those indices, in order.
|
||||||
|
|
||||||
@@ -77,7 +78,7 @@ As the final step, the newly reconstructed `LiteralArray` is added to the litera
|
|||||||
|
|
||||||
### TOY_LITERAL_DICTIONARY_INTERMEDIATE
|
### TOY_LITERAL_DICTIONARY_INTERMEDIATE
|
||||||
|
|
||||||
`TOY_LITERAL_DICTIONARY_INTERMEDIATE` specifies that the literal to be read is a flattened `LiteralDictionary`. A "flattened" compound literal does not actually store it's contents, only references to it's contents' positions within the literal cache.
|
`TOY_LITERAL_DICTIONARY_INTERMEDIATE` specifies that the literal to be read is a flattened `LiteralDictionary`. A "flattened" compound literal does not actually store its contents, only references to its contents' positions within the literal cache.
|
||||||
|
|
||||||
To read this dictionary, you must first read an `unsigned short` which specifies the size (both keys and values), then read that many additional `unsigned shorts`, which are indices of keys and values. Finally, the original `LiteralDictionary` can be reconstructed using those key and value indices.
|
To read this dictionary, you must first read an `unsigned short` which specifies the size (both keys and values), then read that many additional `unsigned shorts`, which are indices of keys and values. Finally, the original `LiteralDictionary` can be reconstructed using those key and value indices.
|
||||||
|
|
||||||
@@ -85,13 +86,13 @@ As the final step, the newly reconstructed `LiteralDictionary` is added to the l
|
|||||||
|
|
||||||
### TOY_LITERAL_FUNCTION
|
### TOY_LITERAL_FUNCTION
|
||||||
|
|
||||||
When a `TOY_LITERAL_FUNCTION` is encountered, the next `unsigned short` to be read (the function index) should be converted into an integer literal, before having it's type manually changed to `TOY_LITERAL_FUNCTION_INTERMEDIATE` for storage within the literal cache.
|
When a `TOY_LITERAL_FUNCTION` is encountered, the next `unsigned short` to be read (the function index) should be converted into an integer literal, before having its type manually changed to `TOY_LITERAL_FUNCTION_INTERMEDIATE` for storage within the literal cache.
|
||||||
|
|
||||||
Functions will be processed properly in a later step - so this literal is added to the cache as a placeholder until that point.
|
Functions will be processed properly in a later step - so this literal is added to the cache as a placeholder until that point.
|
||||||
|
|
||||||
### TOY_LITERAL_IDENTIFIER
|
### TOY_LITERAL_IDENTIFIER
|
||||||
|
|
||||||
This literal specifies that the next collection of null terminated bytes are it's value, interpreted as a null-terminated string.
|
This literal specifies that the next collection of null terminated bytes are its value, interpreted as a null-terminated string.
|
||||||
|
|
||||||
### TOY_LITERAL_TYPE
|
### TOY_LITERAL_TYPE
|
||||||
|
|
||||||
@@ -103,7 +104,7 @@ This literal specifies that the next byte is the type of a literal, and the foll
|
|||||||
|
|
||||||
This literal specifies that the next byte is the type of a literal, and the following byte is a boolean specifying const-ness.
|
This literal specifies that the next byte is the type of a literal, and the following byte is a boolean specifying const-ness.
|
||||||
|
|
||||||
Then if the type is `TOY_LITERAL_ARRAY`, the following `unsigned short` is an index within the cache, representing the type of the contents.
|
Then, if the type is `TOY_LITERAL_ARRAY`, the following `unsigned short` is an index within the cache, representing the type of the contents.
|
||||||
|
|
||||||
Otherwise, if the type is `TOY_LITERAL_DICTIONARY`, the following two `unsigned short`s are indices within the cache, representing the types of the keys and values.
|
Otherwise, if the type is `TOY_LITERAL_DICTIONARY`, the following two `unsigned short`s are indices within the cache, representing the types of the keys and values.
|
||||||
|
|
||||||
@@ -188,6 +189,7 @@ TODO: finish these
|
|||||||
|TOY_OP_PREFIX|256|Used internally.|
|
|TOY_OP_PREFIX|256|Used internally.|
|
||||||
|TOY_OP_POSTFIX|257|Used internally.|
|
|TOY_OP_POSTFIX|257|Used internally.|
|
||||||
|
|
||||||
|
|
||||||
\*If this literal is an identifier, it is instead replaced with the correct given value from the current scope.
|
\*If this literal is an identifier, it is instead replaced with the correct given value from the current scope.
|
||||||
\*\*On failure, the script will print an error message to the error output and exit.
|
\*\*On failure, the script will print an error message to the error output and exit.
|
||||||
|
|
||||||
@@ -216,11 +218,11 @@ There are four main functions for running the interpreter:
|
|||||||
* `Toy_resetInterpreter`
|
* `Toy_resetInterpreter`
|
||||||
* `Toy_freeInterpreter`
|
* `Toy_freeInterpreter`
|
||||||
|
|
||||||
First, `init` zeroes out the interpreter, sets up the printing functions, and delegates to `reset`, which in turn sets up the program's scope (and injects the default global functions). The initialization function is split into two this way so that `reset` can be used independantly on a "dirty" interpreter to ready it for another script (or another run of the same script). `reset` is usually not needed and may be removed in future.
|
First, `init` zeroes out the interpreter, sets up the printing functions, and delegates to `reset`, which in turn sets up the program's scope (and injects the default global functions). The initialization function is split into two this way so that `reset` can be used independently on a "dirty" interpreter to ready it for another script (or another run of the same script). `reset` is usually not needed and may be removed in future.
|
||||||
|
|
||||||
`free` simply frees the interpreter after execution.
|
`free` simply frees the interpreter after execution.
|
||||||
|
|
||||||
Interestingly, `run` doesn't jump straight into exection. Instead, it first does it's own bit of setup, before reading out the bytecode's header. If the header indicates an incompatible version, then the interpreter will refuse to run, to prevent mistakes from ruining the program.
|
Interestingly, `run` doesn't jump straight into execution. Instead, it first does its own bit of setup, before reading out the bytecode's header. If the header indicates an incompatible version, then the interpreter will refuse to run, to prevent mistakes from ruining the program.
|
||||||
|
|
||||||
`run` will also delegate to a function called `readInterpreterSections()`, which reads and reconstructs the "literalCache" - a collection of all values within the program (variable identifiers, variable values, function bytecode, etc.)
|
`run` will also delegate to a function called `readInterpreterSections()`, which reads and reconstructs the "literalCache" - a collection of all values within the program (variable identifiers, variable values, function bytecode, etc.)
|
||||||
|
|
||||||
@@ -230,39 +232,39 @@ Finally, `run` will automatically free the bytecode and associated literalCache
|
|||||||
|
|
||||||
## Executing the Interpreter
|
## Executing the Interpreter
|
||||||
|
|
||||||
Opcodes within the bytecode are 1 byte in length, and specify a single action to take. Each possible action is definied within the interpreter in a function that begins with `exec`, and are called from within a big looping switch statement. If any of these `exec` functions encounters an error, they can simply return false to break the loop.
|
Opcodes within the bytecode are 1 byte in length, and specify a single action to take. Each possible action is defined within the interpreter in a function that begins with `exec`, and are called from within a big looping switch statement. If any of these `exec` functions encounters an error, they can simply return false to break the loop.
|
||||||
|
|
||||||
The interpeter is stack-based; most, if not all of the actions are preformed on literals within a specially designated array called `stack`. for example:
|
The interpreter is stack-based; most, if not all, the actions are preformed on literals within a specially designated array called `stack`. For example:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
case TOY_OP_PRINT:
|
case TOY_OP_PRINT:
|
||||||
if (!execPrint(interpreter)) {
|
if (!execPrint(interpreter)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
```
|
```
|
||||||
|
|
||||||
When a the opcode `TOY_OP_PRINT` is encountered, the top literal within the stack is popped off, and printed (more info on literals below).
|
When the opcode `TOY_OP_PRINT` is encountered, the top literal within the stack is popped off, and printed (more info on literals below).
|
||||||
|
|
||||||
```c
|
```c
|
||||||
static bool execPrint(Toy_Interpreter* interpreter) {
|
static bool execPrint(Toy_Interpreter* interpreter) {
|
||||||
//get the top literal
|
//get the top literal
|
||||||
Toy_Literal lit = Toy_popLiteralArray(&interpreter->stack);
|
Toy_Literal lit = Toy_popLiteralArray(&interpreter->stack);
|
||||||
|
|
||||||
//if the top literal is an identifier, get it's value
|
//if the top literal is an identifier, get it's value
|
||||||
Toy_Literal idn = lit;
|
Toy_Literal idn = lit;
|
||||||
if (TOY_IS_IDENTIFIER(lit) && Toy_parseIdentifierToValue(interpreter, &lit)) {
|
if (TOY_IS_IDENTIFIER(lit) && Toy_parseIdentifierToValue(interpreter, &lit)) {
|
||||||
Toy_freeLiteral(idn);
|
Toy_freeLiteral(idn);
|
||||||
}
|
}
|
||||||
|
|
||||||
//print as a string to the current print method
|
//print as a string to the current print method
|
||||||
Toy_printLiteralCustom(lit, interpreter->printOutput);
|
Toy_printLiteralCustom(lit, interpreter->printOutput);
|
||||||
|
|
||||||
//free the literal
|
//free the literal
|
||||||
Toy_freeLiteral(lit);
|
Toy_freeLiteral(lit);
|
||||||
|
|
||||||
//continue the loop
|
//continue the loop
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -273,7 +275,7 @@ As in most programming languages, variables can be represented by names specifie
|
|||||||
```c
|
```c
|
||||||
Toy_Literal idn = literal; //cache the literal, just in case it's an identifier
|
Toy_Literal idn = literal; //cache the literal, just in case it's an identifier
|
||||||
if (TOY_IS_IDENTIFIER(literal) && Toy_parseIdentifierToValue(interpreter, &literal)) { //if it is an identifier, parse it...
|
if (TOY_IS_IDENTIFIER(literal) && Toy_parseIdentifierToValue(interpreter, &literal)) { //if it is an identifier, parse it...
|
||||||
Toy_freeLiteral(idn); //always remember to free the original identifier, otherwise you'll have a memory leak!
|
Toy_freeLiteral(idn); //always remember to free the original identifier, otherwise you'll have a memory leak!
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -287,7 +289,7 @@ Other functions are available at the top of the interpreter source file:
|
|||||||
* injection utilities
|
* injection utilities
|
||||||
* parsing utilities
|
* parsing utilities
|
||||||
* bytecode utilities
|
* bytecode utilities
|
||||||
* function utilities (these ones is at the very bottom of the source file)
|
* function utilities (these are at the very bottom of the source file)
|
||||||
|
|
||||||
# Literals
|
# Literals
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
# Embedding Toy
|
# Embedding Toy
|
||||||
|
|
||||||
This tutorial assumes that you've managed to embed Toy into your program by following the tutorial [Building Toy](deep-dive/building-toy).
|
This tutorial assumes that you've managed to embed Toy into your program by following the tutorial [Building Toy](deep-dive/building-toy).
|
||||||
@@ -18,7 +19,7 @@ The functions intended for usage by the API are prepended with the C macro `TOY_
|
|||||||
|
|
||||||
## Structures Used Throughout Toy
|
## Structures Used Throughout Toy
|
||||||
|
|
||||||
The main unit of data within Toy's internals is `Toy_Literal`, which can contain any value that can exist within the Toy langauge - even identifiers. The exact implementation of `Toy_Literal` may change or evolve as time goes on, so it's recommended that you only interact with literals directly by using the macros and functions outlined [above](#embedded-api-macros). See the [types](getting-started/types) page for information on exactly what datatypes exist in Toy.
|
The main unit of data within Toy's internals is `Toy_Literal`, which can contain any value that can exist within the Toy language - even identifiers. The exact implementation of `Toy_Literal` may change or evolve as time goes on, so it's recommended that you only interact with literals directly by using the macros and functions outlined [above](#embedded-api-macros). See the [types](getting-started/types) page for information on exactly what data types exist in Toy.
|
||||||
|
|
||||||
There are two main "compound structures" used within Toy's internals - the `Toy_LiteralArray` and `Toy_LiteralDictionary`. The former is an array of `Toy_Literal` instances stored sequentially in memory for fast lookups, while the latter is a key-value hashmap designed for efficient lookups based on a `Toy_Literal` key. These are both accessible via the language as well.
|
There are two main "compound structures" used within Toy's internals - the `Toy_LiteralArray` and `Toy_LiteralDictionary`. The former is an array of `Toy_Literal` instances stored sequentially in memory for fast lookups, while the latter is a key-value hashmap designed for efficient lookups based on a `Toy_Literal` key. These are both accessible via the language as well.
|
||||||
|
|
||||||
@@ -61,23 +62,23 @@ Hooks can simply inject native functions into the current scope, or they can do
|
|||||||
```c
|
```c
|
||||||
//a utility structure for storing the native C functions
|
//a utility structure for storing the native C functions
|
||||||
typedef struct Natives {
|
typedef struct Natives {
|
||||||
char* name;
|
char* name;
|
||||||
Toy_NativeFn fn;
|
Toy_NativeFn fn;
|
||||||
} Natives;
|
} Natives;
|
||||||
|
|
||||||
int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
|
int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
|
||||||
//the list of available native C functions that can be called from Toy
|
//the list of available native C functions that can be called from Toy
|
||||||
Natives natives[] = {
|
Natives natives[] = {
|
||||||
{"clock", nativeClock},
|
{"clock", nativeClock},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
//inject each native C functions into the current scope
|
//inject each native C functions into the current scope
|
||||||
for (int i = 0; natives[i].name; i++) {
|
for (int i = 0; natives[i].name; i++) {
|
||||||
Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn);
|
Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -90,7 +91,7 @@ TOY_API bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, T
|
|||||||
TOY_API bool Toy_callFn (Toy_Interpreter* interpreter, char* name, Toy_LiteralArray* arguments, Toy_LiteralArray* returns);
|
TOY_API bool Toy_callFn (Toy_Interpreter* interpreter, char* name, Toy_LiteralArray* arguments, Toy_LiteralArray* returns);
|
||||||
```
|
```
|
||||||
|
|
||||||
The first argument must be an interpreter. The third argument is a pointer to a `Toy_LiteralArray` containing a list of arguments to pass to the function, and the fourth is a pointer to a `Toy_LiteralArray` where the return values can be stored (an array is used here for a potential future feature). The contents of the argument array is consumed and left in an indeterminate state (but is safe to free), while the returns array always has one value - if the function did not return a value, then it contains a `null` literal.
|
The first argument must be an interpreter. The third argument is a pointer to a `Toy_LiteralArray` containing a list of arguments to pass to the function, and the fourth is a pointer to a `Toy_LiteralArray` where the return values can be stored (an array is used here for a potential future feature). The contents of the argument array are consumed and left in an indeterminate state (but is safe to free), while the returns array always has one value - if the function did not return a value, then it contains a `null` literal.
|
||||||
|
|
||||||
The second arguments to these functions are either the function to be called as a `Toy_Literal`, or the name of the function within the interpreter's scope. The latter API simply finds the specified `Toy_Literal` if it exists and calls the former. As with most APIs, these return `false` if something went wrong.
|
The second arguments to these functions are either the function to be called as a `Toy_Literal`, or the name of the function within the interpreter's scope. The latter API simply finds the specified `Toy_Literal` if it exists and calls the former. As with most APIs, these return `false` if something went wrong.
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
|
|
||||||
# Roadmapping Toy
|
# Roadmapping Toy
|
||||||
|
|
||||||
## Game And Game Engine
|
## Game And Game Engine
|
||||||
|
|
||||||
The Toy programming langauge was designed from the beginning as though it was supposed to be embedded into an imaginary game engine. Development on said engine and an associated game have proceeded smoothly so far.
|
The Toy programming language was designed from the beginning as though it was supposed to be embedded into an imaginary game engine. Development on said engine and an associated game have proceeded smoothly so far.
|
||||||
|
|
||||||
## Microprocessor Support
|
## Microprocessor Support
|
||||||
|
|
||||||
@@ -22,7 +23,7 @@ Some of these have always been planned, but were sidelined or are incomplete for
|
|||||||
|
|
||||||
## Nope Features
|
## Nope Features
|
||||||
|
|
||||||
Some things which simply will not be added in the foreseeable future are:
|
Some things that simply will not be added in the foreseeable future are:
|
||||||
|
|
||||||
* Classes & Structures
|
* Classes & Structures
|
||||||
* Do-while loops
|
* Do-while loops
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Testing Toy
|
# Testing Toy
|
||||||
|
|
||||||
Toy uses GitHub CI/CD for comprehensive automated testing - however, all of the tests are under `test/`, and can be executed by running `make test`. Doing so on linux will attempt to use valgrind; to disable using valgrind, pass in `DISABLE_VALGRIND=true` as an environment variable. GitHub CI also has access to the option `make test-sanitized` which attempts to use memory sanitation.
|
Toy uses GitHub CI/CD for comprehensive automated testing - however, all the tests are under `test/`, and can be executed by running `make test`. Doing so on Linux will attempt to use valgrind; to disable using valgrind, pass in `DISABLE_VALGRIND=true` as an environment variable. GitHub CI also has access to the option `make test-sanitized` which attempts to use memory sanitation.
|
||||||
|
|
||||||
The tests consist of a number of different situations and edge cases which have been discovered, and should probably be thoroughly tested one way or another. There are also several "-bugfix.toy" scripts which explicitly test a bug that has been encountered in one way or another, to prevent regressions. The libs that are stored in `repl/` are also tested - their tests are under `/tests/scripts/lib`; some error cases are also checked by the mustfail tests in `/test/scripts/mustfail`.
|
The tests consist of a number of different situations and edge cases that have been discovered, and should probably be thoroughly tested one way or another. There are also several "-bugfix.toy" scripts that explicitly test a bug that has been encountered in one way or another to prevent regressions. The libs that are stored in `repl/` are also tested - their tests are under `/tests/scripts/lib`; some error cases are also checked by the mustfail tests in `/test/scripts/mustfail`.
|
||||||
|
|||||||
@@ -1,24 +1,23 @@
|
|||||||
# Theorizing Toy
|
# Theorizing Toy
|
||||||
|
|
||||||
Sooner or later, every coder will try to create their own programming language. In my case, it took me over a decade and a half to realize that was even an option, but once I did I read through a fantastic book called [Crafting Interpreters](https://craftinginterpreters.com/). This sent me down the rabbit hole, so to speak.
|
Sooner or later, every coder will try to create their own programming language. In my case, it took me over a decade and a half to realize that was even an option, but once I did, I read through a fantastic book called [Crafting Interpreters](https://craftinginterpreters.com/). This sent me down the rabbit hole, so to speak.
|
||||||
|
|
||||||
The main driving idea behind the Toy programming langauge has remained the same from the very beginning - I wanted a scripting language that could be embedded into a larger host program, to allow for easy modification by the end user. Specifically, I wanted to enable easy modding of video games made in an imaginary game engine.
|
The main driving idea behind the Toy programming language has remained the same from the very beginning - I wanted a scripting language that could be embedded into a larger host program to allow for easy modification by the end user. Specifically, I wanted to enable easy modding of video games made in an imaginary game engine.
|
||||||
|
|
||||||
At the time of writing, I've started working on said engine, building it around Toy, and adjusting Toy to fit the engine as needed. I've also begun working on a game within that engine, as I believe the best way to build an engine is to build a game with it first. The engine has been dubbed "Box", and the game is called "Skylands".
|
At the time of writing, I've started working on said engine, building it around Toy, and adjusting Toy to fit the engine as needed. I've also begun working on a game within that engine, as I believe the best way to build an engine is to build a game with it first. The engine has been dubbed "Box", and the game is called "Skylands".
|
||||||
|
|
||||||
But this post isn't about the engine, it's about Toy - I want to explain, in some detail, my thought processes when developing it. Let's start at the beginning.
|
But this post isn't about the engine; it's about Toy - I want to explain, in some detail, my thought processes when developing it. Let's start at the beginning.
|
||||||
|
|
||||||
```toy
|
```toy
|
||||||
print "Hello world";
|
print "Hello world";
|
||||||
```
|
```
|
||||||
|
|
||||||
I've drawn the `print` keyword from Crafting Interpreter's Lox language, for much the same reason as explained in the book - it's a simple and easy way to debug issues. You'll be able to print out any kind of value or variable from this statement - but it loses some context like function implementations, and the values of `opaque` literals.
|
I've drawn the `print` keyword from Crafting Interpreter's Lox language, for much the same reason as explained in the book - it's a simple and easy way to debug issues. You'll be able to print out any kind of value or variable from this statement - but it loses some context, like function implementations and the values of `opaque` literals.
|
||||||
|
|
||||||
Let's touch on variables quickly - There's about a dozen variable types that can be used, depending on how you count them. They include `bool`, `int`, `float`, `string` and a couple of compound types - but strict typing in Toy is completely optional (`any` is used by default). There are also functions, which are reusable chunks of code, and a pretty standard set of operators with their traditional precedences.
|
Let's touch on variables quickly. There's about a dozen variable types that can be used, depending on how you count them. They include `bool`, `int`, `float`, `string` and a couple of compound types - but strict typing in Toy is completely optional (`any` is used by default). There are also functions, which are reusable chunks of code, and a pretty standard set of operators with their traditional precedences.
|
||||||
|
|
||||||
One way in which Toy stands out is the bytecode compilation step. Before execution, the source code must be compiled into an intermediate bytecode format (a trait also inherited from Lox) before it can be executed by the interpreter. The exact specifications of the bytecode formatting are not currently documented (yet). The intermediate bytecode stage, and the independance of the interpreter from the compiler, also allow unique features such as the possiblity of operating on a microcontroller.
|
One way in which Toy stands out is the bytecode compilation step. Before execution, the source code must be compiled into an intermediate bytecode format (a trait also inherited from Lox) before it can be executed by the interpreter. The exact specifications of the bytecode formatting are not currently documented (yet). The intermediate bytecode stage and the independence of the interpreter from the compiler also allow unique features, such as the possibility of operating on a microcontroller.
|
||||||
|
|
||||||
One major native feature which is missing from Toy is an input system, such as from stdin. Instead, Toy is intended to receive its instructions from the host program, including any input needed. One such example would be a game controller library - something which takes in button presses, and calls certain Toy functions to move a character around the game world. Toy is almost infinitely extensible via the C API's hook injection system.
|
One major native feature that is missing from Toy is an input system, such as from stdin. Instead, Toy is intended to receive its instructions from the host program, including any input needed. One such example would be a game controller library - something that takes in button presses and calls certain Toy functions to move a character around the game world. Toy is almost infinitely extensible via the C API's hook injection system.
|
||||||
|
|
||||||
I would like to keep the core language nice and simple, as much as possible - something you can explain with just the quickstart page. However, feedback and criticism are always welcome.
|
|
||||||
|
|
||||||
|
I would like to keep the core language nice and simple, as much as possible - something you can explain with just the quick-start page. However, feedback and criticism are always welcome.
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
# Box Version Info Library
|
# Box Version Info Library
|
||||||
|
|
||||||
The box_version_info library simply provides version info about the current build of Box.
|
The box_version_info library simply provides version info about the current build of Box.
|
||||||
@@ -13,15 +14,15 @@ import box_version_info as box_version_info; //can be aliased
|
|||||||
|
|
||||||
### major
|
### major
|
||||||
|
|
||||||
This variable is the major version number of Box at the time of compilation.
|
This variable is the major version number of `Box` at the time of compilation.
|
||||||
|
|
||||||
### minor
|
### minor
|
||||||
|
|
||||||
This variable is the minor version number of Box at the time of compilation.
|
This variable is the minor version number of `Box` at the time of compilation.
|
||||||
|
|
||||||
### patch
|
### patch
|
||||||
|
|
||||||
This variable is the patch version number of Box at the time of compilation.
|
This variable is the patch version number of `Box` at the time of compilation.
|
||||||
|
|
||||||
### build
|
### build
|
||||||
|
|
||||||
@@ -29,4 +30,6 @@ This variable is a string representing the date and time that the engine was com
|
|||||||
|
|
||||||
### author
|
### author
|
||||||
|
|
||||||
This variable contains the name of Box's lead author, and his game studio.
|
This variable contains the name of `Box`'s lead author, and his game studio.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
|
|
||||||
# Preface
|
# Preface
|
||||||
|
|
||||||
The game engine is incomplete and still evolving, as such this page should be considered outdated at all times...
|
The game engine is incomplete and still evolving, as such this page should be considered outdated at all times...
|
||||||
|
|
||||||
# Game Engine
|
# Game Engine
|
||||||
|
|
||||||
The Toy programming langauge was designed from the beginning as an embedded scripting language for some kind of game engine. Different iterations have existed with different implementations, some of which could charitably be said to function. The current version, and the most stable and feature complete so far, has reached a point where it needs some kind of concrete engine to improve any further.
|
The Toy programming language was designed from the beginning as an embedded scripting language for some kind of game engine. Different iterations have existed with different implementations, some of which could charitably be said to function. The current version, and the most stable and feature-complete so far, has reached a point where it needs some kind of concrete engine to improve any further.
|
||||||
|
|
||||||
Currently, the engine exists within its own repository, which can be found here:
|
Currently, the engine exists within its own repository, which can be found here:
|
||||||
|
|
||||||
@@ -20,19 +21,19 @@ The engine proper is invoked with just three lifecycle functions`:
|
|||||||
#include "box_engine.h"
|
#include "box_engine.h"
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
//initialize the drive system
|
//initialize the drive system
|
||||||
Toy_initDriveSystem();
|
Toy_initDriveSystem();
|
||||||
Toy_setDrivePath("scripts", "assets/scripts");
|
Toy_setDrivePath("scripts", "assets/scripts");
|
||||||
|
|
||||||
//invoke the engine
|
//invoke the engine
|
||||||
Box_initEngine("scripts:/init.toy"); //passing in the specified init file
|
Box_initEngine("scripts:/init.toy"); //passing in the specified init file
|
||||||
Box_execEngine();
|
Box_execEngine();
|
||||||
Box_freeEngine();
|
Box_freeEngine();
|
||||||
|
|
||||||
//clean up the drive system when you're done
|
//clean up the drive system when you're done
|
||||||
Toy_freeDriveSystem();
|
Toy_freeDriveSystem();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -40,7 +41,7 @@ int main(int argc, char* argv[]) {
|
|||||||
The engine proper holds the following elements:
|
The engine proper holds the following elements:
|
||||||
|
|
||||||
* SDL2 video and audio elements
|
* SDL2 video and audio elements
|
||||||
* Framerate controls
|
* Frame rate controls
|
||||||
* Toy interpreter
|
* Toy interpreter
|
||||||
* Input keyboard mapping dictionaries
|
* Input keyboard mapping dictionaries
|
||||||
* The root node
|
* The root node
|
||||||
@@ -57,26 +58,26 @@ The nodes form a deep tree-like structure, with the "root node" at it's base.
|
|||||||
|
|
||||||
## Node Structure
|
## Node Structure
|
||||||
|
|
||||||
The fundemental building block of the engine's logic is the node structure - nodes can represent anything within the game world, from entities to abstract global systems. You can think of entities as having a 1:1 mapping to Toy scripts, as each one is given bytecode on initialization that populates its internals (external libraries like the runner library are still possible).
|
The fundamental building block of the engine's logic is the node structure - nodes can represent anything within the game world, from entities to abstract global systems. You can think of entities as having a 1:1 mapping to Toy scripts, as each one is given bytecode on initialization that populates its internals (external libraries like the runner library are still possible).
|
||||||
|
|
||||||
A node holds the following elements:
|
A node holds the following elements:
|
||||||
|
|
||||||
* A reference to it's parent
|
* A reference to it's parent
|
||||||
* An array of references to its children, and bookkeeping variables for tracking them
|
* An array of references to its children, and bookkeeping variables for tracking them
|
||||||
* A dictionary of functions defined in the Toy script
|
* A dictionary of functions defined in the Toy script
|
||||||
* A single SDL texture reference, and controls for rendering it (including as an animated spritesheet)
|
* A single SDL texture reference, and controls for rendering it (including as an animated sprite sheet)
|
||||||
* Position, motion and scale values
|
* Position, motion and scale values
|
||||||
|
|
||||||
The nodes are deeply integrated with Toy scripts, while Toy was written specifically for this purpose. The tree-like structure of the nodes all exist entirely within the computer's heap memory as a result of Toy's memory model - this comes with performance drawbacks and cleanup requirements. Child nodes should never be referenced directly, as they may be `NULL` references that have been released, but not yet pruned.
|
The nodes are deeply integrated with Toy scripts, while Toy was written specifically for this purpose. The tree-like structure of the nodes all exist entirely within the computer's heap memory as a result of Toy's memory model - this comes with performance drawbacks and clean up requirements. Child nodes should never be referenced directly, as they may be `NULL` references that have been released, but not yet pruned.
|
||||||
|
|
||||||
The rules of execution for scripts and functions is as follows:
|
The rules of execution for scripts and functions is as follows:
|
||||||
|
|
||||||
* The script is executed during node initialization
|
* The script is executed during node initialization
|
||||||
* All functions (regardless of name) are stored within the node - effectively preserving the scope of the script as a whole
|
* All functions (regardless of name) are stored within the node - effectively preserving the scope of the script as a whole
|
||||||
* These functions can now be invoked from elsewhere in the program
|
* These functions can now be invoked from elsewhere in the program
|
||||||
* Certian function names (listed below) are invoked at specific times during the game loop throughout the entire node tree
|
* Certain function names (listed below) are invoked at specific times during the game loop throughout the entire node tree
|
||||||
* If the specially named functions do not exist, the node is simply skipped
|
* If the specially named functions do not exist, the node is simply skipped
|
||||||
* Every function, which is intended to be called through `callNodeFn()` or at specific times in the loop must take the `opaque` node as its first argument
|
* Every function, which is intended to be called through `callNodeFn()` or at specific times in the loop, must take the `opaque` node as its first argument
|
||||||
|
|
||||||
## Special Function Names
|
## Special Function Names
|
||||||
|
|
||||||
@@ -105,7 +106,7 @@ NOTE: `onLoad()` is invoked every time a node is loaded - but `onInit()` is only
|
|||||||
|
|
||||||
A series of libraries are provided to allow Toy to interface and control the engine. In addition, the libraries stored within Toy's `repl/` directory are also available (see the main page for the list).
|
A series of libraries are provided to allow Toy to interface and control the engine. In addition, the libraries stored within Toy's `repl/` directory are also available (see the main page for the list).
|
||||||
|
|
||||||
During startup, the script named `init.toy` in the the assets/scripts directory is executed. This file can be used to configure input mappings, as well as initializing the window and node tree.
|
During startup, the script named `init.toy` in the assets/scripts directory is executed. This file can be used to configure input mappings, as well as initializing the window and node tree.
|
||||||
|
|
||||||
* Engine Library
|
* Engine Library
|
||||||
* Node Library
|
* Node Library
|
||||||
@@ -113,3 +114,4 @@ During startup, the script named `init.toy` in the the assets/scripts directory
|
|||||||
* Music Library
|
* Music Library
|
||||||
* Sound Library
|
* Sound Library
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -12,19 +12,19 @@ import math;
|
|||||||
|
|
||||||
### PI: float
|
### PI: float
|
||||||
|
|
||||||
This constant represents the ratio of a circle's circumference to its diameter. It's value is approximately `3.14159265358979323846`.
|
This constant represents the ratio of a circle's circumference to its diameter. Its value is approximately `3.14159265358979323846`.
|
||||||
|
|
||||||
### E: float
|
### E: float
|
||||||
|
|
||||||
This constant represents Euler's number, the base of natural logarithms. It's value is approximately `2.71828182845904523536`.
|
This constant represents Euler's number, the base of natural logarithms. Its value is approximately `2.71828182845904523536`.
|
||||||
|
|
||||||
### EPSILON: float
|
### EPSILON: float
|
||||||
|
|
||||||
This constant represents the acceptable amount of error when comparing floats with the functions provided by this library (see [Defined Comparison Functions](#defined-comparison-functions)). It's default value is `0.000001`.
|
This constant represents the acceptable amount of error when comparing floats with the functions provided by this library (see [Defined Comparison Functions](#defined-comparison-functions)). Its default value is `0.000001`.
|
||||||
|
|
||||||
### NAN: float
|
### NAN: float
|
||||||
|
|
||||||
This constant represents "Not-a-Number", often returned when a calculation is impossible e.g. `sqrt(-1)`.
|
This constant represents "Not-a-Number", often returned when a calculation is impossible, e.g. `sqrt(-1)`.
|
||||||
|
|
||||||
### INFINITY: float
|
### INFINITY: float
|
||||||
|
|
||||||
@@ -124,4 +124,4 @@ This function returns true if `x` is Infinite, otherwise it returns false.
|
|||||||
|
|
||||||
### epsilionCompare(x, y): bool
|
### epsilionCompare(x, y): bool
|
||||||
|
|
||||||
This function returns true if `x` and `y` are within `EPSILON` of each other, otherwise it returns false. This is very useful for compairing floating point values.
|
This function returns true if `x` and `y` are within `EPSILON` of each other, otherwise it returns false. This is very useful for comparing floating point values.
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
# Quick Start Guide
|
# Quick Start Guide
|
||||||
|
|
||||||
This guide is intended to get you writing Toy code as fast as possible. As such, it's more of a reference for experienced coders to know what is available and what isn't.
|
This guide is intended to get you writing Toy code as fast as possible. As such, it's more of a reference for experienced coders to know what is available and what isn't.
|
||||||
@@ -23,7 +24,7 @@ var f = 3.14;
|
|||||||
var s = "Hello world";
|
var s = "Hello world";
|
||||||
```
|
```
|
||||||
|
|
||||||
Numbers (both integers and floats) can be delimited with underscores (`_`), to break them up visually e.g. `100_000`.
|
Numbers (both integers and floats) can be delimited with underscores (`_`), to break them up visually, e.g. `100_000`.
|
||||||
|
|
||||||
Strings can be 4096 characters long, and the following characters can be escaped: `\n`, `\t`, `\\` and `\"`.
|
Strings can be 4096 characters long, and the following characters can be escaped: `\n`, `\t`, `\\` and `\"`.
|
||||||
|
|
||||||
@@ -122,7 +123,7 @@ greeting[0:4] = "Goodnight"; //changes greeting to equal "Goodnight world"
|
|||||||
|
|
||||||
## External Libraries
|
## External Libraries
|
||||||
|
|
||||||
The host may, at it's own discretion, make external libraries available to the scripts. To access these, you can use the `import` keyword:
|
The host may, at its own discretion, make external libraries available to the scripts. To access these, you can use the `import` keyword:
|
||||||
|
|
||||||
```
|
```
|
||||||
import standard;
|
import standard;
|
||||||
@@ -199,4 +200,3 @@ Other operators used throughout the language are: the assignment, colon, semicol
|
|||||||
```
|
```
|
||||||
= : ; , . ...
|
= : ; , . ...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
# Random Library
|
# Random Library
|
||||||
|
|
||||||
The random library offers a number of functions geared towards producing pseudorandom values. This library has a concept called "generators", which are opaque objects used to generate a sequence of numbers from an initial integer seed. A seed can be generated from most values using the standard library `hash` function.
|
The random library offers a number of functions geared towards producing pseudorandom values. This library has a concept called "generators", which are opaque objects used to generate a sequence of numbers from an initial integer seed. A seed can be generated from most values using the standard library `hash` function.
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
# Runner Library
|
# Runner Library
|
||||||
|
|
||||||
The runner library is used to execute one script from inside another. It also has functions that allow you to retrieve variables from the other script.
|
The runner library is used to execute one script from inside another. It also has functions that allow you to retrieve variables from the other script.
|
||||||
@@ -21,7 +22,7 @@ This function does a lot of work:
|
|||||||
* It validates the file path using the drive syntax
|
* It validates the file path using the drive syntax
|
||||||
* It reads in the source code of the script file
|
* It reads in the source code of the script file
|
||||||
* It compiles the source script into bytecode
|
* It compiles the source script into bytecode
|
||||||
* It constructs and intializes an Interpreter
|
* It constructs and initializes an Interpreter
|
||||||
* It packages it all into an opaque variable and returns it
|
* It packages it all into an opaque variable and returns it
|
||||||
|
|
||||||
### loadScriptBytecode(path: string): opaque
|
### loadScriptBytecode(path: string): opaque
|
||||||
@@ -31,7 +32,7 @@ This is used to load an external bytecode file into an opaque variable.
|
|||||||
This function does a lot of work:
|
This function does a lot of work:
|
||||||
|
|
||||||
* It validates the file path using the drive syntax
|
* It validates the file path using the drive syntax
|
||||||
* It constructs and intializes an Interpreter
|
* It constructs and initializes an Interpreter
|
||||||
* It packages it all into an opaque variable and returns it
|
* It packages it all into an opaque variable and returns it
|
||||||
|
|
||||||
Note: This function resembles `loadScript()`, but skips the compilation step.
|
Note: This function resembles `loadScript()`, but skips the compilation step.
|
||||||
@@ -58,4 +59,4 @@ This function frees a script's resources, cleaning up any memory that is no long
|
|||||||
|
|
||||||
### checkScriptDirty(self: opaque): bool
|
### checkScriptDirty(self: opaque): bool
|
||||||
|
|
||||||
This function returns true of the script is "dirty", otherwise it returns false.
|
This function returns true if the script is "dirty", otherwise it returns false.
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
# Standard Library
|
# Standard Library
|
||||||
|
|
||||||
The standard library offers a number of miscellaneous utility functions, which can be used for various purposes. These are the most commonly used functions, so the standard library is almost certain to be included in the host program.
|
The standard library offers a number of miscellaneous utility functions, which can be used for various purposes. These are the most commonly used functions, so the standard library is almost certain to be included in the host program.
|
||||||
@@ -57,19 +58,19 @@ This function returns the value of any integer or float passed in, rounded to th
|
|||||||
|
|
||||||
This function expects an integer or float as the value for `self`.
|
This function expects an integer or float as the value for `self`.
|
||||||
|
|
||||||
If `self` is below 0, this function returns -1. Otherwise it returns 1.
|
If `self` is below 0, this function returns -1. Otherwise, it returns 1.
|
||||||
|
|
||||||
### normalize(self): int
|
### normalize(self): int
|
||||||
|
|
||||||
This function expects an integer or float as the value for `self`.
|
This function expects an integer or float as the value for `self`.
|
||||||
|
|
||||||
If `self` is below 0, this function returns -1. Otherwise if `self` is above 0, this function returns 1. Otherwise it returns 0.
|
If `self` is below 0, this function returns -1. Otherwise, if `self` is above 0, this function returns 1. Otherwise it returns 0.
|
||||||
|
|
||||||
### clamp(value, min, max): any
|
### clamp(value, min, max): any
|
||||||
|
|
||||||
This function expects integers or floats as the values for `value`, `min`, and `max`.
|
This function expects integers or floats as the values for `value`, `min`, and `max`.
|
||||||
|
|
||||||
If `value` is smaller than `min`, this function will return `min`. Otherwise, if `value` larget than `max`, it will return `max`. Otherwise, it will return `value`.
|
If `value` is smaller than `min`, this function will return `min`. Otherwise, if `value` larger than `max`, it will return `max`. Otherwise, it will return `value`.
|
||||||
|
|
||||||
### lerp(start, end, amount): any
|
### lerp(start, end, amount): any
|
||||||
|
|
||||||
@@ -81,23 +82,23 @@ This function will return the value of `start` adjusted towards the value of `en
|
|||||||
|
|
||||||
### concat(self, other): any
|
### concat(self, other): any
|
||||||
|
|
||||||
This function only works when self and other are matching compounds (both arrays, dictionaries or strings). It returns a new compound of that kind, with the content of `other` appended to the content of `self`.
|
This function only works when self and others are matching compounds (both arrays, dictionaries or strings). It returns a new compound of that kind, with the content of `other` appended to the content of `self`.
|
||||||
|
|
||||||
### containsKey(self: dictionary, key): bool
|
### containsKey(self: dictionary, key): bool
|
||||||
|
|
||||||
This function returns `true` if `self` contains the given `key`, otherwise it returns false.
|
This function returns `true` if `self` contains the given `key`; otherwise, it returns false.
|
||||||
|
|
||||||
### containsValue(self, value): bool
|
### containsValue(self, value): bool
|
||||||
|
|
||||||
This function returns `true` if `self` contains the given `value`, otherwise it returns false.
|
This function returns `true` if `self` contains the given `value`; otherwise, it returns false.
|
||||||
|
|
||||||
### every(self, func: fn): bool
|
### every(self, func: fn): bool
|
||||||
|
|
||||||
This function takes either an array or a dictionary as the `self` argument, and a function as `func`. The argument `func` must take two arguments - the first is the index/key of the array/dictionary, and the second is the value. The contents of `self` are passed into `func`, one element at a time, until `func` returns `false`, at which point this function returns `false`. Otherwise this function returns `true`.
|
This function takes either an array or a dictionary as the `self` argument and a function as `func`. The argument `func` must take two arguments - the first is the index/key of the array/dictionary, and the second is the value. The contents of `self` are passed into `func`, one element at a time, until `func` returns `false`, at which point this function returns `false`. Otherwise, this function returns `true`.
|
||||||
|
|
||||||
### forEach(self, func: fn)
|
### forEach(self, func: fn)
|
||||||
|
|
||||||
This function takes either an array or a dictionary as the `self` argument, and a function as `func`. The argument `func` must take two arguments - the first is the index/key of the array/dictionary, and the second is the value. The contents of `self` are passed into `func`, one element at a time.
|
This function takes either an array or a dictionary as the `self` argument and a function as `func`. The argument `func` must take two arguments - the first is the index/key of the array/dictionary, and the second is the value. The contents of `self` are passed into `func` one element at a time.
|
||||||
|
|
||||||
```
|
```
|
||||||
import standard;
|
import standard;
|
||||||
@@ -113,7 +114,7 @@ a.forEach(p); //prints 1, 3, and 5 to stdout
|
|||||||
|
|
||||||
### filter(self, func: fn): any
|
### filter(self, func: fn): any
|
||||||
|
|
||||||
This function takes either an array or a dictionary as the `self` argument, and a function as `func`. The argument `func` must take two arguments - the first is the index/key of the array/dictionary, and the second is the value. The contents of `self` are passed into `func`, one element at a time, and the function returns a new compound for every element that `func` returned a truthy value for.
|
This function takes either an array or a dictionary as the `self` argument and a function as `func`. The argument `func` must take two arguments - the first is the index/key of the array/dictionary, and the second is the value. The contents of `self` are passed into `func`, one element at a time, and the function returns a new compound for every element that `func` returned a truthy value for.
|
||||||
|
|
||||||
### getKeys(self: dictionary): [any]
|
### getKeys(self: dictionary): [any]
|
||||||
|
|
||||||
@@ -129,7 +130,7 @@ This function returns the first index within `self` that is equal to `value`, or
|
|||||||
|
|
||||||
### map(self, func: fn): any
|
### map(self, func: fn): any
|
||||||
|
|
||||||
This function takes either an array or a dictionary as the `self` argument, and a function as `func`. The argument `func` must take two arguments - the first is the index/key of the array/dictionary, and the second is the value. It returns an array with the results of each call - the order of the results when called on a dictionary are undefined.
|
This function takes either an array or a dictionary as the `self` argument, and a function as `func`. The argument `func` must take two arguments - the first is the index/key of the array/dictionary, and the second is the value. It returns an array with the results of each call - the order of the results when called on a dictionary is undefined.
|
||||||
|
|
||||||
```
|
```
|
||||||
import standard;
|
import standard;
|
||||||
@@ -145,13 +146,13 @@ print a.map(increment); //prints [2,3,4];
|
|||||||
|
|
||||||
### reduce(self, default: any, func: fn): any
|
### reduce(self, default: any, func: fn): any
|
||||||
|
|
||||||
This function takes either an array or a dictionary as the `self` argument, a default value, and a function as `func`. The argument `func` takes three arguments - the first is the accumulator, the second is the index/key and the third is the value. It applies the given function to every element of the array/dictionary, passing the result of each call as the accumulator to the next (the default value is used for the first call). Finally, the final value of the accumulator is returned to the caller.
|
This function takes either an array or a dictionary as the `self` argument, a default value, and a function as `func`. The argument `func` takes three arguments - the first is the accumulator, the second is the index/key, and the third is the value. It applies the given function to every element of the array/dictionary, passing the result of each call as the accumulator to the next (the default value is used for the first call). Finally, the final value of the accumulator is returned to the caller.
|
||||||
|
|
||||||
```
|
```
|
||||||
import standard;
|
import standard;
|
||||||
|
|
||||||
fn f(acc, k, v) {
|
fn f(acc, k, v) {
|
||||||
return acc + v;
|
return acc + v;
|
||||||
}
|
}
|
||||||
|
|
||||||
var a = [1, 2, 3, 4];
|
var a = [1, 2, 3, 4];
|
||||||
@@ -161,11 +162,11 @@ print a.reduce(0, f); //prints "10"
|
|||||||
|
|
||||||
### some(self, func: fn): bool
|
### some(self, func: fn): bool
|
||||||
|
|
||||||
This function takes either an array or a dictionary as the `self` argument, and a function as `func`. The argument `func` must take two arguments - the first is the index/key of the array/dictionary, and the second is the value. The contents of `self` are passed into `func`, one element at a time, until `func` returns `true`, at which point this function returns `true`. Otherwise this function returns `false`.
|
This function takes either an array or a dictionary as the `self` argument, and a function as `func`. The argument `func` must take two arguments - the first is the index/key of the array/dictionary, and the second is the value. The contents of `self` are passed into `func`, one element at a time, until `func` returns `true`, at which point this function returns `true`. Otherwise, this function returns `false`.
|
||||||
|
|
||||||
### sort(self: array, func: fn)
|
### sort(self: array, func: fn)
|
||||||
|
|
||||||
This function takes an array as the `self` argument, and a comparison function as `func`. The argument `func` must take two arguments, and return a truthy or falsy value. The contents of the array in `self` are sorted based on the results of `func`, as though the function were the less comparator function.
|
This function takes an array as the `self` argument, and a comparison function as `func`. The argument `func` must take two arguments and return a truthy or falsy value. The contents of the array in `self` are sorted based on the results of `func`, as though the function was the less comparator function.
|
||||||
|
|
||||||
```
|
```
|
||||||
import standard;
|
import standard;
|
||||||
@@ -211,3 +212,5 @@ This function is identical to `trim(self, trimChars)`, except it is only applied
|
|||||||
### trimEnd(self: string, trimChars: string = " \t\n\r"): string
|
### trimEnd(self: string, trimChars: string = " \t\n\r"): string
|
||||||
|
|
||||||
This function is identical to `trim(self, trimChars)`, except it is only applied to the end of the first argument.
|
This function is identical to `trim(self, trimChars)`, except it is only applied to the end of the first argument.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Types
|
# Types
|
||||||
|
|
||||||
The type system in toy is opt-in, but allows a lot of robust checks at runtime when needed. Types themselves are first-class citizens. To retreive the type of an existing variable, use the `typeof` keyword.
|
The type system in Toy is opt-in, but allows a lot of robust checks at runtime when needed. Types themselves are first-class citizens. To retrieve the type of an existing variable, use the `typeof` keyword.
|
||||||
|
|
||||||
```
|
```
|
||||||
print typeof value;
|
print typeof value;
|
||||||
@@ -59,7 +59,7 @@ Const-ness, or the ability to fix the value of a variable, is part of the type s
|
|||||||
var ANSWER: int const = 42; //answer will never change
|
var ANSWER: int const = 42; //answer will never change
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also set the members of an array or dicitonary as const, or the entire compound:
|
You can also set the members of an array or dictionary as const, or the entire compound:
|
||||||
|
|
||||||
```
|
```
|
||||||
var members: [int const] = [1, 2, 3]; //1, 2 and 3 cannot be changed, but "members" can be modified or re-assigned
|
var members: [int const] = [1, 2, 3]; //1, 2 and 3 cannot be changed, but "members" can be modified or re-assigned
|
||||||
@@ -69,7 +69,7 @@ var everything: [int] const = [4, 5, 6]; //everything is now const
|
|||||||
|
|
||||||
## Astype
|
## Astype
|
||||||
|
|
||||||
Due to the syntax of Toy, when storing a complex type into a varable, you may need to use the `astype` keyword to differentiate the value from an array or dictionary.
|
Due to the syntax of Toy, when storing a complex type into a variable, you may need to use the `astype` keyword to differentiate the value from an array or dictionary.
|
||||||
|
|
||||||
```
|
```
|
||||||
var t: type = astype [int]; //t is a type, representing an array of integers
|
var t: type = astype [int]; //t is a type, representing an array of integers
|
||||||
@@ -78,7 +78,7 @@ var u: type = [int]; //Error! it tried to assign an array with the sole entry "i
|
|||||||
|
|
||||||
## First-Class Citizens
|
## First-Class Citizens
|
||||||
|
|
||||||
Types are first-class citizens. What this means is that they can be used just like any other value, as well as being stored in variables, and even returned from functions.
|
Types are first-class citizens. What this means is that they can be used just like any other value, as well as being stored in variables and even returning from functions.
|
||||||
|
|
||||||
```
|
```
|
||||||
fn decide(question) {
|
fn decide(question) {
|
||||||
@@ -97,7 +97,7 @@ var number: t = 0; //what if it had been false?
|
|||||||
|
|
||||||
## Opaque Data
|
## Opaque Data
|
||||||
|
|
||||||
Sometimes, you may need to pass data through Toy that Toy can't normally handle. This data is called "opaque" data, and is passed around by reference rather than value. Anything can be passed in as opaque data, as long as it's represented as a void pointer in C.
|
Sometimes, you may need to pass data through Toy that Toy can't normally handle. This data is called "opaque" data and is passed around by reference rather than value. Anything can be passed in as opaque data as long as it's represented as a void pointer in C.
|
||||||
|
|
||||||
```c
|
```c
|
||||||
Toy_Literal opaque = TOY_TO_OPAQUE_LITERAL(&data, 0);
|
Toy_Literal opaque = TOY_TO_OPAQUE_LITERAL(&data, 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user