Compare commits

..

51 Commits

Author SHA1 Message Date
Kayne Ruse 7f5e2a29eb Deprecated old v2 docs branch 2026-05-15 08:51:47 +10:00
Kayne Ruse 8b5a991ed1 Update index.md 2026-05-09 13:10:58 +10:00
Kayne Ruse 511c0280df Update index.md
Added info about my gitea.
2026-05-01 19:17:10 +10:00
Kayne Ruse 34e90879d7 Re-added twitter metatags 2026-04-11 01:18:29 +10:00
Kayne Ruse 08a417a66a Stripped back docs website 2026-04-10 12:32:52 +10:00
Kayne Ruse 60c07d64ef Fixed a typo 2025-03-01 16:21:59 +11:00
Kayne Ruse 0f4d474231 Tweaked repo link 2025-02-28 20:57:51 +11:00
Kayne Ruse a6fc01f7be Updated links after moving the repo 2025-02-28 20:11:03 +11:00
Kayne Ruse 9b68589d87 Swapping v1 and v2 sites 2025-02-28 11:42:53 +11:00
Kayne Ruse 3f0deaeb8a Squish da kitty 2025-02-18 00:04:00 +11:00
Kayne Ruse 5028f9a9f6 Invert blacktocat.png 2025-02-17 23:57:17 +11:00
Kayne Ruse 76437cb093 A better link to the repo 2025-02-17 23:53:22 +11:00
Kayne Ruse 92bc0466eb Added google analytics tag 2025-02-17 23:39:19 +11:00
Kayne Ruse 6eecfc31d6 Tweak 2025-02-02 22:42:57 +11:00
Kayne Ruse f7bab4da10 Tweaked wording 2025-02-02 22:33:11 +11:00
Kayne Ruse d95c6e6479 Oh fuck Jekyll. If this doesn't work, I'm leaving it for now. 2025-02-02 17:11:07 +11:00
Kayne Ruse 47e6983ad1 Jekyll is an ass. 2025-02-02 17:04:21 +11:00
Kayne Ruse 66e8c0fa7a ffs. 2025-02-02 17:00:55 +11:00
Kayne Ruse 2ea552fedd Fixed syntax include 2025-02-02 16:55:40 +11:00
Kayne Ruse 3747d0a326 Tweaked syntax highlighting, added control flow to docs
I also found some issues in the code, so I fixed them first.
2025-02-02 16:44:34 +11:00
Kayne Ruse c2a13e4183 Well, I clucked that up. 2025-01-24 17:15:58 +11:00
Kayne Ruse 062f676f52 Nothing to see here. 2025-01-24 17:11:51 +11:00
Kayne Ruse f5ebbdf847 link to source 2025-01-22 10:22:22 +11:00
Kayne Ruse 1a3d08958b That overflow-x is odd 2025-01-22 10:14:52 +11:00
Kayne Ruse b1a08289e2 Fixing bounds 2025-01-22 10:07:51 +11:00
Kayne Ruse f1c2e449ea Oh, come on 2025-01-22 09:59:47 +11:00
Kayne Ruse a95ed58cd8 There we go 2025-01-22 09:54:59 +11:00
Kayne Ruse 74a898aa47 Does this work? 2025-01-22 09:49:19 +11:00
Kayne Ruse 32601ae9a9 Hide title on mobile 2025-01-22 09:42:34 +11:00
Kayne Ruse 8610ac2529 Started writing some docs 2025-01-14 13:21:09 +11:00
Kayne Ruse 782f60da9f Is it done? 2025-01-12 16:21:10 +11:00
Kayne Ruse 3a25df60e3 Tweaked text column 2025-01-12 16:19:22 +11:00
Kayne Ruse 7d35c5b325 Trying to fix sort order 2025-01-12 16:16:38 +11:00
Kayne Ruse 1e432387c2 Moved the badge 2025-01-12 16:11:12 +11:00
Kayne Ruse 42dbe038cf Tweaked the style 2025-01-12 16:05:25 +11:00
Kayne Ruse 9563185ef1 filling out placeholder files 2025-01-12 15:17:47 +11:00
Kayne Ruse 1db834f721 Added deploy workflow file 2025-01-12 12:30:42 +11:00
Kayne Ruse f39d725001 Trying a new jekyll theme 2025-01-12 12:26:23 +11:00
Kayne Ruse 98ccfb4215 Forcing a deploy 2025-01-11 22:11:37 +11:00
Kayne Ruse 9d26f94e25 tweak 2025-01-11 22:02:54 +11:00
Kayne Ruse ba4d4fedc1 Attempting to make a deployment mirror 2025-01-11 21:26:22 +11:00
Kayne Ruse b2825690ec Whoops 2025-01-03 16:17:14 +11:00
Kayne Ruse 46d5d7245a I wonder if... 2025-01-03 16:14:15 +11:00
Kayne Ruse b0194db1c4 Fiddling with DNS stuff 2025-01-01 21:36:56 +11:00
Kayne Ruse dc8845fd0e Starting fiddling with the docs site proper 2024-12-27 13:40:49 +11:00
Kayne Ruse 2c4324db70 Update operators.md 2024-11-17 20:20:31 +11:00
Kayne Ruse 28b5c2dab0 Update reserved-words.md 2024-11-17 20:12:13 +11:00
Kayne Ruse ebdc4c6cff Update README.md 2024-11-17 20:09:37 +11:00
Kayne Ruse 151ad7656d Added more reserved words 2024-10-27 18:09:52 +11:00
Kayne Ruse 94fabf2f4e Added types.md 2024-10-27 17:59:44 +11:00
Kayne Ruse 655827f672 Initial commit with a few basic files 2024-10-19 21:11:00 +11:00
135 changed files with 119 additions and 15779 deletions
-5
View File
@@ -1,5 +0,0 @@
# These are supported funding model platforms
patreon: krgamestudios
ko_fi: krgamestudios
custom: ["https://www.paypal.com/donate/?hosted_button_id=73Q82T2ZHV8AA"]
-28
View File
@@ -1,28 +0,0 @@
name: Comprehensive Tests
on:
push:
branches: [ "main", "dev" ]
pull_request:
branches: [ "main" ]
jobs:
test-valgrind:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: install valgrind
run: sudo apt install valgrind
- name: make test (valgrind)
run: make test
test-sanitized:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: make test (sanitized)
run: make test-sanitized
-31
View File
@@ -1,31 +0,0 @@
#Editor generated files
*.sln
*.vcproj
*.suo
*.ncb
*.user
compile_commands.json
#Directories
Release/
Debug/
Out/
release/
debug/
out/
.cache/
#Project generated files
*.db
*.o
*.a
*.exe
*.meta
*.log
out
*.stackdump
*.tb
#Shell files
*.bat
*.sh
+1
View File
@@ -0,0 +1 @@
v2.toylang.com
-13
View File
@@ -1,13 +0,0 @@
# License
Copyright (c) 2020-2023 Kayne Ruse, KR Game Studios
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
+2 -74
View File
@@ -1,76 +1,4 @@
<p align="center">
<image src="toylogo.png" />
</p>
This git branch is the (now deprecated) documentation website for The Toy Programming Language version 2.x, which can be found at [https://github.com/krgamestudios/Toy](https://github.com/krgamestudios/Toy).
# Toy
This is the Toy programming language interpreter, written in C.
Special thanks to http://craftinginterpreters.com/ for their fantastic book that set me on this path.
# Nifty Features
* Simple C-like syntax
* Bytecode intermediate compilation
* Optional, but robust type system (including `opaque` for arbitrary data)
* Functions and types are first-class citizens
* Import external libraries
* Fancy slice notation for strings, arrays and dictionaries
* Can re-direct output, error and assertion failure messages
* Open source under the zlib license
## Building
For Windows, Linux and MacOS, simply run `make` in the root directory.
Note: For Linux, you may need to `cd` into the `out` directory before running.
Note: MacOS is not officially supported (no machines for testing), but we'll do our best!
## Tools
Run `make install-tools` to install a number of tools, including:
* VSCode syntax highlighting
## Syntax
```
import standard; //for a bunch of utility functions
print "Hello world"; //"print" is a keyword
var msg = "foobar"; //declare a variable like this
assert true, "This message won't be seen"; //assert is another keyword
//-------------------------
fn makeCounter() { //declare a function like this
var total: int = 0; //declare a variable with a type like this
fn counter(): int { //declare a return type like this
return ++total;
}
return counter; //closures are explicitly supported
}
var tally = makeCounter();
print tally(); //1
print tally(); //2
print tally(); //3
export tally; //export this variable to the host program
```
# License
This source code is covered by the zlib license (see [LICENSE.md](LICENSE.md)).
# Patrons via Patreon
* Seth A. Robinson
Toy v2.x is still under active development, so this documentation will change and evolve over time, and may not reflect the current reference implementation.
+4
View File
@@ -0,0 +1,4 @@
title: The Toy Programming Language
description: Documentation For The Toy Programming Language
keywords: programming,coding
author: Kayne Ruse (Ratstail91)
+8
View File
@@ -0,0 +1,8 @@
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-WQ8Q1JV8E8"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-WQ8Q1JV8E8');
</script>
+21
View File
@@ -0,0 +1,21 @@
<!-- site information -->
<meta name="description" content="{{ site.description }}" />
<meta name="author" content="{{ site.author }}" />
<meta name="keywords" content="{{ site.keywords }}" />
<!-- facebook -->
<meta property="og:url" content="{{ site.url }}" />
<meta property="og:type" content="website" />
<meta property="og:image" content="{{ site.baseurl }}/assets/repo-preview.png" />
<meta property="og:title" content="{{ page.title }}" />
<meta property="og:description" content="{{ page.description }}" />
<!-- twitter -->
<meta name="twitter:card" content="{{ site.title }}" />
<meta name="twitter:url" content="{{ site.url}}" />
<meta name="twitter:type" content="website" />
<meta name="twitter:image" content="{{ site.baseurl }}/assets/repo-preview.png" />
<meta name="twitter:title" content="{{ page.title }}" />
<meta name="twitter:description" content="{{ page.description }}" />
<link rel="icon" href="{{ site.baseurl }}/favicon.png">
+21
View File
@@ -0,0 +1,21 @@
<!doctype html>
<html lang="en">
<head>
<!-- device settings -->
<meta charset = "UTF-8" />
<meta name="Content-Type" content="text/html" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- page title -->
<title>{{ page.title }}</title>
{% include metadata.html %}
{% include analytics.html %}
</head>
<body>
{{ content }}
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

+9
View File
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/mstile-150x150.png"/>
<TileColor>#da532c</TileColor>
</tile>
</msapplication>
</browserconfig>
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

+18
View File
@@ -0,0 +1,18 @@
---
layout: page
title: The Toy Programming Language
---
<div style="justify-self: center;">
<image src="assets/toylogo.png" width="250" height="250" />
</div>
<div style="justify-self: center;">
<a href="https://github.com/krgamestudios/Toy"><img src="https://github.com/krgamestudios/Toy/actions/workflows/continuous-integration-v2.yml/badge.svg"></a>
</div>
The Toy Programming Language is an imperative, bytecode-interpreted, embeddable scripting language. Rather than functioning independently, it serves as part of another program, the "host". This design allows for straightforward customization by both the host's developers and end users, achieved by exposing program logic through text files.
The documentation on this website is under construction, for further information, see the repository: [https://gitea.krgamestudios.com/krgamestudios/Toy](https://gitea.krgamestudios.com/krgamestudios/Toy), or the GitHub mirror: [https://github.com/krgamestudios/Toy](https://github.com/krgamestudios/Toy).
An example of Toy in action: [Vampire Toyvivors](https://gitea.krgamestudios.com/krgamestudios/VampireToyvivors).
-88
View File
@@ -1,88 +0,0 @@
# Optimisation Options
# export CFLAGS+=-O2 -mtune=native -march=native
# export CFLAGS+=-fsanitize=address,undefined
export TOY_OUTDIR = out
all: $(TOY_OUTDIR) repl
#repl builds
repl: $(TOY_OUTDIR) library
$(MAKE) -C repl
repl-static: $(TOY_OUTDIR) static
$(MAKE) -C repl
repl-release: clean $(TOY_OUTDIR) library-release
$(MAKE) -C repl release
repl-static-release: clean $(TOY_OUTDIR) static-release
$(MAKE) -C repl release
#lib builds
library: $(TOY_OUTDIR)
$(MAKE) -j8 -C source library
static: $(TOY_OUTDIR)
$(MAKE) -j8 -C source static
library-release: $(TOY_OUTDIR)
$(MAKE) -j8 -C source library-release
static-release: $(TOY_OUTDIR)
$(MAKE) -j8 -C source static-release
#utils
test: clean $(TOY_OUTDIR)
$(MAKE) -C test
test-sanitized: export CFLAGS+=-fsanitize=address,undefined
test-sanitized: export LIBS+=-static-libasan
test-sanitized: export DISABLE_VALGRIND=true
test-sanitized: clean $(TOY_OUTDIR)
$(MAKE) -C test
$(TOY_OUTDIR):
mkdir $(TOY_OUTDIR)
#utils
install-tools:
cp -rf tools/toylang.vscode-highlighting ~/.vscode/extensions
.PHONY: clean
clean:
ifeq ($(findstring CYGWIN, $(shell uname)),CYGWIN)
find . -type f -name '*.o' -exec rm -f -r -v {} \;
find . -type f -name '*.a' -exec rm -f -r -v {} \;
find . -type f -name '*.exe' -exec rm -f -r -v {} \;
find . -type f -name '*.dll' -exec rm -f -r -v {} \;
find . -type f -name '*.lib' -exec rm -f -r -v {} \;
find . -type f -name '*.so' -exec rm -f -r -v {} \;
find . -empty -type d -delete
else ifeq ($(shell uname),Linux)
find . -type f -name '*.o' -exec rm -f -r -v {} \;
find . -type f -name '*.a' -exec rm -f -r -v {} \;
find . -type f -name '*.exe' -exec rm -f -r -v {} \;
find . -type f -name '*.dll' -exec rm -f -r -v {} \;
find . -type f -name '*.lib' -exec rm -f -r -v {} \;
find . -type f -name '*.so' -exec rm -f -r -v {} \;
rm -rf out
find . -empty -type d -delete
else ifeq ($(OS),Windows_NT)
$(RM) *.o *.a *.exe
else ifeq ($(shell uname),Darwin)
find . -type f -name '*.o' -exec rm -f -r -v {} \;
find . -type f -name '*.a' -exec rm -f -r -v {} \;
find . -type f -name '*.exe' -exec rm -f -r -v {} \;
find . -type f -name '*.dll' -exec rm -f -r -v {} \;
find . -type f -name '*.lib' -exec rm -f -r -v {} \;
find . -type f -name '*.dylib' -exec rm -f -r -v {} \;
find . -type f -name '*.so' -exec rm -f -r -v {} \;
rm -rf out
find . -empty -type d -delete
else
@echo "Deletion failed - what platform is this?"
endif
rebuild: clean all
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

-613
View File
@@ -1,613 +0,0 @@
#include "lib_runner.h"
#include "toy_memory.h"
#include "toy_interpreter.h"
#include "repl_tools.h"
#include <stdio.h>
#include <stdlib.h>
typedef struct Toy_Runner {
Toy_Interpreter interpreter;
unsigned char* bytecode;
size_t size;
bool dirty;
} Toy_Runner;
//Toy native functions
static int nativeLoadScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to loadScript\n");
return -1;
}
//get the argument
Toy_Literal drivePathLiteral = Toy_popLiteralArray(arguments);
Toy_RefString* drivePath = Toy_copyRefString(TOY_AS_STRING(drivePathLiteral));
//get the drive and path as a string (can't trust that pesky strtok - custom split) TODO: move this to refstring library
int driveLength = 0;
while (Toy_toCString(drivePath)[driveLength] != ':') {
if (driveLength >= Toy_lengthRefString(drivePath)) {
interpreter->errorOutput("Incorrect drive path format given to loadScript\n");
Toy_deleteRefString(drivePath);
Toy_freeLiteral(drivePathLiteral);
return -1;
}
driveLength++;
}
Toy_RefString* drive = Toy_createRefStringLength(Toy_toCString(drivePath), driveLength);
Toy_RefString* path = Toy_createRefStringLength( &Toy_toCString(drivePath)[driveLength + 1], Toy_lengthRefString(drivePath) - driveLength );
//get the real drive file path
Toy_Literal driveLiteral = TOY_TO_STRING_LITERAL(drive); //NOTE: driveLiteral takes ownership of the refString
Toy_Literal realDriveLiteral = Toy_getLiteralDictionary(Toy_getDriveDictionary(), driveLiteral);
if (!TOY_IS_STRING(realDriveLiteral)) {
interpreter->errorOutput("Incorrect literal type found for drive: ");
Toy_printLiteralCustom(realDriveLiteral, interpreter->errorOutput);
interpreter->errorOutput("\n");
Toy_freeLiteral(realDriveLiteral);
Toy_freeLiteral(driveLiteral);
Toy_deleteRefString(path);
Toy_deleteRefString(drivePath);
Toy_freeLiteral(drivePathLiteral);
return -1;
}
//get the final real file path (concat) TODO: move this concat to refstring library
Toy_RefString* realDrive = Toy_copyRefString(TOY_AS_STRING(realDriveLiteral));
int realLength = Toy_lengthRefString(realDrive) + Toy_lengthRefString(path);
char* filePath = TOY_ALLOCATE(char, realLength + 1); //+1 for null
snprintf(filePath, realLength, "%s%s", Toy_toCString(realDrive), Toy_toCString(path));
//clean up the drivepath stuff
Toy_deleteRefString(realDrive);
Toy_freeLiteral(realDriveLiteral);
Toy_freeLiteral(driveLiteral);
Toy_deleteRefString(path);
Toy_deleteRefString(drivePath);
Toy_freeLiteral(drivePathLiteral);
//check for file extensions
if (!(filePath[realLength - 5] == '.' && filePath[realLength - 4] == 't' && filePath[realLength - 3] == 'o' && filePath[realLength - 2] == 'y')) {
interpreter->errorOutput("Bad script file extension (expected .toy)\n");
TOY_FREE_ARRAY(char, filePath, realLength);
return -1;
}
//check for break-out attempts
for (int i = 0; i < realLength - 1; i++) {
if (filePath[i] == '.' && filePath[i + 1] == '.') {
interpreter->errorOutput("Parent directory access not allowed\n");
TOY_FREE_ARRAY(char, filePath, realLength);
return -1;
}
}
//load and compile the bytecode
size_t fileSize = 0;
char* source = Toy_readFile(filePath, &fileSize);
if (!source) {
interpreter->errorOutput("Failed to load source file\n");
return -1;
}
unsigned char* bytecode = Toy_compileString(source, &fileSize);
free((void*)source);
if (!bytecode) {
interpreter->errorOutput("Failed to compile source file\n");
return -1;
}
//build the runner object
Toy_Runner* runner = TOY_ALLOCATE(Toy_Runner, 1);
Toy_setInterpreterPrint(&runner->interpreter, interpreter->printOutput);
Toy_setInterpreterAssert(&runner->interpreter, interpreter->assertOutput);
Toy_setInterpreterError(&runner->interpreter, interpreter->errorOutput);
runner->interpreter.hooks = interpreter->hooks;
runner->interpreter.scope = NULL;
Toy_resetInterpreter(&runner->interpreter);
runner->bytecode = bytecode;
runner->size = fileSize;
runner->dirty = false;
//build the opaque object, and push it to the stack
Toy_Literal runnerLiteral = TOY_TO_OPAQUE_LITERAL(runner, TOY_OPAQUE_TAG_RUNNER);
Toy_pushLiteralArray(&interpreter->stack, runnerLiteral);
TOY_FREE_ARRAY(char, filePath, realLength);
return 1;
}
static int nativeLoadScriptBytecode(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to loadScriptBytecode\n");
return -1;
}
//get the argument
Toy_Literal drivePathLiteral = Toy_popLiteralArray(arguments);
Toy_RefString* drivePath = Toy_copyRefString(TOY_AS_STRING(drivePathLiteral));
//get the drive and path as a string (can't trust that pesky strtok - custom split) TODO: move this to refstring library
int driveLength = 0;
while (Toy_toCString(drivePath)[driveLength] != ':') {
if (driveLength >= Toy_lengthRefString(drivePath)) {
interpreter->errorOutput("Incorrect drive path format given to loadScriptBytecode\n");
Toy_deleteRefString(drivePath);
Toy_freeLiteral(drivePathLiteral);
return -1;
}
driveLength++;
}
Toy_RefString* drive = Toy_createRefStringLength(Toy_toCString(drivePath), driveLength);
Toy_RefString* path = Toy_createRefStringLength( &Toy_toCString(drivePath)[driveLength + 1], Toy_lengthRefString(drivePath) - driveLength );
//get the real drive file path
Toy_Literal driveLiteral = TOY_TO_STRING_LITERAL(drive); //NOTE: driveLiteral takes ownership of the refString
Toy_Literal realDriveLiteral = Toy_getLiteralDictionary(Toy_getDriveDictionary(), driveLiteral);
if (!TOY_IS_STRING(realDriveLiteral)) {
interpreter->errorOutput("Incorrect literal type found for drive: ");
Toy_printLiteralCustom(realDriveLiteral, interpreter->errorOutput);
interpreter->errorOutput("\n");
Toy_freeLiteral(realDriveLiteral);
Toy_freeLiteral(driveLiteral);
Toy_deleteRefString(path);
Toy_deleteRefString(drivePath);
Toy_freeLiteral(drivePathLiteral);
return -1;
}
//get the final real file path (concat) TODO: move this concat to refstring library
Toy_RefString* realDrive = Toy_copyRefString(TOY_AS_STRING(realDriveLiteral));
int realLength = Toy_lengthRefString(realDrive) + Toy_lengthRefString(path);
char* filePath = TOY_ALLOCATE(char, realLength + 1); //+1 for null
snprintf(filePath, realLength, "%s%s", Toy_toCString(realDrive), Toy_toCString(path));
//clean up the drivepath stuff
Toy_deleteRefString(realDrive);
Toy_freeLiteral(realDriveLiteral);
Toy_freeLiteral(driveLiteral);
Toy_deleteRefString(path);
Toy_deleteRefString(drivePath);
Toy_freeLiteral(drivePathLiteral);
//check for file extensions
if (!(filePath[realLength - 4] == '.' && filePath[realLength - 3] == 't' && filePath[realLength - 2] == 'b')) {
interpreter->errorOutput("Bad binary file extension (expected .tb)\n");
TOY_FREE_ARRAY(char, filePath, realLength);
return -1;
}
//check for break-out attempts
for (int i = 0; i < realLength - 1; i++) {
if (filePath[i] == '.' && filePath[i + 1] == '.') {
interpreter->errorOutput("Parent directory access not allowed\n");
TOY_FREE_ARRAY(char, filePath, realLength);
return -1;
}
}
//load the bytecode
size_t fileSize = 0;
unsigned char* bytecode = (unsigned char*)Toy_readFile(filePath, &fileSize);
if (!bytecode) {
interpreter->errorOutput("Failed to load bytecode file\n");
return -1;
}
//build the runner object
Toy_Runner* runner = TOY_ALLOCATE(Toy_Runner, 1);
Toy_setInterpreterPrint(&runner->interpreter, interpreter->printOutput);
Toy_setInterpreterAssert(&runner->interpreter, interpreter->assertOutput);
Toy_setInterpreterError(&runner->interpreter, interpreter->errorOutput);
runner->interpreter.hooks = interpreter->hooks;
runner->interpreter.scope = NULL;
Toy_resetInterpreter(&runner->interpreter);
runner->bytecode = bytecode;
runner->size = fileSize;
runner->dirty = false;
//build the opaque object, and push it to the stack
Toy_Literal runnerLiteral = TOY_TO_OPAQUE_LITERAL(runner, TOY_OPAQUE_TAG_RUNNER);
Toy_pushLiteralArray(&interpreter->stack, runnerLiteral);
TOY_FREE_ARRAY(char, filePath, realLength);
return 1;
}
static int nativeRunScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _runScript\n");
return -1;
}
//get the runner object
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
Toy_Literal runnerIdn = runnerLiteral;
if (TOY_IS_IDENTIFIER(runnerLiteral) && Toy_parseIdentifierToValue(interpreter, &runnerLiteral)) {
Toy_freeLiteral(runnerIdn);
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
return -1;
}
Toy_Runner* runner = TOY_AS_OPAQUE(runnerLiteral);
//run
if (runner->dirty) {
interpreter->errorOutput("Can't re-run a dirty script (try resetting it first)\n");
Toy_freeLiteral(runnerLiteral);
return -1;
}
unsigned char* bytecodeCopy = TOY_ALLOCATE(unsigned char, runner->size);
memcpy(bytecodeCopy, runner->bytecode, runner->size); //need a COPY of the bytecode, because the interpreter eats it
Toy_runInterpreter(&runner->interpreter, bytecodeCopy, runner->size);
runner->dirty = true;
//cleanup
Toy_freeLiteral(runnerLiteral);
return 0;
}
static int nativeGetScriptVar(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments to _getScriptVar\n");
return -1;
}
//get the runner object
Toy_Literal varName = Toy_popLiteralArray(arguments);
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
Toy_Literal varNameIdn = varName;
if (TOY_IS_IDENTIFIER(varName) && Toy_parseIdentifierToValue(interpreter, &varName)) {
Toy_freeLiteral(varNameIdn);
}
Toy_Literal runnerIdn = runnerLiteral;
if (TOY_IS_IDENTIFIER(runnerLiteral) && Toy_parseIdentifierToValue(interpreter, &runnerLiteral)) {
Toy_freeLiteral(runnerIdn);
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
return -1;
}
Toy_Runner* runner = TOY_AS_OPAQUE(runnerLiteral);
//dirty check
if (!runner->dirty) {
interpreter->errorOutput("Can't access variable from a non-dirty script (try running it first)\n");
Toy_freeLiteral(runnerLiteral);
return -1;
}
//get the desired variable
Toy_Literal varIdn = TOY_TO_IDENTIFIER_LITERAL(Toy_copyRefString(TOY_AS_STRING(varName)));
Toy_Literal result = TOY_TO_NULL_LITERAL;
Toy_getScopeVariable(runner->interpreter.scope, varIdn, &result);
Toy_pushLiteralArray(&interpreter->stack, result);
//cleanup
Toy_freeLiteral(result);
Toy_freeLiteral(varIdn);
Toy_freeLiteral(varName);
Toy_freeLiteral(runnerLiteral);
return 1;
}
static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count < 2) {
interpreter->errorOutput("Incorrect number of arguments to _callScriptFn\n");
return -1;
}
//get the rest args
Toy_LiteralArray tmp;
Toy_initLiteralArray(&tmp);
while (arguments->count > 2) {
Toy_Literal lit = Toy_popLiteralArray(arguments);
Toy_pushLiteralArray(&tmp, lit);
Toy_freeLiteral(lit);
}
Toy_LiteralArray rest;
Toy_initLiteralArray(&rest);
while (tmp.count) { //correct the order of the rest args
Toy_Literal lit = Toy_popLiteralArray(&tmp);
Toy_pushLiteralArray(&rest, lit);
Toy_freeLiteral(lit);
}
Toy_freeLiteralArray(&tmp);
//get the runner object
Toy_Literal varName = Toy_popLiteralArray(arguments);
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
Toy_Literal varNameIdn = varName;
if (TOY_IS_IDENTIFIER(varName) && Toy_parseIdentifierToValue(interpreter, &varName)) {
Toy_freeLiteral(varNameIdn);
}
Toy_Literal runnerIdn = runnerLiteral;
if (TOY_IS_IDENTIFIER(runnerLiteral) && Toy_parseIdentifierToValue(interpreter, &runnerLiteral)) {
Toy_freeLiteral(runnerIdn);
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
return -1;
}
Toy_Runner* runner = TOY_AS_OPAQUE(runnerLiteral);
//dirty check
if (!runner->dirty) {
interpreter->errorOutput("Can't access fn from a non-dirty script (try running it first)\n");
Toy_freeLiteral(runnerLiteral);
Toy_freeLiteralArray(&rest);
return -1;
}
//get the desired variable
Toy_Literal varIdn = TOY_TO_IDENTIFIER_LITERAL(Toy_copyRefString(TOY_AS_STRING(varName)));
Toy_Literal fn = TOY_TO_NULL_LITERAL;
Toy_getScopeVariable(runner->interpreter.scope, varIdn, &fn);
if (!TOY_IS_FUNCTION(fn)) {
interpreter->errorOutput("Can't run a non-function literal\n");
Toy_freeLiteral(fn);
Toy_freeLiteral(varIdn);
Toy_freeLiteral(varName);
Toy_freeLiteral(runnerLiteral);
Toy_freeLiteralArray(&rest);
}
//call
Toy_LiteralArray resultArray;
Toy_initLiteralArray(&resultArray);
Toy_callLiteralFn(interpreter, fn, &rest, &resultArray);
Toy_Literal result = TOY_TO_NULL_LITERAL;
if (resultArray.count > 0) {
result = Toy_popLiteralArray(&resultArray);
}
Toy_pushLiteralArray(&interpreter->stack, result);
//cleanup
Toy_freeLiteralArray(&resultArray);
Toy_freeLiteral(result);
Toy_freeLiteral(fn);
Toy_freeLiteral(varIdn);
Toy_freeLiteral(varName);
Toy_freeLiteral(runnerLiteral);
Toy_freeLiteralArray(&rest);
return 1;
}
static int nativeResetScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _resetScript\n");
return -1;
}
//get the runner object
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
Toy_Literal runnerIdn = runnerLiteral;
if (TOY_IS_IDENTIFIER(runnerLiteral) && Toy_parseIdentifierToValue(interpreter, &runnerLiteral)) {
Toy_freeLiteral(runnerIdn);
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
return -1;
}
Toy_Runner* runner = TOY_AS_OPAQUE(runnerLiteral);
//reset
if (!runner->dirty) {
interpreter->errorOutput("Can't reset a non-dirty script (try running it first)\n");
Toy_freeLiteral(runnerLiteral);
return -1;
}
Toy_resetInterpreter(&runner->interpreter);
runner->dirty = false;
Toy_freeLiteral(runnerLiteral);
return 0;
}
static int nativeFreeScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _freeScript\n");
return -1;
}
//get the runner object
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
Toy_Literal runnerIdn = runnerLiteral;
if (TOY_IS_IDENTIFIER(runnerLiteral) && Toy_parseIdentifierToValue(interpreter, &runnerLiteral)) {
Toy_freeLiteral(runnerIdn);
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _freeScript\n");
return -1;
}
Toy_Runner* runner = TOY_AS_OPAQUE(runnerLiteral);
//clear out the runner object
runner->interpreter.hooks = NULL;
Toy_freeInterpreter(&runner->interpreter);
TOY_FREE_ARRAY(unsigned char, runner->bytecode, runner->size);
TOY_FREE(Toy_Runner, runner);
Toy_freeLiteral(runnerLiteral);
return 0;
}
static int nativeCheckScriptDirty(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _runScript\n");
return -1;
}
//get the runner object
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
Toy_Literal runnerIdn = runnerLiteral;
if (TOY_IS_IDENTIFIER(runnerLiteral) && Toy_parseIdentifierToValue(interpreter, &runnerLiteral)) {
Toy_freeLiteral(runnerIdn);
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
return -1;
}
Toy_Runner* runner = TOY_AS_OPAQUE(runnerLiteral);
//run
Toy_Literal result = TOY_TO_BOOLEAN_LITERAL(runner->dirty);
Toy_pushLiteralArray(&interpreter->stack, result);
//cleanup
Toy_freeLiteral(result);
Toy_freeLiteral(runnerLiteral);
return 0;
}
//call the hook
typedef struct Natives {
char* name;
Toy_NativeFn fn;
} Natives;
int Toy_hookRunner(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
//build the natives list
Natives natives[] = {
{"loadScript", nativeLoadScript},
{"loadScriptBytecode", nativeLoadScriptBytecode},
{"_runScript", nativeRunScript},
{"_getScriptVar", nativeGetScriptVar},
{"_callScriptFn", nativeCallScriptFn},
{"_resetScript", nativeResetScript},
{"_freeScript", nativeFreeScript},
{"_checkScriptDirty", nativeCheckScriptDirty},
{NULL, NULL}
};
//store the library in an aliased dictionary
if (!TOY_IS_NULL(alias)) {
//make sure the name isn't taken
if (Toy_isDelcaredScopeVariable(interpreter->scope, alias)) {
interpreter->errorOutput("Can't override an existing variable\n");
Toy_freeLiteral(alias);
return false;
}
//create the dictionary to load up with functions
Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
Toy_initLiteralDictionary(dictionary);
//load the dict with functions
for (int i = 0; natives[i].name; i++) {
Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name));
Toy_Literal func = TOY_TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
func.type = TOY_LITERAL_FUNCTION_NATIVE;
Toy_setLiteralDictionary(dictionary, name, func);
Toy_freeLiteral(name);
Toy_freeLiteral(func);
}
//build the type
Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true);
Toy_Literal strType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true);
Toy_Literal fnType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FUNCTION_NATIVE, true);
TOY_TYPE_PUSH_SUBTYPE(&type, strType);
TOY_TYPE_PUSH_SUBTYPE(&type, fnType);
//set scope
Toy_Literal dict = TOY_TO_DICTIONARY_LITERAL(dictionary);
Toy_declareScopeVariable(interpreter->scope, alias, type);
Toy_setScopeVariable(interpreter->scope, alias, dict, false);
//cleanup
Toy_freeLiteral(dict);
Toy_freeLiteral(type);
return 0;
}
//default
for (int i = 0; natives[i].name; i++) {
Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn);
}
return 0;
}
//file system API
static Toy_LiteralDictionary Toy_driveDictionary;
void Toy_initDriveDictionary() {
Toy_initLiteralDictionary(&Toy_driveDictionary);
}
void Toy_freeDriveDictionary() {
Toy_freeLiteralDictionary(&Toy_driveDictionary);
}
Toy_LiteralDictionary* Toy_getDriveDictionary() {
return &Toy_driveDictionary;
}
-12
View File
@@ -1,12 +0,0 @@
#pragma once
#include "toy_interpreter.h"
int Toy_hookRunner(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
//file system API - these need to be set by the host
void Toy_initDriveDictionary();
void Toy_freeDriveDictionary();
Toy_LiteralDictionary* Toy_getDriveDictionary();
#define TOY_OPAQUE_TAG_RUNNER 100
-95
View File
@@ -1,95 +0,0 @@
#include "lib_standard.h"
#include "toy_memory.h"
#include <time.h>
#include <sys/time.h>
static int nativeClock(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 0) {
interpreter->errorOutput("Incorrect number of arguments to clock\n");
return -1;
}
//get the time from C (what a pain)
time_t rawtime = time(NULL);
struct tm* timeinfo = localtime( &rawtime );
char* timestr = asctime(timeinfo);
//push to the stack
int len = strlen(timestr) - 1; //-1 for the newline
Toy_Literal timeLiteral = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(timestr, len));
//push to the stack
Toy_pushLiteralArray(&interpreter->stack, timeLiteral);
//cleanup
Toy_freeLiteral(timeLiteral);
return 1;
}
//call the hook
typedef struct Natives {
char* name;
Toy_NativeFn fn;
} Natives;
int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
//build the natives list
Natives natives[] = {
{"clock", nativeClock},
{NULL, NULL}
};
//store the library in an aliased dictionary
if (!TOY_IS_NULL(alias)) {
//make sure the name isn't taken
if (Toy_isDelcaredScopeVariable(interpreter->scope, alias)) {
interpreter->errorOutput("Can't override an existing variable\n");
Toy_freeLiteral(alias);
return false;
}
//create the dictionary to load up with functions
Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
Toy_initLiteralDictionary(dictionary);
//load the dict with functions
for (int i = 0; natives[i].name; i++) {
Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name));
Toy_Literal func = TOY_TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
func.type = TOY_LITERAL_FUNCTION_NATIVE;
Toy_setLiteralDictionary(dictionary, name, func);
Toy_freeLiteral(name);
Toy_freeLiteral(func);
}
//build the type
Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true);
Toy_Literal strType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true);
Toy_Literal fnType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FUNCTION_NATIVE, true);
TOY_TYPE_PUSH_SUBTYPE(&type, strType);
TOY_TYPE_PUSH_SUBTYPE(&type, fnType);
//set scope
Toy_Literal dict = TOY_TO_DICTIONARY_LITERAL(dictionary);
Toy_declareScopeVariable(interpreter->scope, alias, type);
Toy_setScopeVariable(interpreter->scope, alias, dict, false);
//cleanup
Toy_freeLiteral(dict);
Toy_freeLiteral(type);
return 0;
}
//default
for (int i = 0; natives[i].name; i++) {
Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn);
}
return 0;
}
-6
View File
@@ -1,6 +0,0 @@
#pragma once
#include "toy_interpreter.h"
int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
-412
View File
@@ -1,412 +0,0 @@
#include "lib_timer.h"
#include "toy_memory.h"
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
//GOD DAMN IT: https://stackoverflow.com/questions/15846762/timeval-subtract-explanation
static int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y) {
//normallize
if (x->tv_usec > 999999) {
x->tv_sec += x->tv_usec / 1000000;
x->tv_usec %= 1000000;
}
if (y->tv_usec > 999999) {
y->tv_sec += y->tv_usec / 1000000;
y->tv_usec %= 1000000;
}
//calc
result->tv_sec = x->tv_sec - y->tv_sec;
if ((result->tv_usec = x->tv_usec - y->tv_usec) < 0) {
if (result->tv_sec != 0) { //only works far from 0
result->tv_usec += 1000000;
result->tv_sec--; // borrow
}
}
return result->tv_sec < 0 || (result->tv_sec == 0 && result->tv_usec < 0);
}
//god damn it
static struct timeval* diff(struct timeval* lhs, struct timeval* rhs) {
struct timeval* d = TOY_ALLOCATE(struct timeval, 1);
//I gave up, copied from SO
timeval_subtract(d, rhs, lhs);
return d;
}
//callbacks
static int nativeStartTimer(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 0) {
interpreter->errorOutput("Incorrect number of arguments to startTimer\n");
return -1;
}
//get the timeinfo from C
struct timeval* timeinfo = TOY_ALLOCATE(struct timeval, 1);
gettimeofday(timeinfo, NULL);
//wrap in an opaque literal for Toy
Toy_Literal timeLiteral = TOY_TO_OPAQUE_LITERAL(timeinfo, -1);
Toy_pushLiteralArray(&interpreter->stack, timeLiteral);
Toy_freeLiteral(timeLiteral);
return 1;
}
static int nativeStopTimer(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _stopTimer\n");
return -1;
}
//get the timeinfo from C
struct timeval timerStop;
gettimeofday(&timerStop, NULL);
//unwrap the opaque literal
Toy_Literal timeLiteral = Toy_popLiteralArray(arguments);
Toy_Literal timeLiteralIdn = timeLiteral;
if (TOY_IS_IDENTIFIER(timeLiteral) && Toy_parseIdentifierToValue(interpreter, &timeLiteral)) {
Toy_freeLiteral(timeLiteralIdn);
}
if (!TOY_IS_OPAQUE(timeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _stopTimer\n");
Toy_freeLiteral(timeLiteral);
return -1;
}
struct timeval* timerStart = TOY_AS_OPAQUE(timeLiteral);
//determine the difference, and wrap it
struct timeval* d = diff(timerStart, &timerStop);
Toy_Literal diffLiteral = TOY_TO_OPAQUE_LITERAL(d, -1);
Toy_pushLiteralArray(&interpreter->stack, diffLiteral);
//cleanup
Toy_freeLiteral(timeLiteral);
Toy_freeLiteral(diffLiteral);
return 1;
}
static int nativeCreateTimer(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments to createTimer\n");
return -1;
}
//get the args
Toy_Literal microsecondLiteral = Toy_popLiteralArray(arguments);
Toy_Literal secondLiteral = Toy_popLiteralArray(arguments);
Toy_Literal secondLiteralIdn = secondLiteral;
if (TOY_IS_IDENTIFIER(secondLiteral) && Toy_parseIdentifierToValue(interpreter, &secondLiteral)) {
Toy_freeLiteral(secondLiteralIdn);
}
Toy_Literal microsecondLiteralIdn = microsecondLiteral;
if (TOY_IS_IDENTIFIER(microsecondLiteral) && Toy_parseIdentifierToValue(interpreter, &microsecondLiteral)) {
Toy_freeLiteral(microsecondLiteralIdn);
}
if (!TOY_IS_INTEGER(secondLiteral) || !TOY_IS_INTEGER(microsecondLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to createTimer\n");
Toy_freeLiteral(secondLiteral);
Toy_freeLiteral(microsecondLiteral);
return -1;
}
if (TOY_AS_INTEGER(microsecondLiteral) <= -1000 * 1000 || TOY_AS_INTEGER(microsecondLiteral) >= 1000 * 1000 || (TOY_AS_INTEGER(secondLiteral) != 0 && TOY_AS_INTEGER(microsecondLiteral) < 0) ) {
interpreter->errorOutput("Microseconds out of range in createTimer\n");
Toy_freeLiteral(secondLiteral);
Toy_freeLiteral(microsecondLiteral);
return -1;
}
//get the timeinfo from toy
struct timeval* timeinfo = TOY_ALLOCATE(struct timeval, 1);
timeinfo->tv_sec = TOY_AS_INTEGER(secondLiteral);
timeinfo->tv_usec = TOY_AS_INTEGER(microsecondLiteral);
//wrap in an opaque literal for Toy
Toy_Literal timeLiteral = TOY_TO_OPAQUE_LITERAL(timeinfo, -1);
Toy_pushLiteralArray(&interpreter->stack, timeLiteral);
Toy_freeLiteral(timeLiteral);
Toy_freeLiteral(secondLiteral);
Toy_freeLiteral(microsecondLiteral);
return 1;
}
static int nativeGetTimerSeconds(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _getTimerSeconds\n");
return -1;
}
//unwrap the opaque literal
Toy_Literal timeLiteral = Toy_popLiteralArray(arguments);
Toy_Literal timeLiteralIdn = timeLiteral;
if (TOY_IS_IDENTIFIER(timeLiteral) && Toy_parseIdentifierToValue(interpreter, &timeLiteral)) {
Toy_freeLiteral(timeLiteralIdn);
}
if (!TOY_IS_OPAQUE(timeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _getTimerSeconds\n");
Toy_freeLiteral(timeLiteral);
return -1;
}
struct timeval* timer = TOY_AS_OPAQUE(timeLiteral);
//create the result literal
Toy_Literal result = TOY_TO_INTEGER_LITERAL(timer->tv_sec);
Toy_pushLiteralArray(&interpreter->stack, result);
//cleanup
Toy_freeLiteral(timeLiteral);
Toy_freeLiteral(result);
return 1;
}
static int nativeGetTimerMicroseconds(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _getTimerMicroseconds\n");
return -1;
}
//unwrap the opaque literal
Toy_Literal timeLiteral = Toy_popLiteralArray(arguments);
Toy_Literal timeLiteralIdn = timeLiteral;
if (TOY_IS_IDENTIFIER(timeLiteral) && Toy_parseIdentifierToValue(interpreter, &timeLiteral)) {
Toy_freeLiteral(timeLiteralIdn);
}
if (!TOY_IS_OPAQUE(timeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _getTimerMicroseconds\n");
Toy_freeLiteral(timeLiteral);
return -1;
}
struct timeval* timer = TOY_AS_OPAQUE(timeLiteral);
//create the result literal
Toy_Literal result = TOY_TO_INTEGER_LITERAL(timer->tv_usec);
Toy_pushLiteralArray(&interpreter->stack, result);
//cleanup
Toy_freeLiteral(timeLiteral);
Toy_freeLiteral(result);
return 1;
}
static int nativeCompareTimer(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments to _compareTimer\n");
return -1;
}
//unwrap the opaque literals
Toy_Literal rhsLiteral = Toy_popLiteralArray(arguments);
Toy_Literal lhsLiteral = Toy_popLiteralArray(arguments);
Toy_Literal lhsLiteralIdn = lhsLiteral;
if (TOY_IS_IDENTIFIER(lhsLiteral) && Toy_parseIdentifierToValue(interpreter, &lhsLiteral)) {
Toy_freeLiteral(lhsLiteralIdn);
}
Toy_Literal rhsLiteralIdn = rhsLiteral;
if (TOY_IS_IDENTIFIER(rhsLiteral) && Toy_parseIdentifierToValue(interpreter, &rhsLiteral)) {
Toy_freeLiteral(rhsLiteralIdn);
}
if (!TOY_IS_OPAQUE(lhsLiteral) || !TOY_IS_OPAQUE(rhsLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _compareTimer\n");
Toy_freeLiteral(lhsLiteral);
Toy_freeLiteral(rhsLiteral);
return -1;
}
struct timeval* lhsTimer = TOY_AS_OPAQUE(lhsLiteral);
struct timeval* rhsTimer = TOY_AS_OPAQUE(rhsLiteral);
//determine the difference, and wrap it
struct timeval* d = diff(lhsTimer, rhsTimer);
Toy_Literal diffLiteral = TOY_TO_OPAQUE_LITERAL(d, -1);
Toy_pushLiteralArray(&interpreter->stack, diffLiteral);
//cleanup
Toy_freeLiteral(lhsLiteral);
Toy_freeLiteral(rhsLiteral);
Toy_freeLiteral(diffLiteral);
return 1;
}
static int nativeTimerToString(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _timerToString\n");
return -1;
}
//unwrap in an opaque literal
Toy_Literal timeLiteral = Toy_popLiteralArray(arguments);
Toy_Literal timeLiteralIdn = timeLiteral;
if (TOY_IS_IDENTIFIER(timeLiteral) && Toy_parseIdentifierToValue(interpreter, &timeLiteral)) {
Toy_freeLiteral(timeLiteralIdn);
}
if (!TOY_IS_OPAQUE(timeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _timerToString\n");
Toy_freeLiteral(timeLiteral);
return -1;
}
struct timeval* timer = TOY_AS_OPAQUE(timeLiteral);
//create the string literal
Toy_Literal resultLiteral = TOY_TO_NULL_LITERAL;
if (timer->tv_sec == 0 && timer->tv_usec < 0) { //special case, for when the negative sign is encoded in the usec
char buffer[128];
snprintf(buffer, 128, "-%ld.%06ld", timer->tv_sec, -timer->tv_usec);
resultLiteral = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(buffer, strlen(buffer)));
}
else { //normal case
char buffer[128];
snprintf(buffer, 128, "%ld.%06ld", timer->tv_sec, timer->tv_usec);
resultLiteral = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(buffer, strlen(buffer)));
}
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
//cleanup
Toy_freeLiteral(timeLiteral);
Toy_freeLiteral(resultLiteral);
return 1;
}
static int nativeDestroyTimer(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _destroyTimer\n");
return -1;
}
//unwrap in an opaque literal
Toy_Literal timeLiteral = Toy_popLiteralArray(arguments);
Toy_Literal timeLiteralIdn = timeLiteral;
if (TOY_IS_IDENTIFIER(timeLiteral) && Toy_parseIdentifierToValue(interpreter, &timeLiteral)) {
Toy_freeLiteral(timeLiteralIdn);
}
if (!TOY_IS_OPAQUE(timeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _destroyTimer\n");
Toy_freeLiteral(timeLiteral);
return -1;
}
struct timeval* timer = TOY_AS_OPAQUE(timeLiteral);
TOY_FREE(struct timeval, timer);
Toy_freeLiteral(timeLiteral);
return 0;
}
//call the hook
typedef struct Natives {
char* name;
Toy_NativeFn fn;
} Natives;
int Toy_hookTimer(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
//build the natives list
Natives natives[] = {
{"startTimer", nativeStartTimer},
{"_stopTimer", nativeStopTimer},
{"createTimer", nativeCreateTimer},
{"_getTimerSeconds", nativeGetTimerSeconds},
{"_getTimerMicroseconds", nativeGetTimerMicroseconds},
{"_compareTimer", nativeCompareTimer},
{"_timerToString", nativeTimerToString},
{"_destroyTimer", nativeDestroyTimer},
{NULL, NULL}
};
//store the library in an aliased dictionary
if (!TOY_IS_NULL(alias)) {
//make sure the name isn't taken
if (Toy_isDelcaredScopeVariable(interpreter->scope, alias)) {
interpreter->errorOutput("Can't override an existing variable\n");
Toy_freeLiteral(alias);
return false;
}
//create the dictionary to load up with functions
Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
Toy_initLiteralDictionary(dictionary);
//load the dict with functions
for (int i = 0; natives[i].name; i++) {
Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name));
Toy_Literal func = TOY_TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
func.type = TOY_LITERAL_FUNCTION_NATIVE;
Toy_setLiteralDictionary(dictionary, name, func);
Toy_freeLiteral(name);
Toy_freeLiteral(func);
}
//build the type
Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true);
Toy_Literal strType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true);
Toy_Literal fnType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FUNCTION_NATIVE, true);
TOY_TYPE_PUSH_SUBTYPE(&type, strType);
TOY_TYPE_PUSH_SUBTYPE(&type, fnType);
//set scope
Toy_Literal dict = TOY_TO_DICTIONARY_LITERAL(dictionary);
Toy_declareScopeVariable(interpreter->scope, alias, type);
Toy_setScopeVariable(interpreter->scope, alias, dict, false);
//cleanup
Toy_freeLiteral(dict);
Toy_freeLiteral(type);
return 0;
}
//default
for (int i = 0; natives[i].name; i++) {
Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn);
}
return 0;
}
-6
View File
@@ -1,6 +0,0 @@
#pragma once
#include "toy_interpreter.h"
int Toy_hookTimer(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
-36
View File
@@ -1,36 +0,0 @@
CC=gcc
IDIR+=. ../source
CFLAGS+=$(addprefix -I,$(IDIR)) -g -Wall -W -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable
LIBS+=-ltoy
ODIR = obj
SRC = $(wildcard *.c)
OBJ = $(addprefix $(ODIR)/,$(SRC:.c=.o))
OUTNAME=toy
OUT=../$(TOY_OUTDIR)/toyrepl
all: $(OBJ)
ifeq ($(shell uname),Darwin)
cp $(PWD)/$(TOY_OUTDIR)/lib$(OUTNAME).dylib /usr/local/lib/
$(CC) -DTOY_IMPORT $(CFLAGS) -o $(OUT) $(OBJ) $(LIBS)
else
$(CC) -DTOY_IMPORT $(CFLAGS) -o $(OUT) $(OBJ) -Wl,-rpath,. -L$(realpath $(shell pwd)/../$(TOY_OUTDIR)) $(LIBS)
endif
release: all
strip $(OUT)
$(OBJ): | $(ODIR)
$(ODIR):
mkdir $(ODIR)
$(ODIR)/%.o: %.c
$(CC) -c -o $@ $< $(CFLAGS)
.PHONY: clean
clean:
$(RM) $(ODIR)
rm /usr/local/lib/lib$(OUTNAME).dylib
-173
View File
@@ -1,173 +0,0 @@
#include "repl_tools.h"
#include "lib_standard.h"
#include "lib_timer.h"
#include "lib_runner.h"
#include "toy_console_colors.h"
#include "toy_lexer.h"
#include "toy_parser.h"
#include "toy_compiler.h"
#include "toy_interpreter.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void repl() {
//repl does it's own thing for now
bool error = false;
const int size = 2048;
char input[size];
memset(input, 0, size);
Toy_Interpreter interpreter; //persist the interpreter for the scopes
Toy_initInterpreter(&interpreter);
//inject the libs
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
Toy_injectNativeHook(&interpreter, "timer", Toy_hookTimer);
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
for(;;) {
printf("> ");
//handle EOF for exits
if (!fgets(input, size, stdin)) {
break;
}
//escape the repl (length of 5 to accomodate the newline)
if (strlen(input) == 5 && (!strncmp(input, "exit", 4) || !strncmp(input, "quit", 4))) {
break;
}
//setup this iteration
Toy_Lexer lexer;
Toy_Parser parser;
Toy_Compiler compiler;
Toy_initLexer(&lexer, input);
Toy_initParser(&parser, &lexer);
Toy_initCompiler(&compiler);
//run this iteration
Toy_ASTNode* node = Toy_scanParser(&parser);
while(node != NULL) {
//pack up and restart
if (node->type == TOY_AST_NODE_ERROR) {
printf(TOY_CC_ERROR "error node detected\n" TOY_CC_RESET);
error = true;
Toy_freeASTNode(node);
break;
}
Toy_writeCompiler(&compiler, node);
Toy_freeASTNode(node);
node = Toy_scanParser(&parser);
}
if (!error) {
//get the bytecode dump
int size = 0;
unsigned char* tb = Toy_collateCompiler(&compiler, &size);
//run the bytecode
Toy_runInterpreter(&interpreter, tb, size);
}
//clean up this iteration
Toy_freeCompiler(&compiler);
Toy_freeParser(&parser);
error = false;
}
Toy_freeInterpreter(&interpreter);
}
//entry point
int main(int argc, const char* argv[]) {
Toy_initCommand(argc, argv);
//lib setup (hacky - only really for this program)
Toy_initDriveDictionary();
Toy_Literal driveLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("scripts"));
Toy_Literal pathLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("scripts"));
Toy_setLiteralDictionary(Toy_getDriveDictionary(), driveLiteral, pathLiteral);
Toy_freeLiteral(driveLiteral);
Toy_freeLiteral(pathLiteral);
//command specific actions
if (command.error) {
Toy_usageCommand(argc, argv);
return 0;
}
if (command.help) {
Toy_helpCommand(argc, argv);
return 0;
}
if (command.version) {
Toy_copyrightCommand(argc, argv);
return 0;
}
//version
if (command.verbose) {
printf(TOY_CC_NOTICE "Toy Programming Language Version %d.%d.%d\n" TOY_CC_RESET, TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH);
}
//run source file
if (command.sourcefile) {
Toy_runSourceFile(command.sourcefile);
//lib cleanup
Toy_freeDriveDictionary();
return 0;
}
//run from stdin
if (command.source) {
Toy_runSource(command.source);
//lib cleanup
Toy_freeDriveDictionary();
return 0;
}
//compile source file
if (command.compilefile && command.outfile) {
size_t size = 0;
char* source = Toy_readFile(command.compilefile, &size);
unsigned char* tb = Toy_compileString(source, &size);
if (!tb) {
return 1;
}
Toy_writeFile(command.outfile, tb, size);
return 0;
}
//run binary
if (command.binaryfile) {
Toy_runBinaryFile(command.binaryfile);
//lib cleanup
Toy_freeDriveDictionary();
return 0;
}
repl();
//lib cleanup
Toy_freeDriveDictionary();
return 0;
}
-146
View File
@@ -1,146 +0,0 @@
#include "repl_tools.h"
#include "lib_standard.h"
#include "lib_timer.h"
#include "lib_runner.h"
#include "toy_console_colors.h"
#include "toy_lexer.h"
#include "toy_parser.h"
#include "toy_compiler.h"
#include "toy_interpreter.h"
#include <stdio.h>
#include <stdlib.h>
//IO functions
char* Toy_readFile(char* path, size_t* fileSize) {
FILE* file = fopen(path, "rb");
if (file == NULL) {
fprintf(stderr, TOY_CC_ERROR "Could not open file \"%s\"\n" TOY_CC_RESET, path);
return NULL;
}
fseek(file, 0L, SEEK_END);
*fileSize = ftell(file);
rewind(file);
char* buffer = (char*)malloc(*fileSize + 1);
if (buffer == NULL) {
fprintf(stderr, TOY_CC_ERROR "Not enough memory to read \"%s\"\n" TOY_CC_RESET, path);
return NULL;
}
size_t bytesRead = fread(buffer, sizeof(char), *fileSize, file);
buffer[*fileSize] = '\0'; //NOTE: fread doesn't append this
if (bytesRead < *fileSize) {
fprintf(stderr, TOY_CC_ERROR "Could not read file \"%s\"\n" TOY_CC_RESET, path);
return NULL;
}
fclose(file);
return buffer;
}
int Toy_writeFile(char* path, unsigned char* bytes, size_t size) {
FILE* file = fopen(path, "wb");
if (file == NULL) {
fprintf(stderr, TOY_CC_ERROR "Could not open file \"%s\"\n" TOY_CC_RESET, path);
return -1;
}
int written = fwrite(bytes, size, 1, file);
if (written != 1) {
fprintf(stderr, TOY_CC_ERROR "Could not write file \"%s\"\n" TOY_CC_RESET, path);
return -1;
}
fclose(file);
return 0;
}
//repl functions
unsigned char* Toy_compileString(char* source, size_t* size) {
Toy_Lexer lexer;
Toy_Parser parser;
Toy_Compiler compiler;
Toy_initLexer(&lexer, source);
Toy_initParser(&parser, &lexer);
Toy_initCompiler(&compiler);
//run the parser until the end of the source
Toy_ASTNode* node = Toy_scanParser(&parser);
while(node != NULL) {
//pack up and leave
if (node->type == TOY_AST_NODE_ERROR) {
Toy_freeASTNode(node);
Toy_freeCompiler(&compiler);
Toy_freeParser(&parser);
return NULL;
}
Toy_writeCompiler(&compiler, node);
Toy_freeASTNode(node);
node = Toy_scanParser(&parser);
}
//get the bytecode dump
unsigned char* tb = Toy_collateCompiler(&compiler, (int*)(size));
//cleanup
Toy_freeCompiler(&compiler);
Toy_freeParser(&parser);
//no lexer to clean up
//finally
return tb;
}
void Toy_runBinary(unsigned char* tb, size_t size) {
Toy_Interpreter interpreter;
Toy_initInterpreter(&interpreter);
//inject the libs
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
Toy_injectNativeHook(&interpreter, "timer", Toy_hookTimer);
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
Toy_runInterpreter(&interpreter, tb, size);
Toy_freeInterpreter(&interpreter);
}
void Toy_runBinaryFile(char* fname) {
size_t size = 0; //not used
unsigned char* tb = (unsigned char*)Toy_readFile(fname, &size);
if (!tb) {
return;
}
Toy_runBinary(tb, size);
//interpreter takes ownership of the binary data
}
void Toy_runSource(char* source) {
size_t size = 0;
unsigned char* tb = Toy_compileString(source, &size);
if (!tb) {
return;
}
Toy_runBinary(tb, size);
}
void Toy_runSourceFile(char* fname) {
size_t size = 0; //not used
char* source = Toy_readFile(fname, &size);
Toy_runSource(source);
free((void*)source);
}
-14
View File
@@ -1,14 +0,0 @@
#pragma once
#include "toy_common.h"
char* Toy_readFile(char* path, size_t* fileSize);
int Toy_writeFile(char* path, unsigned char* bytes, size_t size);
unsigned char* Toy_compileString(char* source, size_t* size);
void Toy_runBinary(unsigned char* tb, size_t size);
void Toy_runBinaryFile(char* fname);
void Toy_runSource(char* source);
void Toy_runSourceFile(char* fname);
+16
View File
@@ -0,0 +1,16 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="454.000000pt" height="454.000000pt" viewBox="0 0 454.000000 454.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.14, written by Peter Selinger 2001-2017
</metadata>
<g transform="translate(0.000000,454.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M1178 4533 c-3 -5 -4 -508 -3 -1118 l0 -1111 -565 0 -565 0 -3 -1152
-2 -1152 2230 0 2230 0 -2 1152 -3 1152 -522 0 c-359 0 -523 3 -524 10 0 6 0
509 0 1119 l-1 1107 -1133 0 c-624 0 -1135 -3 -1137 -7z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 730 B

-89
View File
@@ -1,89 +0,0 @@
//single line comment
/*
multi line comment
*/
//test primitive literals
print "hello world";
print null;
print true;
print false;
print 42;
print 3.14;
print -69;
print -4.20;
print 2 + (3 * 3);
//test operators (integers)
print 1 + 1;
print 1 - 1;
print 2 * 2;
print 1 / 2;
print 4 % 2;
//test operators (floats)
print 1.0 + 1.0;
print 1.0 - 1.0;
print 2.0 * 2.0;
print 1.0 / 2.0;
//test scopes
{
print "This statement is within a scope.";
{
print "This is a deeper scope.";
}
}
print "Back to the outer scope.";
//test scope will delegate to higher scope
var a = 1;
{
a = 2;
print a;
}
print a;
//test scope will shadow higher scope on redefine
var b: int = 3;
{
var b = 4;
print b;
}
print b;
//test compounds, repeatedly
print [1, 2, 3];
print [4, 5];
print ["key":"value"];
print [1, 2, 3];
print [4, 5];
print ["key":"value"];
//test empties
print [];
print [:];
//test nested compounds
print [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
//var declarations
var x = 31;
var y : int = 42;
var arr : [int] = [1, 2, 3, 42];
var dict : [string:int] = ["hello": 1, "world":2];
//printing expressions
print x;
print x + y;
print arr;
print dict;
//test asserts at the end of the file
assert x, "This won't be seen";
assert true, "This won't be seen";
assert false, "This is a failed assert, and will end execution";
print "This will not be printed because of the above assert";
-12
View File
@@ -1,12 +0,0 @@
fn fib(n : int) {
if (n < 2) {
return n;
}
return fib(n-1) + fib(n-2);
}
for (var i = 0; i < 20; i++) {
var res = fib(i);
print string i + ": " + string res;
}
-49
View File
@@ -1,49 +0,0 @@
//number of iterations
var SIZE: int const = 100;
//lookup table
var lookup = [
"*": [
"*": [
"*": " ",
" ": "*"
],
" ": [
"*": "*",
" ": " "
]
], " ": [
"*": [
"*": "*",
" ": "*"
],
" ": [
"*": "*",
" ": " "
]
]];
//initial line to build from
var prev: string = "";
for (var i = 0; i < SIZE -1; i++) {
prev += " ";
}
prev += "*"; //initial
print prev;
//run
for (var iteration = 0; iteration < 100; iteration++) {
//left
var output = (lookup[" "][prev[0]][prev[1]]);
//middle
for (var i = 1; i < SIZE-1; i++) {
output += (lookup[prev[i-1]][prev[i]][prev[i+1]]);
}
//right
output += (lookup[prev[SIZE-2]][prev[SIZE-1]][" "]);
print output;
prev = output;
}
-21
View File
@@ -1,21 +0,0 @@
//test basic truth ternaries
{
assert true ? true : false, "Basic true ternary failed";
assert false ? false : true, "Basic false ternary failed";
}
//test nesting
{
fn least(a, b, c) {
return a < b ? a : b < c ? b : c;
}
assert least(1, 2, 3) == 1, "Least 1, 2, 3 failed";
assert least(10, 5, 7) == 5, "Least 10, 5, 7 failed";
assert least(9, 7, 5) == 5, "Least 9, 7, 5 failed";
}
print "All good";
+19
View File
@@ -0,0 +1,19 @@
{
"name": "",
"short_name": "",
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-384x384.png",
"sizes": "384x384",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}
-54
View File
@@ -1,54 +0,0 @@
CC=gcc
IDIR+=.
CFLAGS+=$(addprefix -I,$(IDIR)) -g -Wall -W -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable
LIBS+=
ODIR = obj
SRC = $(wildcard *.c)
OBJ = $(addprefix $(ODIR)/,$(SRC:.c=.o))
OUTNAME=toy
ifeq ($(findstring CYGWIN, $(shell uname)),CYGWIN)
LIBLINE =-Wl,--out-implib=../$(TOY_OUTDIR)/lib$(OUTNAME).dll.a -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--whole-archive $(OBJ) -Wl,--no-whole-archive
OUT=../$(TOY_OUTDIR)/$(OUTNAME).dll
else ifeq ($(shell uname),Linux)
LIBLINE=-Wl,--out-implib=../$(TOY_OUTDIR)/lib$(OUTNAME).a -Wl,--whole-archive $(OBJ) -Wl,--no-whole-archive
OUT=../$(TOY_OUTDIR)/lib$(OUTNAME).so
CFLAGS += -fPIC
else ifeq ($(OS),Windows_NT)
LIBLINE =-Wl,--out-implib=../$(TOY_OUTDIR)/lib$(OUTNAME).dll.a -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--whole-archive $(OBJ) -Wl,--no-whole-archive
OUT=../$(TOY_OUTDIR)/$(OUTNAME).dll
else ifeq ($(shell uname),Darwin)
LIBLINE = $(OBJ)
OUT=../$(TOY_OUTDIR)/lib$(OUTNAME).dylib
else
@echo "Platform test failed - what platform is this?"
exit 1
endif
library: $(OBJ)
$(CC) -DTOY_EXPORT $(CFLAGS) -shared -o $(OUT) $(LIBLINE)
static: $(OBJ)
ar crs ../$(TOY_OUTDIR)/lib$(OUTNAME).a $(OBJ)
library-release: $(OBJ) library
strip $(OUT)
static-release: $(OBJ) static
strip -d ../$(TOY_OUTDIR)/lib$(OUTNAME).a
$(OBJ): | $(ODIR)
$(ODIR):
mkdir $(ODIR)
$(ODIR)/%.o: %.c
$(CC) -c -o $@ $< $(CFLAGS)
.PHONY: clean
clean:
$(RM) $(ODIR)
-385
View File
@@ -1,385 +0,0 @@
#include "toy_ast_node.h"
#include "toy_memory.h"
#include <stdio.h>
#include <stdlib.h>
static void freeASTNodeCustom(Toy_ASTNode* node, bool freeSelf) {
//don't free a NULL node
if (node == NULL) {
return;
}
switch(node->type) {
case TOY_AST_NODE_ERROR:
//NO-OP
break;
case TOY_AST_NODE_LITERAL:
Toy_freeLiteral(node->atomic.literal);
break;
case TOY_AST_NODE_UNARY:
Toy_freeASTNode(node->unary.child);
break;
case TOY_AST_NODE_BINARY:
Toy_freeASTNode(node->binary.left);
Toy_freeASTNode(node->binary.right);
break;
case TOY_AST_NODE_TERNARY:
Toy_freeASTNode(node->ternary.condition);
Toy_freeASTNode(node->ternary.thenPath);
Toy_freeASTNode(node->ternary.elsePath);
break;
case TOY_AST_NODE_GROUPING:
Toy_freeASTNode(node->grouping.child);
break;
case TOY_AST_NODE_BLOCK:
for (int i = 0; i < node->block.count; i++) {
freeASTNodeCustom(node->block.nodes + i, false);
}
TOY_FREE_ARRAY(Toy_ASTNode, node->block.nodes, node->block.capacity);
break;
case TOY_AST_NODE_COMPOUND:
for (int i = 0; i < node->compound.count; i++) {
freeASTNodeCustom(node->compound.nodes + i, false);
}
TOY_FREE_ARRAY(Toy_ASTNode, node->compound.nodes, node->compound.capacity);
break;
case TOY_AST_NODE_PAIR:
Toy_freeASTNode(node->pair.left);
Toy_freeASTNode(node->pair.right);
break;
case TOY_AST_NODE_INDEX:
Toy_freeASTNode(node->index.first);
Toy_freeASTNode(node->index.second);
Toy_freeASTNode(node->index.third);
break;
case TOY_AST_NODE_VAR_DECL:
Toy_freeLiteral(node->varDecl.identifier);
Toy_freeLiteral(node->varDecl.typeLiteral);
Toy_freeASTNode(node->varDecl.expression);
break;
case TOY_AST_NODE_FN_COLLECTION:
for (int i = 0; i < node->fnCollection.count; i++) {
freeASTNodeCustom(node->fnCollection.nodes + i, false);
}
TOY_FREE_ARRAY(Toy_ASTNode, node->fnCollection.nodes, node->fnCollection.capacity);
break;
case TOY_AST_NODE_FN_DECL:
Toy_freeLiteral(node->fnDecl.identifier);
Toy_freeASTNode(node->fnDecl.arguments);
Toy_freeASTNode(node->fnDecl.returns);
Toy_freeASTNode(node->fnDecl.block);
break;
case TOY_AST_NODE_FN_CALL:
Toy_freeASTNode(node->fnCall.arguments);
break;
case TOY_AST_NODE_FN_RETURN:
Toy_freeASTNode(node->returns.returns);
break;
case TOY_AST_NODE_IF:
Toy_freeASTNode(node->pathIf.condition);
Toy_freeASTNode(node->pathIf.thenPath);
Toy_freeASTNode(node->pathIf.elsePath);
break;
case TOY_AST_NODE_WHILE:
Toy_freeASTNode(node->pathWhile.condition);
Toy_freeASTNode(node->pathWhile.thenPath);
break;
case TOY_AST_NODE_FOR:
Toy_freeASTNode(node->pathFor.preClause);
Toy_freeASTNode(node->pathFor.postClause);
Toy_freeASTNode(node->pathFor.condition);
Toy_freeASTNode(node->pathFor.thenPath);
break;
case TOY_AST_NODE_BREAK:
//NO-OP
break;
case TOY_AST_NODE_CONTINUE:
//NO-OP
break;
case TOY_AST_NODE_PREFIX_INCREMENT:
Toy_freeLiteral(node->prefixIncrement.identifier);
break;
case TOY_AST_NODE_PREFIX_DECREMENT:
Toy_freeLiteral(node->prefixDecrement.identifier);
break;
case TOY_AST_NODE_POSTFIX_INCREMENT:
Toy_freeLiteral(node->postfixIncrement.identifier);
break;
case TOY_AST_NODE_POSTFIX_DECREMENT:
Toy_freeLiteral(node->postfixDecrement.identifier);
break;
case TOY_AST_NODE_IMPORT:
Toy_freeLiteral(node->import.identifier);
Toy_freeLiteral(node->import.alias);
break;
}
if (freeSelf) {
TOY_FREE(Toy_ASTNode, node);
}
}
void Toy_freeASTNode(Toy_ASTNode* node) {
freeASTNodeCustom(node, true);
}
//various emitters
void Toy_emitASTNodeLiteral(Toy_ASTNode** nodeHandle, Toy_Literal literal) {
//allocate a new node
*nodeHandle = TOY_ALLOCATE(Toy_ASTNode, 1);
(*nodeHandle)->type = TOY_AST_NODE_LITERAL;
(*nodeHandle)->atomic.literal = Toy_copyLiteral(literal);
}
void Toy_emitASTNodeUnary(Toy_ASTNode** nodeHandle, Toy_Opcode opcode, Toy_ASTNode* child) {
//allocate a new node
*nodeHandle = TOY_ALLOCATE(Toy_ASTNode, 1);
(*nodeHandle)->type = TOY_AST_NODE_UNARY;
(*nodeHandle)->unary.opcode = opcode;
(*nodeHandle)->unary.child = child;
}
void Toy_emitASTNodeBinary(Toy_ASTNode** nodeHandle, Toy_ASTNode* rhs, Toy_Opcode opcode) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
tmp->type = TOY_AST_NODE_BINARY;
tmp->binary.opcode = opcode;
tmp->binary.left = *nodeHandle;
tmp->binary.right = rhs;
*nodeHandle = tmp;
}
void Toy_emitASTNodeTernary(Toy_ASTNode** nodeHandle, Toy_ASTNode* condition, Toy_ASTNode* thenPath, Toy_ASTNode* elsePath) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
tmp->type = TOY_AST_NODE_TERNARY;
tmp->ternary.condition = condition;
tmp->ternary.thenPath = thenPath;
tmp->ternary.elsePath = elsePath;
*nodeHandle = tmp;
}
void Toy_emitASTNodeGrouping(Toy_ASTNode** nodeHandle) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
tmp->type = TOY_AST_NODE_GROUPING;
tmp->grouping.child = *nodeHandle;
*nodeHandle = tmp;
}
void Toy_emitASTNodeBlock(Toy_ASTNode** nodeHandle) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
tmp->type = TOY_AST_NODE_BLOCK;
tmp->block.nodes = NULL; //NOTE: appended by the parser
tmp->block.capacity = 0;
tmp->block.count = 0;
*nodeHandle = tmp;
}
void Toy_emitASTNodeCompound(Toy_ASTNode** nodeHandle, Toy_LiteralType literalType) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
tmp->type = TOY_AST_NODE_COMPOUND;
tmp->compound.literalType = literalType;
tmp->compound.nodes = NULL;
tmp->compound.capacity = 0;
tmp->compound.count = 0;
*nodeHandle = tmp;
}
void Toy_setASTNodePair(Toy_ASTNode* node, Toy_ASTNode* left, Toy_ASTNode* right) {
//set - assume the node has already been allocated
node->type = TOY_AST_NODE_PAIR;
node->pair.left = left;
node->pair.right = right;
}
void Toy_emitASTNodeIndex(Toy_ASTNode** nodeHandle, Toy_ASTNode* first, Toy_ASTNode* second, Toy_ASTNode* third) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
tmp->type = TOY_AST_NODE_INDEX;
tmp->index.first = first;
tmp->index.second = second;
tmp->index.third = third;
*nodeHandle = tmp;
}
void Toy_emitASTNodeVarDecl(Toy_ASTNode** nodeHandle, Toy_Literal identifier, Toy_Literal typeLiteral, Toy_ASTNode* expression) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
tmp->type = TOY_AST_NODE_VAR_DECL;
tmp->varDecl.identifier = identifier;
tmp->varDecl.typeLiteral = typeLiteral;
tmp->varDecl.expression = expression;
*nodeHandle = tmp;
}
void Toy_emitASTNodeFnCollection(Toy_ASTNode** nodeHandle) { //a collection of nodes, intended for use with functions
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
tmp->type = TOY_AST_NODE_FN_COLLECTION;
tmp->fnCollection.nodes = NULL;
tmp->fnCollection.capacity = 0;
tmp->fnCollection.count = 0;
*nodeHandle = tmp;
}
void Toy_emitASTNodeFnDecl(Toy_ASTNode** nodeHandle, Toy_Literal identifier, Toy_ASTNode* arguments, Toy_ASTNode* returns, Toy_ASTNode* block) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
tmp->type = TOY_AST_NODE_FN_DECL;
tmp->fnDecl.identifier = identifier;
tmp->fnDecl.arguments = arguments;
tmp->fnDecl.returns = returns;
tmp->fnDecl.block = block;
*nodeHandle = tmp;
}
void Toy_emitASTNodeFnCall(Toy_ASTNode** nodeHandle, Toy_ASTNode* arguments) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
tmp->type = TOY_AST_NODE_FN_CALL;
tmp->fnCall.arguments = arguments;
tmp->fnCall.argumentCount = arguments->fnCollection.count;
*nodeHandle = tmp;
}
void Toy_emitASTNodeFnReturn(Toy_ASTNode** nodeHandle, Toy_ASTNode* returns) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
tmp->type = TOY_AST_NODE_FN_RETURN;
tmp->returns.returns = returns;
*nodeHandle = tmp;
}
void Toy_emitASTNodeIf(Toy_ASTNode** nodeHandle, Toy_ASTNode* condition, Toy_ASTNode* thenPath, Toy_ASTNode* elsePath) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
tmp->type = TOY_AST_NODE_IF;
tmp->pathIf.condition = condition;
tmp->pathIf.thenPath = thenPath;
tmp->pathIf.elsePath = elsePath;
*nodeHandle = tmp;
}
void Toy_emitASTNodeWhile(Toy_ASTNode** nodeHandle, Toy_ASTNode* condition, Toy_ASTNode* thenPath) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
tmp->type = TOY_AST_NODE_WHILE;
tmp->pathWhile.condition = condition;
tmp->pathWhile.thenPath = thenPath;
*nodeHandle = tmp;
}
void Toy_emitASTNodeFor(Toy_ASTNode** nodeHandle, Toy_ASTNode* preClause, Toy_ASTNode* condition, Toy_ASTNode* postClause, Toy_ASTNode* thenPath) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
tmp->type = TOY_AST_NODE_FOR;
tmp->pathFor.preClause = preClause;
tmp->pathFor.condition = condition;
tmp->pathFor.postClause = postClause;
tmp->pathFor.thenPath = thenPath;
*nodeHandle = tmp;
}
void Toy_emitASTNodeBreak(Toy_ASTNode** nodeHandle) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
tmp->type = TOY_AST_NODE_BREAK;
*nodeHandle = tmp;
}
void Toy_emitASTNodeContinue(Toy_ASTNode** nodeHandle) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
tmp->type = TOY_AST_NODE_CONTINUE;
*nodeHandle = tmp;
}
void Toy_emitASTNodePrefixIncrement(Toy_ASTNode** nodeHandle, Toy_Literal identifier) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
tmp->type = TOY_AST_NODE_PREFIX_INCREMENT;
tmp->prefixIncrement.identifier = Toy_copyLiteral(identifier);
*nodeHandle = tmp;
}
void Toy_emitASTNodePrefixDecrement(Toy_ASTNode** nodeHandle, Toy_Literal identifier) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
tmp->type = TOY_AST_NODE_PREFIX_DECREMENT;
tmp->prefixDecrement.identifier = Toy_copyLiteral(identifier);
*nodeHandle = tmp;
}
void Toy_emitASTNodePostfixIncrement(Toy_ASTNode** nodeHandle, Toy_Literal identifier) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
tmp->type = TOY_AST_NODE_POSTFIX_INCREMENT;
tmp->postfixIncrement.identifier = Toy_copyLiteral(identifier);
*nodeHandle = tmp;
}
void Toy_emitASTNodePostfixDecrement(Toy_ASTNode** nodeHandle, Toy_Literal identifier) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
tmp->type = TOY_AST_NODE_POSTFIX_DECREMENT;
tmp->postfixDecrement.identifier = Toy_copyLiteral(identifier);
*nodeHandle = tmp;
}
void Toy_emitASTNodeImport(Toy_ASTNode** nodeHandle, Toy_Literal identifier, Toy_Literal alias) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
tmp->type = TOY_AST_NODE_IMPORT;
tmp->import.identifier = Toy_copyLiteral(identifier);
tmp->import.alias = Toy_copyLiteral(alias);
*nodeHandle = tmp;
}
-269
View File
@@ -1,269 +0,0 @@
#pragma once
#include "toy_common.h"
#include "toy_literal.h"
#include "toy_opcodes.h"
#include "toy_token_types.h"
//nodes are the intermediaries between parsers and compilers
typedef union Toy_private_node Toy_ASTNode;
typedef enum Toy_ASTNodeType {
TOY_AST_NODE_ERROR,
TOY_AST_NODE_LITERAL, //a simple value
TOY_AST_NODE_UNARY, //one child + opcode
TOY_AST_NODE_BINARY, //two children, left and right + opcode
TOY_AST_NODE_TERNARY, //three children, condition, then path & else path
TOY_AST_NODE_GROUPING, //one child
TOY_AST_NODE_BLOCK, //contains a sub-node array
TOY_AST_NODE_COMPOUND, //contains a sub-node array
TOY_AST_NODE_PAIR, //contains a left and right
TOY_AST_NODE_INDEX, //index a variable
TOY_AST_NODE_VAR_DECL, //contains identifier literal, typenode, expression definition
TOY_AST_NODE_FN_DECL, //containd identifier literal, arguments node, returns node, block node
TOY_AST_NODE_FN_COLLECTION, //parts of a function
TOY_AST_NODE_FN_CALL, //call a function
TOY_AST_NODE_FN_RETURN, //for control flow
TOY_AST_NODE_IF, //for control flow
TOY_AST_NODE_WHILE, //for control flow
TOY_AST_NODE_FOR, //for control flow
TOY_AST_NODE_BREAK, //for control flow
TOY_AST_NODE_CONTINUE, //for control flow
TOY_AST_NODE_PREFIX_INCREMENT, //increment a variable
TOY_AST_NODE_POSTFIX_INCREMENT, //increment a variable
TOY_AST_NODE_PREFIX_DECREMENT, //decrement a variable
TOY_AST_NODE_POSTFIX_DECREMENT, //decrement a variable
TOY_AST_NODE_IMPORT, //import a library
} Toy_ASTNodeType;
//literals
void Toy_emitASTNodeLiteral(Toy_ASTNode** nodeHandle, Toy_Literal literal);
typedef struct Toy_NodeLiteral {
Toy_ASTNodeType type;
Toy_Literal literal;
} Toy_NodeLiteral;
//unary operator
void Toy_emitASTNodeUnary(Toy_ASTNode** nodeHandle, Toy_Opcode opcode, Toy_ASTNode* child);
typedef struct Toy_NodeUnary {
Toy_ASTNodeType type;
Toy_Opcode opcode;
Toy_ASTNode* child;
} Toy_NodeUnary;
//binary operator
void Toy_emitASTNodeBinary(Toy_ASTNode** nodeHandle, Toy_ASTNode* rhs, Toy_Opcode opcode); //handled node becomes lhs
typedef struct Toy_NodeBinary {
Toy_ASTNodeType type;
Toy_Opcode opcode;
Toy_ASTNode* left;
Toy_ASTNode* right;
} Toy_NodeBinary;
//ternary operator
void Toy_emitASTNodeTernary(Toy_ASTNode** nodeHandle, Toy_ASTNode* condition, Toy_ASTNode* thenPath, Toy_ASTNode* elsePath);
typedef struct Toy_NodeTernary {
Toy_ASTNodeType type;
Toy_ASTNode* condition;
Toy_ASTNode* thenPath;
Toy_ASTNode* elsePath;
} Toy_NodeTernary;
//grouping of other AST nodes
void Toy_emitASTNodeGrouping(Toy_ASTNode** nodeHandle);
typedef struct Toy_NodeGrouping {
Toy_ASTNodeType type;
Toy_ASTNode* child;
} Toy_NodeGrouping;
//block of statement nodes
void Toy_emitASTNodeBlock(Toy_ASTNode** nodeHandle);
typedef struct Toy_NodeBlock {
Toy_ASTNodeType type;
Toy_ASTNode* nodes;
int capacity;
int count;
} Toy_NodeBlock;
//compound literals (array, dictionary)
void Toy_emitASTNodeCompound(Toy_ASTNode** nodeHandle, Toy_LiteralType literalType);
typedef struct Toy_NodeCompound {
Toy_ASTNodeType type;
Toy_LiteralType literalType;
Toy_ASTNode* nodes;
int capacity;
int count;
} Toy_NodeCompound;
void Toy_setASTNodePair(Toy_ASTNode* node, Toy_ASTNode* left, Toy_ASTNode* right); //NOTE: this is a set function, not an emit function
typedef struct Toy_NodePair {
Toy_ASTNodeType type;
Toy_ASTNode* left;
Toy_ASTNode* right;
} Toy_NodePair;
void Toy_emitASTNodeIndex(Toy_ASTNode** nodeHandle, Toy_ASTNode* first, Toy_ASTNode* second, Toy_ASTNode* third);
typedef struct Toy_NodeIndex {
Toy_ASTNodeType type;
Toy_ASTNode* first;
Toy_ASTNode* second;
Toy_ASTNode* third;
} Toy_NodeIndex;
//variable declaration
void Toy_emitASTNodeVarDecl(Toy_ASTNode** nodeHandle, Toy_Literal identifier, Toy_Literal type, Toy_ASTNode* expression);
typedef struct Toy_NodeVarDecl {
Toy_ASTNodeType type;
Toy_Literal identifier;
Toy_Literal typeLiteral;
Toy_ASTNode* expression;
} Toy_NodeVarDecl;
//NOTE: fnCollection is used by fnDecl, fnCall and fnReturn
void Toy_emitASTNodeFnCollection(Toy_ASTNode** nodeHandle);
typedef struct Toy_NodeFnCollection {
Toy_ASTNodeType type;
Toy_ASTNode* nodes;
int capacity;
int count;
} Toy_NodeFnCollection;
//function declaration
void Toy_emitASTNodeFnDecl(Toy_ASTNode** nodeHandle, Toy_Literal identifier, Toy_ASTNode* arguments, Toy_ASTNode* returns, Toy_ASTNode* block);
typedef struct Toy_NodeFnDecl {
Toy_ASTNodeType type;
Toy_Literal identifier;
Toy_ASTNode* arguments;
Toy_ASTNode* returns;
Toy_ASTNode* block;
} Toy_NodeFnDecl;
//function call
void Toy_emitASTNodeFnCall(Toy_ASTNode** nodeHandle, Toy_ASTNode* arguments);
typedef struct Toy_NodeFnCall {
Toy_ASTNodeType type;
Toy_ASTNode* arguments;
int argumentCount; //NOTE: leave this, so it can be hacked by dottify()
} Toy_NodeFnCall;
//function return
void Toy_emitASTNodeFnReturn(Toy_ASTNode** nodeHandle, Toy_ASTNode* returns);
typedef struct Toy_NodeFnReturn {
Toy_ASTNodeType type;
Toy_ASTNode* returns;
} Toy_NodeFnReturn;
//control flow path - if-else, while, for, break, continue, return
void Toy_emitASTNodeIf(Toy_ASTNode** nodeHandle, Toy_ASTNode* condition, Toy_ASTNode* thenPath, Toy_ASTNode* elsePath);
void Toy_emitASTNodeWhile(Toy_ASTNode** nodeHandle, Toy_ASTNode* condition, Toy_ASTNode* thenPath);
void Toy_emitASTNodeFor(Toy_ASTNode** nodeHandle, Toy_ASTNode* preClause, Toy_ASTNode* condition, Toy_ASTNode* postClause, Toy_ASTNode* thenPath);
void Toy_emitASTNodeBreak(Toy_ASTNode** nodeHandle);
void Toy_emitASTNodeContinue(Toy_ASTNode** nodeHandle);
typedef struct Toy_NodeIf {
Toy_ASTNodeType type;
Toy_ASTNode* condition;
Toy_ASTNode* thenPath;
Toy_ASTNode* elsePath;
} Toy_NodeIf;
typedef struct Toy_NodeWhile {
Toy_ASTNodeType type;
Toy_ASTNode* condition;
Toy_ASTNode* thenPath;
} Toy_NodeWhile;
typedef struct Toy_NodeFor {
Toy_ASTNodeType type;
Toy_ASTNode* preClause;
Toy_ASTNode* condition;
Toy_ASTNode* postClause;
Toy_ASTNode* thenPath;
} Toy_NodeFor;
typedef struct Toy_NodeBreak {
Toy_ASTNodeType type;
} Toy_NodeBreak;
typedef struct Toy_NodeContinue {
Toy_ASTNodeType type;
} Toy_NodeContinue;
//pre-post increment/decrement
void Toy_emitASTNodePrefixIncrement(Toy_ASTNode** nodeHandle, Toy_Literal identifier);
void Toy_emitASTNodePrefixDecrement(Toy_ASTNode** nodeHandle, Toy_Literal identifier);
void Toy_emitASTNodePostfixIncrement(Toy_ASTNode** nodeHandle, Toy_Literal identifier);
void Toy_emitASTNodePostfixDecrement(Toy_ASTNode** nodeHandle, Toy_Literal identifier);
typedef struct Toy_NodePrefixIncrement {
Toy_ASTNodeType type;
Toy_Literal identifier;
} Toy_NodePrefixIncrement;
typedef struct Toy_NodePrefixDecrement {
Toy_ASTNodeType type;
Toy_Literal identifier;
} Toy_NodePrefixDecrement;
typedef struct Toy_NodePostfixIncrement {
Toy_ASTNodeType type;
Toy_Literal identifier;
} Toy_NodePostfixIncrement;
typedef struct Toy_NodePostfixDecrement {
Toy_ASTNodeType type;
Toy_Literal identifier;
} Toy_NodePostfixDecrement;
//import a library
void Toy_emitASTNodeImport(Toy_ASTNode** nodeHandle, Toy_Literal identifier, Toy_Literal alias);
typedef struct Toy_NodeImport {
Toy_ASTNodeType type;
Toy_Literal identifier;
Toy_Literal alias;
} Toy_NodeImport;
union Toy_private_node {
Toy_ASTNodeType type;
Toy_NodeLiteral atomic;
Toy_NodeUnary unary;
Toy_NodeBinary binary;
Toy_NodeTernary ternary;
Toy_NodeGrouping grouping;
Toy_NodeBlock block;
Toy_NodeCompound compound;
Toy_NodePair pair;
Toy_NodeIndex index;
Toy_NodeVarDecl varDecl;
Toy_NodeFnCollection fnCollection;
Toy_NodeFnDecl fnDecl;
Toy_NodeFnCall fnCall;
Toy_NodeFnReturn returns;
Toy_NodeIf pathIf;
Toy_NodeWhile pathWhile;
Toy_NodeFor pathFor;
Toy_NodeBreak pathBreak;
Toy_NodeContinue pathContinue;
Toy_NodePrefixIncrement prefixIncrement;
Toy_NodePrefixDecrement prefixDecrement;
Toy_NodePostfixIncrement postfixIncrement;
Toy_NodePostfixDecrement postfixDecrement;
Toy_NodeImport import;
};
TOY_API void Toy_freeASTNode(Toy_ASTNode* node);
-1348
View File
File diff suppressed because it is too large Load Diff
-14
View File
@@ -1,14 +0,0 @@
#pragma once
#include "toy_interpreter.h"
//the _index function is a historical oddity - it's used whenever a compound is indexed
int _index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
//globally available native functions
int _set(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
int _get(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
int _push(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
int _pop(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
int _length(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
int _clear(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
-125
View File
@@ -1,125 +0,0 @@
#include "toy_common.h"
#include <stdio.h>
#include <string.h>
#include <assert.h>
//test variable sizes based on platform
#define STATIC_ASSERT(test_for_true) static_assert((test_for_true), "(" #test_for_true ") failed")
STATIC_ASSERT(sizeof(char) == 1);
STATIC_ASSERT(sizeof(short) == 2);
STATIC_ASSERT(sizeof(int) == 4);
STATIC_ASSERT(sizeof(float) == 4);
STATIC_ASSERT(sizeof(unsigned char) == 1);
STATIC_ASSERT(sizeof(unsigned short) == 2);
STATIC_ASSERT(sizeof(unsigned int) == 4);
#ifndef TOY_EXPORT
//declare the singleton
Command command;
void Toy_initCommand(int argc, const char* argv[]) {
//default values
command.error = false;
command.help = false;
command.version = false;
command.binaryfile = NULL;
command.sourcefile = NULL;
command.compilefile = NULL;
command.outfile = "out.tb";
command.source = NULL;
command.verbose = false;
for (int i = 1; i < argc; i++) { //start at 1 to skip the program name
command.error = true; //error state by default, set to false by successful flags
if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
command.help = true;
command.error = false;
continue;
}
if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
command.version = true;
command.error = false;
continue;
}
if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) {
command.verbose = true;
command.error = false;
continue;
}
if ((!strcmp(argv[i], "-f") || !strcmp(argv[i], "--sourcefile")) && i + 1 < argc) {
command.sourcefile = (char*)argv[i + 1];
i++;
command.error = false;
continue;
}
if ((!strcmp(argv[i], "-i") || !strcmp(argv[i], "--input")) && i + 1 < argc) {
command.source = (char*)argv[i + 1];
i++;
command.error = false;
continue;
}
if ((!strcmp(argv[i], "-c") || !strcmp(argv[i], "--compile")) && i + 1 < argc) {
command.compilefile = (char*)argv[i + 1];
i++;
command.error = false;
continue;
}
if ((!strcmp(argv[i], "-o") || !strcmp(argv[i], "--output")) && i + 1 < argc) {
command.outfile = (char*)argv[i + 1];
i++;
command.error = false;
continue;
}
//option without a flag + ending in .tb = binary input
if (i < argc) {
if (strncmp(&(argv[i][strlen(argv[i]) - 3]), ".tb", 3) == 0) {
command.binaryfile = (char*)argv[i];
command.error = false;
continue;
}
}
//don't keep reading in an error state
return;
}
}
void Toy_usageCommand(int argc, const char* argv[]) {
printf("Usage: %s [<file.tb> | -h | -v | [-d][-f file | -i source | -c file [-o outfile]]]\n\n", argv[0]);
}
void Toy_helpCommand(int argc, const char* argv[]) {
Toy_usageCommand(argc, argv);
printf("<file.tb>\t\t\tBinary input file in tb format, must be version %d.%d.%d.\n\n", TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH);
printf("-h\t| --help\t\tShow this help then exit.\n\n");
printf("-v\t| --version\t\tShow version and copyright information then exit.\n\n");
printf("-d\t| --debug\t\tBe verbose when operating.\n\n");
printf("-f\t| --file filename\tParse, compile and execute the source file.\n\n");
printf("-i\t| --input source\tParse, compile and execute this given string of source code.\n\n");
printf("-c\t| --compile filename\tParse and compile the specified source file into an output file.\n\n");
printf("-o\t| --output outfile\tName of the output file built with --compile (default: out.tb).\n\n");
}
void Toy_copyrightCommand(int argc, const char* argv[]) {
printf("Toy Programming Language Interpreter Version %d.%d.%d (built on %s)\n\n", TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH, TOY_VERSION_BUILD);
printf("Copyright (c) 2020-2022 Kayne Ruse, KR Game Studios\n\n");
printf("This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.\n\n");
printf("Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:\n\n");
printf("1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.\n\n");
printf("2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\n\n");
printf("3. This notice may not be removed or altered from any source distribution.\n\n");
}
#endif
-45
View File
@@ -1,45 +0,0 @@
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#define TOY_VERSION_MAJOR 0
#define TOY_VERSION_MINOR 8
#define TOY_VERSION_PATCH 0
#define TOY_VERSION_BUILD __DATE__ " " __TIME__
//platform-specific specifications
#if defined(__linux__)
#define TOY_API extern
#elif defined(_WIN32) || defined(WIN32)
#define TOY_API
#else
#define TOY_API
#endif
#ifndef TOY_EXPORT
//for processing the command line arguments
typedef struct {
bool error;
bool help;
bool version;
char* binaryfile;
char* sourcefile;
char* compilefile;
char* outfile; //defaults to out.tb
char* source;
bool verbose;
} Command;
extern Command command;
void Toy_initCommand(int argc, const char* argv[]);
void Toy_usageCommand(int argc, const char* argv[]);
void Toy_helpCommand(int argc, const char* argv[]);
void Toy_copyrightCommand(int argc, const char* argv[]);
#endif
File diff suppressed because it is too large Load Diff
-21
View File
@@ -1,21 +0,0 @@
#pragma once
#include "toy_common.h"
#include "toy_opcodes.h"
#include "toy_ast_node.h"
#include "toy_literal_array.h"
//the compiler takes the nodes, and turns them into sequential chunks of bytecode, saving literals to an external array
typedef struct Toy_Compiler {
Toy_LiteralArray literalCache;
unsigned char* bytecode;
int capacity;
int count;
} Toy_Compiler;
TOY_API void Toy_initCompiler(Toy_Compiler* compiler);
TOY_API void Toy_writeCompiler(Toy_Compiler* compiler, Toy_ASTNode* node);
TOY_API void Toy_freeCompiler(Toy_Compiler* compiler);
//embed the header, data section, code section, function section, etc.
TOY_API unsigned char* Toy_collateCompiler(Toy_Compiler* compiler, int* size);
-30
View File
@@ -1,30 +0,0 @@
#pragma once
//NOTE: you need both font AND background for these to work
//fonts color
#define TOY_CC_FONT_BLACK "\033[30;"
#define TOY_CC_FONT_RED "\033[31;"
#define TOY_CC_FONT_GREEN "\033[32;"
#define TOY_CC_FONT_YELLOW "\033[33;"
#define TOY_CC_FONT_BLUE "\033[34;"
#define TOY_CC_FONT_PURPLE "\033[35;"
#define TOY_CC_FONT_DGREEN "\033[6;"
#define TOY_CC_FONT_WHITE "\033[7;"
#define TOY_CC_FONT_CYAN "\x1b[36m"
//background color
#define TOY_CC_BACK_BLACK "40m"
#define TOY_CC_BACK_RED "41m"
#define TOY_CC_BACK_GREEN "42m"
#define TOY_CC_BACK_YELLOW "43m"
#define TOY_CC_BACK_BLUE "44m"
#define TOY_CC_BACK_PURPLE "45m"
#define TOY_CC_BACK_DGREEN "46m"
#define TOY_CC_BACK_WHITE "47m"
//useful
#define TOY_CC_NOTICE TOY_CC_FONT_GREEN TOY_CC_BACK_BLACK
#define TOY_CC_WARN TOY_CC_FONT_YELLOW TOY_CC_BACK_BLACK
#define TOY_CC_ERROR TOY_CC_FONT_RED TOY_CC_BACK_BLACK
#define TOY_CC_RESET "\033[0m"
File diff suppressed because it is too large Load Diff
-56
View File
@@ -1,56 +0,0 @@
#pragma once
#include "toy_common.h"
#include "toy_literal.h"
#include "toy_literal_array.h"
#include "toy_literal_dictionary.h"
#include "toy_scope.h"
typedef void (*Toy_PrintFn)(const char*);
//the interpreter acts depending on the bytecode instructions
typedef struct Toy_Interpreter {
//input
unsigned char* bytecode;
int length;
int count;
int codeStart; //BUGFIX: for jumps, must be initialized to -1
Toy_LiteralArray literalCache; //read-only - built from the bytecode, refreshed each time new bytecode is provided
//operation
Toy_Scope* scope;
Toy_LiteralArray stack;
//Library APIs
Toy_LiteralDictionary* hooks;
//debug outputs
Toy_PrintFn printOutput;
Toy_PrintFn assertOutput;
Toy_PrintFn errorOutput;
int depth; //don't overflow
bool panic;
} Toy_Interpreter;
//native API
typedef int (*Toy_NativeFn)(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
TOY_API bool Toy_injectNativeFn(Toy_Interpreter* interpreter, char* name, Toy_NativeFn func);
typedef int (*Toy_HookFn)(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
TOY_API bool Toy_injectNativeHook(Toy_Interpreter* interpreter, char* name, Toy_HookFn hook);
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);
//utilities for the host program
TOY_API bool Toy_parseIdentifierToValue(Toy_Interpreter* interpreter, Toy_Literal* literalPtr);
TOY_API void Toy_setInterpreterPrint(Toy_Interpreter* interpreter, Toy_PrintFn printOutput);
TOY_API void Toy_setInterpreterAssert(Toy_Interpreter* interpreter, Toy_PrintFn assertOutput);
TOY_API void Toy_setInterpreterError(Toy_Interpreter* interpreter, Toy_PrintFn errorOutput);
//main access
TOY_API void Toy_initInterpreter(Toy_Interpreter* interpreter); //start of program
TOY_API void Toy_runInterpreter(Toy_Interpreter* interpreter, unsigned char* bytecode, int length); //run the code
TOY_API void Toy_resetInterpreter(Toy_Interpreter* interpreter); //use this to reset the interpreter's environment between runs
TOY_API void Toy_freeInterpreter(Toy_Interpreter* interpreter); //end of program
-77
View File
@@ -1,77 +0,0 @@
#include "toy_keyword_types.h"
#include "toy_common.h"
#include <string.h>
Toy_KeywordType Toy_keywordTypes[] = {
//type keywords
{TOY_TOKEN_NULL, "null"},
{TOY_TOKEN_BOOLEAN, "bool"},
{TOY_TOKEN_INTEGER, "int"},
{TOY_TOKEN_FLOAT, "float"},
{TOY_TOKEN_STRING, "string"},
{TOY_TOKEN_FUNCTION, "fn"},
{TOY_TOKEN_OPAQUE, "opaque"},
{TOY_TOKEN_ANY, "any"},
//other keywords
{TOY_TOKEN_AS, "as"},
{TOY_TOKEN_ASSERT, "assert"},
{TOY_TOKEN_BREAK, "break"},
{TOY_TOKEN_CLASS, "class"},
{TOY_TOKEN_CONST, "const"},
{TOY_TOKEN_CONTINUE, "continue"},
{TOY_TOKEN_DO, "do"},
{TOY_TOKEN_ELSE, "else"},
{TOY_TOKEN_EXPORT, "export"},
{TOY_TOKEN_FOR, "for"},
{TOY_TOKEN_FOREACH, "foreach"},
{TOY_TOKEN_IF, "if"},
{TOY_TOKEN_IMPORT, "import"},
{TOY_TOKEN_IN, "in"},
{TOY_TOKEN_OF, "of"},
{TOY_TOKEN_PRINT, "print"},
{TOY_TOKEN_RETURN, "return"},
{TOY_TOKEN_TYPE, "type"},
{TOY_TOKEN_ASTYPE, "astype"},
{TOY_TOKEN_TYPEOF, "typeof"},
{TOY_TOKEN_VAR, "var"},
{TOY_TOKEN_WHILE, "while"},
//literal values
{TOY_TOKEN_LITERAL_TRUE, "true"},
{TOY_TOKEN_LITERAL_FALSE, "false"},
//meta tokens
{TOY_TOKEN_PASS, NULL},
{TOY_TOKEN_ERROR, NULL},
{TOY_TOKEN_EOF, NULL},
};
char* Toy_findKeywordByType(Toy_TokenType type) {
if (type == TOY_TOKEN_EOF) {
return "EOF";
}
for(int i = 0; Toy_keywordTypes[i].keyword; i++) {
if (Toy_keywordTypes[i].type == type) {
return Toy_keywordTypes[i].keyword;
}
}
return NULL;
}
Toy_TokenType Toy_findTypeByKeyword(const char* keyword) {
const int length = strlen(keyword);
for (int i = 0; Toy_keywordTypes[i].keyword; i++) {
if (!strncmp(keyword, Toy_keywordTypes[i].keyword, length)) {
return Toy_keywordTypes[i].type;
}
}
return TOY_TOKEN_EOF;
}
-14
View File
@@ -1,14 +0,0 @@
#pragma once
#include "toy_token_types.h"
typedef struct {
Toy_TokenType type;
char* keyword;
} Toy_KeywordType;
extern Toy_KeywordType Toy_keywordTypes[];
char* Toy_findKeywordByType(Toy_TokenType type);
Toy_TokenType Toy_findTypeByKeyword(const char* keyword);
-349
View File
@@ -1,349 +0,0 @@
#include "toy_lexer.h"
#include "toy_console_colors.h"
#include "toy_keyword_types.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
//static generic utility functions
static void cleanLexer(Toy_Lexer* lexer) {
lexer->source = NULL;
lexer->start = 0;
lexer->current = 0;
lexer->line = 1;
}
static bool isAtEnd(Toy_Lexer* lexer) {
return lexer->source[lexer->current] == '\0';
}
static char peek(Toy_Lexer* lexer) {
return lexer->source[lexer->current];
}
static char peekNext(Toy_Lexer* lexer) {
if (isAtEnd(lexer)) return '\0';
return lexer->source[lexer->current + 1];
}
static char advance(Toy_Lexer* lexer) {
if (isAtEnd(lexer)) {
return '\0';
}
//new line
if (lexer->source[lexer->current] == '\n') {
lexer->line++;
}
lexer->current++;
return lexer->source[lexer->current - 1];
}
static void eatWhitespace(Toy_Lexer* lexer) {
const char c = peek(lexer);
switch(c) {
case ' ':
case '\r':
case '\n':
case '\t':
advance(lexer);
break;
//comments
case '/':
//eat the line
if (peekNext(lexer) == '/') {
while (advance(lexer) != '\n' && !isAtEnd(lexer));
break;
}
//eat the block
if (peekNext(lexer) == '*') {
advance(lexer);
advance(lexer);
while(!(peek(lexer) == '*' && peekNext(lexer) == '/')) advance(lexer);
advance(lexer);
advance(lexer);
break;
}
return;
default:
return;
}
//tail recursion
eatWhitespace(lexer);
}
static bool isDigit(Toy_Lexer* lexer) {
return peek(lexer) >= '0' && peek(lexer) <= '9';
}
static bool isAlpha(Toy_Lexer* lexer) {
return
(peek(lexer) >= 'A' && peek(lexer) <= 'Z') ||
(peek(lexer) >= 'a' && peek(lexer) <= 'z') ||
peek(lexer) == '_'
;
}
static bool match(Toy_Lexer* lexer, char c) {
if (peek(lexer) == c) {
advance(lexer);
return true;
}
return false;
}
//token generators
static Toy_Token makeErrorToken(Toy_Lexer* lexer, char* msg) {
Toy_Token token;
token.type = TOY_TOKEN_ERROR;
token.lexeme = msg;
token.length = strlen(msg);
token.line = lexer->line;
#ifndef TOY_EXPORT
if (command.verbose) {
printf("err:");
Toy_printToken(&token);
}
#endif
return token;
}
static Toy_Token makeToken(Toy_Lexer* lexer, Toy_TokenType type) {
Toy_Token token;
token.type = type;
token.length = lexer->current - lexer->start;
token.lexeme = &lexer->source[lexer->current - token.length];
token.line = lexer->line;
#ifndef TOY_EXPORT
//BUG #10: this shows TOKEN_EOF twice due to the overarching structure of the program - can't be fixed
if (command.verbose) {
printf("tok:");
Toy_printToken(&token);
}
#endif
return token;
}
static Toy_Token makeIntegerOrFloat(Toy_Lexer* lexer) {
Toy_TokenType type = TOY_TOKEN_LITERAL_INTEGER; //what am I making?
while(isDigit(lexer)) advance(lexer);
if (peek(lexer) == '.' && (peekNext(lexer) >= '0' && peekNext(lexer) <= '9')) { //BUGFIX: peekNext == digit
type = TOY_TOKEN_LITERAL_FLOAT;
advance(lexer);
while(isDigit(lexer)) advance(lexer);
}
Toy_Token token;
token.type = type;
token.lexeme = &lexer->source[lexer->start];
token.length = lexer->current - lexer->start;
token.line = lexer->line;
#ifndef TOY_EXPORT
if (command.verbose) {
if (type == TOY_TOKEN_LITERAL_INTEGER) {
printf("int:");
} else {
printf("flt:");
}
Toy_printToken(&token);
}
#endif
return token;
}
static Toy_Token makeString(Toy_Lexer* lexer, char terminator) {
while (!isAtEnd(lexer) && peek(lexer) != terminator) {
advance(lexer);
}
advance(lexer); //eat terminator
if (isAtEnd(lexer)) {
return makeErrorToken(lexer, "Unterminated string");
}
Toy_Token token;
token.type = TOY_TOKEN_LITERAL_STRING;
token.lexeme = &lexer->source[lexer->start + 1];
token.length = lexer->current - lexer->start - 2;
token.line = lexer->line;
#ifndef TOY_EXPORT
if (command.verbose) {
printf("str:");
Toy_printToken(&token);
}
#endif
return token;
}
static Toy_Token makeKeywordOrIdentifier(Toy_Lexer* lexer) {
advance(lexer); //first letter can only be alpha
while(isDigit(lexer) || isAlpha(lexer)) {
advance(lexer);
}
//scan for a keyword
for (int i = 0; Toy_keywordTypes[i].keyword; i++) {
if (strlen(Toy_keywordTypes[i].keyword) == (long unsigned int)(lexer->current - lexer->start) && !strncmp(Toy_keywordTypes[i].keyword, &lexer->source[lexer->start], lexer->current - lexer->start)) {
Toy_Token token;
token.type = Toy_keywordTypes[i].type;
token.lexeme = &lexer->source[lexer->start];
token.length = lexer->current - lexer->start;
token.line = lexer->line;
#ifndef TOY_EXPORT
if (command.verbose) {
printf("kwd:");
Toy_printToken(&token);
}
#endif
return token;
}
}
//return an identifier
Toy_Token token;
token.type = TOY_TOKEN_IDENTIFIER;
token.lexeme = &lexer->source[lexer->start];
token.length = lexer->current - lexer->start;
token.line = lexer->line;
#ifndef TOY_EXPORT
if (command.verbose) {
printf("idf:");
Toy_printToken(&token);
}
#endif
return token;
}
//exposed functions
void Toy_initLexer(Toy_Lexer* lexer, char* source) {
cleanLexer(lexer);
lexer->source = source;
}
Toy_Token Toy_scanLexer(Toy_Lexer* lexer) {
eatWhitespace(lexer);
lexer->start = lexer->current;
if (isAtEnd(lexer)) return makeToken(lexer, TOY_TOKEN_EOF);
if (isDigit(lexer)) return makeIntegerOrFloat(lexer);
if (isAlpha(lexer)) return makeKeywordOrIdentifier(lexer);
char c = advance(lexer);
switch(c) {
case '(': return makeToken(lexer, TOY_TOKEN_PAREN_LEFT);
case ')': return makeToken(lexer, TOY_TOKEN_PAREN_RIGHT);
case '{': return makeToken(lexer, TOY_TOKEN_BRACE_LEFT);
case '}': return makeToken(lexer, TOY_TOKEN_BRACE_RIGHT);
case '[': return makeToken(lexer, TOY_TOKEN_BRACKET_LEFT);
case ']': return makeToken(lexer, TOY_TOKEN_BRACKET_RIGHT);
case '+': return makeToken(lexer, match(lexer, '=') ? TOY_TOKEN_PLUS_ASSIGN : match(lexer, '+') ? TOY_TOKEN_PLUS_PLUS: TOY_TOKEN_PLUS);
case '-': return makeToken(lexer, match(lexer, '=') ? TOY_TOKEN_MINUS_ASSIGN : match(lexer, '-') ? TOY_TOKEN_MINUS_MINUS: TOY_TOKEN_MINUS);
case '*': return makeToken(lexer, match(lexer, '=') ? TOY_TOKEN_MULTIPLY_ASSIGN : TOY_TOKEN_MULTIPLY);
case '/': return makeToken(lexer, match(lexer, '=') ? TOY_TOKEN_DIVIDE_ASSIGN : TOY_TOKEN_DIVIDE);
case '%': return makeToken(lexer, match(lexer, '=') ? TOY_TOKEN_MODULO_ASSIGN : TOY_TOKEN_MODULO);
case '!': return makeToken(lexer, match(lexer, '=') ? TOY_TOKEN_NOT_EQUAL : TOY_TOKEN_NOT);
case '=': return makeToken(lexer, match(lexer, '=') ? TOY_TOKEN_EQUAL : TOY_TOKEN_ASSIGN);
case '<': return makeToken(lexer, match(lexer, '=') ? TOY_TOKEN_LESS_EQUAL : TOY_TOKEN_LESS);
case '>': return makeToken(lexer, match(lexer, '=') ? TOY_TOKEN_GREATER_EQUAL : TOY_TOKEN_GREATER);
case '&': //TOKEN_AND not used
if (advance(lexer) != '&') {
return makeErrorToken(lexer, "Unexpected '&'");
} else {
return makeToken(lexer, TOY_TOKEN_AND);
}
case '|': return makeToken(lexer, match(lexer, '|') ? TOY_TOKEN_OR : TOY_TOKEN_PIPE);
case '?': return makeToken(lexer, TOY_TOKEN_QUESTION);
case ':': return makeToken(lexer, TOY_TOKEN_COLON);
case ';': return makeToken(lexer, TOY_TOKEN_SEMICOLON);
case ',': return makeToken(lexer, TOY_TOKEN_COMMA);
case '.':
if (peek(lexer) == '.' && peekNext(lexer) == '.') {
advance(lexer);
advance(lexer);
return makeToken(lexer, TOY_TOKEN_REST);
}
return makeToken(lexer, TOY_TOKEN_DOT);
case '"':
return makeString(lexer, c);
//TODO: possibly support interpolated strings
default: {
char buffer[128];
snprintf(buffer, 128, "Unexpected token: %c", c);
return makeErrorToken(lexer, buffer);
}
}
}
static void trim(char** s, int* l) { //all this to remove a newline?
while( isspace(( (*((unsigned char**)(s)))[(*l) - 1] )) ) (*l)--;
while(**s && isspace( **(unsigned char**)(s)) ) { (*s)++; (*l)--; }
}
//for debugging
void Toy_printToken(Toy_Token* token) {
if (token->type == TOY_TOKEN_ERROR) {
printf(TOY_CC_ERROR "Error\t%d\t%.*s\n" TOY_CC_RESET, token->line, token->length, token->lexeme);
return;
}
printf("\t%d\t%d\t", token->type, token->line);
if (token->type == TOY_TOKEN_IDENTIFIER || token->type == TOY_TOKEN_LITERAL_INTEGER || token->type == TOY_TOKEN_LITERAL_FLOAT || token->type == TOY_TOKEN_LITERAL_STRING) {
printf("%.*s\t", token->length, token->lexeme);
} else {
char* keyword = Toy_findKeywordByType(token->type);
if (keyword != NULL) {
printf("%s", keyword);
} else {
char* str = token->lexeme;
int length = token->length;
trim(&str, &length);
printf("%.*s", length, str);
}
}
printf("\n");
}
-26
View File
@@ -1,26 +0,0 @@
#pragma once
#include "toy_common.h"
#include "toy_token_types.h"
//lexers are bound to a string of code, and return a single token every time scan is called
typedef struct {
char* source;
int start; //start of the token
int current; //current position of the lexer
int line; //track this for error handling
} Toy_Lexer;
//tokens are intermediaries between lexers and parsers
typedef struct {
Toy_TokenType type;
char* lexeme;
int length;
int line;
} Toy_Token;
TOY_API void Toy_initLexer(Toy_Lexer* lexer, char* source);
Toy_Token Toy_scanLexer(Toy_Lexer* lexer);
//for debugging
void Toy_printToken(Toy_Token* token);
-705
View File
@@ -1,705 +0,0 @@
#include "toy_literal.h"
#include "toy_memory.h"
#include "toy_literal_array.h"
#include "toy_literal_dictionary.h"
#include "toy_scope.h"
#include "toy_console_colors.h"
#include <stdio.h>
//hash util functions
static unsigned int hashString(const char* string, int length) {
unsigned int hash = 2166136261u;
for (int i = 0; i < length; i++) {
hash *= string[i];
hash ^= 16777619;
}
return hash;
}
static unsigned int hashUInt(unsigned int x) {
x = ((x >> 16) ^ x) * 0x45d9f3b;
x = ((x >> 16) ^ x) * 0x45d9f3b;
x = (x >> 16) ^ x;
return x;
}
//exposed functions
void Toy_freeLiteral(Toy_Literal literal) {
//refstrings
if (TOY_IS_STRING(literal)) {
Toy_deleteRefString(TOY_AS_STRING(literal));
return;
}
if (TOY_IS_IDENTIFIER(literal)) {
Toy_deleteRefString(TOY_AS_IDENTIFIER(literal));
return;
}
//compounds
if (TOY_IS_ARRAY(literal) || literal.type == TOY_LITERAL_DICTIONARY_INTERMEDIATE || literal.type == TOY_LITERAL_TYPE_INTERMEDIATE) {
Toy_freeLiteralArray(TOY_AS_ARRAY(literal));
TOY_FREE(Toy_LiteralArray, TOY_AS_ARRAY(literal));
return;
}
if (TOY_IS_DICTIONARY(literal)) {
Toy_freeLiteralDictionary(TOY_AS_DICTIONARY(literal));
TOY_FREE(Toy_LiteralDictionary, TOY_AS_DICTIONARY(literal));
return;
}
//complex literals
if (TOY_IS_FUNCTION(literal)) {
Toy_popScope(TOY_AS_FUNCTION(literal).scope);
TOY_AS_FUNCTION(literal).scope = NULL;
TOY_FREE_ARRAY(unsigned char, TOY_AS_FUNCTION(literal).bytecode, TOY_AS_FUNCTION(literal).length);
}
if (TOY_IS_TYPE(literal)) {
for (int i = 0; i < TOY_AS_TYPE(literal).count; i++) {
Toy_freeLiteral(((Toy_Literal*)(TOY_AS_TYPE(literal).subtypes))[i]);
}
TOY_FREE_ARRAY(Toy_Literal, TOY_AS_TYPE(literal).subtypes, TOY_AS_TYPE(literal).capacity);
return;
}
}
bool Toy_private_isTruthy(Toy_Literal x) {
if (TOY_IS_NULL(x)) {
fprintf(stderr, TOY_CC_ERROR "TOY_CC_ERROR: Null is neither true nor false\n" TOY_CC_RESET);
return false;
}
if (TOY_IS_BOOLEAN(x)) {
return TOY_AS_BOOLEAN(x);
}
return true;
}
Toy_Literal Toy_private_toStringLiteral(Toy_RefString* ptr) {
return ((Toy_Literal){TOY_LITERAL_STRING, { .string.ptr = ptr }});
}
Toy_Literal Toy_private_toIdentifierLiteral(Toy_RefString* ptr) {
return ((Toy_Literal){TOY_LITERAL_IDENTIFIER,{ .identifier.ptr = ptr, .identifier.hash = hashString(Toy_toCString(ptr), Toy_lengthRefString(ptr)) }});
}
Toy_Literal* Toy_private_typePushSubtype(Toy_Literal* lit, Toy_Literal subtype) {
//grow the subtype array
if (TOY_AS_TYPE(*lit).count + 1 > TOY_AS_TYPE(*lit).capacity) {
int oldCapacity = TOY_AS_TYPE(*lit).capacity;
TOY_AS_TYPE(*lit).capacity = TOY_GROW_CAPACITY(oldCapacity);
TOY_AS_TYPE(*lit).subtypes = TOY_GROW_ARRAY(Toy_Literal, TOY_AS_TYPE(*lit).subtypes, oldCapacity, TOY_AS_TYPE(*lit).capacity);
}
//actually push
((Toy_Literal*)(TOY_AS_TYPE(*lit).subtypes))[ TOY_AS_TYPE(*lit).count++ ] = subtype;
return &((Toy_Literal*)(TOY_AS_TYPE(*lit).subtypes))[ TOY_AS_TYPE(*lit).count - 1 ];
}
Toy_Literal Toy_copyLiteral(Toy_Literal original) {
switch(original.type) {
case TOY_LITERAL_NULL:
case TOY_LITERAL_BOOLEAN:
case TOY_LITERAL_INTEGER:
case TOY_LITERAL_FLOAT:
//no copying needed
return original;
case TOY_LITERAL_STRING: {
return TOY_TO_STRING_LITERAL(Toy_copyRefString(TOY_AS_STRING(original)));
}
case TOY_LITERAL_ARRAY: {
Toy_LiteralArray* array = TOY_ALLOCATE(Toy_LiteralArray, 1);
Toy_initLiteralArray(array);
//copy each element
for (int i = 0; i < TOY_AS_ARRAY(original)->count; i++) {
Toy_pushLiteralArray(array, TOY_AS_ARRAY(original)->literals[i]);
}
return TOY_TO_ARRAY_LITERAL(array);
}
case TOY_LITERAL_DICTIONARY: {
Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
Toy_initLiteralDictionary(dictionary);
//copy each entry
for (int i = 0; i < TOY_AS_DICTIONARY(original)->capacity; i++) {
if ( !TOY_IS_NULL(TOY_AS_DICTIONARY(original)->entries[i].key) ) {
Toy_setLiteralDictionary(dictionary, TOY_AS_DICTIONARY(original)->entries[i].key, TOY_AS_DICTIONARY(original)->entries[i].value);
}
}
return TOY_TO_DICTIONARY_LITERAL(dictionary);
}
case TOY_LITERAL_FUNCTION: {
unsigned char* buffer = TOY_ALLOCATE(unsigned char, TOY_AS_FUNCTION(original).length);
memcpy(buffer, TOY_AS_FUNCTION(original).bytecode, TOY_AS_FUNCTION(original).length);
Toy_Literal literal = TOY_TO_FUNCTION_LITERAL(buffer, TOY_AS_FUNCTION(original).length);
TOY_AS_FUNCTION(literal).scope = Toy_copyScope(TOY_AS_FUNCTION(original).scope);
return literal;
}
case TOY_LITERAL_IDENTIFIER: {
return TOY_TO_IDENTIFIER_LITERAL(Toy_copyRefString(TOY_AS_IDENTIFIER(original)));
}
case TOY_LITERAL_TYPE: {
Toy_Literal lit = TOY_TO_TYPE_LITERAL(TOY_AS_TYPE(original).typeOf, TOY_AS_TYPE(original).constant);
for (int i = 0; i < TOY_AS_TYPE(original).count; i++) {
TOY_TYPE_PUSH_SUBTYPE(&lit, Toy_copyLiteral( ((Toy_Literal*)(TOY_AS_TYPE(original).subtypes))[i] ));
}
return lit;
}
case TOY_LITERAL_OPAQUE: {
return original; //literally a shallow copy
}
case TOY_LITERAL_DICTIONARY_INTERMEDIATE: {
Toy_LiteralArray* array = TOY_ALLOCATE(Toy_LiteralArray, 1);
Toy_initLiteralArray(array);
//copy each element
for (int i = 0; i < TOY_AS_ARRAY(original)->count; i++) {
Toy_Literal literal = Toy_copyLiteral(TOY_AS_ARRAY(original)->literals[i]);
Toy_pushLiteralArray(array, literal);
Toy_freeLiteral(literal);
}
Toy_Literal ret = TOY_TO_ARRAY_LITERAL(array);
ret.type = TOY_LITERAL_DICTIONARY_INTERMEDIATE;
return ret;
}
case TOY_LITERAL_TYPE_INTERMEDIATE: {
Toy_LiteralArray* array = TOY_ALLOCATE(Toy_LiteralArray, 1);
Toy_initLiteralArray(array);
//copy each element
for (int i = 0; i < TOY_AS_ARRAY(original)->count; i++) {
Toy_Literal literal = Toy_copyLiteral(TOY_AS_ARRAY(original)->literals[i]);
Toy_pushLiteralArray(array, literal);
Toy_freeLiteral(literal);
}
Toy_Literal ret = TOY_TO_ARRAY_LITERAL(array);
ret.type = TOY_LITERAL_TYPE_INTERMEDIATE;
return ret;
}
case TOY_LITERAL_FUNCTION_INTERMEDIATE: //caries a compiler
case TOY_LITERAL_FUNCTION_NATIVE:
case TOY_LITERAL_INDEX_BLANK:
//no copying possible
return original;
default:
fprintf(stderr, TOY_CC_ERROR "TOY_CC_ERROR: Can't copy that literal type: %d\n" TOY_CC_RESET, original.type);
return TOY_TO_NULL_LITERAL;
}
}
bool Toy_literalsAreEqual(Toy_Literal lhs, Toy_Literal rhs) {
//utility for other things
if (lhs.type != rhs.type) {
// ints and floats are compatible
if ((TOY_IS_INTEGER(lhs) || TOY_IS_FLOAT(lhs)) && (TOY_IS_INTEGER(rhs) || TOY_IS_FLOAT(rhs))) {
if (TOY_IS_INTEGER(lhs)) {
return TOY_AS_INTEGER(lhs) + TOY_AS_FLOAT(rhs);
}
else {
return TOY_AS_FLOAT(lhs) + TOY_AS_INTEGER(rhs);
}
}
return false;
}
switch(lhs.type) {
case TOY_LITERAL_NULL:
return true; //can only be true because of the check above
case TOY_LITERAL_BOOLEAN:
return TOY_AS_BOOLEAN(lhs) == TOY_AS_BOOLEAN(rhs);
case TOY_LITERAL_INTEGER:
return TOY_AS_INTEGER(lhs) == TOY_AS_INTEGER(rhs);
case TOY_LITERAL_FLOAT:
return TOY_AS_FLOAT(lhs) == TOY_AS_FLOAT(rhs);
case TOY_LITERAL_STRING:
return Toy_equalsRefString(TOY_AS_STRING(lhs), TOY_AS_STRING(rhs));
case TOY_LITERAL_ARRAY:
case TOY_LITERAL_DICTIONARY_INTERMEDIATE: //BUGFIX
case TOY_LITERAL_TYPE_INTERMEDIATE: //BUGFIX: used for storing types as an array
//mismatched sizes
if (TOY_AS_ARRAY(lhs)->count != TOY_AS_ARRAY(rhs)->count) {
return false;
}
//mismatched elements (in order)
for (int i = 0; i < TOY_AS_ARRAY(lhs)->count; i++) {
if (!Toy_literalsAreEqual( TOY_AS_ARRAY(lhs)->literals[i], TOY_AS_ARRAY(rhs)->literals[i] )) {
return false;
}
}
return true;
case TOY_LITERAL_DICTIONARY:
//relatively slow, especially when nested
for (int i = 0; i < TOY_AS_DICTIONARY(lhs)->capacity; i++) {
if (!TOY_IS_NULL(TOY_AS_DICTIONARY(lhs)->entries[i].key)) { //only compare non-null keys
//check it exists in rhs
if (!Toy_existsLiteralDictionary(TOY_AS_DICTIONARY(rhs), TOY_AS_DICTIONARY(lhs)->entries[i].key)) {
return false;
}
//compare the values
Toy_Literal val = Toy_getLiteralDictionary(TOY_AS_DICTIONARY(rhs), TOY_AS_DICTIONARY(lhs)->entries[i].key); //TODO: could be more efficient
if (!Toy_literalsAreEqual(TOY_AS_DICTIONARY(lhs)->entries[i].value, val)) {
Toy_freeLiteral(val);
return false;
}
Toy_freeLiteral(val);
}
}
return true;
case TOY_LITERAL_FUNCTION:
case TOY_LITERAL_FUNCTION_NATIVE:
return false; //functions are never equal
break;
case TOY_LITERAL_IDENTIFIER:
//check shortcuts
if (TOY_HASH_I(lhs) != TOY_HASH_I(rhs)) {
return false;
}
return Toy_equalsRefString(TOY_AS_IDENTIFIER(lhs), TOY_AS_IDENTIFIER(rhs));
case TOY_LITERAL_TYPE:
//check types
if (TOY_AS_TYPE(lhs).typeOf != TOY_AS_TYPE(rhs).typeOf) {
return false;
}
//const don't match
if (TOY_AS_TYPE(lhs).constant != TOY_AS_TYPE(rhs).constant) {
return false;
}
//check subtypes
if (TOY_AS_TYPE(lhs).count != TOY_AS_TYPE(rhs).count) {
return false;
}
//check array|dictionary signatures are the same (in order)
if (TOY_AS_TYPE(lhs).typeOf == TOY_LITERAL_ARRAY || TOY_AS_TYPE(lhs).typeOf == TOY_LITERAL_DICTIONARY) {
for (int i = 0; i < TOY_AS_TYPE(lhs).count; i++) {
if (!Toy_literalsAreEqual(((Toy_Literal*)(TOY_AS_TYPE(lhs).subtypes))[i], ((Toy_Literal*)(TOY_AS_TYPE(rhs).subtypes))[i])) {
return false;
}
}
}
return true;
case TOY_LITERAL_OPAQUE:
return false; //IDK what this is!
case TOY_LITERAL_ANY:
return true;
case TOY_LITERAL_FUNCTION_INTERMEDIATE:
fprintf(stderr, TOY_CC_ERROR "[internal] Can't compare intermediate functions\n" TOY_CC_RESET);
return false;
case TOY_LITERAL_INDEX_BLANK:
return false;
default:
//should never be seen
fprintf(stderr, TOY_CC_ERROR "[internal] Unrecognized literal type in equality: %d\n" TOY_CC_RESET, lhs.type);
return false;
}
return false;
}
int Toy_hashLiteral(Toy_Literal lit) {
switch(lit.type) {
case TOY_LITERAL_NULL:
return 0;
case TOY_LITERAL_BOOLEAN:
return TOY_AS_BOOLEAN(lit) ? 1 : 0;
case TOY_LITERAL_INTEGER:
return hashUInt((unsigned int)TOY_AS_INTEGER(lit));
case TOY_LITERAL_FLOAT:
return hashUInt(*(unsigned int*)(&TOY_AS_FLOAT(lit)));
case TOY_LITERAL_STRING:
return hashString(Toy_toCString(TOY_AS_STRING(lit)), Toy_lengthRefString(TOY_AS_STRING(lit)));
case TOY_LITERAL_ARRAY: {
unsigned int res = 0;
for (int i = 0; i < TOY_AS_ARRAY(lit)->count; i++) {
res += Toy_hashLiteral(TOY_AS_ARRAY(lit)->literals[i]);
}
return hashUInt(res);
}
case TOY_LITERAL_DICTIONARY: {
unsigned int res = 0;
for (int i = 0; i < TOY_AS_DICTIONARY(lit)->capacity; i++) {
if (!TOY_IS_NULL(TOY_AS_DICTIONARY(lit)->entries[i].key)) { //only hash non-null keys
res += Toy_hashLiteral(TOY_AS_DICTIONARY(lit)->entries[i].key);
res += Toy_hashLiteral(TOY_AS_DICTIONARY(lit)->entries[i].value);
}
}
return hashUInt(res);
}
case TOY_LITERAL_FUNCTION:
case TOY_LITERAL_FUNCTION_NATIVE:
return 0; //can't hash these
case TOY_LITERAL_IDENTIFIER:
return TOY_HASH_I(lit); //pre-computed
case TOY_LITERAL_TYPE:
return TOY_AS_TYPE(lit).typeOf; //nothing else I can do
case TOY_LITERAL_OPAQUE:
case TOY_LITERAL_ANY:
return -1;
default:
//should never bee seen
fprintf(stderr, TOY_CC_ERROR "[internal] Unrecognized literal type in hash: %d\n" TOY_CC_RESET, lit.type);
return 0;
}
}
//utils
static void stdoutWrapper(const char* output) {
printf("%s", output);
}
//buffer the prints
static char* globalPrintBuffer = NULL;
static size_t globalPrintCapacity = 0;
static size_t globalPrintCount = 0;
//BUGFIX: string quotes shouldn't show when just printing strings, but should show when printing them as members of something else
static char quotes = 0; //set to 0 to not show string quotes
static void printToBuffer(const char* str) {
while (strlen(str) + globalPrintCount + 1 > globalPrintCapacity) {
int oldCapacity = globalPrintCapacity;
globalPrintCapacity = TOY_GROW_CAPACITY(globalPrintCapacity);
globalPrintBuffer = TOY_GROW_ARRAY(char, globalPrintBuffer, oldCapacity, globalPrintCapacity);
}
snprintf(globalPrintBuffer + globalPrintCount, strlen(str) + 1, "%s", str);
globalPrintCount += strlen(str);
}
//exposed functions
void Toy_printLiteral(Toy_Literal literal) {
Toy_printLiteralCustom(literal, stdoutWrapper);
}
void Toy_printLiteralCustom(Toy_Literal literal, void (printFn)(const char*)) {
switch(literal.type) {
case TOY_LITERAL_NULL:
printFn("null");
break;
case TOY_LITERAL_BOOLEAN:
printFn(TOY_AS_BOOLEAN(literal) ? "true" : "false");
break;
case TOY_LITERAL_INTEGER: {
char buffer[256];
snprintf(buffer, 256, "%d", TOY_AS_INTEGER(literal));
printFn(buffer);
}
break;
case TOY_LITERAL_FLOAT: {
char buffer[256];
if (TOY_AS_FLOAT(literal) - (int)TOY_AS_FLOAT(literal)) {
snprintf(buffer, 256, "%g", TOY_AS_FLOAT(literal));
}
else {
snprintf(buffer, 256, "%.1f", TOY_AS_FLOAT(literal));
}
printFn(buffer);
}
break;
case TOY_LITERAL_STRING: {
char buffer[TOY_MAX_STRING_LENGTH];
if (!quotes) {
snprintf(buffer, TOY_MAX_STRING_LENGTH, "%.*s", Toy_lengthRefString(TOY_AS_STRING(literal)), Toy_toCString(TOY_AS_STRING(literal)));
}
else {
snprintf(buffer, TOY_MAX_STRING_LENGTH, "%c%.*s%c", quotes, Toy_lengthRefString(TOY_AS_STRING(literal)), Toy_toCString(TOY_AS_STRING(literal)), quotes);
}
printFn(buffer);
}
break;
case TOY_LITERAL_ARRAY: {
Toy_LiteralArray* ptr = TOY_AS_ARRAY(literal);
//hold potential parent-call buffers on the C stack
char* cacheBuffer = globalPrintBuffer;
globalPrintBuffer = NULL;
int cacheCapacity = globalPrintCapacity;
globalPrintCapacity = 0;
int cacheCount = globalPrintCount;
globalPrintCount = 0;
//print the contents to the global buffer
printToBuffer("[");
for (int i = 0; i < ptr->count; i++) {
quotes = '"';
Toy_printLiteralCustom(ptr->literals[i], printToBuffer);
if (i + 1 < ptr->count) {
printToBuffer(",");
}
}
printToBuffer("]");
//swap the parent-call buffer back into place
char* printBuffer = globalPrintBuffer;
int printCapacity = globalPrintCapacity;
int printCount = globalPrintCount;
globalPrintBuffer = cacheBuffer;
globalPrintCapacity = cacheCapacity;
globalPrintCount = cacheCount;
//finally, output and cleanup
printFn(printBuffer);
TOY_FREE_ARRAY(char, printBuffer, printCapacity);
quotes = 0;
}
break;
case TOY_LITERAL_DICTIONARY: {
Toy_LiteralDictionary* ptr = TOY_AS_DICTIONARY(literal);
//hold potential parent-call buffers on the C stack
char* cacheBuffer = globalPrintBuffer;
globalPrintBuffer = NULL;
int cacheCapacity = globalPrintCapacity;
globalPrintCapacity = 0;
int cacheCount = globalPrintCount;
globalPrintCount = 0;
//print the contents to the global buffer
int delimCount = 0;
printToBuffer("[");
for (int i = 0; i < ptr->capacity; i++) {
if (TOY_IS_NULL(ptr->entries[i].key)) {
continue;
}
if (delimCount++ > 0) {
printToBuffer(",");
}
quotes = '"';
Toy_printLiteralCustom(ptr->entries[i].key, printToBuffer);
printToBuffer(":");
quotes = '"';
Toy_printLiteralCustom(ptr->entries[i].value, printToBuffer);
}
//empty dicts MUST have a ":" printed
if (ptr->count == 0) {
printToBuffer(":");
}
printToBuffer("]");
//swap the parent-call buffer back into place
char* printBuffer = globalPrintBuffer;
int printCapacity = globalPrintCapacity;
int printCount = globalPrintCount;
globalPrintBuffer = cacheBuffer;
globalPrintCapacity = cacheCapacity;
globalPrintCount = cacheCount;
//finally, output and cleanup
printFn(printBuffer);
TOY_FREE_ARRAY(char, printBuffer, printCapacity);
quotes = 0;
}
break;
case TOY_LITERAL_FUNCTION:
case TOY_LITERAL_FUNCTION_NATIVE:
printFn("(function)");
break;
case TOY_LITERAL_IDENTIFIER: {
char buffer[256];
snprintf(buffer, 256, "%.*s", Toy_lengthRefString(TOY_AS_IDENTIFIER(literal)), Toy_toCString(TOY_AS_IDENTIFIER(literal)));
printFn(buffer);
}
break;
case TOY_LITERAL_TYPE: {
//hold potential parent-call buffers on the C stack
char* cacheBuffer = globalPrintBuffer;
globalPrintBuffer = NULL;
int cacheCapacity = globalPrintCapacity;
globalPrintCapacity = 0;
int cacheCount = globalPrintCount;
globalPrintCount = 0;
//print the type correctly
printToBuffer("<");
switch(TOY_AS_TYPE(literal).typeOf) {
case TOY_LITERAL_NULL:
printToBuffer("null");
break;
case TOY_LITERAL_BOOLEAN:
printToBuffer("bool");
break;
case TOY_LITERAL_INTEGER:
printToBuffer("int");
break;
case TOY_LITERAL_FLOAT:
printToBuffer("float");
break;
case TOY_LITERAL_STRING:
printToBuffer("string");
break;
case TOY_LITERAL_ARRAY:
//print all in the array
printToBuffer("[");
for (int i = 0; i < TOY_AS_TYPE(literal).count; i++) {
Toy_printLiteralCustom(((Toy_Literal*)(TOY_AS_TYPE(literal).subtypes))[i], printToBuffer);
}
printToBuffer("]");
break;
case TOY_LITERAL_DICTIONARY:
printToBuffer("[");
for (int i = 0; i < TOY_AS_TYPE(literal).count; i += 2) {
Toy_printLiteralCustom(((Toy_Literal*)(TOY_AS_TYPE(literal).subtypes))[i], printToBuffer);
printToBuffer(":");
Toy_printLiteralCustom(((Toy_Literal*)(TOY_AS_TYPE(literal).subtypes))[i + 1], printToBuffer);
}
printToBuffer("]");
break;
case TOY_LITERAL_FUNCTION:
printToBuffer("function");
break;
case TOY_LITERAL_FUNCTION_NATIVE:
printToBuffer("native");
break;
case TOY_LITERAL_IDENTIFIER:
printToBuffer("identifier");
break;
case TOY_LITERAL_TYPE:
printToBuffer("type");
break;
case TOY_LITERAL_OPAQUE:
printToBuffer("opaque");
break;
case TOY_LITERAL_ANY:
printToBuffer("any");
break;
default:
//should never be seen
fprintf(stderr, TOY_CC_ERROR "[internal] Unrecognized literal type in print type: %d\n" TOY_CC_RESET, TOY_AS_TYPE(literal).typeOf);
}
//const (printed last)
if (TOY_AS_TYPE(literal).constant) {
printToBuffer(" const");
}
printToBuffer(">");
//swap the parent-call buffer back into place
char* printBuffer = globalPrintBuffer;
int printCapacity = globalPrintCapacity;
int printCount = globalPrintCount;
globalPrintBuffer = cacheBuffer;
globalPrintCapacity = cacheCapacity;
globalPrintCount = cacheCount;
//finally, output and cleanup
printFn(printBuffer);
TOY_FREE_ARRAY(char, printBuffer, printCapacity);
quotes = 0;
}
break;
case TOY_LITERAL_TYPE_INTERMEDIATE:
case TOY_LITERAL_FUNCTION_INTERMEDIATE:
printFn("Unprintable literal found");
break;
case TOY_LITERAL_OPAQUE:
printFn("(opaque)");
break;
case TOY_LITERAL_ANY:
printFn("(any)");
break;
default:
//should never be seen
fprintf(stderr, TOY_CC_ERROR "[internal] Unrecognized literal type in print: %d\n" TOY_CC_RESET, literal.type);
}
}
-133
View File
@@ -1,133 +0,0 @@
#pragma once
#include "toy_common.h"
#include "toy_refstring.h"
#include <string.h>
typedef enum {
TOY_LITERAL_NULL,
TOY_LITERAL_BOOLEAN,
TOY_LITERAL_INTEGER,
TOY_LITERAL_FLOAT,
TOY_LITERAL_STRING,
TOY_LITERAL_ARRAY,
TOY_LITERAL_DICTIONARY,
TOY_LITERAL_FUNCTION,
TOY_LITERAL_IDENTIFIER,
TOY_LITERAL_TYPE,
TOY_LITERAL_OPAQUE,
TOY_LITERAL_ANY,
//these are meta-level types - not for general use
TOY_LITERAL_TYPE_INTERMEDIATE, //used to process types in the compiler only
TOY_LITERAL_DICTIONARY_INTERMEDIATE, //used to process dictionaries in the compiler only
TOY_LITERAL_FUNCTION_INTERMEDIATE, //used to process functions in the compiler only
TOY_LITERAL_FUNCTION_ARG_REST, //used to process function rest parameters only
TOY_LITERAL_FUNCTION_NATIVE, //for handling native functions only
TOY_LITERAL_INDEX_BLANK, //for blank indexing i.e. arr[:]
} Toy_LiteralType;
typedef struct {
Toy_LiteralType type;
union {
bool boolean;
int integer;
float number;
struct {
Toy_RefString* ptr;
//string hash?
} string;
void* array;
void* dictionary;
struct {
void* bytecode;
void* scope;
int length;
} function;
struct { //for variable names
Toy_RefString* ptr;
int hash;
} identifier;
struct {
Toy_LiteralType typeOf; //no longer a mask
bool constant;
void* subtypes; //for nested types caused by compounds
int capacity;
int count;
} type;
struct {
void* ptr;
int tag; //TODO: remove tags?
} opaque;
} as;
} Toy_Literal;
#define TOY_IS_NULL(value) ((value).type == TOY_LITERAL_NULL)
#define TOY_IS_BOOLEAN(value) ((value).type == TOY_LITERAL_BOOLEAN)
#define TOY_IS_INTEGER(value) ((value).type == TOY_LITERAL_INTEGER)
#define TOY_IS_FLOAT(value) ((value).type == TOY_LITERAL_FLOAT)
#define TOY_IS_STRING(value) ((value).type == TOY_LITERAL_STRING)
#define TOY_IS_ARRAY(value) ((value).type == TOY_LITERAL_ARRAY)
#define TOY_IS_DICTIONARY(value) ((value).type == TOY_LITERAL_DICTIONARY)
#define TOY_IS_FUNCTION(value) ((value).type == TOY_LITERAL_FUNCTION)
#define TOY_IS_FUNCTION_NATIVE(value) ((value).type == TOY_LITERAL_FUNCTION_NATIVE)
#define TOY_IS_IDENTIFIER(value) ((value).type == TOY_LITERAL_IDENTIFIER)
#define TOY_IS_TYPE(value) ((value).type == TOY_LITERAL_TYPE)
#define TOY_IS_OPAQUE(value) ((value).type == TOY_LITERAL_OPAQUE)
#define TOY_AS_BOOLEAN(value) ((value).as.boolean)
#define TOY_AS_INTEGER(value) ((value).as.integer)
#define TOY_AS_FLOAT(value) ((value).as.number)
#define TOY_AS_STRING(value) ((value).as.string.ptr)
#define TOY_AS_ARRAY(value) ((Toy_LiteralArray*)((value).as.array))
#define TOY_AS_DICTIONARY(value) ((Toy_LiteralDictionary*)((value).as.dictionary))
#define TOY_AS_FUNCTION(value) ((value).as.function)
#define TOY_AS_IDENTIFIER(value) ((value).as.identifier.ptr)
#define TOY_AS_TYPE(value) ((value).as.type)
#define TOY_AS_OPAQUE(value) ((value).as.opaque.ptr)
#define TOY_TO_NULL_LITERAL ((Toy_Literal){TOY_LITERAL_NULL, { .integer = 0 }})
#define TOY_TO_BOOLEAN_LITERAL(value) ((Toy_Literal){TOY_LITERAL_BOOLEAN, { .boolean = value }})
#define TOY_TO_INTEGER_LITERAL(value) ((Toy_Literal){TOY_LITERAL_INTEGER, { .integer = value }})
#define TOY_TO_FLOAT_LITERAL(value) ((Toy_Literal){TOY_LITERAL_FLOAT, { .number = value }})
#define TOY_TO_STRING_LITERAL(value) Toy_private_toStringLiteral(value)
#define TOY_TO_ARRAY_LITERAL(value) ((Toy_Literal){TOY_LITERAL_ARRAY, { .array = value }})
#define TOY_TO_DICTIONARY_LITERAL(value) ((Toy_Literal){TOY_LITERAL_DICTIONARY, { .dictionary = value }})
#define TOY_TO_FUNCTION_LITERAL(value, l) ((Toy_Literal){TOY_LITERAL_FUNCTION, { .function.bytecode = value, .function.scope = NULL, .function.length = l }})
#define TOY_TO_IDENTIFIER_LITERAL(value) Toy_private_toIdentifierLiteral(value)
#define TOY_TO_TYPE_LITERAL(value, c) ((Toy_Literal){ TOY_LITERAL_TYPE, { .type.typeOf = value, .type.constant = c, .type.subtypes = NULL, .type.capacity = 0, .type.count = 0 }})
#define TOY_TO_OPAQUE_LITERAL(value, t) ((Toy_Literal){ TOY_LITERAL_OPAQUE, { .opaque.ptr = value, .opaque.tag = t }})
//BUGFIX: For blank indexing
#define TOY_IS_INDEX_BLANK(value) ((value).type == TOY_LITERAL_INDEX_BLANK)
#define TOY_TO_INDEX_BLANK_LITERAL ((Toy_Literal){TOY_LITERAL_INDEX_BLANK, { .integer = 0 }})
TOY_API void Toy_freeLiteral(Toy_Literal literal);
#define TOY_IS_TRUTHY(x) Toy_private_isTruthy(x)
#define TOY_MAX_STRING_LENGTH 4096
#define TOY_HASH_I(lit) ((lit).as.identifier.hash)
#define TOY_TYPE_PUSH_SUBTYPE(lit, subtype) Toy_private_typePushSubtype(lit, subtype)
#define TOY_GET_OPAQUE_TAG(o) o.as.opaque.tag
//BUGFIX: macros are not functions
TOY_API bool Toy_private_isTruthy(Toy_Literal x);
TOY_API Toy_Literal Toy_private_toStringLiteral(Toy_RefString* ptr);
TOY_API Toy_Literal Toy_private_toIdentifierLiteral(Toy_RefString* ptr);
TOY_API Toy_Literal* Toy_private_typePushSubtype(Toy_Literal* lit, Toy_Literal subtype);
//utils
TOY_API Toy_Literal Toy_copyLiteral(Toy_Literal original);
TOY_API bool Toy_literalsAreEqual(Toy_Literal lhs, Toy_Literal rhs);
TOY_API int Toy_hashLiteral(Toy_Literal lit);
TOY_API void Toy_printLiteral(Toy_Literal literal);
TOY_API void Toy_printLiteralCustom(Toy_Literal literal, void (printFn)(const char*));
-98
View File
@@ -1,98 +0,0 @@
#include "toy_literal_array.h"
#include "toy_memory.h"
#include <stdio.h>
#include <string.h>
//exposed functions
void Toy_initLiteralArray(Toy_LiteralArray* array) {
array->capacity = 0;
array->count = 0;
array->literals = NULL;
}
void Toy_freeLiteralArray(Toy_LiteralArray* array) {
//clean up memory
for(int i = 0; i < array->count; i++) {
Toy_freeLiteral(array->literals[i]);
}
TOY_FREE_ARRAY(Toy_Literal, array->literals, array->capacity);
Toy_initLiteralArray(array);
}
int Toy_pushLiteralArray(Toy_LiteralArray* array, Toy_Literal literal) {
if (array->capacity < array->count + 1) {
int oldCapacity = array->capacity;
array->capacity = TOY_GROW_CAPACITY(oldCapacity);
array->literals = TOY_GROW_ARRAY(Toy_Literal, array->literals, oldCapacity, array->capacity);
}
array->literals[array->count] = Toy_copyLiteral(literal);
return array->count++;
}
Toy_Literal Toy_popLiteralArray(Toy_LiteralArray* array) {
if (array->count <= 0) {
return TOY_TO_NULL_LITERAL;
}
//get the return
Toy_Literal ret = array->literals[array->count-1];
//null the existing data
array->literals[array->count-1] = TOY_TO_NULL_LITERAL;
array->count--;
return ret;
}
//find a literal in the array that matches the "literal" argument
int Toy_findLiteralIndex(Toy_LiteralArray* array, Toy_Literal literal) {
for (int i = 0; i < array->count; i++) {
//not the same type
if (array->literals[i].type != literal.type) {
continue;
}
//types match?
if (Toy_literalsAreEqual(array->literals[i], literal)) {
return i;
}
}
return -1;
}
bool Toy_setLiteralArray(Toy_LiteralArray* array, Toy_Literal index, Toy_Literal value) {
if (!TOY_IS_INTEGER(index)) {
return false;
}
int idx = TOY_AS_INTEGER(index);
if (idx < 0 || idx >= array->count) {
return false;
}
Toy_freeLiteral(array->literals[idx]);
array->literals[idx] = Toy_copyLiteral(value);
return true;
}
Toy_Literal Toy_getLiteralArray(Toy_LiteralArray* array, Toy_Literal index) {
if (!TOY_IS_INTEGER(index)) {
return TOY_TO_NULL_LITERAL;
}
int idx = TOY_AS_INTEGER(index);
if (idx < 0 || idx >= array->count) {
return TOY_TO_NULL_LITERAL;
}
return Toy_copyLiteral(array->literals[idx]);
}
-20
View File
@@ -1,20 +0,0 @@
#pragma once
#include "toy_common.h"
#include "toy_literal.h"
typedef struct Toy_LiteralArray {
Toy_Literal* literals;
int capacity;
int count;
} Toy_LiteralArray;
TOY_API void Toy_initLiteralArray(Toy_LiteralArray* array);
TOY_API void Toy_freeLiteralArray(Toy_LiteralArray* array);
TOY_API int Toy_pushLiteralArray(Toy_LiteralArray* array, Toy_Literal literal);
TOY_API Toy_Literal Toy_popLiteralArray(Toy_LiteralArray* array);
TOY_API bool Toy_setLiteralArray(Toy_LiteralArray* array, Toy_Literal index, Toy_Literal value);
TOY_API Toy_Literal Toy_getLiteralArray(Toy_LiteralArray* array, Toy_Literal index);
int Toy_findLiteralIndex(Toy_LiteralArray* array, Toy_Literal literal);
-219
View File
@@ -1,219 +0,0 @@
#include "toy_literal_dictionary.h"
#include "toy_memory.h"
#include "toy_console_colors.h"
#include <stdio.h>
//util functions
static void setEntryValues(Toy_private_entry* entry, Toy_Literal key, Toy_Literal value) {
//much simpler now
Toy_freeLiteral(entry->key);
entry->key = Toy_copyLiteral(key);
Toy_freeLiteral(entry->value);
entry->value = Toy_copyLiteral(value);
}
static Toy_private_entry* getEntryArray(Toy_private_entry* array, int capacity, Toy_Literal key, unsigned int hash, bool mustExist) {
//find "key", starting at index
unsigned int index = hash % capacity;
unsigned int start = index;
//increment once, so it can't equal start
index = (index + 1) % capacity;
//literal probing and collision checking
while (index != start) { //WARNING: this is the only function allowed to retrieve an entry from the array
Toy_private_entry* entry = &array[index];
if (TOY_IS_NULL(entry->key)) { //if key is empty, it's either empty or tombstone
if (TOY_IS_NULL(entry->value) && !mustExist) {
//found a truly empty bucket
return entry;
}
//else it's a tombstone - ignore
} else {
if (Toy_literalsAreEqual(key, entry->key)) {
return entry;
}
}
index = (index + 1) % capacity;
}
return NULL;
}
static void adjustEntryCapacity(Toy_private_entry** dictionaryHandle, int oldCapacity, int capacity) {
//new entry space
Toy_private_entry* newEntries = TOY_ALLOCATE(Toy_private_entry, capacity);
for (int i = 0; i < capacity; i++) {
newEntries[i].key = TOY_TO_NULL_LITERAL;
newEntries[i].value = TOY_TO_NULL_LITERAL;
}
//move the old array into the new one
for (int i = 0; i < oldCapacity; i++) {
if (TOY_IS_NULL((*dictionaryHandle)[i].key)) {
continue;
}
//place the key and value in the new array (reusing string memory)
Toy_private_entry* entry = getEntryArray(newEntries, capacity, TOY_TO_NULL_LITERAL, Toy_hashLiteral((*dictionaryHandle)[i].key), false);
entry->key = (*dictionaryHandle)[i].key;
entry->value = (*dictionaryHandle)[i].value;
}
//clear the old array
TOY_FREE_ARRAY(Toy_private_entry, *dictionaryHandle, oldCapacity);
*dictionaryHandle = newEntries;
}
static bool setEntryArray(Toy_private_entry** dictionaryHandle, int* capacityPtr, int contains, Toy_Literal key, Toy_Literal value, int hash) {
//expand array if needed
if (contains + 1 > *capacityPtr * TOY_DICTIONARY_MAX_LOAD) {
int oldCapacity = *capacityPtr;
*capacityPtr = TOY_GROW_CAPACITY(*capacityPtr);
adjustEntryCapacity(dictionaryHandle, oldCapacity, *capacityPtr); //custom rather than automatic reallocation
}
Toy_private_entry* entry = getEntryArray(*dictionaryHandle, *capacityPtr, key, hash, false);
//true = contains increase
if (TOY_IS_NULL(entry->key)) {
setEntryValues(entry, key, value);
return true;
}
else {
setEntryValues(entry, key, value);
return false;
}
return false;
}
static void freeEntry(Toy_private_entry* entry) {
Toy_freeLiteral(entry->key);
Toy_freeLiteral(entry->value);
entry->key = TOY_TO_NULL_LITERAL;
entry->value = TOY_TO_NULL_LITERAL;
}
static void freeEntryArray(Toy_private_entry* array, int capacity) {
if (array == NULL) {
return;
}
for (int i = 0; i < capacity; i++) {
if (!TOY_IS_NULL(array[i].key)) {
freeEntry(&array[i]);
}
}
TOY_FREE_ARRAY(Toy_private_entry, array, capacity);
}
//exposed functions
void Toy_initLiteralDictionary(Toy_LiteralDictionary* dictionary) {
//HACK: because modulo by 0 is undefined, set the capacity to a non-zero value (and allocate the arrays)
dictionary->entries = NULL;
dictionary->capacity = TOY_GROW_CAPACITY(0);
dictionary->contains = 0;
dictionary->count = 0;
adjustEntryCapacity(&dictionary->entries, 0, dictionary->capacity);
}
void Toy_freeLiteralDictionary(Toy_LiteralDictionary* dictionary) {
freeEntryArray(dictionary->entries, dictionary->capacity);
dictionary->capacity = 0;
dictionary->contains = 0;
}
void Toy_setLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key, Toy_Literal value) {
if (TOY_IS_NULL(key)) {
fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have null keys (set)\n" TOY_CC_RESET);
return;
}
//BUGFIX: Can't hash a function
if (TOY_IS_FUNCTION(key) || TOY_IS_FUNCTION_NATIVE(key)) {
fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have function keys (set)\n" TOY_CC_RESET);
return;
}
if (TOY_IS_OPAQUE(key)) {
fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have opaque keys (set)\n" TOY_CC_RESET);
return;
}
const int increment = setEntryArray(&dictionary->entries, &dictionary->capacity, dictionary->contains, key, value, Toy_hashLiteral(key));
if (increment) {
dictionary->contains++;
dictionary->count++;
}
}
Toy_Literal Toy_getLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key) {
if (TOY_IS_NULL(key)) {
fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have null keys (get)\n" TOY_CC_RESET);
return TOY_TO_NULL_LITERAL;
}
//BUGFIX: Can't hash a function
if (TOY_IS_FUNCTION(key) || TOY_IS_FUNCTION_NATIVE(key)) {
fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have function keys (get)\n" TOY_CC_RESET);
return TOY_TO_NULL_LITERAL;
}
if (TOY_IS_OPAQUE(key)) {
fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have opaque keys (get)\n" TOY_CC_RESET);
return TOY_TO_NULL_LITERAL;
}
Toy_private_entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, Toy_hashLiteral(key), true);
if (entry != NULL) {
return Toy_copyLiteral(entry->value);
}
else {
return TOY_TO_NULL_LITERAL;
}
}
void Toy_removeLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key) {
if (TOY_IS_NULL(key)) {
fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have null keys (remove)\n" TOY_CC_RESET);
return;
}
//BUGFIX: Can't hash a function
if (TOY_IS_FUNCTION(key) || TOY_IS_FUNCTION_NATIVE(key)) {
fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have function keys (remove)\n" TOY_CC_RESET);
return;
}
if (TOY_IS_OPAQUE(key)) {
fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have opaque keys (remove)\n" TOY_CC_RESET);
return;
}
Toy_private_entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, Toy_hashLiteral(key), true);
if (entry != NULL) {
freeEntry(entry);
entry->value = TOY_TO_BOOLEAN_LITERAL(true); //tombstone
dictionary->count--;
}
}
bool Toy_existsLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key) {
//null & not tombstoned
Toy_private_entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, Toy_hashLiteral(key), false);
return !(TOY_IS_NULL(entry->key) && TOY_IS_NULL(entry->value));
}
-29
View File
@@ -1,29 +0,0 @@
#pragma once
#include "toy_common.h"
#include "toy_literal.h"
//TODO: benchmark this
#define TOY_DICTIONARY_MAX_LOAD 0.75
typedef struct Toy_private_entry {
Toy_Literal key;
Toy_Literal value;
} Toy_private_entry;
typedef struct Toy_LiteralDictionary {
Toy_private_entry* entries;
int capacity;
int count;
int contains; //count + tombstones, for internal use
} Toy_LiteralDictionary;
TOY_API void Toy_initLiteralDictionary(Toy_LiteralDictionary* dictionary);
TOY_API void Toy_freeLiteralDictionary(Toy_LiteralDictionary* dictionary);
TOY_API void Toy_setLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key, Toy_Literal value);
TOY_API Toy_Literal Toy_getLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key);
TOY_API void Toy_removeLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key);
TOY_API bool Toy_existsLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key);
-58
View File
@@ -1,58 +0,0 @@
#include "toy_memory.h"
#include "toy_refstring.h"
#include "toy_console_colors.h"
#include <stdio.h>
#include <stdlib.h>
//default allocator
static void* defaultMemoryAllocator(void* pointer, size_t oldSize, size_t newSize) {
if (newSize == 0 && oldSize == 0) {
//causes issues, so just skip out with a NO-OP
return NULL;
}
if (newSize == 0) {
free(pointer);
return NULL;
}
void* mem = realloc(pointer, newSize);
if (mem == NULL) {
fprintf(stderr, TOY_CC_ERROR "[internal] Memory allocation error (requested %d for %ld, replacing %d)\n" TOY_CC_RESET, (int)newSize, (long int)pointer, (int)oldSize);
exit(-1);
}
return mem;
}
//static variables
static Toy_MemoryAllocatorFn allocator;
//preload
static void __attribute__((constructor)) preloadMemoryAllocator() {
Toy_setMemoryAllocator(defaultMemoryAllocator);
}
//exposed API
void* Toy_reallocate(void* pointer, size_t oldSize, size_t newSize) {
return allocator(pointer, oldSize, newSize);
}
void Toy_setMemoryAllocator(Toy_MemoryAllocatorFn fn) {
if (fn == NULL) {
fprintf(stderr, TOY_CC_ERROR "[internal] Memory allocator error (can't be null)\n" TOY_CC_RESET);
exit(-1);
}
if (fn == Toy_reallocate) {
fprintf(stderr, TOY_CC_ERROR "[internal] Memory allocator error (can't loop the Toy_reallocate function)\n" TOY_CC_RESET);
exit(-1);
}
allocator = fn;
Toy_setRefStringAllocatorFn(fn);
}
-18
View File
@@ -1,18 +0,0 @@
#pragma once
#include "toy_common.h"
#define TOY_ALLOCATE(type, count) ((type*)Toy_reallocate(NULL, 0, sizeof(type) * (count)))
#define TOY_FREE(type, pointer) Toy_reallocate(pointer, sizeof(type), 0)
#define TOY_GROW_CAPACITY(capacity) ((capacity) < 8 ? 8 : (capacity) * 2)
#define TOY_GROW_CAPACITY_FAST(capacity) ((capacity) < 32 ? 32 : (capacity) * 2)
#define TOY_GROW_ARRAY(type, pointer, oldCount, count) (type*)Toy_reallocate((type*)pointer, sizeof(type) * (oldCount), sizeof(type) * (count))
#define TOY_SHRINK_ARRAY(type, pointer, oldCount, count) (type*)Toy_reallocate((type*)pointer, sizeof(type) * (oldCount), sizeof(type) * (count))
#define TOY_FREE_ARRAY(type, pointer, oldCount) Toy_reallocate((type*)pointer, sizeof(type) * (oldCount), 0)
//implementation details
void* Toy_reallocate(void* pointer, size_t oldSize, size_t newSize);
//assign the memory allocator
typedef void* (*Toy_MemoryAllocatorFn)(void* pointer, size_t oldSize, size_t newSize);
TOY_API void Toy_setMemoryAllocator(Toy_MemoryAllocatorFn);
-87
View File
@@ -1,87 +0,0 @@
#pragma once
typedef enum Toy_Opcode {
TOY_OP_EOF,
//basic statements
TOY_OP_ASSERT,
TOY_OP_PRINT,
//data
TOY_OP_LITERAL,
TOY_OP_LITERAL_LONG, //for more than 256 literals in a chunk
TOY_OP_LITERAL_RAW, //forcibly get the raw value of the literal
//arithmetic operators
TOY_OP_NEGATE,
TOY_OP_ADDITION,
TOY_OP_SUBTRACTION,
TOY_OP_MULTIPLICATION,
TOY_OP_DIVISION,
TOY_OP_MODULO,
TOY_OP_GROUPING_BEGIN,
TOY_OP_GROUPING_END,
//variable stuff
TOY_OP_SCOPE_BEGIN,
TOY_OP_SCOPE_END,
TOY_OP_TYPE_DECL, //declare a type to be used (as a literal)
TOY_OP_TYPE_DECL_LONG, //declare a type to be used (as a long literal)
TOY_OP_VAR_DECL, //declare a variable to be used (as a literal)
TOY_OP_VAR_DECL_LONG, //declare a variable to be used (as a long literal)
TOY_OP_FN_DECL, //declare a function to be used (as a literal)
TOY_OP_FN_DECL_LONG, //declare a function to be used (as a long literal)
TOY_OP_VAR_ASSIGN, //assign to a literal
TOY_OP_VAR_ADDITION_ASSIGN,
TOY_OP_VAR_SUBTRACTION_ASSIGN,
TOY_OP_VAR_MULTIPLICATION_ASSIGN,
TOY_OP_VAR_DIVISION_ASSIGN,
TOY_OP_VAR_MODULO_ASSIGN,
TOY_OP_TYPE_CAST, //temporarily change a type of an atomic value
TOY_OP_TYPE_OF, //get the type of a variable
TOY_OP_IMPORT,
TOY_OP_EXPORT_removed,
//for indexing
TOY_OP_INDEX,
TOY_OP_INDEX_ASSIGN,
TOY_OP_INDEX_ASSIGN_INTERMEDIATE,
TOY_OP_DOT,
//comparison of values
TOY_OP_COMPARE_EQUAL,
TOY_OP_COMPARE_NOT_EQUAL,
TOY_OP_COMPARE_LESS,
TOY_OP_COMPARE_LESS_EQUAL,
TOY_OP_COMPARE_GREATER,
TOY_OP_COMPARE_GREATER_EQUAL,
TOY_OP_INVERT, //for booleans
//logical operators
TOY_OP_AND,
TOY_OP_OR,
//jumps, and conditional jumps (absolute)
TOY_OP_JUMP,
TOY_OP_IF_FALSE_JUMP,
TOY_OP_FN_CALL,
TOY_OP_FN_RETURN,
//pop the stack at the end of a complex statement
TOY_OP_POP_STACK,
//ternary shorthand
TOY_OP_TERNARY,
//meta
TOY_OP_FN_END, //different from SECTION_END
TOY_OP_SECTION_END = 255,
//TODO: add more
} Toy_Opcode;
-1772
View File
File diff suppressed because it is too large Load Diff
-20
View File
@@ -1,20 +0,0 @@
#pragma once
#include "toy_common.h"
#include "toy_lexer.h"
#include "toy_ast_node.h"
//DOCS: parsers are bound to a lexer, and turn the outputted tokens into AST nodes
typedef struct {
Toy_Lexer* lexer;
bool error; //I've had an error
bool panic; //I am processing an error
//track the last two outputs from the lexer
Toy_Token current;
Toy_Token previous;
} Toy_Parser;
TOY_API void Toy_initParser(Toy_Parser* parser, Toy_Lexer* lexer);
TOY_API void Toy_freeParser(Toy_Parser* parser);
TOY_API Toy_ASTNode* Toy_scanParser(Toy_Parser* parser);
-98
View File
@@ -1,98 +0,0 @@
#include "toy_refstring.h"
#include <string.h>
#include <assert.h>
//test variable sizes based on platform (safety)
#define STATIC_ASSERT(test_for_true) static_assert((test_for_true), "(" #test_for_true ") failed")
STATIC_ASSERT(sizeof(Toy_RefString) == 12);
STATIC_ASSERT(sizeof(int) == 4);
STATIC_ASSERT(sizeof(char) == 1);
//memory allocation
static Toy_RefStringAllocatorFn allocate;
void Toy_setRefStringAllocatorFn(Toy_RefStringAllocatorFn allocator) {
allocate = allocator;
}
//API
Toy_RefString* Toy_createRefString(char* cstring) {
int length = strnlen(cstring, 4096);
return Toy_createRefStringLength(cstring, length);
}
Toy_RefString* Toy_createRefStringLength(char* cstring, int length) {
//allocate the memory area (including metadata space)
Toy_RefString* refString = (Toy_RefString*)allocate(NULL, 0, sizeof(int) * 2 + sizeof(char) * length + 1);
//set the data
refString->refcount = 1;
refString->length = length;
strncpy(refString->data, cstring, refString->length);
refString->data[refString->length] = '\0'; //string terminator
return refString;
}
void Toy_deleteRefString(Toy_RefString* refString) {
//decrement, then check
refString->refcount--;
if (refString->refcount <= 0) {
allocate(refString, sizeof(int) * 2 + sizeof(char) * refString->length + 1, 0);
}
}
int Toy_countRefString(Toy_RefString* refString) {
return refString->refcount;
}
int Toy_lengthRefString(Toy_RefString* refString) {
return refString->length;
}
Toy_RefString* Toy_copyRefString(Toy_RefString* refString) {
//Cheaty McCheater Face
refString->refcount++;
return refString;
}
Toy_RefString* Toy_deepCopyRefString(Toy_RefString* refString) {
//create a new string, with a new refcount
return Toy_createRefStringLength(refString->data, refString->length);
}
char* Toy_toCString(Toy_RefString* refString) {
return refString->data;
}
bool Toy_equalsRefString(Toy_RefString* lhs, Toy_RefString* rhs) {
//same pointer
if (lhs == rhs) {
return true;
}
//different length
if (lhs->length != rhs->length) {
return false;
}
//same string
return strncmp(lhs->data, rhs->data, lhs->length) == 0;
}
bool Toy_equalsRefStringCString(Toy_RefString* lhs, char* cstring) {
//get the rhs length
int length = strnlen(cstring, 4096);
//different length
if (lhs->length != length) {
return false;
}
//same string
return strncmp(lhs->data, cstring, lhs->length) == 0;
}
-27
View File
@@ -1,27 +0,0 @@
#pragma once
#include <stdbool.h>
#include <stddef.h>
//memory allocation hook
typedef void* (*Toy_RefStringAllocatorFn)(void* pointer, size_t oldSize, size_t newSize);
void Toy_setRefStringAllocatorFn(Toy_RefStringAllocatorFn);
//the RefString structure
typedef struct Toy_RefString {
int refcount;
int length;
char data[1];
} Toy_RefString;
//API
Toy_RefString* Toy_createRefString(char* cstring);
Toy_RefString* Toy_createRefStringLength(char* cstring, int length);
void Toy_deleteRefString(Toy_RefString* refString);
int Toy_countRefString(Toy_RefString* refString);
int Toy_lengthRefString(Toy_RefString* refString);
Toy_RefString* Toy_copyRefString(Toy_RefString* refString);
Toy_RefString* Toy_deepCopyRefString(Toy_RefString* refString);
char* Toy_toCString(Toy_RefString* refString);
bool Toy_equalsRefString(Toy_RefString* lhs, Toy_RefString* rhs);
bool Toy_equalsRefStringCString(Toy_RefString* lhs, char* cstring);
-324
View File
@@ -1,324 +0,0 @@
#include "toy_scope.h"
#include "toy_memory.h"
//run up the ancestor chain, freeing anything with 0 references left
static void freeAncestorChain(Toy_Scope* scope) {
scope->references--;
//free scope chain
if (scope->ancestor != NULL) {
freeAncestorChain(scope->ancestor);
}
if (scope->references > 0) {
return;
}
Toy_freeLiteralDictionary(&scope->variables);
Toy_freeLiteralDictionary(&scope->types);
TOY_FREE(Toy_Scope, scope);
}
//return false if invalid type
static bool checkType(Toy_Literal typeLiteral, Toy_Literal original, Toy_Literal value, bool constCheck) {
//for constants, fail if original != value
if (constCheck && TOY_AS_TYPE(typeLiteral).constant && !Toy_literalsAreEqual(original, value)) {
return false;
}
//for any types
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_ANY) {
return true;
}
//don't allow null types
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_NULL) {
return false;
}
//always allow null values
if (TOY_IS_NULL(value)) {
return true;
}
//for each type, if a mismatch is found, return false
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_BOOLEAN && !TOY_IS_BOOLEAN(value)) {
return false;
}
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_INTEGER && !TOY_IS_INTEGER(value)) {
return false;
}
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_FLOAT && !TOY_IS_FLOAT(value)) {
return false;
}
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_STRING && !TOY_IS_STRING(value)) {
return false;
}
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_ARRAY && !TOY_IS_ARRAY(value)) {
return false;
}
if (TOY_IS_ARRAY(value)) {
//check value's type
if (TOY_AS_TYPE(typeLiteral).typeOf != TOY_LITERAL_ARRAY) {
return false;
}
//if null, assume it's a new array variable that needs checking
if (TOY_IS_NULL(original)) {
for (int i = 0; i < TOY_AS_ARRAY(value)->count; i++) {
if (!checkType( ((Toy_Literal*)(TOY_AS_TYPE(typeLiteral).subtypes))[0], TOY_TO_NULL_LITERAL, TOY_AS_ARRAY(value)->literals[i], constCheck)) {
return false;
}
}
return true;
}
//check children
for (int i = 0; i < TOY_AS_ARRAY(value)->count; i++) {
if (TOY_AS_ARRAY(original)->count <= i) {
return true; //assume new entry pushed
}
if (!checkType(((Toy_Literal*)(TOY_AS_TYPE(typeLiteral).subtypes))[0], TOY_AS_ARRAY(original)->literals[i], TOY_AS_ARRAY(value)->literals[i], constCheck)) {
return false;
}
}
}
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_DICTIONARY && !TOY_IS_DICTIONARY(value)) {
return false;
}
if (TOY_IS_DICTIONARY(value)) {
//check value's type
if (TOY_AS_TYPE(typeLiteral).typeOf != TOY_LITERAL_DICTIONARY) {
return false;
}
//if null, assume it's a new dictionary variable that needs checking
if (TOY_IS_NULL(original)) {
for (int i = 0; i < TOY_AS_DICTIONARY(value)->capacity; i++) {
//check the type of key and value
if (!checkType(((Toy_Literal*)(TOY_AS_TYPE(typeLiteral).subtypes))[0], TOY_TO_NULL_LITERAL, TOY_AS_DICTIONARY(value)->entries[i].key, constCheck)) {
return false;
}
if (!checkType(((Toy_Literal*)(TOY_AS_TYPE(typeLiteral).subtypes))[1], TOY_TO_NULL_LITERAL, TOY_AS_DICTIONARY(value)->entries[i].value, constCheck)) {
return false;
}
}
return true;
}
//check each child of value against the child of original
for (int i = 0; i < TOY_AS_DICTIONARY(value)->capacity; i++) {
if (TOY_IS_NULL(TOY_AS_DICTIONARY(value)->entries[i].key)) { //only non-tombstones
continue;
}
//find the internal child of original that matches this child of value
Toy_private_entry* ptr = NULL;
for (int j = 0; j < TOY_AS_DICTIONARY(original)->capacity; j++) {
if (Toy_literalsAreEqual(TOY_AS_DICTIONARY(original)->entries[j].key, TOY_AS_DICTIONARY(value)->entries[i].key)) {
ptr = &TOY_AS_DICTIONARY(original)->entries[j];
break;
}
}
//if not found, assume it's a new entry
if (!ptr) {
continue;
}
//check the type of key and value
if (!checkType(((Toy_Literal*)(TOY_AS_TYPE(typeLiteral).subtypes))[0], ptr->key, TOY_AS_DICTIONARY(value)->entries[i].key, constCheck)) {
return false;
}
if (!checkType(((Toy_Literal*)(TOY_AS_TYPE(typeLiteral).subtypes))[1], ptr->value, TOY_AS_DICTIONARY(value)->entries[i].value, constCheck)) {
return false;
}
}
}
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_FUNCTION && !TOY_IS_FUNCTION(value)) {
return false;
}
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_TYPE && !TOY_IS_TYPE(value)) {
return false;
}
return true;
}
//exposed functions
Toy_Scope* Toy_pushScope(Toy_Scope* ancestor) {
Toy_Scope* scope = TOY_ALLOCATE(Toy_Scope, 1);
scope->ancestor = ancestor;
Toy_initLiteralDictionary(&scope->variables);
Toy_initLiteralDictionary(&scope->types);
//tick up all scope reference counts
scope->references = 0;
for (Toy_Scope* ptr = scope; ptr != NULL; ptr = ptr->ancestor) {
ptr->references++;
}
return scope;
}
Toy_Scope* Toy_popScope(Toy_Scope* scope) {
if (scope == NULL) { //CAN pop a null
return NULL;
}
Toy_Scope* ret = scope->ancestor;
//BUGFIX: when freeing a scope, free the function's scopes manually
for (int i = 0; i < scope->variables.capacity; i++) {
//handle keys, just in case
if (TOY_IS_FUNCTION(scope->variables.entries[i].key)) {
Toy_popScope(TOY_AS_FUNCTION(scope->variables.entries[i].key).scope);
TOY_AS_FUNCTION(scope->variables.entries[i].key).scope = NULL;
}
if (TOY_IS_FUNCTION(scope->variables.entries[i].value)) {
Toy_popScope(TOY_AS_FUNCTION(scope->variables.entries[i].value).scope);
TOY_AS_FUNCTION(scope->variables.entries[i].value).scope = NULL;
}
}
freeAncestorChain(scope);
return ret;
}
Toy_Scope* Toy_copyScope(Toy_Scope* original) {
Toy_Scope* scope = TOY_ALLOCATE(Toy_Scope, 1);
scope->ancestor = original->ancestor;
Toy_initLiteralDictionary(&scope->variables);
Toy_initLiteralDictionary(&scope->types);
//tick up all scope reference counts
scope->references = 0;
for (Toy_Scope* ptr = scope; ptr != NULL; ptr = ptr->ancestor) {
ptr->references++;
}
//copy the contents of the dictionaries
for (int i = 0; i < original->variables.capacity; i++) {
if (!TOY_IS_NULL(original->variables.entries[i].key)) {
Toy_setLiteralDictionary(&scope->variables, original->variables.entries[i].key, original->variables.entries[i].value);
}
}
for (int i = 0; i < original->types.capacity; i++) {
if (!TOY_IS_NULL(original->types.entries[i].key)) {
Toy_setLiteralDictionary(&scope->types, original->types.entries[i].key, original->types.entries[i].value);
}
}
return scope;
}
//returns false if error
bool Toy_declareScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal type) {
//don't redefine a variable within this scope
if (Toy_existsLiteralDictionary(&scope->variables, key)) {
return false;
}
if (!TOY_IS_TYPE(type)) {
return false;
}
//store the type, for later checking on assignment
Toy_setLiteralDictionary(&scope->types, key, type);
Toy_setLiteralDictionary(&scope->variables, key, TOY_TO_NULL_LITERAL);
return true;
}
bool Toy_isDelcaredScopeVariable(Toy_Scope* scope, Toy_Literal key) {
if (scope == NULL) {
return false;
}
//if it's not in this scope, keep searching up the chain
if (!Toy_existsLiteralDictionary(&scope->variables, key)) {
return Toy_isDelcaredScopeVariable(scope->ancestor, key);
}
return true;
}
//return false if undefined, or can't be assigned
bool Toy_setScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal value, bool constCheck) {
//dead end
if (scope == NULL) {
return false;
}
//if it's not in this scope, keep searching up the chain
if (!Toy_existsLiteralDictionary(&scope->variables, key)) {
return Toy_setScopeVariable(scope->ancestor, key, value, constCheck);
}
//type checking
Toy_Literal typeLiteral = Toy_getLiteralDictionary(&scope->types, key);
Toy_Literal original = Toy_getLiteralDictionary(&scope->variables, key);
if (!checkType(typeLiteral, original, value, constCheck)) {
Toy_freeLiteral(typeLiteral);
Toy_freeLiteral(original);
return false;
}
//actually assign
Toy_setLiteralDictionary(&scope->variables, key, value);
Toy_freeLiteral(typeLiteral);
Toy_freeLiteral(original);
return true;
}
bool Toy_getScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal* valueHandle) {
//dead end
if (scope == NULL) {
return false;
}
//if it's not in this scope, keep searching up the chain
if (!Toy_existsLiteralDictionary(&scope->variables, key)) {
return Toy_getScopeVariable(scope->ancestor, key, valueHandle);
}
*valueHandle = Toy_getLiteralDictionary(&scope->variables, key);
return true;
}
Toy_Literal Toy_getScopeType(Toy_Scope* scope, Toy_Literal key) {
//dead end
if (scope == NULL) {
return TOY_TO_NULL_LITERAL;
}
//if it's not in this scope, keep searching up the chain
if (!Toy_existsLiteralDictionary(&scope->types, key)) {
return Toy_getScopeType(scope->ancestor, key);
}
return Toy_getLiteralDictionary(&scope->types, key);
}
-25
View File
@@ -1,25 +0,0 @@
#pragma once
#include "toy_literal_array.h"
#include "toy_literal_dictionary.h"
typedef struct Toy_Scope {
Toy_LiteralDictionary variables; //only allow identifiers as the keys
Toy_LiteralDictionary types; //the types, indexed by identifiers
struct Toy_Scope* ancestor;
int references; //how many scopes point here
} Toy_Scope;
Toy_Scope* Toy_pushScope(Toy_Scope* scope);
Toy_Scope* Toy_popScope(Toy_Scope* scope);
Toy_Scope* Toy_copyScope(Toy_Scope* original);
//returns false if error
bool Toy_declareScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal type);
bool Toy_isDelcaredScopeVariable(Toy_Scope* scope, Toy_Literal key);
//return false if undefined
bool Toy_setScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal value, bool constCheck);
bool Toy_getScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal* value);
Toy_Literal Toy_getScopeType(Toy_Scope* scope, Toy_Literal key);
-93
View File
@@ -1,93 +0,0 @@
#pragma once
typedef enum Toy_TokenType {
//types
TOY_TOKEN_NULL,
TOY_TOKEN_BOOLEAN,
TOY_TOKEN_INTEGER,
TOY_TOKEN_FLOAT,
TOY_TOKEN_STRING,
TOY_TOKEN_ARRAY,
TOY_TOKEN_DICTIONARY,
TOY_TOKEN_FUNCTION,
TOY_TOKEN_OPAQUE,
TOY_TOKEN_ANY,
//keywords and reserved words
TOY_TOKEN_AS,
TOY_TOKEN_ASSERT,
TOY_TOKEN_BREAK,
TOY_TOKEN_CLASS,
TOY_TOKEN_CONST,
TOY_TOKEN_CONTINUE,
TOY_TOKEN_DO,
TOY_TOKEN_ELSE,
TOY_TOKEN_EXPORT,
TOY_TOKEN_FOR,
TOY_TOKEN_FOREACH,
TOY_TOKEN_IF,
TOY_TOKEN_IMPORT,
TOY_TOKEN_IN,
TOY_TOKEN_OF,
TOY_TOKEN_PRINT,
TOY_TOKEN_RETURN,
TOY_TOKEN_TYPE,
TOY_TOKEN_ASTYPE,
TOY_TOKEN_TYPEOF,
TOY_TOKEN_VAR,
TOY_TOKEN_WHILE,
//literal values
TOY_TOKEN_IDENTIFIER,
TOY_TOKEN_LITERAL_TRUE,
TOY_TOKEN_LITERAL_FALSE,
TOY_TOKEN_LITERAL_INTEGER,
TOY_TOKEN_LITERAL_FLOAT,
TOY_TOKEN_LITERAL_STRING,
//math operators
TOY_TOKEN_PLUS,
TOY_TOKEN_MINUS,
TOY_TOKEN_MULTIPLY,
TOY_TOKEN_DIVIDE,
TOY_TOKEN_MODULO,
TOY_TOKEN_PLUS_ASSIGN,
TOY_TOKEN_MINUS_ASSIGN,
TOY_TOKEN_MULTIPLY_ASSIGN,
TOY_TOKEN_DIVIDE_ASSIGN,
TOY_TOKEN_MODULO_ASSIGN,
TOY_TOKEN_PLUS_PLUS,
TOY_TOKEN_MINUS_MINUS,
TOY_TOKEN_ASSIGN,
//logical operators
TOY_TOKEN_PAREN_LEFT,
TOY_TOKEN_PAREN_RIGHT,
TOY_TOKEN_BRACKET_LEFT,
TOY_TOKEN_BRACKET_RIGHT,
TOY_TOKEN_BRACE_LEFT,
TOY_TOKEN_BRACE_RIGHT,
TOY_TOKEN_NOT,
TOY_TOKEN_NOT_EQUAL,
TOY_TOKEN_EQUAL,
TOY_TOKEN_LESS,
TOY_TOKEN_GREATER,
TOY_TOKEN_LESS_EQUAL,
TOY_TOKEN_GREATER_EQUAL,
TOY_TOKEN_AND,
TOY_TOKEN_OR,
//other operators
TOY_TOKEN_QUESTION,
TOY_TOKEN_COLON,
TOY_TOKEN_SEMICOLON,
TOY_TOKEN_COMMA,
TOY_TOKEN_DOT,
TOY_TOKEN_PIPE,
TOY_TOKEN_REST,
//meta tokens
TOY_TOKEN_PASS,
TOY_TOKEN_ERROR,
TOY_TOKEN_EOF,
} Toy_TokenType;
-37
View File
@@ -1,37 +0,0 @@
CC=gcc
IDIR +=. ../source ../repl
CFLAGS +=$(addprefix -I,$(IDIR)) -g -Wall -W -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable
LIBS +=
ODIR = obj
TARGETS = $(wildcard ../source/*.c) $(wildcard ../repl/lib_*.c) ../repl/repl_tools.c
TESTS = $(wildcard test_*.c)
OBJ = $(addprefix $(ODIR)/,$(TARGETS:../source/%.c=%.o)) $(addprefix $(ODIR)/,$(TESTS:.c=.o))
.PRECIOUS: $(TESTS:%.c=../$(TOY_OUTDIR)/%.exe)
all: $(OBJ) $(TESTS:%.c=../$(TOY_OUTDIR)/%.exe)
../$(TOY_OUTDIR)/%.exe: $(ODIR)/%.o
@$(CC) -o $@ $< $(TARGETS:../source/%.c=$(ODIR)/%.o) $(CFLAGS) $(LIBS)
ifeq ($(shell uname)$(DISABLE_VALGRIND),Linux)
valgrind --leak-check=full --track-origins=yes $@
else
$@
endif
$(OBJ): | $(ODIR)
$(ODIR):
mkdir $(ODIR)
$(ODIR)/%.o: %.c
@$(CC) -c -o $@ $< $(CFLAGS)
$(ODIR)/%.o: ../source/%.c
@$(CC) -c -o $@ $< $(CFLAGS)
.PHONY: clean
clean:
$(RM) $(ODIR)
-31
View File
@@ -1,31 +0,0 @@
//test operators (integers)
assert 1 + 1 == 2, "1 + 1 == 2";
assert 1 - 1 == 0, "1 - 1 == 0";
assert 2 * 2 == 4, "2 * 2 == 4";
assert 1 / 2 == 0, "1 / 2 == 0"; //integer division
assert 5 % 2 == 1, "5 % 2 == 1";
//test operators (floats)
assert 1.0 + 1.0 == 2.0, "1.0 + 1.0 == 2.0";
assert 1.0 - 1.0 == 0.0, "1.0 - 1.0 == 0.0";
assert 2.0 * 2.0 == 4.0, "2.0 * 2.0 == 4.0";
assert 1.0 / 2.0 == 0.5, "1.0 / 2.0 == 0.5";
var a = 10;
a += 20;
a -= 25;
assert a == 5, "+= or -= failed";
a *= 5;
a /= 2;
assert a == 12, "*= or /= failed";
a %= 8;
assert a == 4, "%= failed";
print "All good";
-23
View File
@@ -1,23 +0,0 @@
//create a bunch of toy functions as literals to be called from C
fn answer() {
return 42;
}
fn identity(x) {
return x;
}
fn makeCounter() {
var total = 0;
fn counter() {
return ++total;
}
return counter;
}
fn fail() {
assert false, "Failed correctly";
}
-37
View File
@@ -1,37 +0,0 @@
//boolean origin
var b: bool = true;
assert bool b == true, "bool -> bool";
assert int b == 1, "bool -> int";
assert float b == 1, "bool -> float";
assert string b == "true", "bool -> string";
//integer origin
var i: int = 42;
assert bool i == true, "int -> bool";
assert int i == 42, "int -> int";
assert float i == 42, "int -> float";
assert string i == "42", "int -> string";
//float origin
var f: float = 3.14;
assert bool f == true, "float -> bool";
assert int f == 3, "float -> int";
assert float f == 3.14, "float -> float";
assert string f == "3.14", "float -> string";
//string origin
var s: string = "78.9";
assert bool s == true, "string -> bool";
assert int s == 78, "string -> int";
assert float s == 78.9, "string -> float";
assert string s == "78.9", "string -> string";
print "All good";
-13
View File
@@ -1,13 +0,0 @@
//test int -> float coercion
{
var f: float = 0;
assert typeof f == float, "coercion on decl failed";
f = 42;
assert typeof f == float, "coercion on assign failed";
}
print "All good";
-27
View File
@@ -1,27 +0,0 @@
//test numbers
assert 1 < 2, "1 < 2";
assert 1 == 1, "1 == 1";
assert 2 > 1, "2 > 1";
assert 1 <= 2, "1 <= 2";
assert 2 >= 1, "2 >= 1";
//test variables
var a = 1;
var b = 2;
assert a < b, "a < b";
assert a == a, "a == a";
assert b > a, "b > a";
assert a <= b, "a <= b";
assert b >= a, "b >= a";
//test negation
assert !false, "!false";
var c = false;
assert !c, "!c";
print "All good";
-12
View File
@@ -1,12 +0,0 @@
fn fib(n : int) {
if (n < 2) {
return n;
}
return fib(n-1) + fib(n-2);
}
for (var i = 0; i < 20; i++) {
var res = fib(i);
print string i + ": " + string res;
}
-68
View File
@@ -1,68 +0,0 @@
//dot product
var a = [1, 2, 3];
var b = [4, 5, 6];
assert _length(a) == _length(b), "a and b lengths are wrong";
var acc = 0;
for (var i = 0; i < _length(a); i++) {
acc += _get(a, i) * _get(b, i);
}
assert acc == 32, "dot product failed";
//assume the args are matrices
fn matrix(first, second) {
//get the matrix size
var l1 = _length(first); //rows
var l2 = _length(_get(first, 0)); //cols
var l3 = _length(second); //rows
var l4 = _length(_get(second, 0)); //cols
//pre-allocate the matrix
var row = [];
for (var j = 0; j < l4; j++) {
_push(row, 0);
}
var result = [];
for (var i = 0; i < l1; i++) {
_push(result, row);
}
//assign the values
for (var i = 0; i < _length(first); i++) {
//select each element of "first"
var firstElement = _get(first, i);
//for each element of second
for (var i2 = 0; i2 < _length(second); i2++) {
for (var j2 = 0; j2 < _length(_get(second, 0)); j2++) {
var val = _get(_get(first, i), i2) * _get(_get(second, i2), j2);
//TODO: needs better notation than this tmpRow variable
var tmpRow = _get(result, i);
_set(tmpRow, j2, val);
_set(result, i, tmpRow);
//result[ i ][ j2 ] += first[i][i2] * second[i2][j2]
}
}
}
return result;
}
//matrix multiply
var c = [[4], [5], [6]]; //this is a 3x1
var d = [[1, 2, 3]]; //this is a 1x3
// c x d = 3x3
// d x c = 1x1
assert matrix(c, d) == [[4,8,12],[5,10,15],[6,12,18]], "Matrix multiplication failed";
print "All good";
-20
View File
@@ -1,20 +0,0 @@
/*
NOTES: For some reason, this code results in the error:
Undeclared variable "inner"
It only occurs under these very specific conditions.
It appears to be a compiler issue, see issue #38 for more info.
*/
fn _getValue(self) {
return self;
}
var cache;
cache = 42.getValue(); //assignment, rather than declaration, allows the bug
print "All good";
-30
View File
@@ -1,30 +0,0 @@
//test function chaining with the dot operator
fn _identity(self) {
return self;
}
fn _check(self) {
assert self == 42, "dot chaining failed";
return self;
}
var val = 42;
val
.identity()
.check()
.identity()
.check()
;
//test the value is actually altered
fn _increment(self) {
return self + 1;
}
assert 3.increment().increment() == 5, "dot chaining increment failed";
print "All good";
-9
View File
@@ -1,9 +0,0 @@
fn _add(self, inc) {
return self + inc;
}
assert 1.add(2).add(3).add(4) == 10, "dottify bugfix failed";
print "All good";
-77
View File
@@ -1,77 +0,0 @@
//test function return
fn testFourtyTwo() {
return 42;
}
assert testFourtyTwo() == 42, "function returns failed";
//test function parameters
fn identity(x) {
return x;
}
assert identity("hello world") == "hello world", "identity function failed";
//test closures
fn make() {
var counter = 0;
fn count() {
return ++counter;
}
return count;
}
var tally = make();
assert tally() == 1 && tally() == 2, "Closures failed";
//test closures self-capture
fn capture(count: int) {
if (count > 5) {
return count;
}
return capture(count + 1);
}
assert capture(0) == 6, "Self capture failed";
//test expressions as arguments
fn argFn() {
return 42;
}
fn outerFn(val) {
assert val == 42, "expression as argument failed";
}
outerFn(argFn());
//test extra parameters
fn extra(one, two, ...rest) {
assert rest == ["three", "four", "five", "six", "seven"], "rest parameters failed";
}
extra("one", "two", "three", "four", "five", "six", "seven");
//test underscore functions
fn _example(self, a, b, c) {
assert a == "a", "underscore failed (a)";
assert b == "b", "underscore failed (b)";
assert c == "c", "underscore failed (c)";
return self;
}
assert "hello world".example("a", "b", "c") == "hello world", "underscore call failed";
print "All good";
-85
View File
@@ -1,85 +0,0 @@
//test basic indexing
{
var week = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"];
assert week[1] == "tuesday", "basic indexing failed (single element)";
assert week[1:1] == ["tuesday"], "basic indexing failed (single element as array)";
assert week[:] == ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"], "basic default indexing failed (first and second)";
assert week[::] == ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"], "basic default indexing failed (first, second and third)";
}
//test basic replacement
{
var week = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"];
week[3:3] = "Holiday";
assert week == ["monday", "tuesday", "wednesday", "Holiday", "friday", "saturday", "sunday"], "basic replacement failed";
}
//test backwards
{
var week = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"];
assert week[::-1] == ["sunday", "saturday", "friday", "thursday", "wednesday", "tuesday", "monday"], "backwards failed";
}
//test array weird manipulation
{
var week = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"];
week[::-2] = ["first", "second", "third"];
assert week == ["monday", "tuesday", "third", "thursday", "second", "saturday", "first"], "array weird manipulation failed";
}
//test index arithmetic
{
var a = [1, 2, 3];
a[1] *= 3;
assert a == [1, 6, 3], "index arithmetic failed";
}
//test indexing with variables
{
var week = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"];
var first = 1;
var second = 2;
var third = -1;
assert week[first:second:third] == ["wednesday", "tuesday"], "indexing with variables failed";
}
//test nested indexing
{
var a = [[[0]]];
a[0][0][0] = 42;
assert a[0][0] == [42], "nested indexing failed";
}
//test combine example
{
fn combine(a, b, c) {
return [a, b, c];
}
assert combine(1, 2, 3) == [1, 2, 3], "combine example failed";
}
print "All good";
-43
View File
@@ -1,43 +0,0 @@
//test basic insertion
{
var d = [:];
d["foo"] = "bar";
assert d == ["foo":"bar"], "basic insertion failed";
}
//test index arithmetic
{
var d = ["one":1, "two":2, "three":3];
d["three"] *= 3;
assert d == ["one":1, "two":2, "three":9], "index arithmetic failed";
}
//test indexing with variables
{
var d = ["one":1, "two":2, "three":3];
var first = "two";
assert d[first] == 2, "indexing with variables failed";
}
//test nested indexing
{
var d = ["foo": ["bar": 0]];
d["foo"]["bar"] = 42;
print d;
assert d == ["foo": ["bar": 42]], "nested indexing failed";
}
print "All good";
-40
View File
@@ -1,40 +0,0 @@
//test basic indexing
var greeting: string = "hello world";
assert greeting[1] == "e", "basic default index failed (first)";
assert greeting[:] == "hello world", "basic default index failed (first and second)";
assert greeting[::] == "hello world", "basic default index failed (first, second & third)";
assert greeting[0:4] == "hello", "basic indexing failed";
//test basic replacement
greeting[0:4] = "goodnight";
assert greeting == "goodnight world", "basic replacement failed";
//test backwards string
assert greeting[::-1] == "dlrow thgindoog", "backwards string failed";
assert greeting[11:15:-1] == "dlrow", "backwards indexed string failed";
//test string weird manipulation
var numbers = "0123456789";
numbers[::-2] = "abc";
assert numbers == "01234c6b8a", "string weird manipulation failed";
//test indexing with variables
var first = 11;
var second = 15;
var third = -1;
assert greeting[first:second:third] == "dlrow", "indexing with variables failed";
print "All good";
-87
View File
@@ -1,87 +0,0 @@
fn sanity() {
//test true jump
if (true) {
assert true, "if-then failed (1)";
}
else {
assert false, "if-then failed (2)";
}
//test false jump
if (false) {
assert false, "if-then failed (3)";
}
else {
assert true, "if-then failed (4)";
}
//test while loop
var whileCounter = 0;
while (whileCounter < 10) {
whileCounter = whileCounter + 1;
}
assert whileCounter == 10, "while-loop failed";
//test for loop
var forCache = 0;
for (var i = 0; i < 20; i++) {
forCache = i;
}
assert forCache == 19, "for-loop failed";
//test break - while
var breakWhileCache = 0;
while(true) {
breakWhileCache = breakWhileCache + 1;
if (breakWhileCache >= 7) {
break;
}
}
assert breakWhileCache == 7, "break-while failed";
//test continue - while
var continueWhileCache = 0;
while (continueWhileCache < 10) {
continueWhileCache = continueWhileCache + 1;
if (continueWhileCache >= 7) {
continue;
}
assert continueWhileCache < 7, "continue-while failed";
}
//test break - for
for (var i = 0; i < 10; i++) {
if (i >= 7) {
break;
}
assert i < 7, "break-for failed";
}
//test break - continue
for (var i = 0; i < 10; i++) {
if (i >= 7) {
continue;
}
assert i < 7, "continue-for failed";
}
print "All good";
}
//invoke the test
sanity();
-82
View File
@@ -1,82 +0,0 @@
//test true jump
if (true) {
assert true, "if-then failed (1)";
}
else {
assert false, "if-then failed (2)";
}
//test false jump
if (false) {
assert false, "if-then failed (3)";
}
else {
assert true, "if-then failed (4)";
}
//test while loop
var whileCounter = 0;
while (whileCounter < 10) {
whileCounter = whileCounter + 1;
}
assert whileCounter == 10, "while-loop failed";
//test for loop
var forCache = 0;
for (var i = 0; i < 20; i++) {
forCache = i;
}
assert forCache == 19, "for-loop failed";
//test break - while
var breakWhileCache = 0;
while(true) {
breakWhileCache = breakWhileCache + 1;
if (breakWhileCache >= 7) {
break;
}
}
assert breakWhileCache == 7, "break-while failed";
//test continue - while
var continueWhileCache = 0;
while (continueWhileCache < 10) {
continueWhileCache = continueWhileCache + 1;
if (continueWhileCache >= 7) {
continue;
}
assert continueWhileCache < 7, "continue-while failed";
}
//test break - for
for (var i = 0; i < 10; i++) {
if (i >= 7) {
break;
}
assert i < 7, "break-for failed";
}
//test break - continue
for (var i = 0; i < 10; i++) {
if (i >= 7) {
continue;
}
assert i < 7, "continue-for failed";
}
print "All good";
-50
View File
@@ -1,50 +0,0 @@
//test the standard library, under a number of different circumstances
//test basic import
{
import standard;
//this depends on external factors, so only check the length
assert clock().length() == 24, "import library failed";
}
//test import within a function
{
fn f() {
import standard;
assert clock != null, "import library within function failed";
return clock;
}
//invoke
assert f()().length() == 24, "import library within function and return failed";
}
//test closing over standard library element
{
import standard;
fn f() {
assert clock != null, "import library outside function failed";
return clock;
}
//invoke
assert f()().length() == 24, "import library outside function and return failed";
}
//test importing as an alias
{
import standard as std;
assert std["clock"]().length() == 24, "import library as alias failed";
}
print "All good";
-88
View File
@@ -1,88 +0,0 @@
import runner;
//test basic loading and freeing of a script file
{
var s = loadScript("scripts:/runner_sample_code.toy");
s.freeScript();
}
//test basic loading and freeing of a binary file
{
var s = loadScriptBytecode("scripts:/lib/runner/sample_bytecode.tb");
s.freeScript();
}
//test running an external script
{
var s = loadScript("scripts:/runner_sample_code.toy");
s.runScript();
s.freeScript();
}
//test running an external binary file
{
var s = loadScriptBytecode("scripts:/lib/runner/sample_bytecode.tb");
s.runScript();
s.freeScript();
}
//test resetting an external script
{
var s = loadScript("scripts:/runner_sample_code.toy");
s.runScript();
s.resetScript();
assert !s.checkScriptDirty(), "checkScriptDirty failed";
s.runScript();
assert s.checkScriptDirty(), "_checkScriptDirty() failed";
s.resetScript();
s.runScript();
s.freeScript();
}
//test running a nested external script
{
var s = loadScript("scripts:/lib/runner/sample_1.toy");
s.runScript();
s.freeScript();
}
//test retrieving a script variable
{
var s = loadScript("scripts:/runner_sample_code.toy");
s.runScript();
var fib = s.getScriptVar("fib");
assert fib(12) == 144, "_getScriptVar() failed";
s.freeScript();
}
//test calling a script function
{
var s = loadScript("scripts:/runner_sample_code.toy");
s.runScript();
assert s.callScriptFn("fib", 12) == 144, "_callScriptFn() failed";
s.freeScript();
}
print "All good";
-9
View File
@@ -1,9 +0,0 @@
import runner;
//delegate to the other sample script
var s = loadScript("scripts:/lib/runner/sample_2.toy");
s.runScript();
s.freeScript();
-1
View File
@@ -1 +0,0 @@
assert true, "Nested sample scripts worked";
Binary file not shown.
-10
View File
@@ -1,10 +0,0 @@
//test the standard library
{
import standard;
//this depends on external factors, so only check the length
assert clock().length() == 24, "clock() import failed";
}
print "All good";
-92
View File
@@ -1,92 +0,0 @@
//test the timer library
{
//create a timer, run it for a short period
import timer;
var timerA: opaque = startTimer();
for (var i: int = 0; i < 1000 * 1; i++);
var diffA: opaque = timerA.stopTimer();
//create another timer, run it for a longer period
var timerB: opaque = startTimer();
for (var i: int = 0; i < 1000 * 10; i++);
var diffB: opaque = timerB.stopTimer();
//check to ensure that the second timer took longer than the first
//WARNING: this has the small possibility of failing due to external factors
var difference: opaque = diffA.compareTimer(diffB);
assert difference.getTimerSeconds() >= 0, "compareTimer() (seconds) failed";
if (difference.getTimerSeconds() == 0) {
assert difference.getTimerMicroseconds() >= 0, "compareTimer() (microseconds) failed";
}
//all timers must be destroyed after use
timerA.destroyTimer();
timerB.destroyTimer();
diffA.destroyTimer();
diffB.destroyTimer();
difference.destroyTimer();
}
{
//create a timer, manipulate it's values
import timer;
//set the timer values manually
var timer: opaque = createTimer(42, 8891);
//check the timer values
assert timer.getTimerSeconds() == 42, "getTimerSeconds() failed";
assert timer.getTimerMicroseconds() == 8891, "getTimerMicroseconds() failed";
//all timers must be destroyed after use
timer.destroyTimer();
}
{
//set a timer to check string representation
import timer;
var timer: opaque = createTimer(42, 999);
assert timer.timerToString() == "42.000999", "timerToString() failed";
//all timers must be destroyed after use
timer.destroyTimer();
}
{
//test positive and negative values of timers
import timer;
var a = createTimer(1, 0);
var b = createTimer(2, 0);
var acmp = a.compareTimer(b);
var bcmp = b.compareTimer(a);
var c = createTimer(0, 1);
var d = createTimer(0, 2);
var ccmp = c.compareTimer(d);
var dcmp = d.compareTimer(c);
assert acmp.timerToString() == "1.000000", "positive and negative tests failed (acmp)";
assert bcmp.timerToString() == "-1.000000", "positive and negative tests failed (bcmp)";
assert ccmp.timerToString() == "0.000001", "positive and negative tests failed (ccmp)";
assert dcmp.timerToString() == "-0.000001", "positive and negative tests failed (dcmp)";
a.destroyTimer();
b.destroyTimer();
c.destroyTimer();
d.destroyTimer();
acmp.destroyTimer();
bcmp.destroyTimer();
ccmp.destroyTimer();
dcmp.destroyTimer();
}
print "All good";
-6
View File
@@ -1,6 +0,0 @@
assert true && true, "boolean and failed";
assert true || true, "boolean or failed";
assert false || true && true, "boolen precedence failed";
print "All good";
-339
View File
@@ -1,339 +0,0 @@
var arr: [string] = [
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"10",
"11",
"12",
"13",
"14",
"15",
"16",
"17",
"18",
"19",
"20",
"21",
"22",
"23",
"24",
"25",
"26",
"27",
"28",
"29",
"30",
"31",
"32",
"33",
"34",
"35",
"36",
"37",
"38",
"39",
"40",
"41",
"42",
"43",
"44",
"45",
"46",
"47",
"48",
"49",
"50",
"51",
"52",
"53",
"54",
"55",
"56",
"57",
"58",
"59",
"60",
"61",
"62",
"63",
"64",
"65",
"66",
"67",
"68",
"69",
"70",
"71",
"72",
"73",
"74",
"75",
"76",
"77",
"78",
"79",
"80",
"81",
"82",
"83",
"84",
"85",
"86",
"87",
"88",
"89",
"90",
"91",
"92",
"93",
"94",
"95",
"96",
"97",
"98",
"99",
//-------------------------
"100",
"101",
"102",
"103",
"104",
"105",
"106",
"107",
"108",
"109",
"110",
"111",
"112",
"113",
"114",
"115",
"116",
"117",
"118",
"119",
"120",
"121",
"122",
"123",
"124",
"125",
"126",
"127",
"128",
"129",
"130",
"131",
"132",
"133",
"134",
"135",
"136",
"137",
"138",
"139",
"140",
"141",
"142",
"143",
"144",
"145",
"146",
"147",
"148",
"149",
"150",
"151",
"152",
"153",
"154",
"155",
"156",
"157",
"158",
"159",
"160",
"161",
"162",
"163",
"164",
"165",
"166",
"167",
"168",
"169",
"170",
"171",
"172",
"173",
"174",
"175",
"176",
"177",
"178",
"179",
"180",
"181",
"182",
"183",
"184",
"185",
"186",
"187",
"188",
"189",
"190",
"191",
"192",
"193",
"194",
"195",
"196",
"197",
"198",
"199",
//-------------------------
"200",
"201",
"202",
"203",
"204",
"205",
"206",
"207",
"208",
"209",
"210",
"211",
"212",
"213",
"214",
"215",
"216",
"217",
"218",
"219",
"220",
"221",
"222",
"223",
"224",
"225",
"226",
"227",
"228",
"229",
"230",
"231",
"232",
"233",
"234",
"235",
"236",
"237",
"238",
"239",
"240",
"241",
"242",
"243",
"244",
"245",
"246",
"247",
"248",
"249",
"250",
"251",
"252",
"253",
"254",
"255",
"256",
"257",
"258",
"259",
"260",
"261",
"262",
"263",
"264",
"265",
"266",
"267",
"268",
"269",
"270",
"271",
"272",
"273",
"274",
"275",
"276",
"277",
"278",
"279",
"280",
"281",
"282",
"283",
"284",
"285",
"286",
"287",
"288",
"289",
"290",
"291",
"292",
"293",
"294",
"295",
"296",
"297",
"298",
"299"
];
print arr;
-4
View File
@@ -1,4 +0,0 @@
//NOTE: dictionaries are NOT stored in order
var dict: [string : string] = ["0":"0","1":"1","2":"2","3":"3","4":"4","5":"5","6":"6","7":"7","8":"8","9":"9","10":"10","11":"11","12":"12","13":"13","14":"14","15":"15","16":"16","17":"17","18":"18","19":"19","20":"20","21":"21","22":"22","23":"23","24":"24","25":"25","26":"26","27":"27","28":"28","29":"29","30":"30","31":"31","32":"32","33":"33","34":"34","35":"35","36":"36","37":"37","38":"38","39":"39","40":"40","41":"41","42":"42","43":"43","44":"44","45":"45","46":"46","47":"47","48":"48","49":"49","50":"50","51":"51","52":"52","53":"53","54":"54","55":"55","56":"56","57":"57","58":"58","59":"59","60":"60","61":"61","62":"62","63":"63","64":"64","65":"65","66":"66","67":"67","68":"68","69":"69","70":"70","71":"71","72":"72","73":"73","74":"74","75":"75","76":"76","77":"77","78":"78","79":"79","80":"80","81":"81","82":"82","83":"83","84":"84","85":"85","86":"86","87":"87","88":"88","89":"89","90":"90","91":"91","92":"92","93":"93","94":"94","95":"95","96":"96","97":"97","98":"98","99":"99","100":"100","101":"101","102":"102","103":"103","104":"104","105":"105","106":"106","107":"107","108":"108","109":"109","110":"110","111":"111","112":"112","113":"113","114":"114","115":"115","116":"116","117":"117","118":"118","119":"119","120":"120","121":"121","122":"122","123":"123","124":"124","125":"125","126":"126","127":"127","128":"128","129":"129","130":"130","131":"131","132":"132","133":"133","134":"134","135":"135","136":"136","137":"137","138":"138","139":"139","140":"140","141":"141","142":"142","143":"143","144":"144","145":"145","146":"146","147":"147","148":"148","149":"149","150":"150","151":"151","152":"152","153":"153","154":"154","155":"155","156":"156","157":"157","158":"158","159":"159","160":"160","161":"161","162":"162","163":"163","164":"164","165":"165","166":"166","167":"167","168":"168","169":"169","170":"170","171":"171","172":"172","173":"173","174":"174","175":"175","176":"176","177":"177","178":"178","179":"179","180":"180","181":"181","182":"182","183":"183","184":"184","185":"185","186":"186","187":"187","188":"188","189":"189","190":"190","191":"191","192":"192","193":"193","194":"194","195":"195","196":"196","197":"197","198":"198","199":"199","200":"200","201":"201","202":"202","203":"203","204":"204","205":"205","206":"206","207":"207","208":"208","209":"209","210":"210","211":"211","212":"212","213":"213","214":"214","215":"215","216":"216","217":"217","218":"218","219":"219","220":"220","221":"221","222":"222","223":"223","224":"224","225":"225","226":"226","227":"227","228":"228","229":"229","230":"230","231":"231","232":"232","233":"233","234":"234","235":"235","236":"236","237":"237","238":"238","239":"239","240":"240","241":"241","242":"242","243":"243","244":"244","245":"245","246":"246","247":"247","248":"248","249":"249","250":"250","251":"251","252":"252","253":"253","254":"254","255":"255","256":"256","257":"257","258":"258","259":"259","260":"260","261":"261","262":"262","263":"263","264":"264","265":"265","266":"266","267":"267","268":"268","269":"269","270":"270","271":"271","272":"272","273":"273","274":"274","275":"275","276":"276","277":"277","278":"278","279":"279","280":"280","281":"281","282":"282","283":"283","284":"284","285":"285","286":"286","287":"287","288":"288","289":"289","290":"290","291":"291","292":"292","293":"293","294":"294","295":"295","296":"296","297":"297","298":"298","299":"299"];
print dict;
-335
View File
@@ -1,335 +0,0 @@
print 0;
print 1;
print 2;
print 3;
print 4;
print 5;
print 6;
print 7;
print 8;
print 9;
print 10;
print 11;
print 12;
print 13;
print 14;
print 15;
print 16;
print 17;
print 18;
print 19;
print 20;
print 21;
print 22;
print 23;
print 24;
print 25;
print 26;
print 27;
print 28;
print 29;
print 30;
print 31;
print 32;
print 33;
print 34;
print 35;
print 36;
print 37;
print 38;
print 39;
print 40;
print 41;
print 42;
print 43;
print 44;
print 45;
print 46;
print 47;
print 48;
print 49;
print 50;
print 51;
print 52;
print 53;
print 54;
print 55;
print 56;
print 57;
print 58;
print 59;
print 60;
print 61;
print 62;
print 63;
print 64;
print 65;
print 66;
print 67;
print 68;
print 69;
print 70;
print 71;
print 72;
print 73;
print 74;
print 75;
print 76;
print 77;
print 78;
print 79;
print 80;
print 81;
print 82;
print 83;
print 84;
print 85;
print 86;
print 87;
print 88;
print 89;
print 90;
print 91;
print 92;
print 93;
print 94;
print 95;
print 96;
print 97;
print 98;
print 99;
//-------------------------
print 100;
print 101;
print 102;
print 103;
print 104;
print 105;
print 106;
print 107;
print 108;
print 109;
print 110;
print 111;
print 112;
print 113;
print 114;
print 115;
print 116;
print 117;
print 118;
print 119;
print 120;
print 121;
print 122;
print 123;
print 124;
print 125;
print 126;
print 127;
print 128;
print 129;
print 130;
print 131;
print 132;
print 133;
print 134;
print 135;
print 136;
print 137;
print 138;
print 139;
print 140;
print 141;
print 142;
print 143;
print 144;
print 145;
print 146;
print 147;
print 148;
print 149;
print 150;
print 151;
print 152;
print 153;
print 154;
print 155;
print 156;
print 157;
print 158;
print 159;
print 160;
print 161;
print 162;
print 163;
print 164;
print 165;
print 166;
print 167;
print 168;
print 169;
print 170;
print 171;
print 172;
print 173;
print 174;
print 175;
print 176;
print 177;
print 178;
print 179;
print 180;
print 181;
print 182;
print 183;
print 184;
print 185;
print 186;
print 187;
print 188;
print 189;
print 190;
print 191;
print 192;
print 193;
print 194;
print 195;
print 196;
print 197;
print 198;
print 199;
//-------------------------
print 200;
print 201;
print 202;
print 203;
print 204;
print 205;
print 206;
print 207;
print 208;
print 209;
print 210;
print 211;
print 212;
print 213;
print 214;
print 215;
print 216;
print 217;
print 218;
print 219;
print 220;
print 221;
print 222;
print 223;
print 224;
print 225;
print 226;
print 227;
print 228;
print 229;
print 230;
print 231;
print 232;
print 233;
print 234;
print 235;
print 236;
print 237;
print 238;
print 239;
print 240;
print 241;
print 242;
print 243;
print 244;
print 245;
print 246;
print 247;
print 248;
print 249;
print 250;
print 251;
print 252;
print 253;
print 254;
print 255;
print 256;
print 257;
print 258;
print 259;
print 260;
print 261;
print 262;
print 263;
print 264;
print 265;
print 266;
print 267;
print 268;
print 269;
print 270;
print 271;
print 272;
print 273;
print 274;
print 275;
print 276;
print 277;
print 278;
print 279;
print 280;
print 281;
print 282;
print 283;
print 284;
print 285;
print 286;
print 287;
print 288;
print 289;
print 290;
print 291;
print 292;
print 293;
print 294;
print 295;
print 296;
print 297;
print 298;
print 299;
//-------------------------
@@ -1,8 +0,0 @@
import runner;
var s = loadScript("scripts:/lib/../runner_sample_code.toy");
s.runScript();
s.freeScript();

Some files were not shown because too many files have changed in this diff Show More