mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
Tweaked tabs-vs-spaces
This commit is contained in:
@@ -25,3 +25,8 @@
|
||||
|
||||
gtag('config', 'G-57STKDE8LE');
|
||||
</script>
|
||||
|
||||
<!-- tweak for markdown layouts -->
|
||||
<style>
|
||||
* {tab-size: 4;}
|
||||
</style>
|
||||
@@ -10,19 +10,19 @@ To use the drive system, first you must designate specific folders which can be
|
||||
#include "drive_system.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
//the drive system uses a LiteralDictionary, which must be initialized with this
|
||||
Toy_initDriveSystem();
|
||||
//the drive system uses a LiteralDictionary, which must be initialized with this
|
||||
Toy_initDriveSystem();
|
||||
|
||||
Toy_setDrivePath("scripts", "assets/scripts");
|
||||
Toy_setDrivePath("sprites", "assets/sprites");
|
||||
Toy_setDrivePath("fonts", "assets/fonts");
|
||||
Toy_setDrivePath("scripts", "assets/scripts");
|
||||
Toy_setDrivePath("sprites", "assets/sprites");
|
||||
Toy_setDrivePath("fonts", "assets/fonts");
|
||||
|
||||
//TODO: do you stuff here
|
||||
//TODO: do you stuff here
|
||||
|
||||
//clean up the drive dictionary when you're done
|
||||
Toy_freeDriveSystem();
|
||||
//clean up the drive dictionary when you're done
|
||||
Toy_freeDriveSystem();
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ Sometimes, native functions will receive `Toy_Literal` identifiers instead of th
|
||||
```c
|
||||
Toy_Literal foobarIdn = 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,7 +101,7 @@ This function sets the function called by the `print` keyword. By default, the f
|
||||
|
||||
```c
|
||||
static void printWrapper(const char* output) {
|
||||
printf("%s\n", output);
|
||||
printf("%s\n", output);
|
||||
}
|
||||
```
|
||||
|
||||
@@ -113,7 +113,7 @@ This function sets the function called by the `assert` keyword on failure. By de
|
||||
|
||||
```c
|
||||
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
|
||||
static void errorWrapper(const char* output) {
|
||||
fprintf(stderr, "%s", output); //no newline
|
||||
fprintf(stderr, "%s", output); //no newline
|
||||
}
|
||||
```
|
||||
|
||||
@@ -15,17 +15,17 @@ Next, you'll want to run make the from within Toy's `source`, assuming the outpu
|
||||
|
||||
```make
|
||||
toy: $(OUTDIR)
|
||||
$(MAKE) -C Toy/source
|
||||
$(MAKE) -C Toy/source
|
||||
|
||||
$(OUTDIR):
|
||||
mkdir $(OUTDIR)
|
||||
mkdir $(OUTDIR)
|
||||
```
|
||||
|
||||
Finally, link against the outputted library, with the source directory as the location of the header files.
|
||||
|
||||
```make
|
||||
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.
|
||||
|
||||
@@ -237,34 +237,34 @@ Opcodes within the bytecode are 1 byte in length, and specify a single action to
|
||||
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
|
||||
case TOY_OP_PRINT:
|
||||
if (!execPrint(interpreter)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case TOY_OP_PRINT:
|
||||
if (!execPrint(interpreter)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
```
|
||||
|
||||
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
|
||||
static bool execPrint(Toy_Interpreter* interpreter) {
|
||||
//get the top literal
|
||||
Toy_Literal lit = Toy_popLiteralArray(&interpreter->stack);
|
||||
//get the top literal
|
||||
Toy_Literal lit = Toy_popLiteralArray(&interpreter->stack);
|
||||
|
||||
//if the top literal is an identifier, get it's value
|
||||
Toy_Literal idn = lit;
|
||||
if (TOY_IS_IDENTIFIER(lit) && Toy_parseIdentifierToValue(interpreter, &lit)) {
|
||||
Toy_freeLiteral(idn);
|
||||
}
|
||||
//if the top literal is an identifier, get it's value
|
||||
Toy_Literal idn = lit;
|
||||
if (TOY_IS_IDENTIFIER(lit) && Toy_parseIdentifierToValue(interpreter, &lit)) {
|
||||
Toy_freeLiteral(idn);
|
||||
}
|
||||
|
||||
//print as a string to the current print method
|
||||
Toy_printLiteralCustom(lit, interpreter->printOutput);
|
||||
//print as a string to the current print method
|
||||
Toy_printLiteralCustom(lit, interpreter->printOutput);
|
||||
|
||||
//free the literal
|
||||
Toy_freeLiteral(lit);
|
||||
//free the literal
|
||||
Toy_freeLiteral(lit);
|
||||
|
||||
//continue the loop
|
||||
return true;
|
||||
//continue the loop
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -275,7 +275,7 @@ As in most programming languages, variables can be represented by names specifie
|
||||
```c
|
||||
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...
|
||||
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!
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -62,23 +62,23 @@ Hooks can simply inject native functions into the current scope, or they can do
|
||||
```c
|
||||
//a utility structure for storing the native C functions
|
||||
typedef struct Natives {
|
||||
char* name;
|
||||
Toy_NativeFn fn;
|
||||
char* name;
|
||||
Toy_NativeFn fn;
|
||||
} Natives;
|
||||
|
||||
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
|
||||
Natives natives[] = {
|
||||
{"clock", nativeClock},
|
||||
{NULL, NULL}
|
||||
};
|
||||
//the list of available native C functions that can be called from Toy
|
||||
Natives natives[] = {
|
||||
{"clock", nativeClock},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
//inject each native C functions into the current scope
|
||||
for (int i = 0; natives[i].name; i++) {
|
||||
Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn);
|
||||
}
|
||||
//inject each native C functions into the current scope
|
||||
for (int i = 0; natives[i].name; i++) {
|
||||
Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -88,7 +88,7 @@ In some situations, you may find it convenient to call a function written in Toy
|
||||
|
||||
```c
|
||||
TOY_API bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_LiteralArray* arguments, Toy_LiteralArray* returns);
|
||||
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 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.
|
||||
|
||||
@@ -21,19 +21,19 @@ The engine proper is invoked with just three lifecycle functions`:
|
||||
#include "box_engine.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
//initialize the drive system
|
||||
Toy_initDriveSystem();
|
||||
Toy_setDrivePath("scripts", "assets/scripts");
|
||||
//initialize the drive system
|
||||
Toy_initDriveSystem();
|
||||
Toy_setDrivePath("scripts", "assets/scripts");
|
||||
|
||||
//invoke the engine
|
||||
Box_initEngine("scripts:/init.toy"); //passing in the specified init file
|
||||
Box_execEngine();
|
||||
Box_freeEngine();
|
||||
//invoke the engine
|
||||
Box_initEngine("scripts:/init.toy"); //passing in the specified init file
|
||||
Box_execEngine();
|
||||
Box_freeEngine();
|
||||
|
||||
//clean up the drive system when you're done
|
||||
Toy_freeDriveSystem();
|
||||
//clean up the drive system when you're done
|
||||
Toy_freeDriveSystem();
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -46,19 +46,19 @@ You can control the program flow with either `if`, `while` or `for`. The only fa
|
||||
|
||||
```
|
||||
if (check()) {
|
||||
//do this
|
||||
//do this
|
||||
}
|
||||
else {
|
||||
//otherwise do this
|
||||
//otherwise do this
|
||||
}
|
||||
|
||||
var i = 0;
|
||||
while (i < 10) {
|
||||
print i++;
|
||||
print i++;
|
||||
}
|
||||
|
||||
for (var i = 0; i < 10; i++) {
|
||||
print i;
|
||||
print i;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -70,7 +70,7 @@ Functions are defined with the `fn` keyword, and can take any number of argument
|
||||
|
||||
```
|
||||
fn combine(a, b, c) {
|
||||
return [a, b, c];
|
||||
return [a, b, c];
|
||||
}
|
||||
|
||||
print combine(1, 2, 3);
|
||||
@@ -80,7 +80,7 @@ Variable number of parameters, called rest parameters, can be passed in as an ar
|
||||
|
||||
```
|
||||
fn combine(...rest) {
|
||||
return rest;
|
||||
return rest;
|
||||
}
|
||||
|
||||
print combine(1, 2, 3);
|
||||
@@ -92,7 +92,7 @@ Functions can be called using the universal function call syntax, which is just
|
||||
|
||||
```
|
||||
fn printMe(self) {
|
||||
print self;
|
||||
print self;
|
||||
}
|
||||
|
||||
array.printMe();
|
||||
|
||||
@@ -104,7 +104,7 @@ This function takes either an array or a dictionary as the `self` argument and a
|
||||
import standard;
|
||||
|
||||
fn p(i, x) {
|
||||
print x;
|
||||
print x;
|
||||
}
|
||||
|
||||
var a = [1, 3, 5];
|
||||
@@ -136,7 +136,7 @@ This function takes either an array or a dictionary as the `self` argument, and
|
||||
import standard;
|
||||
|
||||
fn increment(k, v) {
|
||||
return v + 1;
|
||||
return v + 1;
|
||||
}
|
||||
|
||||
var a = [1, 2, 3];
|
||||
@@ -152,7 +152,7 @@ This function takes either an array or a dictionary as the `self` argument, a de
|
||||
import standard;
|
||||
|
||||
fn f(acc, k, v) {
|
||||
return acc + v;
|
||||
return acc + v;
|
||||
}
|
||||
|
||||
var a = [1, 2, 3, 4];
|
||||
@@ -172,7 +172,7 @@ This function takes an array as the `self` argument, and a comparison function a
|
||||
import standard;
|
||||
|
||||
fn less(a, b) {
|
||||
return a < b;
|
||||
return a < b;
|
||||
}
|
||||
|
||||
var a = [4, 1, 3, 2];
|
||||
|
||||
@@ -46,8 +46,8 @@ 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"]
|
||||
"Lucy": ["1234", "Cabbage Ln"],
|
||||
"Bob": ["5678", "Candy Rd"]
|
||||
];
|
||||
```
|
||||
|
||||
@@ -82,12 +82,12 @@ Types are first-class citizens. What this means is that they can be used just li
|
||||
|
||||
```
|
||||
fn decide(question) {
|
||||
if (question) {
|
||||
return int;
|
||||
}
|
||||
else {
|
||||
return float;
|
||||
}
|
||||
if (question) {
|
||||
return int;
|
||||
}
|
||||
else {
|
||||
return float;
|
||||
}
|
||||
}
|
||||
|
||||
var t = decide(true);
|
||||
|
||||
Reference in New Issue
Block a user