Sorted out some folders for the docs

This commit is contained in:
2023-02-16 21:44:06 +11:00
committed by GitHub
parent 329d085beb
commit 0b885d0a30
15 changed files with 30 additions and 65 deletions

View File

@@ -0,0 +1,31 @@
# About Library
The about library simply provides version info about the current build of Toy.
The about library can usually be accessed with the `import` keyword:
```
import about;
import about as about; //can easily be aliased
```
## major
This variable is the major version number of Toy at the time of compilation.
## minor
This variable is the minor version number of Toy at the time of compilation.
## patch
This variable is the patch version number of Toy at the time of compilation.
## build
This variable is a string representing the date and time that the interpreter was compiled.
## author
This variable contains the name of Toy's lead author, and his game studio.

View File

@@ -0,0 +1,18 @@
# 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 best way to create a game engine is to build a game first, then extract the engine from the finished product. Therefore, a game is being built, currently under the codename "airport", around the Toy langauge.
[https://github.com/Ratstail91/airport](https://github.com/Ratstail91/airport)
This game has a simple design (it's an idle clicker), but should support enough features to make the engine worthwhile.
More details, such as a name for the engine, will come eventually.
## Engine Structure
The engine uses a node-based structure, inspired by Godot's own node structure. Each node has a script attached, and can programmatically load other nodes.
The engine also uses Toy's memory model i.e. `Toy_reallocate()` wrapped in a number of macros.

View File

@@ -0,0 +1,202 @@
# 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.
Toy programs begin at the top of the file, and continue until the end, unless an error is encountered.
## Print Keyword
This keyword prints values to stdout for debugging (this can be altered by the host program).
```
print "Hello World\n";
```
## Names and Variables
Variables can store data of any kind, unless a type is specified; see [types](types). Names can be up to 256 characters long; see [Reserved Keywords](#reserved-keywords) for a list of keywords that can't be used as a name.
```
var b = true;
var i = 42;
var f = 3.14;
var s = "Hello world";
```
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 `\"`.
## Compounds
Larger containers of data are available - arrays and dictionaries. Arrays are collections of data stored sequentially, while dictionaries are hash-maps of key-value pairs:
```
var array = []; //define an array
var dict = [:]; //define a dictionary
dict["foo"] = "bar"; //you can use indexing to add to a dictionary
array.push(42); //you must use a function to push to an array
```
## Control Flow
You can control the program flow with either `if`, `while` or `for`. The only falsy value is `false`.
```
if (check()) {
//do this
}
else {
//otherwise do this
}
var i = 0;
while (i < 10) {
print i++;
}
for (var i = 0; i < 10; i++) {
print i;
}
```
`continue` and `break` both behave as you'd expect.
## Functions
Functions are defined with the `fn` keyword, and can take any number of arguments. They can return a value as well.
```
fn combine(a, b, c) {
return [a, b, c];
}
print combine(1, 2, 3);
```
Variable number of parameters, called rest parameters, can be passed in as an array.
```
fn combine(...rest) {
return rest;
}
print combine(1, 2, 3);
```
## UFCS and Global Functions
Functions can be called using the universal function call syntax, which is just syntactic sugar for a normal function call:
```
fn printMe(self) {
print self;
}
array.printMe();
```
There are several globally available functions provided by default:
```
set(self, key, value) //array, dictionary
get(self, key) //array, dictionary
push(self, value) //array
pop(self) //array
length(self) //array, dictionary, string
clear(self) //array, dictionary
```
## Slice Notation
When indexing a compound value, you can use slice notation to manipulate it's elements:
```
var greeting = "Hello world";
print greeting[::-1]; //dlrow olleH
greeting[0:4] = "Goodnight"; //changes greeting to equal "Goodnight world"
```
## 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:
```
import standard;
print clock(); //made available by "standard"
```
## Assertion Tests
For testing purposes, there is the `assert` keyword. `assert` takes two arguments, separated by a comma; if the first resolves to a truthy value, then the whole statement is a no-op. Otherwise, the second argument, which MUST be a string, is displayed as an error and the script exits.
```
var answer = 42;
assert answer == 42, "This will not be seen";
//both false and null trigger assert's exit condition
assert null, "This will be seen before the script exits";
```
## Reserved Keywords
The following list cannot be used as names, due to their significance (or potential later use) in the language.
* any
* as
* astype
* assert
* bool
* break
* class (reserved)
* const
* continue
* do (reserved)
* else
* export (reserved)
* false
* float
* fn
* for
* foreach (reserved)
* if
* import
* in (reserved)
* int
* null
* of (reserved)
* opaque
* print
* return
* string
* true
* type
* typeof
* var
* while
## Full List of Operators
The following mathematical operators are available. A definition is omitted here, as they are commonly used in most programming languages.
```
+ - * / % += -= *= /= %= ++(prefix) --(prefix) (postfix)++ (postfix)--
```
Likewise, the following logical operators are available (`&&` is more tightly bound than `||` due to historical reasons):
```
( ) [ ] { } ! != == < > <= >= && || ?:
```
Other operators used throughout the language are: the assignment, colon, semicolon, comma, dot and rest operators:
```
= : ; , . ...
```

View File

@@ -0,0 +1,85 @@
# 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 has a concept called a "dirty" script - dirty scripts are those which have already been run, and whose variables can be accessed. Dirty scripts must be reset before it is run again.
When using this library, you must first initialize the "drives" that are available. A drive is a simple way to ensure that the user and any modders don't have access to the entire hard drive. To set up the drives, you must designate a name for each folder you wish to enable access to, like so:
```c
//it's a good idea to place this early in the program's execution, where it will only be run once
int main(int argc, const char* argv[]) {
//the drive system uses a LiteralDictionary, which must be initialized with this
Toy_initDriveDictionary();
//create a pair of literals, the first for the drive name, the second for the path
Toy_Literal driveLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("scripts"));
Toy_Literal pathLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("C:/path/to/scripts"));
//set these within the drive dictionary
Toy_setLiteralDictionary(Toy_getDriveDictionary(), driveLiteral, pathLiteral);
//these literals are no longer needed
Toy_freeLiteral(driveLiteral);
Toy_freeLiteral(pathLiteral);
//run the rest of your program
repl();
//clean up the drive dictionary when you're done
Toy_freeDriveDictionary();
return 0;
}
```
The runner library can usually be accessed with the `import` keyword:
```toy
import runner;
```
## loadScript(path: string)
This is used to load an external script into an opaque variable.
This function does a lot of work:
* It validates the file path using the drive syntax (see above)
* It reads in the source code of the script file
* It compiles the source script into bytecode
* It constructs and intializes an Interpreter
* It packages it all into an opaque variable and returns it
## loadScriptBytecode(path: string)
This is used to load an external bytecode file into an opaque variable.
This function does a lot of work:
* It validates the file path using the drive syntax (see above)
* It constructs and intializes an Interpreter
* It packages it all into an opaque variable and returns it
Note: This function resembles `loadScript()`, but skips the compilation step.
## runScript(self: opaque)
This function executes an external script, which must first be loaded into an opaque variable with either `loadScript()` or `loadScriptBytecode()`.
## getScriptVar(self: opaque, name: string)
This function retrieves a variable from the top level of a script's environment.
## callScriptFn(self: opaque, name: string, ...rest)
This function retrieves a function from the top level of a script's environment, and calls it with `rest` as the argument list.
## resetScript(self: opaque)
This function resets the script so that it is no longer in a "dirty" state, and can be re-run using `runScript()`.
## freeScript(self: opaque)
This function frees a script's resources, cleaning up any memory that is no longer needed. Failing to call this will result in a memory leak.

View File

@@ -0,0 +1,147 @@
# 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 can usually be accessed with the `import` keyword:
```
import standard;
```
## clock()
This function returns a string representation of the current timestamp.
## concat(self, other)
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`.
## containsKey(self: dictionary, key)
This function returns `true` if `self` contains the given `key`, otherwise it returns false.
## containsValue(self, value)
This function returns `true` if `self` contains the given `value`, otherwise it returns false.
## every(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, until `func` returns `false`, at which point this function returns `false`. Otherwise this function returns `true`.
## 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.
```
import compound;
fn p(i, x) {
print x;
}
var a = [1, 3, 5];
a.forEach(p); //prints 1, 3, and 5 to stdout
```
## filter(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, and the function returns a new compound for every element that `func` returned a truthy value for.
## getKeys(self: dictionary)
This returns an array of all non-null keys stored within the dictionary. The order is undefined.
## getValues(self: dictionary)
This returns an array of all values with non-null keys stored within the dictionary. The order is undefined.
## indexOf(self: array, value)
This function returns the first index within `self` that is equal to `value`, or `null` if none are found.
## map(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. It returns an array with the results of each call - the order of the results when called on a dictionary are undefined.
```
import compound;
fn increment(k, v) {
return v + 1;
}
var a = [1, 2, 3];
print a.map(increment); //prints [2,3,4];
```
## reduce(self, default, func: fn)
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 compound;
fn f(acc, k, v) {
return acc + v;
}
var a = [1, 2, 3, 4];
print a.reduce(0, f); //prints "10"
```
## some(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, until `func` returns `true`, at which point this function returns `true`. Otherwise this function returns `false`.
## 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 function were the less comparison function.
```
import compound;
fn less(a, b) {
return a < b;
}
var a = [4, 1, 3, 2];
print a.sort(less); //prints "[1, 2, 3, 4]"
```
## toLower(self: string)
This function returns a new string which is identical to the string `self`, except any uppercase letters are replaced with the corresponding lowercase letters.
## toString(self)
This function returns a string representation of `self`. This is intended for arrays and dictionaries, but can theoretically work on any printable value.
If the resulting string is longer than `TOY_MAX_STRING_LENGTH` - 1, then it is truncated.
## toUpper(self: string)
This function returns a new string which is identical to the string `self`, except any lowercase letters are replaced with the corresponding uppercase letters.
## trim(self: string, trimChars: string = " \t\n\r")
This function returns a new string which is identical to the string `self`, except any characters at the beginning or end of `self` which are present in the argument `trimChars` are removed. The argument `trimChars` is optional, and has the following characters as the default value:
* The space character
* The horizontal tab character
* The newline character
* The carriage return character
These characters used because they are the only control characters currently supported by Toy.
## trimBegin(self: string, trimChars: string = " \t\n\r")
This is identical to `_trim(self, trimChars)`, except it is only applied to the beginning of the first argument.
## trimEnd(self: string, trimChars: string = " \t\n\r")
This is identical to `_trim(self, trimChars)`, except it is only applied to the end of the first argument.

112
getting-started/types.md Normal file
View File

@@ -0,0 +1,112 @@
# 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.
```
print typeof value;
```
The types available are:
| Type | Signature | Description |
| --- | --- | --- |
| null | null | Represents a lack of any meaningful value |
| boolean | bool | Either true or false |
| integer | int | Any whole number. The limits are implementation dependent |
| float | float | Any floating point number. The limits are implementation dependent |
| string | string | A series of characters, forming text |
| array | n/a | A series of values arranged sequentially in memory, indexable with an integer |
| dictionary | n/a | A series of key-value pairs stored in a hash-table, indexable with the keys |
| function | fn | A chunk of reusable code, which can potentially return a value of some kind |
| type | type | The type of types |
| opaque | opaque | Arbitrary data passed from the host, which Toy can't natively understand |
| any | any | Can hold any value |
## Specifying Types For Variables
To specify a type for a variable, use `:` followed by the signature. In this example, the variable `total` can only ever hold integers (or `null`):
```
var total: int = 0;
```
To specify the type of an array or dictionary, use some variation of these signatures:
```
var array: [int] = [1, 2, 3]; //an array of integers
var dictionary: [string : int] = ["key":42]; //a dictionary of key-value pairs
```
Complex, hard-to-write types can be stored in variables, like so:
```
//define a variable called "entry"
var entry: type = astype [string: [string]];
//define a phonebook which follows the above signature
var phonebook: entry = [
"Lucy": ["1234", "Cabbage Ln"],
"Bob": ["5678", "Candy Rd"]
];
```
## Const
Const-ness, or the ability to fix the value of a variable, is part of the type system. To define a constant, follow the type signature with the `const` keyword:
```
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:
```
var members: [int const] = [1, 2, 3]; //1, 2 and 3 cannot be changed, but "members" can be modified or re-assigned
var everything: [int] const = [4, 5, 6]; //everything is now const
```
## 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.
```
var t: type = astype [int]; //t is a type, representing an array of integers
var u: type = [int]; //Error! it tried to assign an array with the sole entry "int"
```
## 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.
```
fn decide(question) {
if (question) {
return int;
}
else {
return float;
}
}
var t = decide(true);
var number: t = 0; //what if it had been false?
```
## 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.
```c
Toy_Literal opaque = TOY_TO_OPAQUE_LITERAL(&data, 0);
//...
void* dataPtr = TOY_AS_OPAQUE(opaque);
int tag = TOY_GET_OPAQUE_TAG(opaque); //for identifying the data in the host
```
Managing and cleaning up opaque data is a task left entirely to the host program - you can do this with the opaque literal's tag.