Compare commits

..

148 Commits

Author SHA1 Message Date
Kayne Ruse 733df87c08 Added dist target, lowered recursion depth limit 2023-06-07 14:58:51 +10:00
Kayne Ruse bfd506f497 Forgot memory allocator for reffunctions 2023-06-07 02:02:35 +10:00
Kayne Ruse 18b59c9e84 Bumped version number 2023-06-07 00:11:34 +10:00
Ratstail91 d3eb31d964 Added TOY_DISABLE_REPL option for compiling 2023-06-07 00:04:05 +10:00
Kayne Ruse 07f4a98b95 Replacing Toy_Literal function bytecode with Toy_RefFunction, addressing #77
This seems to have worked way too easily.
2023-06-06 23:35:59 +10:00
Kayne Ruse 0949fd6ff9 Dang 2023-06-06 21:46:42 +10:00
Kayne Ruse 03e5096f10 Moved test_sum into it's own directory under scripts/ 2023-06-06 21:14:05 +10:00
Kayne Ruse bb81b8c474 Changed recursion limit to 10,000 (was 200) 2023-06-06 21:02:01 +10:00
Kayne Ruse cf6db57787 Whitespace tweak 2023-03-25 01:43:51 +11:00
Kayne Ruse 17f0e4476b Caught a bug that the test cases failed to find 2023-03-17 21:58:13 +11:00
Kayne Ruse 1095e1a885 Added type casting a grouping bugfix, resolved #76 2023-03-17 20:57:47 +11:00
Kayne Ruse 2edfbbe3ef Found a compiler bug, thanks Aedan! 2023-03-17 14:01:16 +11:00
Ratstail91 4b83f1f0d6 Fixed a dumb typo 2023-03-15 06:39:19 +11:00
Kayne Ruse e2fa1cf2e8 Moved lib_runner's drive system into the core of the lang 2023-03-15 06:12:35 +11:00
Kayne Ruse a04d2c4816 Tweaked TOY_EXPORT omitting extra repl stuff 2023-03-15 04:56:26 +11:00
Kayne Ruse f2f8aed23a Added short-circuiting support to && and || 2023-03-11 17:59:09 +11:00
Kayne Ruse 68ed52b347 Tweaked precedence of binary expressions 2023-03-11 17:47:43 +11:00
Kayne Ruse 88dac53ae0 Added toy.h, thanks for the suggestion GabrielGavrilov!
Resolved #72
2023-03-10 08:41:58 +11:00
Kayne Ruse f84cdff883 Fixed order of operations 2023-03-07 06:49:17 +11:00
Ratstail91 f869c9425a Corrected an error message 2023-03-05 13:05:16 +11:00
Ratstail91 76ddd5703e Hack: just track the intermediate depth externally 2023-03-05 00:24:07 +11:00
Ratstail91 669808730e Minor tweak that shouldn't break anything 2023-03-04 22:57:41 +11:00
Ratstail91 e6d9809da5 Famous last words: I think I fixed it 2023-03-04 22:18:17 +11:00
Ratstail91 502032e514 Testing an obscure bugfix 2023-03-04 15:41:55 +11:00
Ratstail91 6e9d42f892 Merge branch 'dev' 2023-02-28 17:39:05 +11:00
Ratstail91 70ca27486e Bugfix a leak? 2023-02-28 17:37:43 +11:00
Ratstail91 12fa434e0f Experimenting with cleaning up loopy code 2023-02-28 17:29:37 +11:00
Ratstail91 efc1e764d2 Patched a casting error in round 2023-02-27 23:27:11 +11:00
Kayne Ruse c5c0122243 BUGFIX: typeof keyword precedence was off 2023-02-27 21:47:38 +11:00
Kayne Ruse 348b7b8c24 Added some math utils to standard
* ceil
* floor
* max
* min
* round
2023-02-27 21:32:31 +11:00
Kayne Ruse e243ad949a Removed a divide instruction (modulo) from the final output, thanks Wren! 2023-02-26 22:41:58 +11:00
Ratstail91 9b673f23ad Reduced C callstack size in Toy_Scope 2023-02-26 22:31:37 +11:00
Kayne Ruse 624a0c80ba Prevented NO-OP calls to the memory allocator
Also shaved off about 1-2 milliseconds of execution time of fib-memo.toy
2023-02-26 21:20:22 +11:00
Ratstail91 1064b69d04 BUGFIX: Integer and float comparisons always return true 2023-02-26 01:27:21 +11:00
Ratstail91 e9b347acb6 MSVC + Box Engine are dumber than a bag of rocks 2023-02-25 04:40:12 +11:00
Ratstail91 071c8da2aa Visual Studio broke itself - fixed 2023-02-25 04:28:07 +11:00
Ratstail91 d6538812bf Merge branch 'main' of https://github.com/Ratstail91/Toy 2023-02-25 04:18:03 +11:00
Ratstail91 3aeddff736 Tweaks to dictionary for performance 2023-02-24 22:13:50 +11:00
Ratstail91 c88c1b125d Merge remote-tracking branch 'refs/remotes/origin/main' 2023-02-24 21:53:42 +11:00
Kayne Ruse 1513ba9878 tweaked scripts folder 2023-02-23 22:45:38 +11:00
Kayne Ruse bc0289c3f4 tweaked scripts folder 2023-02-23 20:23:10 +11:00
Kayne Ruse 92c71a374d Implemented a basic random library 2023-02-23 19:19:17 +11:00
Kayne Ruse e0547474b8 Merge remote-tracking branch 'refs/remotes/origin/main' 2023-02-23 18:37:11 +11:00
Kayne Ruse 3e6d21afbb Added abs(), hash() to libstandard 2023-02-23 18:36:12 +11:00
Kayne Ruse d3df01c1c4 Updated .gitignore 2023-02-23 03:33:52 +11:00
Ratstail91 cdca6fa45c Fixed directory in solution file 2023-02-22 20:06:48 +11:00
Kayne Ruse 1dde9d8f29 Improved error message in set() and push()
The actual issue was that the type check wasn't catching the issue, so
it reached the scope before it was caught. Fixed it, anyway.
2023-02-20 13:04:35 +00:00
Kayne Ruse 7f0f17b6e0 Patched up failures from Toy_parseIdentifierToValue
I really don't like that function - it needs to be replaced.
2023-02-20 06:11:30 +00:00
Kayne Ruse 3507104121 Fixed indexAccess potentially going awry with bad inputs
There's always one or two that slip through
2023-02-20 05:28:25 +00:00
Kayne Ruse 87de634e30 Updated version number to 1.0.0 2023-02-20 02:08:42 +00:00
Kayne Ruse 6fa224fa7b Hooks can't be dict keys, tweaked Toy_readFile 2023-02-18 16:47:38 +00:00
Kayne Ruse 8a68d864e6 Opaque type check added 2023-02-18 15:21:49 +00:00
Kayne Ruse 49f240ea07 Minor tweak 2023-02-18 12:15:23 +00:00
Kayne Ruse 3acbd7447a Merge remote-tracking branch 'refs/remotes/origin/main' 2023-02-18 11:57:22 +00:00
Kayne Ruse 6f126e6daa Minor tweaks and renames, as I'm documenting 2023-02-18 11:56:18 +00:00
Kayne Ruse 2adb9d9158 Tweaked lib runner API 2023-02-16 22:04:47 +00:00
Kayne Ruse 1668dca255 Tweaked some APIs, hid some functions I don't want in the API 2023-02-16 13:06:07 +00:00
Kayne Ruse 501ff6fff4 Chased a ghost for a few hours 2023-02-14 18:55:24 +00:00
Kayne Ruse 3845627fe5 Added release build to MSVC 2023-02-14 18:03:04 +00:00
Kayne Ruse cdae03bd54 String and identifier making fixed for MSVC, just in case 2023-02-14 17:38:10 +00:00
Kayne Ruse 7b501b71b5 commandLine now initializes with default values 2023-02-14 17:00:16 +00:00
Kayne Ruse 913738a4d1 Tweaked the runner test, should be orders of magnitude faster 2023-02-14 16:16:48 +00:00
Kayne Ruse 3312a38c7c Updated memusage tool 2023-02-14 16:05:43 +00:00
Kayne Ruse 71b57fd42c Fixed scripts for distribution 2023-02-14 10:35:08 +00:00
Kayne Ruse 453afbab41 Fixed a stupid bug in MSVC 2023-02-14 10:24:43 +00:00
Kayne Ruse 57af5a6d59 Tweaked some scripts 2023-02-14 09:21:22 +00:00
Kayne Ruse 0737b2a483 Dropped underscore functions in favour of UFCS 2023-02-14 08:37:31 +00:00
Kayne Ruse eae96d6403 Corrected the order of arguments to Toy_callLiteralFn() 2023-02-14 08:00:35 +00:00
Kayne Ruse b55b8e879e Added -n option to diable print newline 2023-02-13 15:51:38 +00:00
Kayne Ruse 1ed114b80d Allow for stmt to have empty clauses, resolved #58 2023-02-13 14:45:24 +00:00
Kayne Ruse eb8e522bf2 Merged standard and timer, resolved #48 2023-02-13 13:58:41 +00:00
Kayne Ruse 16b71ba6f4 Implemented quicksort in _sort() 2023-02-13 13:31:58 +00:00
Kayne Ruse 9725f3c6a3 Patched some very obscure bugs 2023-02-12 16:54:44 +00:00
Kayne Ruse 8653a2663f Added _indexOf 2023-02-12 14:32:26 +00:00
Kayne Ruse ab2cd5dc93 Removed lib timer properly, see #62 2023-02-12 14:19:14 +00:00
Kayne Ruse 724804a78a Playing with level.toy 2023-02-11 15:27:23 +00:00
Kayne Ruse 77a128e0f7 Added the -t option to the repl 2023-02-11 14:51:19 +00:00
Kayne Ruse 5343e1054d Straightened out file extensions 2023-02-11 14:26:55 +00:00
Kayne Ruse 3930ec0477 Tweaked README.md 2023-02-11 06:48:16 +00:00
Kayne Ruse 996744d7ec Resolved #59 2023-02-11 05:10:32 +00:00
Kayne Ruse c00b32017b Dummied out lib timer 2023-02-11 01:42:44 +00:00
Kayne Ruse 457014d577 Added MSVC build support, likely broke tests 2023-02-11 00:49:21 +00:00
Kayne Ruse be4cbf1ad6 Pack 'em up! 2023-02-10 21:53:38 +00:00
Kayne Ruse aeb008c684 Fixed unary negation bug, removed newline from print 2023-02-10 18:38:25 +00:00
Kayne Ruse 53012dbce1 Added _filter() 2023-02-10 15:41:38 +00:00
Kayne Ruse 4fe57f9562 Added _containsKey() and _containsValue() 2023-02-10 15:27:39 +00:00
Kayne Ruse 3ba2e420ea Added _every() and _some() 2023-02-10 15:00:15 +00:00
Kayne Ruse c81a139c97 Now handles unterminated block comments without freezing 2023-02-10 12:26:38 +00:00
Kayne Ruse 66ea684a90 Disabled comments in the repl 2023-02-10 12:11:42 +00:00
Kayne Ruse a26a6a56d0 Patched a pre/postfix increment/decrement segfault 2023-02-10 11:49:59 +00:00
Kayne Ruse ee226ea426 Strengthened constness for cstrings and bytecode 2023-02-10 08:52:38 +00:00
Kayne Ruse 76a0290290 Removed export keyword from README.md 2023-02-09 17:46:28 +00:00
Kayne Ruse 85dc24c4a6 Updated bug report template 2023-02-09 17:25:24 +00:00
Kayne Ruse 1804e380a0 tweak 2023-02-09 17:06:51 +00:00
Kayne Ruse 7567f4f3b2 Experimenting with issues 2023-02-09 17:05:20 +00:00
Kayne Ruse e8160eb9df Fixed string indexing with null 2023-02-09 16:46:36 +00:00
Kayne Ruse 276648630e trying to uncluster-bomb the builtin functions 2023-02-09 16:12:42 +00:00
Kayne Ruse e946a5f071 Patched segault in parser 2023-02-09 12:37:18 +00:00
Kayne Ruse 932401c26d Can now correctly parse escaped characters 2023-02-09 08:44:08 +00:00
Kayne Ruse fc67d6a18b Fixed a segfault 2023-02-09 08:24:16 +00:00
Kayne Ruse 60908c8bf3 Added panic state to Toy_Compiler to catch a certain condition 2023-02-09 07:58:55 +00:00
Kayne Ruse b8e3324acb tweak 2023-02-07 18:32:59 +00:00
Kayne Ruse 0fc8183799 Added _reduce 2023-02-06 09:46:20 +00:00
Kayne Ruse 9a6aa8d15e Added _trimBegin() and _trimEnd() 2023-02-06 06:11:17 +00:00
Kayne Ruse 0b9051cab2 Experimenting with numbers 2023-02-06 05:37:41 +00:00
Kayne Ruse 0d7e4db661 Fixed repl bug 2023-02-06 04:47:30 +00:00
Kayne Ruse d5c833b344 I wish I could test on windows 2023-02-06 01:05:44 +00:00
Kayne Ruse c875ae7a0e Added _forEach and _map, added tests for them 2023-02-06 00:51:07 +00:00
Kayne Ruse c0ec5ef28e Tested _concat() with clashing dict keys 2023-02-05 22:46:00 +00:00
Kayne Ruse be91de9535 Fixed a leak 2023-02-05 20:46:55 +00:00
Kayne Ruse 3088c4fe6d Implemented _concat 2023-02-05 20:45:31 +00:00
Kayne Ruse 9bd0cd23e7 Imported an example file for bytecode size testing, see #21 2023-02-05 15:40:17 +00:00
Kayne Ruse 29f8a698b4 Added a mustfail test 2023-02-05 15:19:04 +00:00
Kayne Ruse 41d274177a String concatenation restricted to + and += signs 2023-02-05 15:15:32 +00:00
Kayne Ruse 7ea249f723 Added the about library, resolved #51 2023-02-05 14:43:46 +00:00
Kayne Ruse 3949be3706 Quick potential bugfix 2023-02-05 13:34:39 +00:00
Kayne Ruse 0e932f24cc Added _toString() 2023-02-05 13:29:44 +00:00
Kayne Ruse 60225b733b Added _getKeys() and _getValues() 2023-02-05 12:49:12 +00:00
Kayne Ruse 15f99495a1 Aesthetics 2023-02-05 11:31:17 +00:00
Kayne Ruse 7b26527e95 Nesting index multiplication assignment fixed
This affects all arithmetic types applied to inner-nested compounds.
2023-02-05 06:28:24 +00:00
Kayne Ruse 386201b6e9 Added fib-memo.toy, fixed bugs until it worked 2023-02-04 17:01:58 +00:00
Kayne Ruse 8d278077b1 Added constant folding for strings, tweaked some error messages 2023-02-04 09:50:29 +00:00
Kayne Ruse 57c16d2ede Fixed an obscure memory leak, potential issue with lib_runner on linux 2023-02-04 15:30:46 +11:00
Kayne Ruse 2f1613e306 Caught an error in the compiler 2023-02-04 03:03:56 +00:00
Kayne Ruse 2776c87026 Ambiguous ternary syntax might be an issue 2023-02-04 02:59:10 +00:00
Kayne Ruse 8cc33f5fbb Added to ternary expression tests 2023-02-03 17:22:44 +00:00
Kayne Ruse 90f91a234a r is a bad character to escape 2023-01-31 12:38:42 +00:00
Kayne Ruse fcd1cdf70b Added a few characters that can be escaped 2023-01-31 12:37:18 +00:00
Kayne Ruse e265038547 Tested custom char trims 2023-01-29 08:38:26 +00:00
Kayne Ruse a357e0b0d4 Implemented _trim() 2023-01-29 08:30:31 +00:00
Kayne Ruse 2c5e3c6aa5 Started working on compound library 2023-01-29 07:23:52 +00:00
Kayne Ruse aeda0a0d94 Fixed pointer to int casting 2023-01-28 09:11:38 +00:00
Kayne Ruse ebbcba1b16 Enabled -std=c18 -pedantic, fixed all resulting errors
Thanks @gyrovorbis
2023-01-28 08:54:46 +00:00
Kayne Ruse 4bce10803e Added official support for mingw32 2023-01-28 07:56:11 +00:00
Kayne Ruse daee91904d Trying to test on windows 2023-01-28 06:20:36 +00:00
Kayne Ruse c397384766 Merge remote-tracking branch 'refs/remotes/origin/main' 2023-01-28 06:11:54 +00:00
Kayne Ruse 667efc2feb Removed nonstandard C constructor attribute 2023-01-28 06:06:04 +00:00
Kayne Ruse f4469fc53d Removed file extension guard 2023-01-27 07:03:36 +00:00
Kayne Ruse c86c5800a7 Moved guard 2023-01-27 06:31:13 +00:00
Kayne Ruse e4d843ad3a Type check 2023-01-27 06:16:39 +00:00
Kayne Ruse 6667bce3d7 Finally fixed the buffer
I suppose valgrind, et. al. complaining is a good thing, overall.
2023-01-27 06:01:05 +00:00
Kayne Ruse 50b07da188 Put the clear BEFORE the return 2023-01-27 05:56:23 +00:00
Kayne Ruse 708db75760 Forgot to free this buffer 2023-01-27 05:53:35 +00:00
Kayne Ruse b632ce77ba Moved drive to filepath code into a function 2023-01-27 05:49:14 +00:00
Kayne Ruse b2c3dd894c Added a memusage tool 2023-01-25 15:11:22 +00:00
Kayne Ruse 9b21bfb53b Missed a rename 2023-01-25 13:54:28 +00:00
Kayne Ruse d3adac8a59 Fixed the parser - whoops 2023-01-25 13:17:57 +00:00
Kayne Ruse 5183037a99 Missed the globals 2023-01-25 13:15:16 +00:00
102 changed files with 6217 additions and 1950 deletions
+29
View File
@@ -0,0 +1,29 @@
---
name: Bug Report
about: Create a report to help us improve
labels: bug
---
## Describe the bug
A clear and concise description of what the bug is.
## To Reproduce
Steps to reproduce the behaviour:
1. run `git pull` on the repository
2. run `make rebuild` on the code
3. ...
You can include some screenshots here if you'd like!
## Versioning
- OS: [for example MacOS, Windows, iOS, Android]
- Version: [What version of Toy was this running?]
### Additional context
Add any other context about the problem here.
+17
View File
@@ -0,0 +1,17 @@
---
name: Feature Request
about: Suggest an idea
labels: enhancement
---
### Describe the feature youd like
A clear and concise description of what youd like to be able to do with Toy.
### Describe alternatives you've considered
A clear and concise description of any alternative solutions or workarounds you've considered.
### Additional context
Add any other context about the feature request here.
+8 -2
View File
@@ -8,7 +8,6 @@ on:
jobs:
test-valgrind:
runs-on: ubuntu-latest
steps:
@@ -19,10 +18,17 @@ jobs:
run: make test
test-sanitized:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: make test (sanitized)
run: make test-sanitized
test-mingw32:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- name: make test (mingw32)
run: make test
+6 -3
View File
@@ -1,6 +1,4 @@
#Editor generated files
*.sln
*.vcproj
*.suo
*.ncb
*.user
@@ -13,18 +11,23 @@ Out/
release/
debug/
out/
bin/
.cache/
.vs/
#Project generated files
*.db
*.o
*.a
*.so
*.dll
*.exe
*.meta
*.log
out
*.out
*.stackdump
*.tb
*.filters
#Shell files
*.bat
+3 -6
View File
@@ -21,11 +21,11 @@ Special thanks to http://craftinginterpreters.com/ for their fantastic book that
## Building
For Windows, Linux and MacOS, simply run `make` in the root directory.
For Windows(mingw32 & cygwin), Linux and MacOS, simply run `make` in the root directory.
Note: For Linux, you may need to `cd` into the `out` directory before running.
For Windows(MSVC), Visual Studio project files are included.
Note: MacOS is not officially supported (no machines for testing), but we'll do our best!
Note: MacOS and Windows(MSVC) are not officially supported, but we'll do our best!
## Tools
@@ -38,7 +38,6 @@ Run `make install-tools` to install a number of tools, including:
```
import standard; //for a bunch of utility functions
print "Hello world"; //"print" is a keyword
var msg = "foobar"; //declare a variable like this
@@ -62,8 +61,6 @@ var tally = makeCounter();
print tally(); //1
print tally(); //2
print tally(); //3
export tally; //export this variable to the host program
```
# License
+157
View File
@@ -0,0 +1,157 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<ProjectGuid>{97F823E5-3AB8-47EF-B142-C15DD7CADF76}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IgnoreImportLibrary>false</IgnoreImportLibrary>
<OutDir>$(SolutionDir)out\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(SolutionDir)out\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<Optimization>Disabled</Optimization>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Link>
<AdditionalDependencies>Toy.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)out\$(Configuration)</AdditionalLibraryDirectories>
</Link>
<ClCompile>
<AdditionalIncludeDirectories>$(SolutionDir)/source;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard_C>stdc17</LanguageStandard_C>
<PreprocessorDefinitions>
</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<LanguageStandard_C>stdc17</LanguageStandard_C>
<PreprocessorDefinitions>
</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)/source;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>$(SolutionDir)out\$(Configuration)</AdditionalLibraryDirectories>
<AdditionalDependencies>Toy.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="repl\lib_about.c" />
<ClCompile Include="repl\lib_random.c" />
<ClCompile Include="repl\lib_runner.c" />
<ClCompile Include="repl\lib_standard.c" />
<ClCompile Include="repl\repl_main.c" />
<ClCompile Include="repl\repl_tools.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="repl\lib_about.h" />
<ClInclude Include="repl\lib_random.h" />
<ClInclude Include="repl\lib_runner.h" />
<ClInclude Include="repl\lib_standard.h" />
<ClInclude Include="repl\repl_tools.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="Toy.vcxproj">
<Project>{26360002-cc2a-469a-9b28-ba0c1af41657}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+164
View File
@@ -0,0 +1,164 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<ProjectGuid>{26360002-CC2A-469A-9B28-BA0C1AF41657}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>$(SolutionDir)out\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(SolutionDir)out\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;TOY_EXPORTS;TOY_EXPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<Optimization>Disabled</Optimization>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;TOY_EXPORTS;TOY_EXPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PreprocessorDefinitions>TOY_EXPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<LanguageStandard_C>stdc17</LanguageStandard_C>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<LanguageStandard_C>stdc17</LanguageStandard_C>
<PreprocessorDefinitions>TOY_EXPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="source\toy_ast_node.c" />
<ClCompile Include="source\toy_builtin.c" />
<ClCompile Include="source\toy_common.c" />
<ClCompile Include="source\toy_compiler.c" />
<ClCompile Include="source\toy_drive_system.c" />
<ClCompile Include="source\toy_interpreter.c" />
<ClCompile Include="source\toy_keyword_types.c" />
<ClCompile Include="source\toy_lexer.c" />
<ClCompile Include="source\toy_literal.c" />
<ClCompile Include="source\toy_literal_array.c" />
<ClCompile Include="source\toy_literal_dictionary.c" />
<ClCompile Include="source\toy_memory.c" />
<ClCompile Include="source\toy_parser.c" />
<ClCompile Include="source\toy_reffunction.c" />
<ClCompile Include="source\toy_refstring.c" />
<ClCompile Include="source\toy_scope.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="source\toy.h" />
<ClInclude Include="source\toy_ast_node.h" />
<ClInclude Include="source\toy_builtin.h" />
<ClInclude Include="source\toy_common.h" />
<ClInclude Include="source\toy_compiler.h" />
<ClInclude Include="source\toy_console_colors.h" />
<ClInclude Include="source\toy_drive_system.h" />
<ClInclude Include="source\toy_interpreter.h" />
<ClInclude Include="source\toy_keyword_types.h" />
<ClInclude Include="source\toy_lexer.h" />
<ClInclude Include="source\toy_literal.h" />
<ClInclude Include="source\toy_literal_array.h" />
<ClInclude Include="source\toy_literal_dictionary.h" />
<ClInclude Include="source\toy_memory.h" />
<ClInclude Include="source\toy_opcodes.h" />
<ClInclude Include="source\toy_parser.h" />
<ClInclude Include="source\toy_reffunction.h" />
<ClInclude Include="source\toy_refstring.h" />
<ClInclude Include="source\toy_scope.h" />
<ClInclude Include="source\toy_token_types.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+44
View File
@@ -0,0 +1,44 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.4.33213.308
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Toy", "Toy.vcxproj", "{26360002-CC2A-469A-9B28-BA0C1AF41657}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Repl", "Repl.vcxproj", "{97F823E5-3AB8-47EF-B142-C15DD7CADF76}"
ProjectSection(ProjectDependencies) = postProject
{26360002-CC2A-469A-9B28-BA0C1AF41657} = {26360002-CC2A-469A-9B28-BA0C1AF41657}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{26360002-CC2A-469A-9B28-BA0C1AF41657}.Debug|x64.ActiveCfg = Debug|x64
{26360002-CC2A-469A-9B28-BA0C1AF41657}.Debug|x64.Build.0 = Debug|x64
{26360002-CC2A-469A-9B28-BA0C1AF41657}.Debug|x86.ActiveCfg = Debug|Win32
{26360002-CC2A-469A-9B28-BA0C1AF41657}.Debug|x86.Build.0 = Debug|Win32
{26360002-CC2A-469A-9B28-BA0C1AF41657}.Release|x64.ActiveCfg = Release|x64
{26360002-CC2A-469A-9B28-BA0C1AF41657}.Release|x64.Build.0 = Release|x64
{26360002-CC2A-469A-9B28-BA0C1AF41657}.Release|x86.ActiveCfg = Release|Win32
{26360002-CC2A-469A-9B28-BA0C1AF41657}.Release|x86.Build.0 = Release|Win32
{97F823E5-3AB8-47EF-B142-C15DD7CADF76}.Debug|x64.ActiveCfg = Debug|x64
{97F823E5-3AB8-47EF-B142-C15DD7CADF76}.Debug|x64.Build.0 = Debug|x64
{97F823E5-3AB8-47EF-B142-C15DD7CADF76}.Debug|x86.ActiveCfg = Debug|Win32
{97F823E5-3AB8-47EF-B142-C15DD7CADF76}.Debug|x86.Build.0 = Debug|Win32
{97F823E5-3AB8-47EF-B142-C15DD7CADF76}.Release|x64.ActiveCfg = Release|x64
{97F823E5-3AB8-47EF-B142-C15DD7CADF76}.Release|x64.Build.0 = Release|x64
{97F823E5-3AB8-47EF-B142-C15DD7CADF76}.Release|x86.ActiveCfg = Release|Win32
{97F823E5-3AB8-47EF-B142-C15DD7CADF76}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7089F1AD-8EC0-4F27-AFD1-5FD43D91AABC}
EndGlobalSection
EndGlobal
+9 -7
View File
@@ -1,6 +1,4 @@
# Optimisation Options
# export CFLAGS+=-O2 -mtune=native -march=native
# export CFLAGS+=-fsanitize=address,undefined
export CFLAGS+=-std=c18 -pedantic -Werror
export TOY_OUTDIR = out
@@ -8,10 +6,10 @@ all: $(TOY_OUTDIR) repl
#repl builds
repl: $(TOY_OUTDIR) library
$(MAKE) -C repl
$(MAKE) -j8 -C repl
repl-static: $(TOY_OUTDIR) static
$(MAKE) -C repl
$(MAKE) -j8 -C repl
repl-release: clean $(TOY_OUTDIR) library-release
$(MAKE) -C repl release
@@ -26,12 +24,16 @@ library: $(TOY_OUTDIR)
static: $(TOY_OUTDIR)
$(MAKE) -j8 -C source static
library-release: $(TOY_OUTDIR)
library-release: clean $(TOY_OUTDIR)
$(MAKE) -j8 -C source library-release
static-release: $(TOY_OUTDIR)
static-release: clean $(TOY_OUTDIR)
$(MAKE) -j8 -C source static-release
#distribution
dist: export CFLAGS+=-O2 -mtune=native -march=native
dist: repl-release
#utils
test: clean $(TOY_OUTDIR)
$(MAKE) -C test
+162
View File
@@ -0,0 +1,162 @@
#include "lib_about.h"
#include "toy_memory.h"
int Toy_hookAbout(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
//the about keys
Toy_Literal majorKeyLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("major"));
Toy_Literal minorKeyLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("minor"));
Toy_Literal patchKeyLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("patch"));
Toy_Literal buildKeyLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("build"));
Toy_Literal authorKeyLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("author"));
//the about identifiers
Toy_Literal majorIdentifierLiteral = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString("major"));
Toy_Literal minorIdentifierLiteral = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString("minor"));
Toy_Literal patchIdentifierLiteral = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString("patch"));
Toy_Literal buildIdentifierLiteral = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString("build"));
Toy_Literal authorIdentifierLiteral = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString("author"));
//the about values
Toy_Literal majorLiteral = TOY_TO_INTEGER_LITERAL(TOY_VERSION_MAJOR);
Toy_Literal minorLiteral = TOY_TO_INTEGER_LITERAL(TOY_VERSION_MINOR);
Toy_Literal patchLiteral = TOY_TO_INTEGER_LITERAL(TOY_VERSION_PATCH);
Toy_Literal buildLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString(TOY_VERSION_BUILD));
Toy_Literal authorLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("Kayne Ruse, KR Game Studios"));
//store as 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);
Toy_freeLiteral(majorKeyLiteral);
Toy_freeLiteral(minorKeyLiteral);
Toy_freeLiteral(patchKeyLiteral);
Toy_freeLiteral(buildKeyLiteral);
Toy_freeLiteral(authorKeyLiteral);
Toy_freeLiteral(majorIdentifierLiteral);
Toy_freeLiteral(minorIdentifierLiteral);
Toy_freeLiteral(patchIdentifierLiteral);
Toy_freeLiteral(buildIdentifierLiteral);
Toy_freeLiteral(authorIdentifierLiteral);
Toy_freeLiteral(majorLiteral);
Toy_freeLiteral(minorLiteral);
Toy_freeLiteral(patchLiteral);
Toy_freeLiteral(buildLiteral);
Toy_freeLiteral(authorLiteral);
return -1;
}
//create the dictionary to load up with values
Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
Toy_initLiteralDictionary(dictionary);
//set each key/value pair
Toy_setLiteralDictionary(dictionary, majorKeyLiteral, majorLiteral);
Toy_setLiteralDictionary(dictionary, minorKeyLiteral, minorLiteral);
Toy_setLiteralDictionary(dictionary, patchKeyLiteral, patchLiteral);
Toy_setLiteralDictionary(dictionary, buildKeyLiteral, buildLiteral);
Toy_setLiteralDictionary(dictionary, authorKeyLiteral, authorLiteral);
//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 anyType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_ANY, true);
TOY_TYPE_PUSH_SUBTYPE(&type, strType);
TOY_TYPE_PUSH_SUBTYPE(&type, anyType);
//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);
}
//store globally
else {
//make sure the names aren't taken
if (Toy_isDelcaredScopeVariable(interpreter->scope, majorKeyLiteral) ||
Toy_isDelcaredScopeVariable(interpreter->scope, minorKeyLiteral) ||
Toy_isDelcaredScopeVariable(interpreter->scope, patchKeyLiteral) ||
Toy_isDelcaredScopeVariable(interpreter->scope, buildKeyLiteral) ||
Toy_isDelcaredScopeVariable(interpreter->scope, authorKeyLiteral)) {
interpreter->errorOutput("Can't override an existing variable\n");
Toy_freeLiteral(alias);
Toy_freeLiteral(majorKeyLiteral);
Toy_freeLiteral(minorKeyLiteral);
Toy_freeLiteral(patchKeyLiteral);
Toy_freeLiteral(buildKeyLiteral);
Toy_freeLiteral(authorKeyLiteral);
Toy_freeLiteral(majorIdentifierLiteral);
Toy_freeLiteral(minorIdentifierLiteral);
Toy_freeLiteral(patchIdentifierLiteral);
Toy_freeLiteral(buildIdentifierLiteral);
Toy_freeLiteral(authorIdentifierLiteral);
Toy_freeLiteral(majorLiteral);
Toy_freeLiteral(minorLiteral);
Toy_freeLiteral(patchLiteral);
Toy_freeLiteral(buildLiteral);
Toy_freeLiteral(authorLiteral);
return -1;
}
Toy_Literal intType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_INTEGER, true);
Toy_Literal strType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true);
//major
Toy_declareScopeVariable(interpreter->scope, majorIdentifierLiteral, intType);
Toy_setScopeVariable(interpreter->scope, majorIdentifierLiteral, majorLiteral, false);
//minor
Toy_declareScopeVariable(interpreter->scope, minorIdentifierLiteral, intType);
Toy_setScopeVariable(interpreter->scope, minorIdentifierLiteral, minorLiteral, false);
//patch
Toy_declareScopeVariable(interpreter->scope, patchIdentifierLiteral, intType);
Toy_setScopeVariable(interpreter->scope, patchIdentifierLiteral, patchLiteral, false);
//build
Toy_declareScopeVariable(interpreter->scope, buildIdentifierLiteral, strType);
Toy_setScopeVariable(interpreter->scope, buildIdentifierLiteral, buildLiteral, false);
//author
Toy_declareScopeVariable(interpreter->scope, authorIdentifierLiteral, strType);
Toy_setScopeVariable(interpreter->scope, authorIdentifierLiteral, authorLiteral, false);
Toy_freeLiteral(intType);
Toy_freeLiteral(strType);
}
//cleanup
Toy_freeLiteral(majorKeyLiteral);
Toy_freeLiteral(minorKeyLiteral);
Toy_freeLiteral(patchKeyLiteral);
Toy_freeLiteral(buildKeyLiteral);
Toy_freeLiteral(authorKeyLiteral);
Toy_freeLiteral(majorIdentifierLiteral);
Toy_freeLiteral(minorIdentifierLiteral);
Toy_freeLiteral(patchIdentifierLiteral);
Toy_freeLiteral(buildIdentifierLiteral);
Toy_freeLiteral(authorIdentifierLiteral);
Toy_freeLiteral(majorLiteral);
Toy_freeLiteral(minorLiteral);
Toy_freeLiteral(patchLiteral);
Toy_freeLiteral(buildLiteral);
Toy_freeLiteral(authorLiteral);
return 0;
}
+1 -1
View File
@@ -2,5 +2,5 @@
#include "toy_interpreter.h"
int Toy_hookTimer(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
int Toy_hookAbout(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
+196
View File
@@ -0,0 +1,196 @@
#include "lib_random.h"
#include "toy_memory.h"
static int hashInt(int x) {
x = ((x >> 16) ^ x) * 0x45d9f3b;
x = ((x >> 16) ^ x) * 0x45d9f3b;
x = ((x >> 16) ^ x) * 0x45d9f3b;
x = (x >> 16) ^ x;
return x;
}
typedef struct Toy_RandomGenerator {
int seed; //mutated with each call
} Toy_RandomGenerator;
//Toy native functions
static int nativeCreateRandomGenerator(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to createRandomGenerator\n");
return -1;
}
//get the seed argument
Toy_Literal seedLiteral = Toy_popLiteralArray(arguments);
Toy_Literal seedLiteralIdn = seedLiteral;
if (TOY_IS_IDENTIFIER(seedLiteral) && Toy_parseIdentifierToValue(interpreter, &seedLiteral)) {
Toy_freeLiteral(seedLiteralIdn);
}
if (TOY_IS_IDENTIFIER(seedLiteral)) {
Toy_freeLiteral(seedLiteral);
return -1;
}
if (!TOY_IS_INTEGER(seedLiteral)) {
interpreter->errorOutput("Incorrect literal type passed to createRandomGenerator");
Toy_freeLiteral(seedLiteral);
return -1;
}
//generate the generator object
Toy_RandomGenerator* generator = TOY_ALLOCATE(Toy_RandomGenerator, 1);
generator->seed = TOY_AS_INTEGER(seedLiteral);
Toy_Literal generatorLiteral = TOY_TO_OPAQUE_LITERAL(generator, TOY_OPAQUE_TAG_RANDOM);
//return and cleanup
Toy_pushLiteralArray(&interpreter->stack, generatorLiteral);
Toy_freeLiteral(seedLiteral);
Toy_freeLiteral(generatorLiteral);
return 1;
}
static int nativeGenerateRandomNumber(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to generateRandomNumber\n");
return -1;
}
//get the runner object
Toy_Literal generatorLiteral = Toy_popLiteralArray(arguments);
Toy_Literal generatorLiteralIdn = generatorLiteral;
if (TOY_IS_IDENTIFIER(generatorLiteral) && Toy_parseIdentifierToValue(interpreter, &generatorLiteral)) {
Toy_freeLiteral(generatorLiteralIdn);
}
if (TOY_IS_IDENTIFIER(generatorLiteral)) {
Toy_freeLiteral(generatorLiteral);
return -1;
}
if (TOY_GET_OPAQUE_TAG(generatorLiteral) != TOY_OPAQUE_TAG_RANDOM) {
interpreter->errorOutput("Unrecognized opaque literal in generateRandomNumber\n");
return -1;
}
Toy_RandomGenerator* generator = TOY_AS_OPAQUE(generatorLiteral);
//generate the new value and package up the return
generator->seed = hashInt(generator->seed);
Toy_Literal resultLiteral = TOY_TO_INTEGER_LITERAL(generator->seed);
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
//cleanup
Toy_freeLiteral(generatorLiteral);
Toy_freeLiteral(resultLiteral);
return 0;
}
static int nativeFreeRandomGenerator(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to freeRandomGenerator\n");
return -1;
}
//get the runner object
Toy_Literal generatorLiteral = Toy_popLiteralArray(arguments);
Toy_Literal generatorLiteralIdn = generatorLiteral;
if (TOY_IS_IDENTIFIER(generatorLiteral) && Toy_parseIdentifierToValue(interpreter, &generatorLiteral)) {
Toy_freeLiteral(generatorLiteralIdn);
}
if (TOY_IS_IDENTIFIER(generatorLiteral)) {
Toy_freeLiteral(generatorLiteral);
return -1;
}
if (TOY_GET_OPAQUE_TAG(generatorLiteral) != TOY_OPAQUE_TAG_RANDOM) {
interpreter->errorOutput("Unrecognized opaque literal in freeRandomGenerator\n");
return -1;
}
Toy_RandomGenerator* generator = TOY_AS_OPAQUE(generatorLiteral);
//clear out the runner object
TOY_FREE(Toy_RandomGenerator, generator);
Toy_freeLiteral(generatorLiteral);
return 0;
}
//call the hook
typedef struct Natives {
const char* name;
Toy_NativeFn fn;
} Natives;
int Toy_hookRandom(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
//build the natives list
Natives natives[] = {
{"createRandomGenerator", nativeCreateRandomGenerator},
{"generateRandomNumber", nativeGenerateRandomNumber},
{"freeRandomGenerator", nativeFreeRandomGenerator},
{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 -1;
}
//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_NATIVE_LITERAL(natives[i].fn);
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;
}
+7
View File
@@ -0,0 +1,7 @@
#pragma once
#include "toy_interpreter.h"
int Toy_hookRandom(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
#define TOY_OPAQUE_TAG_RANDOM 200
+91 -151
View File
@@ -1,16 +1,16 @@
#include "lib_runner.h"
#include "toy_memory.h"
#include "toy_drive_system.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;
const unsigned char* bytecode;
size_t size;
bool dirty;
@@ -24,87 +24,49 @@ static int nativeLoadScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu
return -1;
}
//get the argument
//get the file path literal with a handle
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_Literal drivePathLiteralIdn = drivePathLiteral;
if (TOY_IS_IDENTIFIER(drivePathLiteral) && Toy_parseIdentifierToValue(interpreter, &drivePathLiteral)) {
Toy_freeLiteral(drivePathLiteralIdn);
}
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);
if (TOY_IS_IDENTIFIER(drivePathLiteral)) {
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);
Toy_Literal filePathLiteral = Toy_getDrivePathLiteral(interpreter, &drivePathLiteral);
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);
if (TOY_IS_NULL(filePathLiteral)) {
Toy_freeLiteral(filePathLiteral);
Toy_freeLiteral(drivePathLiteral);
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;
}
}
Toy_freeLiteral(drivePathLiteral);
//use raw types - easier
const char* filePath = Toy_toCString(TOY_AS_STRING(filePathLiteral));
size_t filePathLength = Toy_lengthRefString(TOY_AS_STRING(filePathLiteral));
//load and compile the bytecode
size_t fileSize = 0;
char* source = Toy_readFile(filePath, &fileSize);
const char* source = (const char*)Toy_readFile(filePath, &fileSize);
if (!source) {
interpreter->errorOutput("Failed to load source file\n");
Toy_freeLiteral(filePathLiteral);
return -1;
}
unsigned char* bytecode = Toy_compileString(source, &fileSize);
const unsigned char* bytecode = Toy_compileString(source, &fileSize);
free((void*)source);
if (!bytecode) {
interpreter->errorOutput("Failed to compile source file\n");
Toy_freeLiteral(filePathLiteral);
return -1;
}
@@ -124,7 +86,8 @@ static int nativeLoadScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu
Toy_Literal runnerLiteral = TOY_TO_OPAQUE_LITERAL(runner, TOY_OPAQUE_TAG_RUNNER);
Toy_pushLiteralArray(&interpreter->stack, runnerLiteral);
TOY_FREE_ARRAY(char, filePath, realLength);
//free the drive path
Toy_freeLiteral(filePathLiteral);
return 1;
}
@@ -138,70 +101,30 @@ static int nativeLoadScriptBytecode(Toy_Interpreter* interpreter, Toy_LiteralArr
//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_Literal drivePathLiteralIdn = drivePathLiteral;
if (TOY_IS_IDENTIFIER(drivePathLiteral) && Toy_parseIdentifierToValue(interpreter, &drivePathLiteral)) {
Toy_freeLiteral(drivePathLiteralIdn);
}
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);
if (TOY_IS_IDENTIFIER(drivePathLiteral)) {
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);
Toy_Literal filePathLiteral = Toy_getDrivePathLiteral(interpreter, &drivePathLiteral);
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);
if (TOY_IS_NULL(filePathLiteral)) {
Toy_freeLiteral(filePathLiteral);
Toy_freeLiteral(drivePathLiteral);
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;
}
}
Toy_freeLiteral(drivePathLiteral);
//use raw types - easier
const char* filePath = Toy_toCString(TOY_AS_STRING(filePathLiteral));
size_t filePathLength = Toy_lengthRefString(TOY_AS_STRING(filePathLiteral));
//load the bytecode
size_t fileSize = 0;
@@ -228,7 +151,8 @@ static int nativeLoadScriptBytecode(Toy_Interpreter* interpreter, Toy_LiteralArr
Toy_Literal runnerLiteral = TOY_TO_OPAQUE_LITERAL(runner, TOY_OPAQUE_TAG_RUNNER);
Toy_pushLiteralArray(&interpreter->stack, runnerLiteral);
TOY_FREE_ARRAY(char, filePath, realLength);
//free the drive path
Toy_freeLiteral(filePathLiteral);
return 1;
}
@@ -236,7 +160,7 @@ static int nativeLoadScriptBytecode(Toy_Interpreter* interpreter, Toy_LiteralArr
static int nativeRunScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _runScript\n");
interpreter->errorOutput("Incorrect number of arguments to runScript\n");
return -1;
}
@@ -248,8 +172,13 @@ static int nativeRunScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argum
Toy_freeLiteral(runnerIdn);
}
if (TOY_IS_IDENTIFIER(runnerLiteral)) {
Toy_freeLiteral(runnerLiteral);
return -1;
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
interpreter->errorOutput("Unrecognized opaque literal in runScript\n");
return -1;
}
@@ -277,7 +206,7 @@ static int nativeRunScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argum
static int nativeGetScriptVar(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments to _getScriptVar\n");
interpreter->errorOutput("Incorrect number of arguments to getScriptVar\n");
return -1;
}
@@ -295,8 +224,14 @@ static int nativeGetScriptVar(Toy_Interpreter* interpreter, Toy_LiteralArray* ar
Toy_freeLiteral(runnerIdn);
}
if (TOY_IS_IDENTIFIER(varName) || TOY_IS_IDENTIFIER(runnerLiteral)) {
Toy_freeLiteral(varName);
Toy_freeLiteral(runnerLiteral);
return -1;
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
interpreter->errorOutput("Unrecognized opaque literal in getScriptVar\n");
return -1;
}
@@ -328,7 +263,7 @@ static int nativeGetScriptVar(Toy_Interpreter* interpreter, Toy_LiteralArray* ar
static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count < 2) {
interpreter->errorOutput("Incorrect number of arguments to _callScriptFn\n");
interpreter->errorOutput("Incorrect number of arguments to callScriptFn\n");
return -1;
}
@@ -345,7 +280,7 @@ static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* ar
Toy_LiteralArray rest;
Toy_initLiteralArray(&rest);
while (tmp.count) { //correct the order of the rest args
while (tmp.count > 0) { //correct the order of the rest args
Toy_Literal lit = Toy_popLiteralArray(&tmp);
Toy_pushLiteralArray(&rest, lit);
Toy_freeLiteral(lit);
@@ -353,7 +288,6 @@ static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* ar
Toy_freeLiteralArray(&tmp);
//get the runner object
Toy_Literal varName = Toy_popLiteralArray(arguments);
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
@@ -368,8 +302,14 @@ static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* ar
Toy_freeLiteral(runnerIdn);
}
if (TOY_IS_IDENTIFIER(varName) || TOY_IS_IDENTIFIER(runnerLiteral)) {
Toy_freeLiteral(varName);
Toy_freeLiteral(runnerLiteral);
return -1;
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
interpreter->errorOutput("Unrecognized opaque literal in callScriptFn\n");
return -1;
}
@@ -425,7 +365,7 @@ static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* ar
static int nativeResetScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _resetScript\n");
interpreter->errorOutput("Incorrect number of arguments to resetScript\n");
return -1;
}
@@ -437,8 +377,13 @@ static int nativeResetScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arg
Toy_freeLiteral(runnerIdn);
}
if (TOY_IS_IDENTIFIER(runnerLiteral)) {
Toy_freeLiteral(runnerLiteral);
return -1;
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
interpreter->errorOutput("Unrecognized opaque literal in resetScript\n");
return -1;
}
@@ -461,7 +406,7 @@ static int nativeResetScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arg
static int nativeFreeScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _freeScript\n");
interpreter->errorOutput("Incorrect number of arguments to freeScript\n");
return -1;
}
@@ -473,8 +418,13 @@ static int nativeFreeScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu
Toy_freeLiteral(runnerIdn);
}
if (TOY_IS_IDENTIFIER(runnerLiteral)) {
Toy_freeLiteral(runnerLiteral);
return -1;
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _freeScript\n");
interpreter->errorOutput("Unrecognized opaque literal in freeScript\n");
return -1;
}
@@ -495,7 +445,7 @@ static int nativeFreeScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu
static int nativeCheckScriptDirty(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _runScript\n");
interpreter->errorOutput("Incorrect number of arguments to checkScriptDirty\n");
return -1;
}
@@ -507,8 +457,13 @@ static int nativeCheckScriptDirty(Toy_Interpreter* interpreter, Toy_LiteralArray
Toy_freeLiteral(runnerIdn);
}
if (TOY_IS_IDENTIFIER(runnerLiteral)) {
Toy_freeLiteral(runnerLiteral);
return -1;
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
interpreter->errorOutput("Unrecognized opaque literal in checkScriptDirty\n");
return -1;
}
@@ -528,7 +483,7 @@ static int nativeCheckScriptDirty(Toy_Interpreter* interpreter, Toy_LiteralArray
//call the hook
typedef struct Natives {
char* name;
const char* name;
Toy_NativeFn fn;
} Natives;
@@ -537,12 +492,12 @@ int Toy_hookRunner(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Lit
Natives natives[] = {
{"loadScript", nativeLoadScript},
{"loadScriptBytecode", nativeLoadScriptBytecode},
{"_runScript", nativeRunScript},
{"_getScriptVar", nativeGetScriptVar},
{"_callScriptFn", nativeCallScriptFn},
{"_resetScript", nativeResetScript},
{"_freeScript", nativeFreeScript},
{"_checkScriptDirty", nativeCheckScriptDirty},
{"runScript", nativeRunScript},
{"getScriptVar", nativeGetScriptVar},
{"callScriptFn", nativeCallScriptFn},
{"resetScript", nativeResetScript},
{"freeScript", nativeFreeScript},
{"checkScriptDirty", nativeCheckScriptDirty},
{NULL, NULL}
};
@@ -552,7 +507,7 @@ int Toy_hookRunner(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Lit
if (Toy_isDelcaredScopeVariable(interpreter->scope, alias)) {
interpreter->errorOutput("Can't override an existing variable\n");
Toy_freeLiteral(alias);
return false;
return -1;
}
//create the dictionary to load up with functions
@@ -562,8 +517,7 @@ int Toy_hookRunner(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Lit
//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_Literal func = TOY_TO_FUNCTION_NATIVE_LITERAL(natives[i].fn);
Toy_setLiteralDictionary(dictionary, name, func);
@@ -597,17 +551,3 @@ int Toy_hookRunner(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Lit
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;
}
+1 -5
View File
@@ -4,9 +4,5 @@
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
+1996 -5
View File
File diff suppressed because it is too large Load Diff
-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;
}
+104 -53
View File
@@ -1,41 +1,42 @@
#include "repl_tools.h"
#include "lib_about.h"
#include "lib_standard.h"
#include "lib_timer.h"
#include "lib_random.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 "toy.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void repl() {
#define INPUT_BUFFER_SIZE 2048
void repl(const char* initialInput) {
//repl does it's own thing for now
bool error = false;
const int size = 2048;
char input[size];
memset(input, 0, size);
char input[INPUT_BUFFER_SIZE];
memset(input, 0, INPUT_BUFFER_SIZE);
Toy_Interpreter interpreter; //persist the interpreter for the scopes
Toy_initInterpreter(&interpreter);
//inject the libs
Toy_injectNativeHook(&interpreter, "about", Toy_hookAbout);
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
Toy_injectNativeHook(&interpreter, "timer", Toy_hookTimer);
Toy_injectNativeHook(&interpreter, "random", Toy_hookRandom);
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
for(;;) {
printf("> ");
//handle EOF for exits
if (!fgets(input, size, stdin)) {
break;
if (!initialInput) {
//handle EOF for exits
printf("> ");
if (!fgets(input, INPUT_BUFFER_SIZE, stdin)) {
break;
}
}
//escape the repl (length of 5 to accomodate the newline)
@@ -48,7 +49,8 @@ void repl() {
Toy_Parser parser;
Toy_Compiler compiler;
Toy_initLexer(&lexer, input);
Toy_initLexer(&lexer, initialInput ? initialInput : input);
Toy_private_setComments(&lexer, initialInput != NULL); //BUGFIX: disable comments here
Toy_initParser(&parser, &lexer);
Toy_initCompiler(&compiler);
@@ -57,7 +59,9 @@ void repl() {
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);
if (Toy_commandLine.verbose) {
printf(TOY_CC_ERROR "Error node detected\n" TOY_CC_RESET);
}
error = true;
Toy_freeASTNode(node);
break;
@@ -70,7 +74,7 @@ void repl() {
if (!error) {
//get the bytecode dump
int size = 0;
size_t size = 0;
unsigned char* tb = Toy_collateCompiler(&compiler, &size);
//run the bytecode
@@ -81,6 +85,15 @@ void repl() {
Toy_freeCompiler(&compiler);
Toy_freeParser(&parser);
error = false;
if (initialInput) {
free((void*)initialInput);
initialInput = NULL;
if (interpreter.panic) {
break;
}
}
}
Toy_freeInterpreter(&interpreter);
@@ -88,86 +101,124 @@ void repl() {
//entry point
int main(int argc, const char* argv[]) {
Toy_initCommand(argc, argv);
Toy_initCommandLine(argc, argv);
//lib setup (hacky - only really for this program)
Toy_initDriveDictionary();
//setup the drive system (for filesystem access)
Toy_initDriveSystem();
Toy_setDrivePath("scripts", "scripts");
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);
//command line specific actions
if (Toy_commandLine.error) {
Toy_usageCommandLine(argc, argv);
return 0;
}
if (command.help) {
Toy_helpCommand(argc, argv);
if (Toy_commandLine.help) {
Toy_helpCommandLine(argc, argv);
return 0;
}
if (command.version) {
Toy_copyrightCommand(argc, argv);
if (Toy_commandLine.version) {
Toy_copyrightCommandLine(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);
if (Toy_commandLine.verbose) {
printf(TOY_CC_NOTICE "Toy Programming Language Version %d.%d.%d, built '%s'\n" TOY_CC_RESET, TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH, TOY_VERSION_BUILD);
}
//run source file
if (command.sourcefile) {
Toy_runSourceFile(command.sourcefile);
if (Toy_commandLine.sourcefile) {
//only works on toy files
const char* s = strrchr(Toy_commandLine.sourcefile, '.');
if (!s || strcmp(s, ".toy")) {
fprintf(stderr, TOY_CC_ERROR "Bad file extension passed to %s (expected '.toy', found '%s')" TOY_CC_RESET, argv[0], s);
return -1;
}
//run the source file
Toy_runSourceFile(Toy_commandLine.sourcefile);
//lib cleanup
Toy_freeDriveDictionary();
Toy_freeDriveSystem();
return 0;
}
//run from stdin
if (command.source) {
Toy_runSource(command.source);
if (Toy_commandLine.source) {
Toy_runSource(Toy_commandLine.source);
//lib cleanup
Toy_freeDriveDictionary();
Toy_freeDriveSystem();
return 0;
}
//compile source file
if (command.compilefile && command.outfile) {
if (Toy_commandLine.compilefile && Toy_commandLine.outfile) {
//only works on toy and tb files
const char* c = strrchr(Toy_commandLine.compilefile, '.');
if (!c || strcmp(c, ".toy")) {
fprintf(stderr, TOY_CC_ERROR "Bad file extension passed to %s (expected '.toy', found '%s')" TOY_CC_RESET, argv[0], c);
return -1;
}
const char* o = strrchr(Toy_commandLine.outfile, '.');
if (!o || strcmp(o, ".tb")) {
fprintf(stderr, TOY_CC_ERROR "Bad file extension passed to %s (expected '.tb', found '%s')" TOY_CC_RESET, argv[0], o);
return -1;
}
//compile and save
size_t size = 0;
char* source = Toy_readFile(command.compilefile, &size);
unsigned char* tb = Toy_compileString(source, &size);
const char* source = (const char*)Toy_readFile(Toy_commandLine.compilefile, &size);
if (!source) {
return 1;
}
const unsigned char* tb = Toy_compileString(source, &size);
if (!tb) {
return 1;
}
Toy_writeFile(command.outfile, tb, size);
Toy_writeFile(Toy_commandLine.outfile, tb, size);
return 0;
}
//run binary
if (command.binaryfile) {
Toy_runBinaryFile(command.binaryfile);
if (Toy_commandLine.binaryfile) {
//only works on tb files
const char* c = strrchr(Toy_commandLine.binaryfile, '.');
if (!c || strcmp(c, ".tb")) {
fprintf(stderr, TOY_CC_ERROR "Bad file extension passed to %s (expected '.tb', found '%s')" TOY_CC_RESET, argv[0], c); //this one is never seen
return -1;
}
//run the binary file
Toy_runBinaryFile(Toy_commandLine.binaryfile);
//lib cleanup
Toy_freeDriveDictionary();
Toy_freeDriveSystem();
return 0;
}
repl();
const char* initialSource = NULL;
if (Toy_commandLine.initialfile) {
//only works on toy files
const char* s = strrchr(Toy_commandLine.initialfile, '.');
if (!s || strcmp(s, ".toy")) {
fprintf(stderr, TOY_CC_ERROR "Bad file extension passed to %s (expected '.toy', found '%s')" TOY_CC_RESET, argv[0], s);
return -1;
}
size_t size;
initialSource = (const char*)Toy_readFile(Toy_commandLine.initialfile, &size);
}
repl(initialSource);
//lib cleanup
Toy_freeDriveDictionary();
Toy_freeDriveSystem();
return 0;
}
+25 -20
View File
@@ -1,6 +1,7 @@
#include "repl_tools.h"
#include "lib_about.h"
#include "lib_standard.h"
#include "lib_timer.h"
#include "lib_random.h"
#include "lib_runner.h"
#include "toy_console_colors.h"
@@ -14,7 +15,7 @@
#include <stdlib.h>
//IO functions
char* Toy_readFile(char* path, size_t* fileSize) {
const unsigned char* Toy_readFile(const char* path, size_t* fileSize) {
FILE* file = fopen(path, "rb");
if (file == NULL) {
@@ -26,14 +27,14 @@ char* Toy_readFile(char* path, size_t* fileSize) {
*fileSize = ftell(file);
rewind(file);
char* buffer = (char*)malloc(*fileSize + 1);
unsigned char* buffer = (unsigned 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);
size_t bytesRead = fread(buffer, sizeof(unsigned char), *fileSize, file);
buffer[*fileSize] = '\0'; //NOTE: fread doesn't append this
@@ -47,7 +48,7 @@ char* Toy_readFile(char* path, size_t* fileSize) {
return buffer;
}
int Toy_writeFile(char* path, unsigned char* bytes, size_t size) {
int Toy_writeFile(const char* path, const unsigned char* bytes, size_t size) {
FILE* file = fopen(path, "wb");
if (file == NULL) {
@@ -55,7 +56,7 @@ int Toy_writeFile(char* path, unsigned char* bytes, size_t size) {
return -1;
}
int written = fwrite(bytes, size, 1, file);
size_t written = fwrite(bytes, size, 1, file);
if (written != 1) {
fprintf(stderr, TOY_CC_ERROR "Could not write file \"%s\"\n" TOY_CC_RESET, path);
@@ -68,7 +69,7 @@ int Toy_writeFile(char* path, unsigned char* bytes, size_t size) {
}
//repl functions
unsigned char* Toy_compileString(char* source, size_t* size) {
const unsigned char* Toy_compileString(const char* source, size_t* size) {
Toy_Lexer lexer;
Toy_Parser parser;
Toy_Compiler compiler;
@@ -77,10 +78,10 @@ unsigned char* Toy_compileString(char* source, size_t* size) {
Toy_initParser(&parser, &lexer);
Toy_initCompiler(&compiler);
//run the parser until the end of the source
//step 1 - run the parser until the end of the source
Toy_ASTNode* node = Toy_scanParser(&parser);
while(node != NULL) {
//pack up and leave
//on error, pack up and leave
if (node->type == TOY_AST_NODE_ERROR) {
Toy_freeASTNode(node);
Toy_freeCompiler(&compiler);
@@ -93,8 +94,8 @@ unsigned char* Toy_compileString(char* source, size_t* size) {
node = Toy_scanParser(&parser);
}
//get the bytecode dump
unsigned char* tb = Toy_collateCompiler(&compiler, (int*)(size));
//step 2 - get the bytecode dump
const unsigned char* tb = Toy_collateCompiler(&compiler, size);
//cleanup
Toy_freeCompiler(&compiler);
@@ -105,22 +106,23 @@ unsigned char* Toy_compileString(char* source, size_t* size) {
return tb;
}
void Toy_runBinary(unsigned char* tb, size_t size) {
void Toy_runBinary(const unsigned char* tb, size_t size) {
Toy_Interpreter interpreter;
Toy_initInterpreter(&interpreter);
//inject the libs
Toy_injectNativeHook(&interpreter, "about", Toy_hookAbout);
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
Toy_injectNativeHook(&interpreter, "timer", Toy_hookTimer);
Toy_injectNativeHook(&interpreter, "random", Toy_hookRandom);
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
Toy_runInterpreter(&interpreter, tb, size);
Toy_runInterpreter(&interpreter, tb, (int)size);
Toy_freeInterpreter(&interpreter);
}
void Toy_runBinaryFile(char* fname) {
void Toy_runBinaryFile(const char* fname) {
size_t size = 0; //not used
unsigned char* tb = (unsigned char*)Toy_readFile(fname, &size);
const unsigned char* tb = Toy_readFile(fname, &size);
if (!tb) {
return;
}
@@ -128,9 +130,9 @@ void Toy_runBinaryFile(char* fname) {
//interpreter takes ownership of the binary data
}
void Toy_runSource(char* source) {
void Toy_runSource(const char* source) {
size_t size = 0;
unsigned char* tb = Toy_compileString(source, &size);
const unsigned char* tb = Toy_compileString(source, &size);
if (!tb) {
return;
}
@@ -138,9 +140,12 @@ void Toy_runSource(char* source) {
Toy_runBinary(tb, size);
}
void Toy_runSourceFile(char* fname) {
void Toy_runSourceFile(const char* fname) {
size_t size = 0; //not used
char* source = Toy_readFile(fname, &size);
const char* source = (const char*)Toy_readFile(fname, &size);
if (!source) {
return;
}
Toy_runSource(source);
free((void*)source);
}
+7 -7
View File
@@ -2,13 +2,13 @@
#include "toy_common.h"
char* Toy_readFile(char* path, size_t* fileSize);
int Toy_writeFile(char* path, unsigned char* bytes, size_t size);
const unsigned char* Toy_readFile(const char* path, size_t* fileSize);
int Toy_writeFile(const char* path, const unsigned char* bytes, size_t size);
unsigned char* Toy_compileString(char* source, size_t* size);
const unsigned char* Toy_compileString(const 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);
void Toy_runBinary(const unsigned char* tb, size_t size);
void Toy_runBinaryFile(const char* fname);
void Toy_runSource(const char* source);
void Toy_runSourceFile(const char* fname);
-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";
+21
View File
@@ -0,0 +1,21 @@
//memoize the fib function
var memo: [int : int] = [:];
fn fib(n : int) {
if (n < 2) {
return n;
}
var result = memo[n];
if (result == null) {
result = fib(n-1) + fib(n-2);
memo[n] = result;
}
return result;
}
for (var i = 0; i < 40; i++) {
var res = fib(i);
print string i + ": " + string res;
}
+4 -6
View File
@@ -1,12 +1,10 @@
//WARNING: please think twice before using this in a test
fn fib(n : int) {
if (n < 2) {
return n;
}
return fib(n-1) + fib(n-2);
if (n < 2) return n;
return fib(n-1) + fib(n-2);
}
for (var i = 0; i < 20; i++) {
for (var i = 0; i <= 35; i++) {
var res = fib(i);
print string i + ": " + string res;
}
+90
View File
@@ -0,0 +1,90 @@
/*
How to run this program:
toyrepl -n -t scripts/level.toy
How to move around:
move(up);
move(down);
move(left);
move(right);
*/
//constants
var WIDTH: int const = 12;
var HEIGHT: int const = 12;
//WIDTH * HEIGHT in size
var tiles: [[int]] const = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1],
[1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1],
[1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1],
[1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] //BUG: map is twisted along this diagonal
];
var tileset: [int: string] const = [
0: " ",
1: "X "
];
//variables
var posX: int = 4;
var posY: int = 4;
//functions
fn draw() {
for (var j: int = 0; j < HEIGHT; j++) {
for (var i: int = 0; i < WIDTH; i++) {
//draw the player pos
if (i == posX && j == posY) {
print "O ";
continue;
}
print tileset[ tiles[i][j] ];
}
print "\n";
}
print "\n";
}
fn moveRelative(xrel: int, yrel: int) {
if (xrel > 1 || xrel < -1 || yrel > 1 || yrel < -1 || (xrel != 0 && yrel != 0)) {
print "too fast!\n";
return;
}
if (tiles[posX + xrel][posY + yrel] > 0) {
print "Can't move that way\n";
return;
}
posX += xrel;
posY += yrel;
draw();
}
//wrap for easy use
var up: [int] const = [0, -1];
var down: [int] const = [0, 1];
var left: [int] const = [-1, 0];
var right: [int] const = [1, 0];
fn move(dir: [int] const) {
return moveRelative(dir[0], dir[1]);
}
//initial display
move([0, 0]);
+36
View File
@@ -0,0 +1,36 @@
/*
Since this is a pseudo-random generator, and there's no internal state to the algorithm other
than the generator opaque, there needs to be a "call counter" (current depth) to shuffle the
initial seeds, otherwise generators created from other generators will resemble their parents,
but one call greater.
*/
import standard;
import random;
var DEPTH: int const = 20;
var levels = [];
//generate the level seeds
var generator: opaque = createRandomGenerator(clock().hash());
for (var i: int = 0; i < DEPTH; i++) {
levels.push(generator.generateRandomNumber());
}
generator.freeRandomGenerator();
//generate "levels" of a roguelike
for (var i = 0; i < DEPTH; i++) {
var rng: opaque = createRandomGenerator(levels[i] + i);
print "---";
print levels[i];
print rng.generateRandomNumber();
print rng.generateRandomNumber();
print rng.generateRandomNumber();
rng.freeRandomGenerator();
}
+1 -1
View File
@@ -32,7 +32,7 @@ prev += "*"; //initial
print prev;
//run
for (var iteration = 0; iteration < 100; iteration++) {
for (var iteration = 0; iteration < SIZE -1; iteration++) {
//left
var output = (lookup[" "][prev[0]][prev[1]]);
-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";
+70
View File
@@ -0,0 +1,70 @@
#pragma once
/* toy.h - A Toy Programming Language
If you're looking how to use Toy directly, try https://toylang.com/
Otherwise, these headers may help learn how Toy works internally.
*/
/* utilities - these define a bunch of useful macros based on platform.
The most important one is `TOY_API`, which highlights functions intended for the end user.
*/
#include "toy_common.h"
#include "toy_console_colors.h"
#include "toy_memory.h"
#include "toy_drive_system.h"
/* core pipeline - from source to execution
Each step is as follows:
source -> lexer -> token
token -> parser -> AST
AST -> compiler -> bytecode
bytecode -> interpreter -> result
I should note that the parser -> compiler phase is actually made up of two steps - the write step
and the collate step. See `Toy_compileString()` in `repl/repl_tools.c` for an example of how to compile
properly.
*/
#include "toy_lexer.h"
#include "toy_parser.h"
#include "toy_compiler.h"
#include "toy_interpreter.h"
/* building block structures - the basic units of operation
Literals represent any value within the language, including some internal ones that you never see.
Literal Arrays are literally arrays within memory, and are the most heavily used structure in Toy.
Literal Dictionaries are unordered key-value hashmaps, that use a running strategy for collisions.
*/
#include "toy_literal.h"
#include "toy_literal_array.h"
#include "toy_literal_dictionary.h"
/* other components - you probably won't use these directly, but they're a good learning opportunity.
`Toy_Scope` holds the variables of a specific scope within Toy - be it a script, a function, a block, etc.
Scopes are also where the type system lives at runtime. They use identifier literals as keys, exclusively.
`Toy_RefString` is a utility class that wraps traditional C strings, making them less memory intensive and
faster to copy and move. In reality, since strings are considered immutable, multiple variables can point
to the same string to save memory, and you can just create a new one of these vars pointing to the original
rather than copying entirely for a speed boost. This module has it's own memory allocator system that is
plugged into the main memory allocator.
`Toy_RefFunction` acts similarly to `Toy_RefString`, but instead operates on function bytecode.
*/
#include "toy_scope.h"
#include "toy_refstring.h"
#include "toy_reffunction.h"
+27 -9
View File
@@ -40,17 +40,21 @@ static void freeASTNodeCustom(Toy_ASTNode* node, bool freeSelf) {
break;
case TOY_AST_NODE_BLOCK:
for (int i = 0; i < node->block.count; i++) {
freeASTNodeCustom(node->block.nodes + i, false);
if (node->block.capacity > 0) {
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);
}
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);
if (node->compound.capacity > 0) {
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);
}
TOY_FREE_ARRAY(Toy_ASTNode, node->compound.nodes, node->compound.capacity);
break;
case TOY_AST_NODE_PAIR:
@@ -71,10 +75,12 @@ static void freeASTNodeCustom(Toy_ASTNode* node, bool freeSelf) {
break;
case TOY_AST_NODE_FN_COLLECTION:
for (int i = 0; i < node->fnCollection.count; i++) {
freeASTNodeCustom(node->fnCollection.nodes + i, false);
if (node->fnCollection.capacity > 0) {
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);
}
TOY_FREE_ARRAY(Toy_ASTNode, node->fnCollection.nodes, node->fnCollection.capacity);
break;
case TOY_AST_NODE_FN_DECL:
@@ -135,6 +141,10 @@ static void freeASTNodeCustom(Toy_ASTNode* node, bool freeSelf) {
Toy_freeLiteral(node->import.identifier);
Toy_freeLiteral(node->import.alias);
break;
case TOY_AST_NODE_PASS:
//EMPTY
break;
}
if (freeSelf) {
@@ -383,3 +393,11 @@ void Toy_emitASTNodeImport(Toy_ASTNode** nodeHandle, Toy_Literal identifier, Toy
*nodeHandle = tmp;
}
void Toy_emitASTNodePass(Toy_ASTNode** nodeHandle) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
tmp->type = TOY_AST_NODE_PASS;
*nodeHandle = tmp;
}
+4
View File
@@ -34,6 +34,7 @@ typedef enum Toy_ASTNodeType {
TOY_AST_NODE_PREFIX_DECREMENT, //decrement a variable
TOY_AST_NODE_POSTFIX_DECREMENT, //decrement a variable
TOY_AST_NODE_IMPORT, //import a library
TOY_AST_NODE_PASS, //for doing nothing
} Toy_ASTNodeType;
//literals
@@ -238,6 +239,9 @@ typedef struct Toy_NodeImport {
Toy_Literal alias;
} Toy_NodeImport;
//for doing nothing
void Toy_emitASTNodePass(Toy_ASTNode** nodeHandle);
union Toy_private_node {
Toy_ASTNodeType type;
Toy_NodeLiteral atomic;
+434 -188
View File
File diff suppressed because it is too large Load Diff
+7 -7
View File
@@ -3,12 +3,12 @@
#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);
int Toy_private_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);
int Toy_private_set(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
int Toy_private_get(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
int Toy_private_push(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
int Toy_private_pop(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
int Toy_private_length(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
int Toy_private_clear(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
+62 -47
View File
@@ -4,7 +4,7 @@
#include <string.h>
#include <assert.h>
//test variable sizes based on platform
//test variable sizes based on platform - see issue #35
#define STATIC_ASSERT(test_for_true) static_assert((test_for_true), "(" #test_for_true ") failed")
STATIC_ASSERT(sizeof(char) == 1);
@@ -15,77 +15,91 @@ STATIC_ASSERT(sizeof(unsigned char) == 1);
STATIC_ASSERT(sizeof(unsigned short) == 2);
STATIC_ASSERT(sizeof(unsigned int) == 4);
#ifndef TOY_EXPORT
#ifndef TOY_DISABLE_REPL
//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;
//declare the singleton with default values
Toy_CommandLine Toy_commandLine = {
.error = false,
.help = false,
.version = false,
.binaryfile = NULL,
.sourcefile = NULL,
.compilefile = NULL,
.outfile = "out.tb",
.source = NULL,
.initialfile = NULL,
.enablePrintNewline = true,
.verbose = false
};
void Toy_initCommandLine(int argc, const char* argv[]) {
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
Toy_commandLine.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;
Toy_commandLine.help = true;
Toy_commandLine.error = false;
continue;
}
if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
command.version = true;
command.error = false;
Toy_commandLine.version = true;
Toy_commandLine.error = false;
continue;
}
if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) {
command.verbose = true;
command.error = false;
Toy_commandLine.verbose = true;
Toy_commandLine.error = false;
continue;
}
if ((!strcmp(argv[i], "-f") || !strcmp(argv[i], "--sourcefile")) && i + 1 < argc) {
command.sourcefile = (char*)argv[i + 1];
Toy_commandLine.sourcefile = (char*)argv[i + 1];
i++;
command.error = false;
Toy_commandLine.error = false;
continue;
}
if ((!strcmp(argv[i], "-i") || !strcmp(argv[i], "--input")) && i + 1 < argc) {
command.source = (char*)argv[i + 1];
Toy_commandLine.source = (char*)argv[i + 1];
i++;
command.error = false;
Toy_commandLine.error = false;
continue;
}
if ((!strcmp(argv[i], "-c") || !strcmp(argv[i], "--compile")) && i + 1 < argc) {
command.compilefile = (char*)argv[i + 1];
Toy_commandLine.compilefile = (char*)argv[i + 1];
i++;
command.error = false;
Toy_commandLine.error = false;
continue;
}
if ((!strcmp(argv[i], "-o") || !strcmp(argv[i], "--output")) && i + 1 < argc) {
command.outfile = (char*)argv[i + 1];
Toy_commandLine.outfile = (char*)argv[i + 1];
i++;
command.error = false;
Toy_commandLine.error = false;
continue;
}
if ((!strcmp(argv[i], "-t") || !strcmp(argv[i], "--initial")) && i + 1 < argc) {
Toy_commandLine.initialfile = (char*)argv[i + 1];
i++;
Toy_commandLine.error = false;
continue;
}
if (!strcmp(argv[i], "-n")) {
Toy_commandLine.enablePrintNewline = false;
Toy_commandLine.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;
Toy_commandLine.binaryfile = (char*)argv[i];
Toy_commandLine.error = false;
continue;
}
}
@@ -95,26 +109,27 @@ void Toy_initCommand(int argc, const char* argv[]) {
}
}
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_usageCommandLine(int argc, const char* argv[]) {
printf("Usage: %s [ file.tb | -h | -v | -d | -f file.toy | -i source | -c file.toy -o out.tb | -t file.toy ]\n\n", argv[0]);
}
void Toy_helpCommand(int argc, const char* argv[]) {
Toy_usageCommand(argc, argv);
void Toy_helpCommandLine(int argc, const char* argv[]) {
Toy_usageCommandLine(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");
printf(" -h, --help\t\t\tShow this help then exit.\n");
printf(" -v, --version\t\t\tShow version and copyright information then exit.\n");
printf(" -d, --debug\t\t\tBe verbose when operating.\n");
printf(" -f, --file filename\t\tParse, compile and execute the source file.\n");
printf(" -i, --input source\t\tParse, compile and execute this given string of source code.\n");
printf(" -c, --compile filename\tParse and compile the specified source file into an output file.\n");
printf(" -o, --output outfile\t\tName of the output file built with --compile (default: out.tb).\n");
printf(" -t, --initial filename\tStart the repl as normal, after first running the given file.\n");
printf(" -n\t\t\t\tDisable the newline character at the end of the print statement.\n");
}
void Toy_copyrightCommand(int argc, const char* argv[]) {
void Toy_copyrightCommandLine(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("Copyright (c) 2020-2023 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");
+29 -17
View File
@@ -4,25 +4,33 @@
#include <stddef.h>
#include <stdint.h>
#define TOY_VERSION_MAJOR 0
#define TOY_VERSION_MINOR 8
#define TOY_VERSION_PATCH 0
#define TOY_VERSION_MAJOR 1
#define TOY_VERSION_MINOR 1
#define TOY_VERSION_PATCH 4
#define TOY_VERSION_BUILD __DATE__ " " __TIME__
//platform-specific specifications
#if defined(__linux__)
//platform/compiler-specific instructions
#if defined(__linux__) || defined(__MINGW32__) || defined(__GNUC__)
#define TOY_API extern
#elif defined(_WIN32) || defined(WIN32)
#define TOY_API
#elif defined(_MSC_VER)
#ifndef TOY_EXPORT
#define TOY_API __declspec(dllimport)
#else
#define TOY_API __declspec(dllexport)
#endif
#else
#define TOY_API
#define TOY_API extern
#endif
#ifndef TOY_EXPORT
//for processing the command line arguments
#ifndef TOY_DISABLE_REPL
//for processing the command line arguments in the repl
typedef struct {
bool error;
bool help;
@@ -32,14 +40,18 @@ typedef struct {
char* compilefile;
char* outfile; //defaults to out.tb
char* source;
char* initialfile;
bool enablePrintNewline;
bool verbose;
} Command;
} Toy_CommandLine;
extern Command command;
//these are intended for the repl only, despite using the api prefix
TOY_API Toy_CommandLine Toy_commandLine;
void Toy_initCommand(int argc, const char* argv[]);
TOY_API void Toy_initCommandLine(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
TOY_API void Toy_usageCommandLine(int argc, const char* argv[]);
TOY_API void Toy_helpCommandLine(int argc, const char* argv[]);
TOY_API void Toy_copyrightCommandLine(int argc, const char* argv[]);
#endif
+119 -22
View File
@@ -9,12 +9,14 @@
#include "toy_console_colors.h"
#include <stdio.h>
#include <string.h>
void Toy_initCompiler(Toy_Compiler* compiler) {
Toy_initLiteralArray(&compiler->literalCache);
compiler->bytecode = NULL;
compiler->capacity = 0;
compiler->count = 0;
compiler->panic = false;
}
//separated out, so it can be recursive
@@ -128,11 +130,12 @@ static int writeNodeCompoundToCache(Toy_Compiler* compiler, Toy_ASTNode* node) {
}
//push the store to the cache, with instructions about how pack it
Toy_Literal literal = TOY_TO_DICTIONARY_LITERAL(store);
literal.type = TOY_LITERAL_DICTIONARY_INTERMEDIATE; //god damn it
Toy_Literal literal = TOY_TO_DICTIONARY_LITERAL((Toy_LiteralDictionary*)store); //cast from array to dict, because it's intermediate
literal.type = TOY_LITERAL_DICTIONARY_INTERMEDIATE; //god damn it - nested in a dictionary
index = Toy_pushLiteralArray(&compiler->literalCache, literal);
Toy_freeLiteral(literal);
}
else if (node->compound.literalType == TOY_LITERAL_ARRAY) {
//ensure each literal value is in the cache, individually
for (int i = 0; i < node->compound.count; i++) {
@@ -160,18 +163,20 @@ static int writeNodeCompoundToCache(Toy_Compiler* compiler, Toy_ASTNode* node) {
break;
default:
fprintf(stderr, TOY_CC_ERROR "[internal] Unrecognized node type in writeNodeCompoundToCache()" TOY_CC_RESET);
fprintf(stderr, TOY_CC_ERROR "[internal] Unrecognized node type in writeNodeCompoundToCache()\n" TOY_CC_RESET);
return -1;
}
}
//push the store to the cache, with instructions about how pack it
Toy_Literal literal = TOY_TO_ARRAY_LITERAL(store);
literal.type = TOY_LITERAL_ARRAY_INTERMEDIATE; //god damn it - nested in an array
index = Toy_pushLiteralArray(&compiler->literalCache, literal);
Toy_freeLiteral(literal);
}
else {
fprintf(stderr, TOY_CC_ERROR "[internal] Unrecognized compound type in writeNodeCompoundToCache()" TOY_CC_RESET);
fprintf(stderr, TOY_CC_ERROR "[internal] Unrecognized compound type in writeNodeCompoundToCache()\n" TOY_CC_RESET);
return -1;
}
return index;
@@ -298,6 +303,12 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
//special case for when indexing and assigning
if (override != TOY_OP_EOF && node->binary.opcode >= TOY_OP_VAR_ASSIGN && node->binary.opcode <= TOY_OP_VAR_MODULO_ASSIGN) {
Toy_writeCompilerWithJumps(compiler, node->binary.right, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
//Special case if there's an index on both sides of the sign, just set it as indexing
if (node->binary.left->type == TOY_AST_NODE_BINARY && node->binary.right->type == TOY_AST_NODE_BINARY && node->binary.left->binary.opcode == TOY_OP_INDEX && node->binary.right->binary.opcode == TOY_OP_INDEX) {
compiler->bytecode[compiler->count++] = (unsigned char)TOY_OP_INDEX;
}
compiler->bytecode[compiler->count++] = (unsigned char)TOY_OP_INDEX_ASSIGN; //1 byte WARNING: enum trickery
compiler->bytecode[compiler->count++] = (unsigned char)node->binary.opcode; //1 byte
return TOY_OP_EOF;
@@ -311,7 +322,7 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
//return this if...
Toy_Opcode ret = Toy_writeCompilerWithJumps(compiler, node->binary.right, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
if (node->binary.opcode == TOY_OP_INDEX && rootNode->type == TOY_AST_NODE_BINARY && rootNode->binary.opcode == TOY_OP_VAR_ASSIGN) { //why var assign?
if (node->binary.opcode == TOY_OP_INDEX && rootNode->type == TOY_AST_NODE_BINARY && (rootNode->binary.opcode >= TOY_OP_VAR_ASSIGN && rootNode->binary.opcode <= TOY_OP_VAR_MODULO_ASSIGN) && rootNode->binary.right != node) { //range-based check for assignment type; make sure the index is on the left of the assignment symbol
return TOY_OP_INDEX_ASSIGN_INTERMEDIATE;
}
@@ -320,9 +331,37 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
return node->binary.opcode;
}
if (ret != TOY_OP_EOF && (node->binary.opcode == TOY_OP_VAR_ASSIGN || node->binary.opcode == TOY_OP_AND || node->binary.opcode == TOY_OP_OR || (node->binary.opcode >= TOY_OP_COMPARE_EQUAL && node->binary.opcode <= TOY_OP_INVERT))) {
compiler->bytecode[compiler->count++] = (unsigned char)ret; //1 byte
ret = TOY_OP_EOF; //untangle in this case
//untangle in these cases - (WTF, are you serious?)
if (ret != TOY_OP_EOF) {
switch(node->binary.opcode) {
case TOY_OP_NEGATE:
case TOY_OP_ADDITION:
case TOY_OP_SUBTRACTION:
case TOY_OP_MULTIPLICATION:
case TOY_OP_DIVISION:
case TOY_OP_MODULO:
case TOY_OP_VAR_ASSIGN:
case TOY_OP_VAR_ADDITION_ASSIGN:
case TOY_OP_VAR_SUBTRACTION_ASSIGN:
case TOY_OP_VAR_MULTIPLICATION_ASSIGN:
case TOY_OP_VAR_DIVISION_ASSIGN:
case TOY_OP_VAR_MODULO_ASSIGN:
case TOY_OP_COMPARE_EQUAL:
case TOY_OP_COMPARE_NOT_EQUAL:
case TOY_OP_COMPARE_LESS:
case TOY_OP_COMPARE_LESS_EQUAL:
case TOY_OP_COMPARE_GREATER:
case TOY_OP_COMPARE_GREATER_EQUAL:
case TOY_OP_INVERT:
case TOY_OP_AND:
case TOY_OP_OR:
//place the rhs result before the outer instruction
compiler->bytecode[compiler->count++] = (unsigned char)ret; //1 byte
ret = TOY_OP_EOF;
default:
break;
}
}
compiler->bytecode[compiler->count++] = (unsigned char)node->binary.opcode; //1 byte
@@ -332,7 +371,7 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
break;
case TOY_AST_NODE_TERNARY: {
// TODO
// TODO: a ?: b;
//process the condition
Toy_Opcode override = Toy_writeCompilerWithJumps(compiler, node->ternary.condition, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
@@ -365,7 +404,7 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
//write the else path
Toy_Opcode override2 = Toy_writeCompilerWithJumps(compiler, node->pathIf.elsePath, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
if (override2 != TOY_OP_EOF) {//compensate for indexing & dot notation being screwy
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
compiler->bytecode[compiler->count++] = (unsigned char)override2; //1 byte
}
//update the jumpToEnd to point here
@@ -401,6 +440,11 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
case TOY_AST_NODE_COMPOUND: {
int index = writeNodeCompoundToCache(compiler, node);
if (index < 0) {
compiler->panic = true;
return TOY_OP_EOF;
}
//push the node opcode to the bytecode
if (index >= 256) {
//push a "long" index
@@ -468,9 +512,13 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
}
//adopt the panic state if anything happened
if (fnCompiler->panic) {
compiler->panic = true;
}
//create the function in the literal cache (by storing the compiler object)
Toy_Literal fnLiteral = TOY_TO_FUNCTION_LITERAL(fnCompiler, 0);
fnLiteral.type = TOY_LITERAL_FUNCTION_INTERMEDIATE; //NOTE: changing type
Toy_Literal fnLiteral = ((Toy_Literal){ .as = { .generic = fnCompiler }, .type = TOY_LITERAL_FUNCTION_INTERMEDIATE});
//push the name
int identifierIndex = Toy_findLiteralIndex(&compiler->literalCache, node->fnDecl.identifier);
@@ -504,6 +552,11 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
case TOY_AST_NODE_FN_COLLECTION: {
//embed these in the bytecode...
unsigned short index = (unsigned short)writeNodeCollectionToCache(compiler, node);
if (index == (unsigned short)-1) {
compiler->panic = true;
return TOY_OP_EOF;
}
memcpy(compiler->bytecode + compiler->count, &index, sizeof(index));
compiler->count += sizeof(unsigned short);
@@ -754,7 +807,7 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
case TOY_AST_NODE_BREAK: {
if (!breakAddressesPtr) {
fprintf(stderr, TOY_CC_ERROR "TOY_CC_ERROR: Can't place a break statement here\n" TOY_CC_RESET);
fprintf(stderr, TOY_CC_ERROR "[internal] Can't place a break statement here\n" TOY_CC_RESET);
break;
}
@@ -772,7 +825,7 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
case TOY_AST_NODE_CONTINUE: {
if (!continueAddressesPtr) {
fprintf(stderr, TOY_CC_ERROR "TOY_CC_ERROR: Can't place a continue statement here\n" TOY_CC_RESET);
fprintf(stderr, TOY_CC_ERROR "[internal] Can't place a continue statement here\n" TOY_CC_RESET);
break;
}
@@ -940,6 +993,11 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
return TOY_OP_INDEX_ASSIGN; //override binary's instruction IF it is assign
}
break;
case TOY_AST_NODE_PASS: {
return TOY_OP_PASS;
}
break;
}
return TOY_OP_EOF;
@@ -951,6 +1009,8 @@ void Toy_writeCompiler(Toy_Compiler* compiler, Toy_ASTNode* node) {
if (op != TOY_OP_EOF) {//compensate for indexing & dot notation being screwy
compiler->bytecode[compiler->count++] = (unsigned char)op; //1 byte
}
//TODO: could free up AST Nodes
}
void Toy_freeCompiler(Toy_Compiler* compiler) {
@@ -959,6 +1019,7 @@ void Toy_freeCompiler(Toy_Compiler* compiler) {
compiler->bytecode = NULL;
compiler->capacity = 0;
compiler->count = 0;
compiler->panic = false;
}
static void emitByte(unsigned char** collationPtr, int* capacityPtr, int* countPtr, unsigned char byte) {
@@ -1006,7 +1067,12 @@ static void emitFloat(unsigned char** collationPtr, int* capacityPtr, int* count
}
//return the result
static unsigned char* collateCompilerHeaderOpt(Toy_Compiler* compiler, int* size, bool embedHeader) {
static unsigned char* collateCompilerHeaderOpt(Toy_Compiler* compiler, size_t* size, bool embedHeader) {
if (compiler->panic) {
fprintf(stderr, TOY_CC_ERROR "[internal] Can't collate a panicked compiler\n" TOY_CC_RESET);
return NULL;
}
int capacity = TOY_GROW_CAPACITY(0);
int count = 0;
unsigned char* collation = TOY_ALLOCATE(unsigned char, capacity);
@@ -1072,7 +1138,7 @@ static unsigned char* collateCompilerHeaderOpt(Toy_Compiler* compiler, int* size
Toy_Literal str = compiler->literalCache.literals[i];
for (int c = 0; c < TOY_AS_STRING(str)->length; c++) {
for (int c = 0; c < (int)Toy_lengthRefString(TOY_AS_STRING(str)); c++) {
emitByte(&collation, &capacity, &count, Toy_toCString(TOY_AS_STRING(str))[c]);
}
@@ -1095,7 +1161,22 @@ static unsigned char* collateCompilerHeaderOpt(Toy_Compiler* compiler, int* size
}
break;
case TOY_LITERAL_DICTIONARY_INTERMEDIATE: {
case TOY_LITERAL_ARRAY_INTERMEDIATE: {
emitByte(&collation, &capacity, &count, TOY_LITERAL_ARRAY_INTERMEDIATE);
Toy_LiteralArray* ptr = TOY_AS_ARRAY(compiler->literalCache.literals[i]);
//length of the array, as a short
Toy_emitShort(&collation, &capacity, &count, ptr->count);
//each element of the array
for (int i = 0; i < ptr->count; i++) {
Toy_emitShort(&collation, &capacity, &count, (unsigned short)TOY_AS_INTEGER(ptr->literals[i])); //shorts representing the indexes of the values
}
}
break;
case TOY_LITERAL_DICTIONARY: {
emitByte(&collation, &capacity, &count, TOY_LITERAL_DICTIONARY);
Toy_LiteralArray* ptr = TOY_AS_ARRAY(compiler->literalCache.literals[i]); //used an array for storage above
@@ -1110,20 +1191,35 @@ static unsigned char* collateCompilerHeaderOpt(Toy_Compiler* compiler, int* size
}
break;
case TOY_LITERAL_DICTIONARY_INTERMEDIATE: {
emitByte(&collation, &capacity, &count, TOY_LITERAL_DICTIONARY_INTERMEDIATE);
Toy_LiteralArray* ptr = TOY_AS_ARRAY(compiler->literalCache.literals[i]); //used an array for storage above
//length of the array, as a short
Toy_emitShort(&collation, &capacity, &count, ptr->count); //count is the array size, NOT the dictionary size
//each element of the array
for (int i = 0; i < ptr->count; i++) {
Toy_emitShort(&collation, &capacity, &count, (unsigned short)TOY_AS_INTEGER(ptr->literals[i])); //shorts representing the indexes of the values
}
}
break;
case TOY_LITERAL_FUNCTION_INTERMEDIATE: {
//extract the compiler
Toy_Literal fn = compiler->literalCache.literals[i];
void* fnCompiler = TOY_AS_FUNCTION(fn).bytecode; //store the compiler here for now
void* fnCompiler = fn.as.generic; //store the compiler here for now
//collate the function into bytecode (without header)
int size = 0;
size_t size = 0;
unsigned char* bytes = collateCompilerHeaderOpt((Toy_Compiler*)fnCompiler, &size, false);
//emit how long this section is, +1 for ending mark
Toy_emitShort(&fnCollation, &fnCapacity, &fnCount, (unsigned short)size + 1);
//write the fn to the fn collation
for (int i = 0; i < size; i++) {
for (size_t i = 0; i < size; i++) {
emitByte(&fnCollation, &fnCapacity, &fnCount, bytes[i]);
}
@@ -1144,7 +1240,7 @@ static unsigned char* collateCompilerHeaderOpt(Toy_Compiler* compiler, int* size
Toy_Literal identifier = compiler->literalCache.literals[i];
for (int c = 0; c < TOY_AS_IDENTIFIER(identifier)->length; c++) {
for (int c = 0; c < (int)Toy_lengthRefString(TOY_AS_IDENTIFIER(identifier)); c++) {
emitByte(&collation, &capacity, &count, Toy_toCString(TOY_AS_IDENTIFIER(identifier))[c]);
}
@@ -1230,6 +1326,7 @@ static unsigned char* collateCompilerHeaderOpt(Toy_Compiler* compiler, int* size
return collation;
}
unsigned char* Toy_collateCompiler(Toy_Compiler* compiler, int* size) {
//the whole point of the compiler is to alter bytecode, so leave it as non-const
unsigned char* Toy_collateCompiler(Toy_Compiler* compiler, size_t* size) {
return collateCompilerHeaderOpt(compiler, size, true);
}
+2 -1
View File
@@ -11,6 +11,7 @@ typedef struct Toy_Compiler {
unsigned char* bytecode;
int capacity;
int count;
bool panic;
} Toy_Compiler;
TOY_API void Toy_initCompiler(Toy_Compiler* compiler);
@@ -18,4 +19,4 @@ 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);
TOY_API unsigned char* Toy_collateCompiler(Toy_Compiler* compiler, size_t* size);
+47 -3
View File
@@ -1,6 +1,19 @@
#pragma once
//NOTE: you need both font AND background for these to work
/* toy_console_colors.h - console utility
This file provides a number of macros that can set the color of text in a console
window. These are used for convenience only. They are supposed to be dropped into
a printf()'s first argument, like so:
printf(TOY_CC_NOTICE "Hello world" TOY_CC_RESET);
NOTE: you need both font AND background for these to work
*/
//platform/compiler-specific instructions
#if defined(__linux__) || defined(__MINGW32__) || defined(__GNUC__)
//fonts color
#define TOY_CC_FONT_BLACK "\033[30;"
@@ -25,6 +38,37 @@
//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_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"
#else
//fonts color
#define TOY_CC_FONT_BLACK
#define TOY_CC_FONT_RED
#define TOY_CC_FONT_GREEN
#define TOY_CC_FONT_YELLOW
#define TOY_CC_FONT_BLUE
#define TOY_CC_FONT_PURPLE
#define TOY_CC_FONT_DGREEN
#define TOY_CC_FONT_WHITE
#define TOY_CC_FONT_CYAN
//background color
#define TOY_CC_BACK_BLACK
#define TOY_CC_BACK_RED
#define TOY_CC_BACK_GREEN
#define TOY_CC_BACK_YELLOW
#define TOY_CC_BACK_BLUE
#define TOY_CC_BACK_PURPLE
#define TOY_CC_BACK_DGREEN
#define TOY_CC_BACK_WHITE
//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
#endif
+99
View File
@@ -0,0 +1,99 @@
#include "toy_drive_system.h"
#include "toy_memory.h"
#include "toy_literal_dictionary.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//file system API
static Toy_LiteralDictionary driveDictionary;
void Toy_initDriveSystem() {
Toy_initLiteralDictionary(&driveDictionary);
}
void Toy_freeDriveSystem() {
Toy_freeLiteralDictionary(&driveDictionary);
}
TOY_API void Toy_setDrivePath(char* drive, char* path) {
Toy_Literal driveLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString(drive));
Toy_Literal pathLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString(path));
Toy_setLiteralDictionary(&driveDictionary, driveLiteral, pathLiteral);
Toy_freeLiteral(driveLiteral);
Toy_freeLiteral(pathLiteral);
}
Toy_Literal Toy_getDrivePathLiteral(Toy_Interpreter* interpreter, Toy_Literal* drivePathLiteral) {
//check argument types
if (!TOY_IS_STRING(*drivePathLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to Toy_getDrivePathLiteral\n");
return TOY_TO_NULL_LITERAL;
}
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
size_t driveLength = 0;
while (Toy_toCString(drivePath)[driveLength] != ':') {
if (driveLength >= Toy_lengthRefString(drivePath)) {
interpreter->errorOutput("Incorrect drive path format given to Toy_getDrivePathLiteral\n");
return TOY_TO_NULL_LITERAL;
}
driveLength++;
}
Toy_RefString* drive = Toy_createRefStringLength(Toy_toCString(drivePath), driveLength);
Toy_RefString* filePath = 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 pathLiteral = Toy_getLiteralDictionary(&driveDictionary, driveLiteral);
if (!TOY_IS_STRING(pathLiteral)) {
interpreter->errorOutput("Incorrect literal type found for drive: ");
Toy_printLiteralCustom(pathLiteral, interpreter->errorOutput);
interpreter->errorOutput("\n");
Toy_freeLiteral(driveLiteral);
Toy_freeLiteral(pathLiteral);
Toy_deleteRefString(filePath);
Toy_deleteRefString(drivePath);
return TOY_TO_NULL_LITERAL;
}
//get the final real file path (concat) TODO: move this concat to refstring library
Toy_RefString* path = Toy_copyRefString(TOY_AS_STRING(pathLiteral));
size_t fileLength = Toy_lengthRefString(path) + Toy_lengthRefString(filePath);
char* file = TOY_ALLOCATE(char, fileLength + 1); //+1 for null
snprintf(file, fileLength, "%s%s", Toy_toCString(path), Toy_toCString(filePath));
//clean up the drive/path stuff
Toy_deleteRefString(drivePath);
Toy_deleteRefString(filePath);
Toy_deleteRefString(path);
Toy_freeLiteral(driveLiteral);
Toy_freeLiteral(pathLiteral);
//check for break-out attempts
for (size_t i = 0; i < fileLength - 1; i++) {
if (file[i] == '.' && file[i + 1] == '.') {
interpreter->errorOutput("Parent directory access not allowed\n");
TOY_FREE_ARRAY(char, file, fileLength + 1);
return TOY_TO_NULL_LITERAL;
}
}
Toy_Literal result = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(file, fileLength));
TOY_FREE_ARRAY(char, file, fileLength + 1);
return result;
}
+12
View File
@@ -0,0 +1,12 @@
#include "toy_common.h"
#include "toy_literal.h"
#include "toy_interpreter.h"
//file system API - these need to be set by the host
TOY_API void Toy_initDriveSystem();
TOY_API void Toy_freeDriveSystem();
//file system API - for use with libs
TOY_API void Toy_setDrivePath(char* drive, char* path);
TOY_API Toy_Literal Toy_getDrivePathLiteral(Toy_Interpreter* interpreter, Toy_Literal* drivePathLiteral);
+501 -388
View File
File diff suppressed because it is too large Load Diff
+5 -10
View File
@@ -6,12 +6,10 @@
#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;
const unsigned char* bytecode;
int length;
int count;
int codeStart; //BUGFIX: for jumps, must be initialized to -1
@@ -34,14 +32,11 @@ typedef struct Toy_Interpreter {
} 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_injectNativeFn(Toy_Interpreter* interpreter, const char* name, Toy_NativeFn func);
TOY_API bool Toy_injectNativeHook(Toy_Interpreter* interpreter, const 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);
TOY_API bool Toy_callFn(Toy_Interpreter* interpreter, const char* name, Toy_LiteralArray* arguments, Toy_LiteralArray* returns);
//utilities for the host program
TOY_API bool Toy_parseIdentifierToValue(Toy_Interpreter* interpreter, Toy_Literal* literalPtr);
@@ -51,6 +46,6 @@ TOY_API void Toy_setInterpreterError(Toy_Interpreter* interpreter, Toy_PrintFn e
//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_runInterpreter(Toy_Interpreter* interpreter, const unsigned char* bytecode, size_t 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
+57 -23
View File
@@ -12,6 +12,7 @@ static void cleanLexer(Toy_Lexer* lexer) {
lexer->start = 0;
lexer->current = 0;
lexer->line = 1;
lexer->commentsEnabled = true;
}
static bool isAtEnd(Toy_Lexer* lexer) {
@@ -54,9 +55,13 @@ static void eatWhitespace(Toy_Lexer* lexer) {
//comments
case '/':
if (!lexer->commentsEnabled) {
return;
}
//eat the line
if (peekNext(lexer) == '/') {
while (advance(lexer) != '\n' && !isAtEnd(lexer));
while (!isAtEnd(lexer) && advance(lexer) != '\n');
break;
}
@@ -64,7 +69,7 @@ static void eatWhitespace(Toy_Lexer* lexer) {
if (peekNext(lexer) == '*') {
advance(lexer);
advance(lexer);
while(!(peek(lexer) == '*' && peekNext(lexer) == '/')) advance(lexer);
while(!isAtEnd(lexer) && !(peek(lexer) == '*' && peekNext(lexer) == '/')) advance(lexer);
advance(lexer);
advance(lexer);
break;
@@ -110,9 +115,9 @@ static Toy_Token makeErrorToken(Toy_Lexer* lexer, char* msg) {
token.line = lexer->line;
#ifndef TOY_EXPORT
if (command.verbose) {
if (Toy_commandLine.verbose) {
printf("err:");
Toy_printToken(&token);
Toy_private_printToken(&token);
}
#endif
@@ -129,9 +134,9 @@ static Toy_Token makeToken(Toy_Lexer* lexer, Toy_TokenType type) {
#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) {
if (Toy_commandLine.verbose) {
printf("tok:");
Toy_printToken(&token);
Toy_private_printToken(&token);
}
#endif
@@ -141,12 +146,12 @@ static Toy_Token makeToken(Toy_Lexer* lexer, Toy_TokenType type) {
static Toy_Token makeIntegerOrFloat(Toy_Lexer* lexer) {
Toy_TokenType type = TOY_TOKEN_LITERAL_INTEGER; //what am I making?
while(isDigit(lexer)) advance(lexer);
while(isDigit(lexer) || peek(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);
while(isDigit(lexer) || peek(lexer) == '_') advance(lexer);
}
Toy_Token token;
@@ -157,26 +162,51 @@ static Toy_Token makeIntegerOrFloat(Toy_Lexer* lexer) {
token.line = lexer->line;
#ifndef TOY_EXPORT
if (command.verbose) {
if (Toy_commandLine.verbose) {
if (type == TOY_TOKEN_LITERAL_INTEGER) {
printf("int:");
} else {
printf("flt:");
}
Toy_printToken(&token);
Toy_private_printToken(&token);
}
#endif
return token;
}
static bool isEscapableCharacter(char c) {
switch (c) {
case 'n':
case 't':
case '\\':
case '"':
return true;
default:
return false;
}
}
static Toy_Token makeString(Toy_Lexer* lexer, char terminator) {
while (!isAtEnd(lexer) && peek(lexer) != terminator) {
while (!isAtEnd(lexer)) {
//stop if you've hit the terminator
if (peek(lexer) == terminator) {
advance(lexer); //eat terminator
break;
}
//skip escaped control characters
if (peek(lexer) == '\\' && isEscapableCharacter(peekNext(lexer))) {
advance(lexer);
advance(lexer);
continue;
}
//otherwise
advance(lexer);
}
advance(lexer); //eat terminator
if (isAtEnd(lexer)) {
return makeErrorToken(lexer, "Unterminated string");
}
@@ -189,9 +219,9 @@ static Toy_Token makeString(Toy_Lexer* lexer, char terminator) {
token.line = lexer->line;
#ifndef TOY_EXPORT
if (command.verbose) {
if (Toy_commandLine.verbose) {
printf("str:");
Toy_printToken(&token);
Toy_private_printToken(&token);
}
#endif
@@ -216,9 +246,9 @@ static Toy_Token makeKeywordOrIdentifier(Toy_Lexer* lexer) {
token.line = lexer->line;
#ifndef TOY_EXPORT
if (command.verbose) {
if (Toy_commandLine.verbose) {
printf("kwd:");
Toy_printToken(&token);
Toy_private_printToken(&token);
}
#endif
@@ -235,9 +265,9 @@ static Toy_Token makeKeywordOrIdentifier(Toy_Lexer* lexer) {
token.line = lexer->line;
#ifndef TOY_EXPORT
if (command.verbose) {
if (Toy_commandLine.verbose) {
printf("idf:");
Toy_printToken(&token);
Toy_private_printToken(&token);
}
#endif
@@ -245,13 +275,13 @@ static Toy_Token makeKeywordOrIdentifier(Toy_Lexer* lexer) {
}
//exposed functions
void Toy_initLexer(Toy_Lexer* lexer, char* source) {
void Toy_initLexer(Toy_Lexer* lexer, const char* source) {
cleanLexer(lexer);
lexer->source = source;
}
Toy_Token Toy_scanLexer(Toy_Lexer* lexer) {
Toy_Token Toy_private_scanLexer(Toy_Lexer* lexer) {
eatWhitespace(lexer);
lexer->start = lexer->current;
@@ -322,7 +352,7 @@ static void trim(char** s, int* l) { //all this to remove a newline?
}
//for debugging
void Toy_printToken(Toy_Token* token) {
void Toy_private_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;
@@ -338,7 +368,7 @@ void Toy_printToken(Toy_Token* token) {
if (keyword != NULL) {
printf("%s", keyword);
} else {
char* str = token->lexeme;
char* str = (char*)token->lexeme; //strip const-ness for trimming
int length = token->length;
trim(&str, &length);
printf("%.*s", length, str);
@@ -347,3 +377,7 @@ void Toy_printToken(Toy_Token* token) {
printf("\n");
}
void Toy_private_setComments(Toy_Lexer* lexer, bool enabled) {
lexer->commentsEnabled = enabled;
}
+8 -5
View File
@@ -5,22 +5,25 @@
//lexers are bound to a string of code, and return a single token every time scan is called
typedef struct {
char* source;
const char* source;
int start; //start of the token
int current; //current position of the lexer
int line; //track this for error handling
bool commentsEnabled; //BUGFIX: enable comments (disabled in repl)
} Toy_Lexer;
//tokens are intermediaries between lexers and parsers
typedef struct {
Toy_TokenType type;
char* lexeme;
const 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);
TOY_API void Toy_initLexer(Toy_Lexer* lexer, const char* source);
TOY_API Toy_Token Toy_private_scanLexer(Toy_Lexer* lexer);
//for debugging
void Toy_printToken(Toy_Token* token);
TOY_API void Toy_private_printToken(Toy_Token* token);
TOY_API void Toy_private_setComments(Toy_Lexer* lexer, bool enabled);
+45 -26
View File
@@ -8,6 +8,7 @@
#include "toy_console_colors.h"
#include <stdio.h>
#include <string.h>
//hash util functions
static unsigned int hashString(const char* string, int length) {
@@ -42,7 +43,7 @@ void Toy_freeLiteral(Toy_Literal literal) {
}
//compounds
if (TOY_IS_ARRAY(literal) || literal.type == TOY_LITERAL_DICTIONARY_INTERMEDIATE || literal.type == TOY_LITERAL_TYPE_INTERMEDIATE) {
if (TOY_IS_ARRAY(literal) || literal.type == TOY_LITERAL_ARRAY_INTERMEDIATE || 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;
@@ -58,10 +59,10 @@ void Toy_freeLiteral(Toy_Literal literal) {
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);
Toy_deleteRefFunction((Toy_RefFunction*)(TOY_AS_FUNCTION(literal).inner.ptr));
}
if (TOY_IS_TYPE(literal)) {
if (TOY_IS_TYPE(literal) && TOY_AS_TYPE(literal).capacity > 0) {
for (int i = 0; i < TOY_AS_TYPE(literal).count; i++) {
Toy_freeLiteral(((Toy_Literal*)(TOY_AS_TYPE(literal).subtypes))[i]);
}
@@ -72,7 +73,7 @@ void Toy_freeLiteral(Toy_Literal literal) {
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);
fprintf(stderr, TOY_CC_ERROR "Null is neither true nor false\n" TOY_CC_RESET);
return false;
}
@@ -83,12 +84,8 @@ bool Toy_private_isTruthy(Toy_Literal 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)) }});
return ((Toy_Literal){{ .identifier = { .ptr = ptr, .hash = hashString(Toy_toCString(ptr), Toy_lengthRefString(ptr)) }},TOY_LITERAL_IDENTIFIER});
}
Toy_Literal* Toy_private_typePushSubtype(Toy_Literal* lit, Toy_Literal subtype) {
@@ -145,17 +142,16 @@ Toy_Literal Toy_copyLiteral(Toy_Literal original) {
}
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(Toy_copyRefFunction( TOY_AS_FUNCTION(original).inner.ptr ));
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)));
//NOTE: could optimise this by copying the hash manually, but it's a very small increase in performance
return TOY_TO_IDENTIFIER_LITERAL(Toy_copyRefString(TOY_AS_IDENTIFIER(original)));
}
case TOY_LITERAL_TYPE: {
@@ -172,6 +168,22 @@ Toy_Literal Toy_copyLiteral(Toy_Literal original) {
return original; //literally a shallow copy
}
case TOY_LITERAL_ARRAY_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_ARRAY_INTERMEDIATE;
return ret;
}
case TOY_LITERAL_DICTIONARY_INTERMEDIATE: {
Toy_LiteralArray* array = TOY_ALLOCATE(Toy_LiteralArray, 1);
Toy_initLiteralArray(array);
@@ -206,12 +218,13 @@ Toy_Literal Toy_copyLiteral(Toy_Literal original) {
case TOY_LITERAL_FUNCTION_INTERMEDIATE: //caries a compiler
case TOY_LITERAL_FUNCTION_NATIVE:
case TOY_LITERAL_FUNCTION_HOOK:
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);
fprintf(stderr, TOY_CC_ERROR "Can't copy that literal type: %d\n" TOY_CC_RESET, original.type);
return TOY_TO_NULL_LITERAL;
}
}
@@ -222,10 +235,10 @@ bool Toy_literalsAreEqual(Toy_Literal lhs, Toy_Literal rhs) {
// 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);
return TOY_AS_INTEGER(lhs) == TOY_AS_FLOAT(rhs);
}
else {
return TOY_AS_FLOAT(lhs) + TOY_AS_INTEGER(rhs);
return TOY_AS_FLOAT(lhs) == TOY_AS_INTEGER(rhs);
}
}
@@ -249,6 +262,7 @@ bool Toy_literalsAreEqual(Toy_Literal lhs, Toy_Literal rhs) {
return Toy_equalsRefString(TOY_AS_STRING(lhs), TOY_AS_STRING(rhs));
case TOY_LITERAL_ARRAY:
case TOY_LITERAL_ARRAY_INTERMEDIATE:
case TOY_LITERAL_DICTIONARY_INTERMEDIATE: //BUGFIX
case TOY_LITERAL_TYPE_INTERMEDIATE: //BUGFIX: used for storing types as an array
//mismatched sizes
@@ -287,6 +301,7 @@ bool Toy_literalsAreEqual(Toy_Literal lhs, Toy_Literal rhs) {
case TOY_LITERAL_FUNCTION:
case TOY_LITERAL_FUNCTION_NATIVE:
case TOY_LITERAL_FUNCTION_HOOK:
return false; //functions are never equal
break;
@@ -357,8 +372,10 @@ int Toy_hashLiteral(Toy_Literal lit) {
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_FLOAT: {
unsigned int* ptr = (unsigned int*)(&TOY_AS_FLOAT(lit));
return hashUInt(*ptr);
}
case TOY_LITERAL_STRING:
return hashString(Toy_toCString(TOY_AS_STRING(lit)), Toy_lengthRefString(TOY_AS_STRING(lit)));
@@ -384,20 +401,21 @@ int Toy_hashLiteral(Toy_Literal lit) {
case TOY_LITERAL_FUNCTION:
case TOY_LITERAL_FUNCTION_NATIVE:
return 0; //can't hash these
case TOY_LITERAL_FUNCTION_HOOK:
return -1; //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
return -1; //not much i can really do
case TOY_LITERAL_OPAQUE:
case TOY_LITERAL_ANY:
return -1;
default:
//should never bee seen
//should never be seen
fprintf(stderr, TOY_CC_ERROR "[internal] Unrecognized literal type in hash: %d\n" TOY_CC_RESET, lit.type);
return 0;
}
@@ -424,7 +442,7 @@ static void printToBuffer(const char* str) {
globalPrintBuffer = TOY_GROW_ARRAY(char, globalPrintBuffer, oldCapacity, globalPrintCapacity);
}
snprintf(globalPrintBuffer + globalPrintCount, strlen(str) + 1, "%s", str);
snprintf(globalPrintBuffer + globalPrintCount, strlen(str) + 1, "%s", str ? str : "\0");
globalPrintCount += strlen(str);
}
@@ -433,7 +451,7 @@ void Toy_printLiteral(Toy_Literal literal) {
Toy_printLiteralCustom(literal, stdoutWrapper);
}
void Toy_printLiteralCustom(Toy_Literal literal, void (printFn)(const char*)) {
void Toy_printLiteralCustom(Toy_Literal literal, Toy_PrintFn printFn) {
switch(literal.type) {
case TOY_LITERAL_NULL:
printFn("null");
@@ -467,10 +485,10 @@ void Toy_printLiteralCustom(Toy_Literal literal, void (printFn)(const char*)) {
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)));
snprintf(buffer, TOY_MAX_STRING_LENGTH, "%.*s", (int)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);
snprintf(buffer, TOY_MAX_STRING_LENGTH, "%c%.*s%c", quotes, (int)Toy_lengthRefString(TOY_AS_STRING(literal)), Toy_toCString(TOY_AS_STRING(literal)), quotes);
}
printFn(buffer);
}
@@ -570,12 +588,13 @@ void Toy_printLiteralCustom(Toy_Literal literal, void (printFn)(const char*)) {
case TOY_LITERAL_FUNCTION:
case TOY_LITERAL_FUNCTION_NATIVE:
case TOY_LITERAL_FUNCTION_HOOK:
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)));
snprintf(buffer, 256, "%.*s", (int)Toy_lengthRefString(TOY_AS_IDENTIFIER(literal)), Toy_toCString(TOY_AS_IDENTIFIER(literal)));
printFn(buffer);
}
break;
+68 -41
View File
@@ -3,8 +3,17 @@
#include "toy_common.h"
#include "toy_refstring.h"
#include "toy_reffunction.h"
#include <string.h>
//forward delcare stuff
struct Toy_Literal;
struct Toy_Interpreter;
struct Toy_LiteralArray;
struct Toy_LiteralDictionary;
struct Toy_Scope;
typedef int (*Toy_NativeFn)(struct Toy_Interpreter* interpreter, struct Toy_LiteralArray* arguments);
typedef int (*Toy_HookFn)(struct Toy_Interpreter* interpreter, struct Toy_Literal identifier, struct Toy_Literal alias);
typedef void (*Toy_PrintFn)(const char*);
typedef enum {
TOY_LITERAL_NULL,
@@ -22,51 +31,62 @@ typedef enum {
//these are meta-level types - not for general use
TOY_LITERAL_TYPE_INTERMEDIATE, //used to process types in the compiler only
TOY_LITERAL_ARRAY_INTERMEDIATE, //used to process arrays 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_FUNCTION_HOOK, //for handling hook functions within literals only
TOY_LITERAL_INDEX_BLANK, //for blank indexing i.e. arr[:]
} Toy_LiteralType;
typedef struct {
Toy_LiteralType type;
typedef struct Toy_Literal {
union {
bool boolean;
int integer;
float number;
bool boolean; //1
int integer; //4
float number;//4
struct {
Toy_RefString* ptr;
Toy_RefString* ptr; //8
//string hash?
} string;
} string; //8
void* array;
void* dictionary;
struct Toy_LiteralArray* array; //8
struct Toy_LiteralDictionary* dictionary; //8
struct {
void* bytecode;
void* scope;
int length;
} function;
union {
Toy_RefFunction* ptr; //8
Toy_NativeFn native; //8
Toy_HookFn hook; //8
} inner; //8
struct Toy_Scope* scope; //8
} function; //16
struct { //for variable names
Toy_RefString* ptr;
int hash;
} identifier;
Toy_RefString* ptr; //8
int hash; //4
} identifier; //16
struct {
Toy_LiteralType typeOf; //no longer a mask
bool constant;
void* subtypes; //for nested types caused by compounds
int capacity;
int count;
} type;
struct Toy_Literal* subtypes; //8
Toy_LiteralType typeOf; //4
unsigned char capacity; //1
unsigned char count; //1
bool constant; //1
} type; //16
struct {
void* ptr;
int tag; //TODO: remove tags?
} opaque;
} as;
void* ptr; //8
int tag; //4
} opaque; //16
void* generic; //8
} as; //16
Toy_LiteralType type; //4
//4 - unused
//shenanigans with byte alignment reduces the size of Toy_Literal
} Toy_Literal;
#define TOY_IS_NULL(value) ((value).type == TOY_LITERAL_NULL)
@@ -78,6 +98,7 @@ typedef struct {
#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_FUNCTION_HOOK(value) ((value).type == TOY_LITERAL_FUNCTION_HOOK)
#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)
@@ -89,38 +110,43 @@ typedef struct {
#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_FUNCTION_NATIVE(value) ((value).as.function.inner.native)
#define TOY_AS_FUNCTION_HOOK(value) ((value).as.function.inner.hook)
#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_NULL_LITERAL ((Toy_Literal){{ .integer = 0 }, TOY_LITERAL_NULL})
#define TOY_TO_BOOLEAN_LITERAL(value) ((Toy_Literal){{ .boolean = value }, TOY_LITERAL_BOOLEAN})
#define TOY_TO_INTEGER_LITERAL(value) ((Toy_Literal){{ .integer = value }, TOY_LITERAL_INTEGER})
#define TOY_TO_FLOAT_LITERAL(value) ((Toy_Literal){{ .number = value }, TOY_LITERAL_FLOAT})
#define TOY_TO_STRING_LITERAL(value) ((Toy_Literal){{ .string = { .ptr = value }},TOY_LITERAL_STRING})
#define TOY_TO_ARRAY_LITERAL(value) ((Toy_Literal){{ .array = value }, TOY_LITERAL_ARRAY})
#define TOY_TO_DICTIONARY_LITERAL(value) ((Toy_Literal){{ .dictionary = value }, TOY_LITERAL_DICTIONARY})
#define TOY_TO_FUNCTION_LITERAL(value) ((Toy_Literal){{ .function = { .inner = { .ptr = value }, .scope = NULL }}, TOY_LITERAL_FUNCTION})
#define TOY_TO_FUNCTION_NATIVE_LITERAL(value) ((Toy_Literal){{ .function = { .inner = { .native = value }, .scope = NULL }}, TOY_LITERAL_FUNCTION_NATIVE})
#define TOY_TO_FUNCTION_HOOK_LITERAL(value) ((Toy_Literal){{ .function = { .inner = { .hook = value }, .scope = NULL }}, TOY_LITERAL_FUNCTION_HOOK})
#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 }})
#define TOY_TO_TYPE_LITERAL(value, c) ((Toy_Literal){{ .type = { .typeOf = value, .constant = c, .subtypes = NULL, .capacity = 0, .count = 0 }}, TOY_LITERAL_TYPE})
#define TOY_TO_OPAQUE_LITERAL(value, t) ((Toy_Literal){{ .opaque = { .ptr = value, .tag = t }}, TOY_LITERAL_OPAQUE})
//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 }})
#define TOY_TO_INDEX_BLANK_LITERAL ((Toy_Literal){{ .integer = 0 }, TOY_LITERAL_INDEX_BLANK})
TOY_API void Toy_freeLiteral(Toy_Literal literal);
#define TOY_IS_TRUTHY(x) Toy_private_isTruthy(x)
#define TOY_AS_FUNCTION_BYTECODE_LENGTH(lit) (Toy_lengthRefFunction((lit).inner.ptr))
#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
#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);
@@ -129,5 +155,6 @@ 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);
//not thread-safe
TOY_API void Toy_printLiteral(Toy_Literal literal);
TOY_API void Toy_printLiteralCustom(Toy_Literal literal, void (printFn)(const char*));
TOY_API void Toy_printLiteralCustom(Toy_Literal literal, Toy_PrintFn);
+4 -2
View File
@@ -18,8 +18,10 @@ void Toy_freeLiteralArray(Toy_LiteralArray* array) {
Toy_freeLiteral(array->literals[i]);
}
TOY_FREE_ARRAY(Toy_Literal, array->literals, array->capacity);
Toy_initLiteralArray(array);
if (array->capacity > 0) {
TOY_FREE_ARRAY(Toy_Literal, array->literals, array->capacity);
Toy_initLiteralArray(array);
}
}
int Toy_pushLiteralArray(Toy_LiteralArray* array, Toy_Literal literal) {
+2
View File
@@ -18,3 +18,5 @@ TOY_API bool Toy_setLiteralArray(Toy_LiteralArray* array, Toy_Literal index, Toy
TOY_API Toy_Literal Toy_getLiteralArray(Toy_LiteralArray* array, Toy_Literal index);
int Toy_findLiteralIndex(Toy_LiteralArray* array, Toy_Literal literal);
//TODO: add a function to get the capacity & count
+41 -28
View File
@@ -7,7 +7,7 @@
#include <stdio.h>
//util functions
static void setEntryValues(Toy_private_entry* entry, Toy_Literal key, Toy_Literal value) {
static void setEntryValues(Toy_private_dictionary_entry* entry, Toy_Literal key, Toy_Literal value) {
//much simpler now
Toy_freeLiteral(entry->key);
entry->key = Toy_copyLiteral(key);
@@ -16,17 +16,23 @@ static void setEntryValues(Toy_private_entry* entry, Toy_Literal key, Toy_Litera
entry->value = Toy_copyLiteral(value);
}
static Toy_private_entry* getEntryArray(Toy_private_entry* array, int capacity, Toy_Literal key, unsigned int hash, bool mustExist) {
static Toy_private_dictionary_entry* getEntryArray(Toy_private_dictionary_entry* array, int capacity, Toy_Literal key, unsigned int hash, bool mustExist) {
if (!capacity) {
return NULL;
}
//find "key", starting at index
unsigned int index = hash % capacity;
unsigned int start = index;
int index = hash % capacity;
int start = index;
//increment once, so it can't equal start
index = (index + 1) % capacity;
if (++index >= capacity) {
index = 0;
}
//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];
Toy_private_dictionary_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) {
@@ -40,15 +46,18 @@ static Toy_private_entry* getEntryArray(Toy_private_entry* array, int capacity,
}
}
index = (index + 1) % capacity;
if (++index >= capacity) {
index = 0;
}
//index = (index + 1) % capacity;
}
return NULL;
}
static void adjustEntryCapacity(Toy_private_entry** dictionaryHandle, int oldCapacity, int capacity) {
static void adjustEntryCapacity(Toy_private_dictionary_entry** dictionaryHandle, int oldCapacity, int capacity) {
//new entry space
Toy_private_entry* newEntries = TOY_ALLOCATE(Toy_private_entry, capacity);
Toy_private_dictionary_entry* newEntries = TOY_ALLOCATE(Toy_private_dictionary_entry, capacity);
for (int i = 0; i < capacity; i++) {
newEntries[i].key = TOY_TO_NULL_LITERAL;
@@ -62,19 +71,21 @@ static void adjustEntryCapacity(Toy_private_entry** dictionaryHandle, int oldCap
}
//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);
Toy_private_dictionary_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);
if (oldCapacity > 0) {
TOY_FREE_ARRAY(Toy_private_dictionary_entry, *dictionaryHandle, oldCapacity);
}
*dictionaryHandle = newEntries;
}
static bool setEntryArray(Toy_private_entry** dictionaryHandle, int* capacityPtr, int contains, Toy_Literal key, Toy_Literal value, int hash) {
static bool setEntryArray(Toy_private_dictionary_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;
@@ -82,7 +93,7 @@ static bool setEntryArray(Toy_private_entry** dictionaryHandle, int* capacityPtr
adjustEntryCapacity(dictionaryHandle, oldCapacity, *capacityPtr); //custom rather than automatic reallocation
}
Toy_private_entry* entry = getEntryArray(*dictionaryHandle, *capacityPtr, key, hash, false);
Toy_private_dictionary_entry* entry = getEntryArray(*dictionaryHandle, *capacityPtr, key, hash, false);
//true = contains increase
if (TOY_IS_NULL(entry->key)) {
@@ -97,14 +108,14 @@ static bool setEntryArray(Toy_private_entry** dictionaryHandle, int* capacityPtr
return false;
}
static void freeEntry(Toy_private_entry* entry) {
static void freeEntry(Toy_private_dictionary_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) {
static void freeEntryArray(Toy_private_dictionary_entry* array, int capacity) {
if (array == NULL) {
return;
}
@@ -115,23 +126,25 @@ static void freeEntryArray(Toy_private_entry* array, int capacity) {
}
}
TOY_FREE_ARRAY(Toy_private_entry, array, capacity);
TOY_FREE_ARRAY(Toy_private_dictionary_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->capacity = 0;
dictionary->contains = 0;
dictionary->count = 0;
adjustEntryCapacity(&dictionary->entries, 0, dictionary->capacity);
dictionary->capacity = 0;
}
void Toy_freeLiteralDictionary(Toy_LiteralDictionary* dictionary) {
freeEntryArray(dictionary->entries, dictionary->capacity);
dictionary->capacity = 0;
dictionary->contains = 0;
if (dictionary->capacity > 0) {
freeEntryArray(dictionary->entries, dictionary->capacity);
dictionary->capacity = 0;
dictionary->contains = 0;
}
}
void Toy_setLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key, Toy_Literal value) {
@@ -141,7 +154,7 @@ void Toy_setLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key
}
//BUGFIX: Can't hash a function
if (TOY_IS_FUNCTION(key) || TOY_IS_FUNCTION_NATIVE(key)) {
if (TOY_IS_FUNCTION(key) || TOY_IS_FUNCTION_NATIVE(key) || TOY_IS_FUNCTION_HOOK(key)) {
fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have function keys (set)\n" TOY_CC_RESET);
return;
}
@@ -166,7 +179,7 @@ Toy_Literal Toy_getLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Lite
}
//BUGFIX: Can't hash a function
if (TOY_IS_FUNCTION(key) || TOY_IS_FUNCTION_NATIVE(key)) {
if (TOY_IS_FUNCTION(key) || TOY_IS_FUNCTION_NATIVE(key) || TOY_IS_FUNCTION_HOOK(key)) {
fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have function keys (get)\n" TOY_CC_RESET);
return TOY_TO_NULL_LITERAL;
}
@@ -176,7 +189,7 @@ Toy_Literal Toy_getLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Lite
return TOY_TO_NULL_LITERAL;
}
Toy_private_entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, Toy_hashLiteral(key), true);
Toy_private_dictionary_entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, Toy_hashLiteral(key), true);
if (entry != NULL) {
return Toy_copyLiteral(entry->value);
@@ -193,7 +206,7 @@ void Toy_removeLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal
}
//BUGFIX: Can't hash a function
if (TOY_IS_FUNCTION(key) || TOY_IS_FUNCTION_NATIVE(key)) {
if (TOY_IS_FUNCTION(key) || TOY_IS_FUNCTION_NATIVE(key) || TOY_IS_FUNCTION_HOOK(key)) {
fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have function keys (remove)\n" TOY_CC_RESET);
return;
}
@@ -203,7 +216,7 @@ void Toy_removeLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal
return;
}
Toy_private_entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, Toy_hashLiteral(key), true);
Toy_private_dictionary_entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, Toy_hashLiteral(key), true);
if (entry != NULL) {
freeEntry(entry);
@@ -214,6 +227,6 @@ void Toy_removeLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal
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));
Toy_private_dictionary_entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, Toy_hashLiteral(key), false);
return entry != NULL && !(TOY_IS_NULL(entry->key) && TOY_IS_NULL(entry->value));
}
+3 -3
View File
@@ -7,13 +7,13 @@
//TODO: benchmark this
#define TOY_DICTIONARY_MAX_LOAD 0.75
typedef struct Toy_private_entry {
typedef struct Toy_private_dictionary_entry {
Toy_Literal key;
Toy_Literal value;
} Toy_private_entry;
} Toy_private_dictionary_entry;
typedef struct Toy_LiteralDictionary {
Toy_private_entry* entries;
Toy_private_dictionary_entry* entries;
int capacity;
int count;
int contains; //count + tombstones, for internal use
+10 -14
View File
@@ -1,5 +1,6 @@
#include "toy_memory.h"
#include "toy_refstring.h"
#include "toy_reffunction.h"
#include "toy_console_colors.h"
@@ -7,35 +8,29 @@
#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;
}
void* Toy_private_defaultMemoryAllocator(void* pointer, size_t oldSize, size_t newSize) {
//causes issues, so just skip out with a NO-OP (DISABLED for performance reasons)
// if (newSize == 0 && oldSize == 0) {
// 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);
fprintf(stderr, TOY_CC_ERROR "[internal] Memory allocation error (requested %zu, replacing %zu)\n" TOY_CC_RESET, newSize, oldSize);
return NULL;
}
return mem;
}
//static variables
static Toy_MemoryAllocatorFn allocator;
//preload
static void __attribute__((constructor)) preloadMemoryAllocator() {
Toy_setMemoryAllocator(defaultMemoryAllocator);
}
static Toy_MemoryAllocatorFn allocator = Toy_private_defaultMemoryAllocator;
//exposed API
void* Toy_reallocate(void* pointer, size_t oldSize, size_t newSize) {
@@ -55,4 +50,5 @@ void Toy_setMemoryAllocator(Toy_MemoryAllocatorFn fn) {
allocator = fn;
Toy_setRefStringAllocatorFn(fn);
Toy_setRefFunctionAllocatorFn(fn);
}
+11 -8
View File
@@ -2,16 +2,19 @@
#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)
#define TOY_GROW_CAPACITY(capacity) ((capacity) < 8 ? 8 : (capacity) * 2)
#define TOY_GROW_CAPACITY_FAST(capacity) ((capacity) < 32 ? 32 : (capacity) * 2)
#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_FREE_ARRAY(type, pointer, oldCount) Toy_reallocate((type*)pointer, sizeof(type) * (oldCount), 0)
#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))
//implementation details
void* Toy_reallocate(void* pointer, size_t oldSize, size_t newSize);
TOY_API 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);
+3
View File
@@ -3,6 +3,9 @@
typedef enum Toy_Opcode {
TOY_OP_EOF,
//do nothing
TOY_OP_PASS,
//basic statements
TOY_OP_ASSERT,
TOY_OP_PRINT,
+194 -43
View File
@@ -32,7 +32,7 @@ static void error(Toy_Parser* parser, Toy_Token token, const char* message) {
static void advance(Toy_Parser* parser) {
parser->previous = parser->current;
parser->current = Toy_scanLexer(parser->lexer);
parser->current = Toy_private_scanLexer(parser->lexer);
if (parser->current.type == TOY_TOKEN_ERROR) {
error(parser, parser->current, "Toy_Lexer error");
@@ -58,8 +58,8 @@ static void consume(Toy_Parser* parser, Toy_TokenType tokenType, const char* msg
static void synchronize(Toy_Parser* parser) {
#ifndef TOY_EXPORT
if (command.verbose) {
fprintf(stderr, TOY_CC_ERROR "synchronizing\n" TOY_CC_RESET);
if (Toy_commandLine.verbose) {
fprintf(stderr, TOY_CC_ERROR "Synchronizing input\n" TOY_CC_RESET);
}
#endif
@@ -112,6 +112,7 @@ typedef struct {
PrecedenceRule precedence;
} ParseRule;
//no static!
ParseRule parseRules[];
//forward declarations
@@ -139,7 +140,7 @@ static Toy_Opcode asType(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
static Toy_Opcode typeOf(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
Toy_ASTNode* rhs = NULL;
parsePrecedence(parser, &rhs, PREC_TERNARY);
parsePrecedence(parser, &rhs, PREC_CALL);
Toy_emitASTNodeUnary(nodeHandle, TOY_OP_TYPE_OF, rhs);
return TOY_OP_EOF;
}
@@ -260,17 +261,48 @@ static Toy_Opcode string(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
//handle strings
switch(parser->previous.type) {
case TOY_TOKEN_LITERAL_STRING: {
int length = parser->previous.length;
//unescape valid escaped characters
int strLength = 0;
char* buffer = TOY_ALLOCATE(char, parser->previous.length);
//for safety
if (length > TOY_MAX_STRING_LENGTH) {
length = TOY_MAX_STRING_LENGTH;
char buffer[256];
snprintf(buffer, 256, TOY_CC_ERROR "Strings can only be a maximum of %d characters long" TOY_CC_RESET, TOY_MAX_STRING_LENGTH);
error(parser, parser->previous, buffer);
for (int i = 0; i < parser->previous.length; i++) {
if (parser->previous.lexeme[i] != '\\') { //copy normally
buffer[strLength++] = parser->previous.lexeme[i];
continue;
}
//unescape based on the character
switch(parser->previous.lexeme[++i]) {
case 'n':
buffer[strLength++] = '\n';
break;
case 't':
buffer[strLength++] = '\t';
break;
case '\\':
buffer[strLength++] = '\\';
break;
case '"':
buffer[strLength++] = '"';
break;
default: {
char msg[256];
snprintf(msg, 256, TOY_CC_ERROR "Unrecognized escape character %c in string" TOY_CC_RESET, parser->previous.lexeme[++i]);
error(parser, parser->previous, msg);
}
}
}
Toy_Literal literal = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(parser->previous.lexeme, length));
//for length safety
if (strLength > TOY_MAX_STRING_LENGTH) {
strLength = TOY_MAX_STRING_LENGTH;
char msg[256];
snprintf(msg, 256, TOY_CC_ERROR "Strings can only be a maximum of %d characters long" TOY_CC_RESET, TOY_MAX_STRING_LENGTH);
error(parser, parser->previous, msg);
}
Toy_Literal literal = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(buffer, strLength));
TOY_FREE_ARRAY(char, buffer, parser->previous.length);
Toy_emitASTNodeLiteral(nodeHandle, literal);
Toy_freeLiteral(literal);
return TOY_OP_EOF;
@@ -309,99 +341,99 @@ static Toy_Opcode binary(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
switch(parser->previous.type) {
//arithmetic
case TOY_TOKEN_PLUS: {
parsePrecedence(parser, nodeHandle, PREC_TERM);
parsePrecedence(parser, nodeHandle, PREC_TERM + 1);
return TOY_OP_ADDITION;
}
case TOY_TOKEN_MINUS: {
parsePrecedence(parser, nodeHandle, PREC_TERM);
parsePrecedence(parser, nodeHandle, PREC_TERM + 1);
return TOY_OP_SUBTRACTION;
}
case TOY_TOKEN_MULTIPLY: {
parsePrecedence(parser, nodeHandle, PREC_FACTOR);
parsePrecedence(parser, nodeHandle, PREC_FACTOR + 1);
return TOY_OP_MULTIPLICATION;
}
case TOY_TOKEN_DIVIDE: {
parsePrecedence(parser, nodeHandle, PREC_FACTOR);
parsePrecedence(parser, nodeHandle, PREC_FACTOR + 1);
return TOY_OP_DIVISION;
}
case TOY_TOKEN_MODULO: {
parsePrecedence(parser, nodeHandle, PREC_FACTOR);
parsePrecedence(parser, nodeHandle, PREC_FACTOR + 1);
return TOY_OP_MODULO;
}
//assignment
case TOY_TOKEN_ASSIGN: {
parsePrecedence(parser, nodeHandle, PREC_ASSIGNMENT);
parsePrecedence(parser, nodeHandle, PREC_ASSIGNMENT + 1);
return TOY_OP_VAR_ASSIGN;
}
case TOY_TOKEN_PLUS_ASSIGN: {
parsePrecedence(parser, nodeHandle, PREC_ASSIGNMENT);
parsePrecedence(parser, nodeHandle, PREC_ASSIGNMENT + 1);
return TOY_OP_VAR_ADDITION_ASSIGN;
}
case TOY_TOKEN_MINUS_ASSIGN: {
parsePrecedence(parser, nodeHandle, PREC_ASSIGNMENT);
parsePrecedence(parser, nodeHandle, PREC_ASSIGNMENT + 1);
return TOY_OP_VAR_SUBTRACTION_ASSIGN;
}
case TOY_TOKEN_MULTIPLY_ASSIGN: {
parsePrecedence(parser, nodeHandle, PREC_ASSIGNMENT);
parsePrecedence(parser, nodeHandle, PREC_ASSIGNMENT + 1);
return TOY_OP_VAR_MULTIPLICATION_ASSIGN;
}
case TOY_TOKEN_DIVIDE_ASSIGN: {
parsePrecedence(parser, nodeHandle, PREC_ASSIGNMENT);
parsePrecedence(parser, nodeHandle, PREC_ASSIGNMENT + 1);
return TOY_OP_VAR_DIVISION_ASSIGN;
}
case TOY_TOKEN_MODULO_ASSIGN: {
parsePrecedence(parser, nodeHandle, PREC_ASSIGNMENT);
parsePrecedence(parser, nodeHandle, PREC_ASSIGNMENT + 1);
return TOY_OP_VAR_MODULO_ASSIGN;
}
//comparison
case TOY_TOKEN_EQUAL: {
parsePrecedence(parser, nodeHandle, PREC_COMPARISON);
parsePrecedence(parser, nodeHandle, PREC_COMPARISON + 1);
return TOY_OP_COMPARE_EQUAL;
}
case TOY_TOKEN_NOT_EQUAL: {
parsePrecedence(parser, nodeHandle, PREC_COMPARISON);
parsePrecedence(parser, nodeHandle, PREC_COMPARISON + 1);
return TOY_OP_COMPARE_NOT_EQUAL;
}
case TOY_TOKEN_LESS: {
parsePrecedence(parser, nodeHandle, PREC_COMPARISON);
parsePrecedence(parser, nodeHandle, PREC_COMPARISON + 1);
return TOY_OP_COMPARE_LESS;
}
case TOY_TOKEN_LESS_EQUAL: {
parsePrecedence(parser, nodeHandle, PREC_COMPARISON);
parsePrecedence(parser, nodeHandle, PREC_COMPARISON + 1);
return TOY_OP_COMPARE_LESS_EQUAL;
}
case TOY_TOKEN_GREATER: {
parsePrecedence(parser, nodeHandle, PREC_COMPARISON);
parsePrecedence(parser, nodeHandle, PREC_COMPARISON + 1);
return TOY_OP_COMPARE_GREATER;
}
case TOY_TOKEN_GREATER_EQUAL: {
parsePrecedence(parser, nodeHandle, PREC_COMPARISON);
parsePrecedence(parser, nodeHandle, PREC_COMPARISON + 1);
return TOY_OP_COMPARE_GREATER_EQUAL;
}
case TOY_TOKEN_AND: {
parsePrecedence(parser, nodeHandle, PREC_COMPARISON);
parsePrecedence(parser, nodeHandle, PREC_AND + 1);
return TOY_OP_AND;
}
case TOY_TOKEN_OR: {
parsePrecedence(parser, nodeHandle, PREC_COMPARISON);
parsePrecedence(parser, nodeHandle, PREC_OR + 1);
return TOY_OP_OR;
}
@@ -416,7 +448,7 @@ static Toy_Opcode unary(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
if (parser->previous.type == TOY_TOKEN_MINUS) {
//temp handle to potentially negate values
parsePrecedence(parser, &tmpNode, PREC_TERNARY); //can be a literal
parsePrecedence(parser, &tmpNode, PREC_TERM); //can be a literal
//optimisation: check for negative literals
if (tmpNode != NULL && tmpNode->type == TOY_AST_NODE_LITERAL && (TOY_IS_INTEGER(tmpNode->atomic.literal) || TOY_IS_FLOAT(tmpNode->atomic.literal))) {
@@ -476,6 +508,22 @@ static Toy_Opcode unary(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
return TOY_OP_EOF;
}
static char* removeChar(const char* lexeme, int length, char c) {
int resPos = 0;
char* result = TOY_ALLOCATE(char, length + 1);
for (int i = 0; i < length; i++) {
if (lexeme[i] == c) {
continue;
}
result[resPos++] = lexeme[i];
}
result[resPos] = '\0';
return result;
}
static Toy_Opcode atomic(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
switch(parser->previous.type) {
case TOY_TOKEN_NULL:
@@ -492,14 +540,18 @@ static Toy_Opcode atomic(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
case TOY_TOKEN_LITERAL_INTEGER: {
int value = 0;
sscanf(parser->previous.lexeme, "%d", &value);
const char* lexeme = removeChar(parser->previous.lexeme, parser->previous.length, '_');
sscanf(lexeme, "%d", &value);
TOY_FREE_ARRAY(char, lexeme, parser->previous.length + 1);
Toy_emitASTNodeLiteral(nodeHandle, TOY_TO_INTEGER_LITERAL(value));
return TOY_OP_EOF;
}
case TOY_TOKEN_LITERAL_FLOAT: {
float value = 0;
sscanf(parser->previous.lexeme, "%f", &value);
const char* lexeme = removeChar(parser->previous.lexeme, parser->previous.length, '_');
sscanf(lexeme, "%f", &value);
TOY_FREE_ARRAY(char, lexeme, parser->previous.length + 1);
Toy_emitASTNodeLiteral(nodeHandle, TOY_TO_FLOAT_LITERAL(value));
return TOY_OP_EOF;
}
@@ -606,7 +658,7 @@ static Toy_Opcode castingInfix(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
break;
case TOY_TOKEN_LITERAL_STRING:
atomic(parser, nodeHandle);
string(parser, nodeHandle);
break;
default:
@@ -624,6 +676,10 @@ static Toy_Opcode incrementPrefix(Toy_Parser* parser, Toy_ASTNode** nodeHandle)
Toy_ASTNode* tmpNode = NULL;
identifier(parser, &tmpNode);
if (!tmpNode) {
return TOY_OP_EOF;
}
Toy_emitASTNodePrefixIncrement(nodeHandle, tmpNode->atomic.literal);
Toy_freeASTNode(tmpNode);
@@ -637,6 +693,10 @@ static Toy_Opcode incrementInfix(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
advance(parser);
if (!tmpNode) {
return TOY_OP_EOF;
}
Toy_emitASTNodePostfixIncrement(nodeHandle, tmpNode->atomic.literal);
Toy_freeASTNode(tmpNode);
@@ -648,7 +708,11 @@ static Toy_Opcode decrementPrefix(Toy_Parser* parser, Toy_ASTNode** nodeHandle)
advance(parser);
Toy_ASTNode* tmpNode = NULL;
identifier(parser, &tmpNode); //weird
identifier(parser, &tmpNode);
if (!tmpNode) {
return TOY_OP_EOF;
}
Toy_emitASTNodePrefixDecrement(nodeHandle, tmpNode->atomic.literal);
@@ -663,6 +727,10 @@ static Toy_Opcode decrementInfix(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
advance(parser);
if (!tmpNode) {
return TOY_OP_EOF;
}
Toy_emitASTNodePostfixDecrement(nodeHandle, tmpNode->atomic.literal);
Toy_freeASTNode(tmpNode);
@@ -671,6 +739,27 @@ static Toy_Opcode decrementInfix(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
}
static Toy_Opcode fnCall(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
//wait - is the previous token a type? this should be casting instead
if (parser->previous.type >= TOY_TOKEN_NULL && parser->previous.type <= TOY_TOKEN_ANY) {
//casting type
Toy_ASTNode* lhsNode = NULL;
castingPrefix(parser, &lhsNode);
advance(parser);
//casting value
Toy_ASTNode* rhsNode = NULL;
grouping(parser, &rhsNode);
//emit the cast node
Toy_emitASTNodeBinary(&lhsNode, rhsNode, TOY_OP_TYPE_CAST);
//pass it off to the caller
*nodeHandle = lhsNode;
return TOY_OP_GROUPING_BEGIN; //dummy value
}
advance(parser); //skip the left paren
//binary() is an infix rule - so only get the RHS of the operator
@@ -742,13 +831,20 @@ static Toy_Opcode indexAccess(Toy_Parser* parser, Toy_ASTNode** nodeHandle) { //
//eat the first
if (!match(parser, TOY_TOKEN_COLON)) {
Toy_freeASTNode(first);
first = NULL;
parsePrecedence(parser, &first, PREC_TERNARY);
match(parser, TOY_TOKEN_COLON);
readFirst = true;
}
if (match(parser, TOY_TOKEN_BRACKET_RIGHT)) {
if (!first) {
Toy_freeASTNode(first);
Toy_freeASTNode(second);
Toy_freeASTNode(third);
return TOY_OP_EOF;
}
if (match(parser, TOY_TOKEN_BRACKET_RIGHT)) {
if (readFirst) {
Toy_freeASTNode(second);
second = NULL;
@@ -764,10 +860,18 @@ static Toy_Opcode indexAccess(Toy_Parser* parser, Toy_ASTNode** nodeHandle) { //
//eat the second
if (!match(parser, TOY_TOKEN_COLON)) {
Toy_freeASTNode(second);
second = NULL;
parsePrecedence(parser, &second, PREC_TERNARY);
match(parser, TOY_TOKEN_COLON);
}
if (!second) {
Toy_freeASTNode(first);
Toy_freeASTNode(second);
Toy_freeASTNode(third);
return TOY_OP_EOF;
}
if (match(parser, TOY_TOKEN_BRACKET_RIGHT)) {
Toy_freeASTNode(third);
third = NULL;
@@ -777,7 +881,16 @@ static Toy_Opcode indexAccess(Toy_Parser* parser, Toy_ASTNode** nodeHandle) { //
//eat the third
Toy_freeASTNode(third);
third = NULL;
parsePrecedence(parser, &third, PREC_TERNARY);
if (!third) {
Toy_freeASTNode(first);
Toy_freeASTNode(second);
Toy_freeASTNode(third);
return TOY_OP_EOF;
}
Toy_emitASTNodeIndex(nodeHandle, first, second, third);
consume(parser, TOY_TOKEN_BRACKET_RIGHT, "Expected ']' in index notation");
@@ -950,6 +1063,21 @@ static bool calcStaticBinaryArithmetic(Toy_Parser* parser, Toy_ASTNode** nodeHan
Toy_Literal rhs = (*nodeHandle)->binary.right->atomic.literal;
Toy_Literal result = TOY_TO_NULL_LITERAL;
//special case for string concatenation ONLY
if (TOY_IS_STRING(lhs) && TOY_IS_STRING(rhs) && (*nodeHandle)->binary.opcode == TOY_OP_ADDITION) {
//check for overflow
int totalLength = TOY_AS_STRING(lhs)->length + TOY_AS_STRING(rhs)->length;
if (totalLength > TOY_MAX_STRING_LENGTH) {
error(parser, parser->previous, "Can't concatenate these strings, result is too long (error found in constant folding)\n");
return false;
}
//concat the strings
char buffer[TOY_MAX_STRING_LENGTH];
snprintf(buffer, TOY_MAX_STRING_LENGTH, "%s%s", Toy_toCString(TOY_AS_STRING(lhs)), Toy_toCString(TOY_AS_STRING(rhs)));
result = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(buffer, totalLength));
}
//type coersion
if (TOY_IS_FLOAT(lhs) && TOY_IS_INTEGER(rhs)) {
rhs = TOY_TO_FLOAT_LITERAL(TOY_AS_INTEGER(rhs));
@@ -1153,7 +1281,7 @@ static void parsePrecedence(Toy_Parser* parser, Toy_ASTNode** nodeHandle, Preced
Toy_emitASTNodeBinary(nodeHandle, rhsNode, opcode);
//optimise away the constants
if (!calcStaticBinaryArithmetic(parser, nodeHandle)) {
if (!parser->panic && !calcStaticBinaryArithmetic(parser, nodeHandle)) {
return;
}
}
@@ -1267,13 +1395,36 @@ static void forStmt(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
//read the clauses
consume(parser, TOY_TOKEN_PAREN_LEFT, "Expected '(' at beginning of for clause");
declaration(parser, &preClause); //allow defining variables in the pre-clause
//check the pre-clause
if (parser->current.type != TOY_TOKEN_SEMICOLON) {
declaration(parser, &preClause); //allow defining variables in the pre-clause
}
else {
consume(parser, TOY_TOKEN_SEMICOLON, "Expected ';' after empty declaration of for clause");
Toy_emitASTNodePass(&preClause);
}
parsePrecedence(parser, &condition, PREC_TERNARY);
consume(parser, TOY_TOKEN_SEMICOLON, "Expected ';' after condition of for clause");
//check the condition clause
if (parser->current.type != TOY_TOKEN_SEMICOLON) {
parsePrecedence(parser, &condition, PREC_TERNARY);
consume(parser, TOY_TOKEN_SEMICOLON, "Expected ';' after condition of for clause");
}
else {
consume(parser, TOY_TOKEN_SEMICOLON, "Expected ';' after empty condition of for clause");
//empty clause defaults to forever
Toy_Literal f = TOY_TO_BOOLEAN_LITERAL(true);
Toy_emitASTNodeLiteral(&condition, f);
}
parsePrecedence(parser, &postClause, PREC_ASSIGNMENT);
consume(parser, TOY_TOKEN_PAREN_RIGHT, "Expected ')' at end of for clause");
//check the postfix clause
if (parser->current.type != TOY_TOKEN_PAREN_RIGHT) {
parsePrecedence(parser, &postClause, PREC_ASSIGNMENT);
consume(parser, TOY_TOKEN_PAREN_RIGHT, "Expected ')' at end of for clause");
}
else {
consume(parser, TOY_TOKEN_PAREN_RIGHT, "Expected ')' after empty increment of for clause");
Toy_emitASTNodePass(&postClause);
}
//read the path
declaration(parser, &thenPath);
+55
View File
@@ -0,0 +1,55 @@
#include "toy_reffunction.h"
#include <string.h>
//memory allocation
extern void* Toy_private_defaultMemoryAllocator(void* pointer, size_t oldSize, size_t newSize);
static Toy_RefFunctionAllocatorFn allocate = Toy_private_defaultMemoryAllocator;
void Toy_setRefFunctionAllocatorFn(Toy_RefFunctionAllocatorFn allocator) {
allocate = allocator;
}
//API
Toy_RefFunction* Toy_createRefFunction(const void* data, size_t length) {
//allocate the memory area (including metadata space)
Toy_RefFunction* refFunction = allocate(NULL, 0, sizeof(size_t) + sizeof(int) + sizeof(char) * length);
if (refFunction == NULL) {
return NULL;
}
//set the data
refFunction->refCount = 1;
refFunction->length = length;
memcpy(refFunction->data, data, refFunction->length);
return refFunction;
}
void Toy_deleteRefFunction(Toy_RefFunction* refFunction) {
//decrement, then check
refFunction->refCount--;
if (refFunction->refCount <= 0) {
allocate(refFunction, sizeof(size_t) + sizeof(int) + sizeof(char) * (refFunction->length + 1), 0);
}
}
int Toy_countRefFunction(Toy_RefFunction* refFunction) {
return refFunction->refCount;
}
size_t Toy_lengthRefFunction(Toy_RefFunction* refFunction) {
return refFunction->length;
}
Toy_RefFunction* Toy_copyRefFunction(Toy_RefFunction* refFunction) {
//Cheaty McCheater Face
refFunction->refCount++;
return refFunction;
}
Toy_RefFunction* Toy_deepCopyRefFunction(Toy_RefFunction* refFunction) {
//create a new function, with a new refCount
return Toy_createRefFunction(refFunction->data, refFunction->length);
}
+23
View File
@@ -0,0 +1,23 @@
#pragma once
#include "toy_common.h"
//memory allocation hook
typedef void* (*Toy_RefFunctionAllocatorFn)(void* pointer, size_t oldSize, size_t newSize);
TOY_API void Toy_setRefFunctionAllocatorFn(Toy_RefFunctionAllocatorFn);
//the RefFunction structure
typedef struct Toy_RefFunction {
size_t length;
int refCount;
unsigned char data[];
} Toy_RefFunction;
//API
TOY_API Toy_RefFunction* Toy_createRefFunction(const void* data, size_t length);
TOY_API void Toy_deleteRefFunction(Toy_RefFunction* refFunction);
TOY_API int Toy_countRefFunction(Toy_RefFunction* refFunction);
TOY_API size_t Toy_lengthRefFunction(Toy_RefFunction* refFunction);
TOY_API Toy_RefFunction* Toy_copyRefFunction(Toy_RefFunction* refFunction);
TOY_API Toy_RefFunction* Toy_deepCopyRefFunction(Toy_RefFunction* refFunction);
+21 -26
View File
@@ -1,35 +1,30 @@
#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;
extern void* Toy_private_defaultMemoryAllocator(void* pointer, size_t oldSize, size_t newSize);
static Toy_RefStringAllocatorFn allocate = Toy_private_defaultMemoryAllocator;
void Toy_setRefStringAllocatorFn(Toy_RefStringAllocatorFn allocator) {
allocate = allocator;
}
//API
Toy_RefString* Toy_createRefString(char* cstring) {
int length = strnlen(cstring, 4096);
Toy_RefString* Toy_createRefString(const char* cstring) {
size_t length = strlen(cstring);
return Toy_createRefStringLength(cstring, length);
}
Toy_RefString* Toy_createRefStringLength(char* cstring, int length) {
Toy_RefString* Toy_createRefStringLength(const char* cstring, size_t length) {
//allocate the memory area (including metadata space)
Toy_RefString* refString = (Toy_RefString*)allocate(NULL, 0, sizeof(int) * 2 + sizeof(char) * length + 1);
Toy_RefString* refString = allocate(NULL, 0, sizeof(size_t) + sizeof(int) + sizeof(char) * (length + 1));
if (refString == NULL) {
return NULL;
}
//set the data
refString->refcount = 1;
refString->refCount = 1;
refString->length = length;
strncpy(refString->data, cstring, refString->length);
@@ -40,32 +35,32 @@ Toy_RefString* Toy_createRefStringLength(char* cstring, int length) {
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);
refString->refCount--;
if (refString->refCount <= 0) {
allocate(refString, sizeof(size_t) + sizeof(int) + sizeof(char) * (refString->length + 1), 0);
}
}
int Toy_countRefString(Toy_RefString* refString) {
return refString->refcount;
return refString->refCount;
}
int Toy_lengthRefString(Toy_RefString* refString) {
size_t Toy_lengthRefString(Toy_RefString* refString) {
return refString->length;
}
Toy_RefString* Toy_copyRefString(Toy_RefString* refString) {
//Cheaty McCheater Face
refString->refcount++;
refString->refCount++;
return refString;
}
Toy_RefString* Toy_deepCopyRefString(Toy_RefString* refString) {
//create a new string, with a new refcount
//create a new string, with a new refCount
return Toy_createRefStringLength(refString->data, refString->length);
}
char* Toy_toCString(Toy_RefString* refString) {
const char* Toy_toCString(Toy_RefString* refString) {
return refString->data;
}
@@ -86,7 +81,7 @@ bool Toy_equalsRefString(Toy_RefString* lhs, Toy_RefString* rhs) {
bool Toy_equalsRefStringCString(Toy_RefString* lhs, char* cstring) {
//get the rhs length
int length = strnlen(cstring, 4096);
size_t length = strlen(cstring);
//different length
if (lhs->length != length) {
@@ -95,4 +90,4 @@ bool Toy_equalsRefStringCString(Toy_RefString* lhs, char* cstring) {
//same string
return strncmp(lhs->data, cstring, lhs->length) == 0;
}
}
+20 -16
View File
@@ -1,27 +1,31 @@
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include "toy_common.h"
#include <string.h>
//memory allocation hook
typedef void* (*Toy_RefStringAllocatorFn)(void* pointer, size_t oldSize, size_t newSize);
void Toy_setRefStringAllocatorFn(Toy_RefStringAllocatorFn);
TOY_API void Toy_setRefStringAllocatorFn(Toy_RefStringAllocatorFn);
//the RefString structure
typedef struct Toy_RefString {
int refcount;
int length;
char data[1];
size_t length;
int refCount;
char data[];
} 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);
TOY_API Toy_RefString* Toy_createRefString(const char* cstring);
TOY_API Toy_RefString* Toy_createRefStringLength(const char* cstring, size_t length);
TOY_API void Toy_deleteRefString(Toy_RefString* refString);
TOY_API int Toy_countRefString(Toy_RefString* refString);
TOY_API size_t Toy_lengthRefString(Toy_RefString* refString);
TOY_API Toy_RefString* Toy_copyRefString(Toy_RefString* refString);
TOY_API Toy_RefString* Toy_deepCopyRefString(Toy_RefString* refString);
TOY_API const char* Toy_toCString(Toy_RefString* refString);
TOY_API bool Toy_equalsRefString(Toy_RefString* lhs, Toy_RefString* rhs);
TOY_API bool Toy_equalsRefStringCString(Toy_RefString* lhs, char* cstring);
//TODO: merge refstring memory
+64 -62
View File
@@ -4,21 +4,19 @@
//run up the ancestor chain, freeing anything with 0 references left
static void freeAncestorChain(Toy_Scope* scope) {
scope->references--;
while (scope != NULL) {
Toy_Scope* next = scope->ancestor;
//free scope chain
if (scope->ancestor != NULL) {
freeAncestorChain(scope->ancestor);
scope->references--;
if (scope->references <= 0) {
Toy_freeLiteralDictionary(&scope->variables);
Toy_freeLiteralDictionary(&scope->types);
TOY_FREE(Toy_Scope, scope);
}
scope = next;
}
if (scope->references > 0) {
return;
}
Toy_freeLiteralDictionary(&scope->variables);
Toy_freeLiteralDictionary(&scope->types);
TOY_FREE(Toy_Scope, scope);
}
//return false if invalid type
@@ -126,7 +124,7 @@ static bool checkType(Toy_Literal typeLiteral, Toy_Literal original, Toy_Literal
}
//find the internal child of original that matches this child of value
Toy_private_entry* ptr = NULL;
Toy_private_dictionary_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)) {
@@ -159,6 +157,10 @@ static bool checkType(Toy_Literal typeLiteral, Toy_Literal original, Toy_Literal
return false;
}
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_OPAQUE && !TOY_IS_OPAQUE(value)) {
return false;
}
return true;
}
@@ -185,7 +187,7 @@ Toy_Scope* Toy_popScope(Toy_Scope* scope) {
Toy_Scope* ret = scope->ancestor;
//BUGFIX: when freeing a scope, free the function's scopes manually
//BUGFIX: when freeing a scope, free the functions' scopes manually - I *think* this is related to the closure hack-in
for (int i = 0; i < scope->variables.capacity; i++) {
//handle keys, just in case
if (TOY_IS_FUNCTION(scope->variables.entries[i].key)) {
@@ -205,6 +207,10 @@ Toy_Scope* Toy_popScope(Toy_Scope* scope) {
}
Toy_Scope* Toy_copyScope(Toy_Scope* original) {
if (original == NULL) {
return NULL;
}
Toy_Scope* scope = TOY_ALLOCATE(Toy_Scope, 1);
scope->ancestor = original->ancestor;
Toy_initLiteralDictionary(&scope->variables);
@@ -251,74 +257,70 @@ bool Toy_declareScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal typ
}
bool Toy_isDelcaredScopeVariable(Toy_Scope* scope, Toy_Literal key) {
if (scope == NULL) {
return false;
while (scope != NULL) {
if (Toy_existsLiteralDictionary(&scope->variables, key)) {
return true;
}
scope = scope->ancestor;
}
//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;
}
//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;
}
while (scope != NULL) {
//if it's not in this scope, keep searching up the chain
if (!Toy_existsLiteralDictionary(&scope->variables, key)) {
scope = scope->ancestor;
continue;
}
//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);
//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); //key & value are copied here
if (!checkType(typeLiteral, original, value, constCheck)) {
Toy_freeLiteral(typeLiteral);
Toy_freeLiteral(original);
return false;
return true;
}
//actually assign
Toy_setLiteralDictionary(&scope->variables, key, value);
Toy_freeLiteral(typeLiteral);
Toy_freeLiteral(original);
return true;
return false;
}
bool Toy_getScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal* valueHandle) {
//dead end
if (scope == NULL) {
return false;
//optimized to reduce call stack
while (scope != NULL) {
if (Toy_existsLiteralDictionary(&scope->variables, key)) {
*valueHandle = Toy_getLiteralDictionary(&scope->variables, key);
return true;
}
scope = scope->ancestor;
}
//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;
return false;
}
Toy_Literal Toy_getScopeType(Toy_Scope* scope, Toy_Literal key) {
//dead end
if (scope == NULL) {
return TOY_TO_NULL_LITERAL;
while (scope != NULL) {
if (Toy_existsLiteralDictionary(&scope->types, key)) {
return Toy_getLiteralDictionary(&scope->types, key);
}
scope = scope->ancestor;
}
//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);
return TOY_TO_NULL_LITERAL;
}
+9 -8
View File
@@ -1,5 +1,6 @@
#pragma once
#include "toy_literal.h"
#include "toy_literal_array.h"
#include "toy_literal_dictionary.h"
@@ -10,16 +11,16 @@ typedef struct Toy_Scope {
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);
TOY_API Toy_Scope* Toy_pushScope(Toy_Scope* scope);
TOY_API Toy_Scope* Toy_popScope(Toy_Scope* scope);
TOY_API 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);
TOY_API bool Toy_declareScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal type);
TOY_API 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_API bool Toy_setScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal value, bool constCheck);
TOY_API bool Toy_getScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal* value);
Toy_Literal Toy_getScopeType(Toy_Scope* scope, Toy_Literal key);
TOY_API Toy_Literal Toy_getScopeType(Toy_Scope* scope, Toy_Literal key);
+18
View File
@@ -28,4 +28,22 @@ a %= 8;
assert a == 4, "%= failed";
//strings as special cases
var s = "foo";
assert s + "bar" == "foobar", "string addition failed";
assert s == "foo", "string addition failed (was too sticky)";
s += "bar";
assert s == "foobar", "string addition failed (wasn't sticky enough)";
//check order of operations
assert 30 / 3 * 2 == 20, "Order of operations failed (raw numbers)";
var x = 30;
var y = 3;
var z = 2;
assert x / y * z == 20, "Order of operations failed (variables)";
print "All good";
@@ -0,0 +1,7 @@
var s = "42";
var t = "69";
assert int (s + t) - 1 == 4268, "casting parentheses failed";
print "All good";
+3
View File
@@ -23,5 +23,8 @@ assert !false, "!false";
var c = false;
assert !c, "!c";
//test multiple comparisons
assert 1 == 2 == false, "Left-accociative equality failed";
print "All good";
+17 -17
View File
@@ -2,11 +2,11 @@
var a = [1, 2, 3];
var b = [4, 5, 6];
assert _length(a) == _length(b), "a and b lengths are wrong";
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);
for (var i = 0; i < length(a); i++) {
acc += get(a, i) * get(b, i);
}
assert acc == 32, "dot product failed";
@@ -15,38 +15,38 @@ 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 l1 = length(first); //rows
var l2 = length(get(first, 0)); //cols
var l3 = _length(second); //rows
var l4 = _length(_get(second, 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);
push(row, 0);
}
var result = [];
for (var i = 0; i < l1; i++) {
_push(result, row);
push(result, row);
}
//assign the values
for (var i = 0; i < _length(first); i++) {
for (var i = 0; i < length(first); i++) {
//select each element of "first"
var firstElement = _get(first, i);
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++) {
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);
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);
var tmpRow = get(result, i);
set(tmpRow, j2, val);
set(result, i, tmpRow);
//result[ i ][ j2 ] += first[i][i2] * second[i2][j2]
}
+1 -1
View File
@@ -9,7 +9,7 @@ It appears to be a compiler issue, see issue #38 for more info.
*/
fn _getValue(self) {
fn getValue(self) {
return self;
}
+3 -3
View File
@@ -1,10 +1,10 @@
//test function chaining with the dot operator
fn _identity(self) {
fn identity(self) {
return self;
}
fn _check(self) {
fn check(self) {
assert self == 42, "dot chaining failed";
return self;
}
@@ -20,7 +20,7 @@ val
//test the value is actually altered
fn _increment(self) {
fn increment(self) {
return self + 1;
}
+23
View File
@@ -0,0 +1,23 @@
var days = [
"sunday",
"monday",
"tuesday",
"wednesday",
"thursday",
"friday",
"saturday"
];
var rng = 10; //for chosen at random
var index = rng % days.length();
assert index == 3, "dot modulo bugfix failed";
rng %= days.length();
assert rng == 3, "dot modulo assign bugfix failed";
print "All good";
+1 -1
View File
@@ -1,5 +1,5 @@
fn _add(self, inc) {
fn add(self, inc) {
return self + inc;
}
+1 -1
View File
@@ -63,7 +63,7 @@ extra("one", "two", "three", "four", "five", "six", "seven");
//test underscore functions
fn _example(self, a, b, c) {
fn example(self, a, b, c) {
assert a == "a", "underscore failed (a)";
assert b == "b", "underscore failed (b)";
assert c == "c", "underscore failed (c)";
+10
View File
@@ -72,6 +72,16 @@
}
//test nested indexing multipliciation assignment
{
var a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
a[1][1] *= 10;
assert a == [[1, 2, 3], [4, 50, 6], [7, 8, 9]], "nested indexing multipliciation assignment failed";
}
//test combine example
{
fn combine(a, b, c) {
@@ -0,0 +1,15 @@
/*
This ensures that when indexing on both sides of an assignment,
it works correctly.
*/
var a = [1, 2, 3];
var b = [4, 5, 6];
a[1] = b[1];
assert a == [1, 5, 3], "index assignment both failed";
print "All good";
@@ -0,0 +1,19 @@
/*
Compiler note:
This is also to test a specific element in the compiler.
It ensures that when doing indexing and assignment in one statement,
the index is NOT on the right. If it is, then it is treated like a normal
assignment.
*/
//polyfill the _insert function
var a = [1, 2, 3];
var b = a[1];
assert b == 2, "index assignment left failed";
print "All good";
+3 -5
View File
@@ -30,13 +30,11 @@
//test nested indexing
{
var d = ["foo": ["bar": 0]];
var d = ["foo" : ["bar" : ["bazz" : ["fizz" : 5]]]];
d["foo"]["bar"] = 42;
d["foo"]["bar"]["bazz"]["fizz"] = 66;
print d;
assert d == ["foo": ["bar": 42]], "nested indexing failed";
assert d == ["foo": ["bar": ["bazz": ["fizz": 66]]]], "nested indexing failed";
}
+4 -4
View File
@@ -18,7 +18,7 @@ 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";
assert greeting[10:14:-1] == "dlrow", "backwards indexed string failed";
//test string weird manipulation
@@ -26,12 +26,12 @@ var numbers = "0123456789";
numbers[::-2] = "abc";
assert numbers == "01234c6b8a", "string weird manipulation failed";
assert numbers == "0123c5b7a9", "string weird manipulation failed";
//test indexing with variables
var first = 11;
var second = 15;
var first = 10;
var second = 14;
var third = -1;
assert greeting[first:second:third] == "dlrow", "indexing with variables failed";
+7
View File
@@ -0,0 +1,7 @@
import about as about;
import about;
assert author == "Kayne Ruse, KR Game Studios", "Author failed";
print "All good";
+17
View File
@@ -0,0 +1,17 @@
import standard;
import random;
var generator: opaque = createRandomGenerator(clock().hash()); //create a new generator object, from a non-determinant source
var a: int = generator.generateRandomNumber();
var b: int = generator.generateRandomNumber();
var c: int = generator.generateRandomNumber();
generator.freeRandomGenerator();
assert a != b, "random a != random b failed";
assert a != c, "random a != random c failed";
assert b != c, "random b != random c failed";
print "All good";
Binary file not shown.
+412 -4
View File
@@ -1,9 +1,417 @@
//test the standard library
{
import standard;
import standard;
//test clock
{
//this depends on external factors, so only check the length
assert clock().length() == 24, "clock() import failed";
assert clock().length() == 24, "clock().length() failed";
}
//test hash
{
assert typeof "Hello world".hash() == int, "typeof \"Hello world\".hash() failed";
assert "Hello world".hash() == 994097935, "\"Hello world\".hash() failed"; //NOTE: specific value based on algorithm
}
//test abs
{
assert abs(-5) == 5, "abs(-integer) failed";
assert abs(-5.5) == 5.5, "abs(-float) failed";
assert abs(5) == 5, "abs(+integer) failed";
assert abs(5.5) == 5.5, "abs(+float) failed";
var x = -5;
assert x.abs() == 5, "var.abs() failed";
}
//test ceil
{
assert ceil(4) == 4, "ceil(int) failed";
assert ceil(4.0) == 4, "ceil(float) failed";
assert ceil(4.1) == 5, "ceil() failed";
var x = 4.1;
assert x.ceil() == 5, "var.ceil() failed";
}
//test floor
{
assert floor(4) == 4, "floor(int) failed";
assert floor(4.0) == 4, "floor(float) failed";
assert floor(4.1) == 4, "floor() failed";
var x = 4.1;
assert x.floor() == 4, "var.floor() failed";
}
//test max
{
assert max(1, 2, 3) == 3, "max() failed";
var a = 1;
var b = 2;
var c = 3;
assert max(a, b, c) == 3, "var.max() failed";
assert max(1, 2, 3, 4, 5, 6, 7, 8, 9, 0) == 9, "max() with many args failed";
assert typeof max(1, 2, 3) == int, "typeof max() == int failed";
assert typeof max(1, 2, 3.4) == float, "typeof max() == float failed";
}
//test min
{
assert min(1, 2, 3) == 1, "min() failed";
var a = 1;
var b = 2;
var c = 3;
assert min(a, b, c) == 1, "var.min() failed";
assert min(1, 2, 3, 4, 5, 6, 7, 8, 9, 0) == 0, "min() with many args failed";
assert typeof min(1, 2, 3) == int, "typeof min() == int failed";
assert typeof min(1, 2, 3.4) == float, "typeof min() == float failed";
}
//test round
{
assert round(4) == 4, "round(int) failed";
assert round(4.0) == 4, "round(float) failed";
assert round(4.1) == 4, "round(less than half) failed";
assert round(4.9) == 5, "round(greater than half) failed";
assert round(4.5) == 5, "round(exactly half) failed";
var x = 4.1;
assert x.round() == 4, "var.round() failed";
assert typeof round(1.0) == int, "typeof round() == int failed";
}
//test concat
{
//test array concat
{
var a = [1, 2, 3];
var b = [4, 5, 6];
var c = a.concat(b).concat(b);
assert c == [1, 2, 3, 4, 5, 6, 4, 5, 6], "array.concat() failed";
}
//test dictionary concat
{
var a = ["one" : 1, "two": 2, "three": 3];
var b = ["four" : 4, "five": 5, "six": 6];
var c = a.concat(b);
assert c.length() == 6, "dictionary.concat().length() failed";
assert c == ["one" : 1, "two": 2, "three": 3, "four" : 4, "five": 5, "six": 6], "dictionary.concat() comparison failed";
}
//test dictionary concat with clashing keys
{
var a = ["one" : 1, "two": 2, "three": 3, "random": 1];
var b = ["four" : 4, "five": 5, "six": 6, "random": 2];
var c = a.concat(b);
assert c["random"] == 1, "dictionary.concat() clashing keys failed";
}
//test string concat
{
var a = "foo";
var b = "bar";
var c = a.concat(b);
assert c == "foobar", "string.concat() failed";
}
}
//test containsKey
{
var d = ["one": 1, "two": 2];
assert d.containsKey("one") == true, "dictionary.containsKey() == true failed";
assert d.containsKey("three") == false, "dictionary.containsKey() == false failed";
}
//test containsValue
{
var a = [1, 2, 3];
var d = ["one": 1, "two": 2];
assert a.containsValue(1) == true, "array.containsValue() == true failed";
assert a.containsValue(5) == false, "array.containsValue() == false failed";
assert d.containsValue(1) == true, "dictionary.containsValue() == true failed";
assert d.containsValue(3) == false, "dictionary.containsValue() == false failed";
}
//test every
{
var a = [1, 2, 3];
var d = ["one": 1, "two": 2];
var counter = 0;
fn f(k, v) {
counter++;
return v;
}
assert a.every(f) == true, "array.every() == true failed";
assert d.every(f) == true, "dictionary.every() == true failed";
assert counter == 5, "Unexpected number of calls for _every() == true";
counter = 0;
a[1] = false;
d["two"] = false;
assert a.every(f) == false, "array.every() == false failed";
assert d.every(f) == false, "dictionary.every() == false failed";
assert counter == 4, "Unexpected number of calls for _every() == false";
}
//test filter
{
var a = [1, 2, 3, 4];
var d = ["one": 1, "two": 2, "three": 3, "four": 4];
fn f(k, v) {
return v % 2 == 0;
}
assert a.filter(f) == [2, 4], "array.filter() failed";
assert d.filter(f) == ["two": 2, "four": 4], "dictionary.filter() failed";
}
//test forEach
{
var counter = 0;
fn p(k, v) {
counter++;
print string k + ": " + string v;
}
var a = ["a", "b"];
var d = ["foo": 1, "bar": 2, "bazz": 3, "fizz": 4];
a.forEach(p);
assert counter == 2, "forEach ran an unusual number of times";
counter = 0;
d.forEach(p);
assert counter == 4, "forEach ran an unusual number of times";
}
//test getKeys
{
var d = ["foo": 1, "bar": 2];
var a = d.getKeys();
assert a.length() == 2, "_getKeys() length failed";
//NOTE: dependant on hash algorithm
assert a == ["bar", "foo"], "_getKeys() result failed";
}
//test getValues
{
var d = ["foo": 1, "bar": 2];
var a = d.getValues();
assert a.length() == 2, "_getValues() length failed";
//NOTE: dependant on hash algorithm
assert a == [2, 1], "_getValues() result failed";
}
//test indexOf
{
var a = [1, 2, 42, 3];
//results are zero-indexed
assert a.indexOf(42) == 2, "_indexOf() failed";
assert a.indexOf(4) == null, "_indexOf() == null failed";
}
//test map
{
//test map with toy functions
{
fn increment(k, v) {
return v + 1;
}
var a = [1, 2, 3];
var d = ["four": 4, "five": 5, "six": 6];
assert a.map(increment).map(increment).map(increment) == [4,5,6], "array.map() failed";
assert d.map(increment).map(increment).map(increment) == [8,9,7], "dictionary.map() failed";
}
//test map with native functions
{
//TODO: write some native functions for use with map
}
}
//test reduce
{
var a = [1, 2, 3, 4];
var d = ["one": 1, "two": 2, "three": 3, "four": 4];
fn f(acc, k, v) {
return acc + v;
}
assert a.reduce(0, f) == 10, "array.reduce() failed";
assert d.reduce(0, f) == 10, "dictionary.reduce() failed";
}
//test some
{
var a = [false, false, false];
var d = ["one": false, "two": false];
var counter = 0;
fn f(k, v) {
counter++;
return v;
}
assert a.some(f) == false, "array.some() == false failed";
assert d.some(f) == false, "dictionary.some() == false failed";
assert counter == 5, "Unexpected number of calls for _some() == false";
counter = 0;
a[1] = true;
d["two"] = true;
assert a.some(f) == true, "array.some() == true failed";
assert d.some(f) == true, "dictionary.some() == true failed";
assert counter == 4, "Unexpected number of calls for _some() == true";
}
//test sort
{
fn less(a, b) {
return a < b;
}
fn greater(a, b) {
return a > b;
}
var a = [7, 2, 1, 8, 6, 3, 5, 4];
var b = [7, 2, 1, 4, 6, 3, 5, 8];
var c = [1, 2, 3, 4, 5, 6, 7, 8];
var d = [7, 2, 1, 8, 6, 3, 5, 4];
a = a.sort(less);
b = b.sort(less);
c = c.sort(less);
d = d.sort(greater);
assert a == [1, 2, 3, 4, 5, 6, 7, 8], "array.sort(less) failed";
assert b == [1, 2, 3, 4, 5, 6, 7, 8], "array.sort(less) with pivot high failed";
assert c == [1, 2, 3, 4, 5, 6, 7, 8], "array.sort(less) pre-sorted array failed";
assert d == [8, 7, 6, 5, 4, 3, 2, 1], "array.sort(greater) failed";
}
//test toLower
{
assert "Hello World".toLower() == "hello world", "_toLower() failed";
}
//test toString
{
var a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
var s = a.toString();
assert s == "[[1,2,3],[4,5,6],[7,8,9]]", "array._toString() failed";
}
//test toUpper
{
assert "Hello World".toUpper() == "HELLO WORLD", "_toUpper() failed";
}
//test trim defaults
{
{
//test a bunch
fn test(s, pass) {
var result = s.trim();
assert result == pass, "_trim(" + result + ") failed";
}
test("hello world", "hello world");
test(" hello world", "hello world");
test("hello world ", "hello world");
test(" hello world ", "hello world");
test(" hello world", "hello world");
test("hello world ", "hello world");
test(" hello world ", "hello world");
test(" hello world", "hello world");
test("hello world ", "hello world");
test(" hello world ", "hello world");
//one for goot luck
assert " hello world ".trim() == "hello world", "hello world.trim() failed";
}
//test trim custom values
{
var chars = "heliod";
assert "hello world".trim(chars) == " wor", "custom _trim() failed";
}
//test trimBegin() & trimEnd()
assert " foo ".trimBegin() == "foo ", "string.trimBegin() failed";
assert " foo ".trimEnd() == " foo", "string.trimBegin() failed";
}
@@ -0,0 +1 @@
print "foo" + + "bar";
@@ -0,0 +1,2 @@
1.type();
@@ -2,6 +2,3 @@
var t = astype [int];
var arr: t = [1, 2, 3.14];
}
print "All good";
@@ -2,6 +2,3 @@
var t = astype [string:int];
var dict: t = ["one": 1, "two": 2, 3:4];
}
print "All good";
@@ -2,6 +2,3 @@
var t = astype [string:int];
var dict: t = ["one": 1, "two": 2, "pi": 3.14];
}
print "All good";
@@ -0,0 +1 @@
"a"[--];
@@ -2,6 +2,3 @@
var a: [int] = [1, 2, 3];
print a[a];
}
print "All good";
+3
View File
@@ -0,0 +1,3 @@
{
var s = "foo" - "bar";
}
+39 -39
View File
@@ -3,41 +3,41 @@
//test arrays without types
var array = [];
assert _length(array) == 0, "_length failed with array";
assert length(array) == 0, "length failed with array";
_push(array, 1);
_push(array, 2);
_push(array, 3);
_push(array, 4);
_push(array, "foo");
push(array, 1);
push(array, 2);
push(array, 3);
push(array, 4);
push(array, "foo");
assert _length(array) == 5, "_push failed with array";
assert _pop(array) == "foo", "_pop failed with array";
assert length(array) == 5, "push failed with array";
assert pop(array) == "foo", "pop failed with array";
_set(array, 2, "bar");
assert array == [1, 2, "bar", 4], "_set failed with array";
assert _get(array, 3) == 4, "_get failed with array";
set(array, 2, "bar");
assert array == [1, 2, "bar", 4], "set failed with array";
assert get(array, 3) == 4, "get failed with array";
//test dictionaries without types
var dict = [:];
_set(dict, "key", "value");
_set(dict, 1, 2);
set(dict, "key", "value");
set(dict, 1, 2);
assert dict == ["key":"value", 1:2], "_set failed with dictionaries";
assert _get(dict, "key") == "value", "_get failed with dictionaries";
assert dict == ["key":"value", 1:2], "set failed with dictionaries";
assert get(dict, "key") == "value", "get failed with dictionaries";
//test _length
assert _length(array) == 4 && _length(dict) == 2, "_length failed with array or dictionaries";
//test length
assert length(array) == 4 && length(dict) == 2, "length failed with array or dictionaries";
//test clear
_clear(array);
_clear(dict);
clear(array);
clear(dict);
assert _length(array) == 0 && _length(dict) == 0, "_clear failed with array or dictionaries";
assert length(array) == 0 && length(dict) == 0, "clear failed with array or dictionaries";
}
@@ -45,46 +45,46 @@
//test arrays with types
var array: [int] = [];
assert _length(array) == 0, "_length failed with array (+ types)";
assert length(array) == 0, "length failed with array (+ types)";
_push(array, 1);
_push(array, 2);
_push(array, 3);
_push(array, 4);
_push(array, 10);
push(array, 1);
push(array, 2);
push(array, 3);
push(array, 4);
push(array, 10);
assert _length(array) == 5, "_push or failed with array (+ types)";
assert _pop(array) == 10, "_pop failed with array (+ types)";
assert length(array) == 5, "push or failed with array (+ types)";
assert pop(array) == 10, "pop failed with array (+ types)";
_set(array, 2, 70);
assert array == [1, 2, 70, 4], "_set failed with array (+ types)";
assert _get(array, 3) == 4, "_get failed with array (+ types)";
set(array, 2, 70);
assert array == [1, 2, 70, 4], "set failed with array (+ types)";
assert get(array, 3) == 4, "get failed with array (+ types)";
//test dictionaries with types
var dict: [string : string] = [:];
_set(dict, "key", "value");
set(dict, "key", "value");
assert dict == ["key":"value"], "_set failed with dictionaries (+ types)";
assert _get(dict, "key") == "value", "_get failed with dictionaries (+ types)";
assert dict == ["key":"value"], "set failed with dictionaries (+ types)";
assert get(dict, "key") == "value", "get failed with dictionaries (+ types)";
//test length with types
assert _length(array) == 4 && _length(dict) == 1, "_length failed with array or dictionaries (+ types)";
assert length(array) == 4 && length(dict) == 1, "length failed with array or dictionaries (+ types)";
//test clear with types
_clear(array);
_clear(dict);
clear(array);
clear(dict);
assert _length(array) == 0 && _length(dict) == 0, "_clear failed with array or dictionaries (+ types)";
assert length(array) == 0 && length(dict) == 0, "clear failed with array or dictionaries (+ types)";
}
{
var str = "hello world";
assert _length(str) == 11, "_length failed with string";
assert length(str) == 11, "length failed with string";
}
+7
View File
@@ -0,0 +1,7 @@
//This is just a check to ensure that unary minus doesn't screw up the AST
var xrel: int = 0;
var yrel: int = 0;
assert (xrel > 1 || xrel < -1 || yrel > 1 || yrel < -1) == false, "or-chaining bugfix failed";
+22
View File
@@ -0,0 +1,22 @@
//polyfill the insert function
fn insert(self, k, v) {
var tmp1 = v;
var tmp2;
for (var i = k; i < self.length(); i++) {
tmp2 = self[i];
self[i] = tmp1;
tmp1 = tmp2;
}
self.push(tmp1);
return self;
}
var a = [1, 2, 3];
a = a.insert(1, 42);
assert a == [1, 42, 2, 3], "polyfill insert failed";
print "All good";
+23
View File
@@ -0,0 +1,23 @@
//polyfill the remove function
fn remove(self, k) {
var result = [];
for (var i = 0; i <= k - 1; i++) {
result.push( self[i] );
}
for (var i = k + 1; i < self.length(); i++) {
result.push( self[i] );
}
return result;
}
var a = [1, 2, 3];
assert a.remove(0) == [2, 3], "polyfill remove(start) failed";
assert a.remove(1) == [1, 3], "polyfill remove(middle) failed";
assert a.remove(2) == [1, 2], "polyfill remove(end) failed";
print "All good";
+15 -6
View File
@@ -1,12 +1,21 @@
fn fib(n : int) {
if (n < 2) {
return n;
}
//memoize the fib function
var memo: [int : int] = [:];
return fib(n-1) + fib(n-2);
fn fib(n : int) {
if (n < 2) {
return n;
}
var result = memo[n];
if (result == null) {
result = fib(n-1) + fib(n-2);
memo[n] = result;
}
return result;
}
for (var i = 0; i < 20; i++) {
for (var i = 0; i < 40; i++) {
var res = fib(i);
print string i + ": " + string res;
}
@@ -0,0 +1,9 @@
//explicitly support && and || short circuits
assert 1 && 2 == 2, "&& short-circuit failed";
assert 1 || 2 == 1, "|| short-circuit failed";
print "All good";
+17 -1
View File
@@ -4,7 +4,6 @@
assert false ? false : true, "Basic false ternary failed";
}
//test nesting
{
fn least(a, b, c) {
@@ -16,6 +15,23 @@
assert least(9, 7, 5) == 5, "Least 9, 7, 5 failed";
}
//test division prevention
{
var x = 0;
assert (x ? 0 : 1 / x) == 0, "Division by zero prevention failed";
}
//test ambiguous syntax
{
var aa = 1;
var bbb = 2;
var cccc = 3;
var ddddd = 4;
var eeeeee = 5;
assert (aa ? bbb ? cccc : ddddd : eeeeee) == 3, "Ambiguous syntax failed";
}
print "All good";
+23 -23
View File
@@ -20,15 +20,15 @@ static void noPrintFn(const char* output) {
}
void error(char* msg) {
printf("%s", msg);
printf("%s\n", msg);
exit(-1);
}
int main() {
{
size_t size = 0;
char* source = Toy_readFile("scripts/call-from-host.toy", &size);
unsigned char* tb = Toy_compileString(source, &size);
const char* source = (const char*)Toy_readFile("scripts/call-from-host.toy", &size);
const unsigned char* tb = Toy_compileString(source, &size);
free((void*)source);
if (!tb) {
@@ -52,15 +52,15 @@ int main() {
//check the results
if (arguments.count != 0) {
error("Arguments has the wrong number of members\n");
error("Arguments has the wrong number of members");
}
if (returns.count != 1) {
error("Returns has the wrong number of members\n");
error("Returns has the wrong number of members");
}
if (!TOY_IS_INTEGER(returns.literals[0]) || TOY_AS_INTEGER(returns.literals[0]) != 42) {
error("Returned value is incorrect\n");
error("Returned value is incorrect");
}
Toy_freeLiteralArray(&arguments);
@@ -85,17 +85,17 @@ int main() {
//check the results
if (arguments.count != 0) {
error("Arguments has the wrong number of members\n");
error("Arguments has the wrong number of members");
}
if (returns.count != 1) {
error("Returns has the wrong number of members\n");
error("Returns has the wrong number of members");
}
float epsilon = 0.1; //because floats are evil
if (!TOY_IS_FLOAT(returns.literals[0]) || fabs(TOY_AS_FLOAT(returns.literals[0]) - pi) > epsilon) {
error("Returned value is incorrect\n");
error("Returned value is incorrect");
}
Toy_freeLiteralArray(&arguments);
@@ -115,11 +115,11 @@ int main() {
//check the results
if (arguments.count != 0) {
error("Arguments has the wrong number of members\n");
error("Arguments has the wrong number of members");
}
if (returns.count != 1) {
error("Returns has the wrong number of members\n");
error("Returns has the wrong number of members");
}
//grab the resulting literal
@@ -139,15 +139,15 @@ int main() {
//check the results
if (arguments.count != 0) {
error("Arguments (1) has the wrong number of members\n");
error("Arguments (1) has the wrong number of members");
}
if (returns.count != 1) {
error("Returns (1) has the wrong number of members\n");
error("Returns (1) has the wrong number of members");
}
if (!TOY_IS_INTEGER(returns.literals[0]) || TOY_AS_INTEGER(returns.literals[0]) != 1) {
error("Returned value (1) is incorrect\n");
error("Returned value (1) is incorrect");
}
Toy_freeLiteralArray(&arguments);
@@ -164,15 +164,15 @@ int main() {
//check the results
if (arguments.count != 0) {
error("Arguments (2) has the wrong number of members\n");
error("Arguments (2) has the wrong number of members");
}
if (returns.count != 1) {
error("Returns (2) has the wrong number of members\n");
error("Returns (2) has the wrong number of members");
}
if (!TOY_IS_INTEGER(returns.literals[0]) || TOY_AS_INTEGER(returns.literals[0]) != 2) {
error("Returned value (2) is incorrect\n");
error("Returned value (2) is incorrect");
}
Toy_freeLiteralArray(&arguments);
@@ -189,15 +189,15 @@ int main() {
//check the results
if (arguments.count != 0) {
error("Arguments (3) has the wrong number of members\n");
error("Arguments (3) has the wrong number of members");
}
if (returns.count != 1) {
error("Returns (3) has the wrong number of members\n");
error("Returns (3) has the wrong number of members");
}
if (!TOY_IS_INTEGER(returns.literals[0]) || TOY_AS_INTEGER(returns.literals[0]) != 3) {
error("Returned value (3) is incorrect\n");
error("Returned value (3) is incorrect");
}
Toy_freeLiteralArray(&arguments);
@@ -222,15 +222,15 @@ int main() {
//check the results
if (arguments.count != 0) {
error("Arguments has the wrong number of members\n");
error("Arguments has the wrong number of members");
}
if (returns.count != 1 || !TOY_IS_NULL(returns.literals[0])) {
error("Returns has the wrong number of members\n");
error("Returns has the wrong number of members");
}
if (!ret) {
error("Assertion gives the wrong return value\n");
error("Assertion gives the wrong return value");
}
Toy_freeLiteralArray(&arguments);
+3 -3
View File
@@ -39,7 +39,7 @@ int main() {
Toy_writeCompiler(&compiler, node);
//collate
int size = 0;
size_t size = 0;
unsigned char* bytecode = Toy_collateCompiler(&compiler, &size);
//cleanup
@@ -52,7 +52,7 @@ int main() {
{
//source
size_t sourceLength = 0;
char* source = Toy_readFile("scripts/compiler_sample_code.toy", &sourceLength);
const char* source = (const char*)Toy_readFile("scripts/compiler_sample_code.toy", &sourceLength);
//test basic compilation & collation
Toy_Lexer lexer;
@@ -78,7 +78,7 @@ int main() {
}
//collate
int size = 0;
size_t size = 0;
unsigned char* bytecode = Toy_collateCompiler(&compiler, &size);
//cleanup
+17 -9
View File
@@ -30,7 +30,7 @@ static void noAssertFn(const char* output) {
}
}
void runBinaryCustom(unsigned char* tb, size_t size) {
void runBinaryCustom(const unsigned char* tb, size_t size) {
Toy_Interpreter interpreter;
Toy_initInterpreter(&interpreter);
@@ -42,18 +42,18 @@ void runBinaryCustom(unsigned char* tb, size_t size) {
Toy_freeInterpreter(&interpreter);
}
void runSourceCustom(char* source) {
void runSourceCustom(const char* source) {
size_t size = 0;
unsigned char* tb = Toy_compileString(source, &size);
const unsigned char* tb = Toy_compileString(source, &size);
if (!tb) {
return;
}
runBinaryCustom(tb, size);
}
void runSourceFileCustom(char* fname) {
void runSourceFileCustom(const char* fname) {
size_t size = 0; //not used
char* source = Toy_readFile(fname, &size);
const char* source = (const char*)Toy_readFile(fname, &size);
runSourceCustom(source);
free((void*)source);
}
@@ -68,7 +68,7 @@ int main() {
{
//source
char* source = "print null;";
const char* source = "print null;";
//test basic compilation & collation
Toy_Lexer lexer;
@@ -87,8 +87,8 @@ int main() {
Toy_writeCompiler(&compiler, node);
//collate
int size = 0;
unsigned char* bytecode = Toy_collateCompiler(&compiler, &size);
size_t size = 0;
const unsigned char* bytecode = Toy_collateCompiler(&compiler, &size);
//NOTE: suppress print output for testing
Toy_setInterpreterPrint(&interpreter, noPrintFn);
@@ -106,17 +106,21 @@ int main() {
{
//run each file in tests/scripts/
char* filenames[] = {
const char* filenames[] = {
"arithmetic.toy",
"casting-parentheses-bugfix.toy",
"casting.toy",
"coercions.toy",
"comparisons.toy",
"dot-and-matrix.toy",
"dot-assignments-bugfix.toy",
"dot-chaining.toy",
"dot-modulo-bugfix.toy",
"dottify-bugfix.toy",
"functions.toy",
"index-arrays.toy",
"index-assignment-both-bugfix.toy",
"index-assignment-left-bugfix.toy",
"index-dictionaries.toy",
"index-strings.toy",
"jumps.toy",
@@ -126,7 +130,11 @@ int main() {
"long-dictionary.toy",
"long-literals.toy",
"native-functions.toy",
"or-chaining-bugfix.toy",
"panic-within-functions.toy",
"polyfill-insert.toy",
"polyfill-remove.toy",
"short-circuiting-support.toy",
"ternary-expressions.toy",
"types.toy",
NULL
+4 -4
View File
@@ -15,10 +15,10 @@ int main() {
Toy_initLexer(&lexer, source);
//get each token
Toy_Token print = Toy_scanLexer(&lexer);
Toy_Token null = Toy_scanLexer(&lexer);
Toy_Token semi = Toy_scanLexer(&lexer);
Toy_Token eof = Toy_scanLexer(&lexer);
Toy_Token print = Toy_private_scanLexer(&lexer);
Toy_Token null = Toy_private_scanLexer(&lexer);
Toy_Token semi = Toy_private_scanLexer(&lexer);
Toy_Token eof = Toy_private_scanLexer(&lexer);
//test each token is correct
if (strncmp(print.lexeme, "print", print.length)) {
+15 -15
View File
@@ -6,6 +6,7 @@
#include "toy_console_colors.h"
#include "toy_memory.h"
#include "toy_drive_system.h"
#include <stdio.h>
#include <stdlib.h>
@@ -13,9 +14,10 @@
#include "../repl/repl_tools.h"
#include "../repl/lib_standard.h"
#include "../repl/lib_timer.h"
#include "../repl/lib_about.h"
#include "../repl/lib_random.h"
#include "../repl/lib_runner.h"
#include "../repl/lib_standard.h"
//supress the print output
static void noPrintFn(const char* output) {
@@ -35,7 +37,7 @@ static void errorWrapper(const char* output) {
fprintf(stderr, TOY_CC_ERROR "%s" TOY_CC_RESET, output);
}
void runBinaryWithLibrary(unsigned char* tb, size_t size, char* library, Toy_HookFn hook) {
void runBinaryWithLibrary(const unsigned char* tb, size_t size, const char* library, Toy_HookFn hook) {
Toy_Interpreter interpreter;
Toy_initInterpreter(&interpreter);
@@ -45,6 +47,9 @@ void runBinaryWithLibrary(unsigned char* tb, size_t size, char* library, Toy_Hoo
Toy_setInterpreterError(&interpreter, errorWrapper);
//inject the standard libraries into this interpreter
if (hook != Toy_hookStandard) {
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
}
Toy_injectNativeHook(&interpreter, library, hook);
Toy_runInterpreter(&interpreter, tb, size);
@@ -59,23 +64,18 @@ typedef struct Payload {
int main() {
//setup the runner filesystem (hacky)
Toy_initDriveDictionary();
Toy_initDriveSystem();
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);
Toy_setDrivePath("scripts", "scripts");
{
//run each file in test/scripts
Payload payloads[] = {
{"interactions.toy", "standard", Toy_hookStandard}, //interactions needs standard
{"about.toy", "about", Toy_hookAbout},
{"standard.toy", "standard", Toy_hookStandard},
{"timer.toy", "timer", Toy_hookTimer},
{"runner.toy", "runner", Toy_hookRunner},
{"random.toy", "random", Toy_hookRandom},
{NULL, NULL, NULL}
};
@@ -87,14 +87,14 @@ int main() {
//compile the source
size_t size = 0;
char* source = Toy_readFile(fname, &size);
const char* source = (const char*)Toy_readFile(fname, &size);
if (!source) {
printf(TOY_CC_ERROR "Failed to load file: %s\n" TOY_CC_RESET, fname);
failedAsserts++;
continue;
}
unsigned char* tb = Toy_compileString(source, &size);
const unsigned char* tb = Toy_compileString(source, &size);
free((void*)source);
if (!tb) {
@@ -108,7 +108,7 @@ int main() {
}
//lib cleanup
Toy_freeDriveDictionary();
Toy_freeDriveSystem();
if (!failedAsserts) {
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
+11 -7
View File
@@ -23,7 +23,7 @@ static void noErrorFn(const char* output) {
errorsTriggered++;
}
unsigned char* compileStringCustom(char* source, size_t* size) {
const unsigned char* compileStringCustom(const char* source, size_t* size) {
Toy_Lexer lexer;
Toy_Parser parser;
Toy_Compiler compiler;
@@ -50,7 +50,7 @@ unsigned char* compileStringCustom(char* source, size_t* size) {
}
//get the bytecode dump
unsigned char* tb = Toy_collateCompiler(&compiler, (int*)(size));
const unsigned char* tb = Toy_collateCompiler(&compiler, size);
//cleanup
Toy_freeCompiler(&compiler);
@@ -61,7 +61,7 @@ unsigned char* compileStringCustom(char* source, size_t* size) {
return tb;
}
void runBinaryCustom(unsigned char* tb, size_t size) {
void runBinaryCustom(const unsigned char* tb, size_t size) {
Toy_Interpreter interpreter;
Toy_initInterpreter(&interpreter);
@@ -73,18 +73,18 @@ void runBinaryCustom(unsigned char* tb, size_t size) {
Toy_freeInterpreter(&interpreter);
}
void runSourceCustom(char* source) {
void runSourceCustom(const char* source) {
size_t size = 0;
unsigned char* tb = compileStringCustom(source, &size);
const unsigned char* tb = compileStringCustom(source, &size);
if (!tb) {
return;
}
runBinaryCustom(tb, size);
}
void runSourceFileCustom(char* fname) {
void runSourceFileCustom(const char* fname) {
size_t size = 0; //not used
char* source = Toy_readFile(fname, &size);
const char* source = (const char*)Toy_readFile(fname, &size);
runSourceCustom(source);
free((void*)source);
}
@@ -96,10 +96,14 @@ int main() {
//run each file in tests/scripts/
char* filenames[] = {
"access-parent-directory.toy",
"arithmetic-without-operand.toy",
"bad-function-identifier.toy",
"declare-types-array.toy",
"declare-types-dictionary-key.toy",
"declare-types-dictionary-value.toy",
"index-access-bugfix.toy",
"index-arrays-non-integer.toy",
"string-concat.toy",
"unary-inverted-nothing.toy",
"unary-negative-nothing.toy",
NULL
+2 -2
View File
@@ -68,8 +68,8 @@ static int consume(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
int main() {
{
size_t size = 0;
char* source = Toy_readFile("scripts/opaque-data-type.toy", &size);
unsigned char* tb = Toy_compileString(source, &size);
const char* source = (const char*)Toy_readFile("scripts/opaque-data-type.toy", &size);
const unsigned char* tb = Toy_compileString(source, &size);
free((void*)source);
if (!tb) {
+83 -7
View File
@@ -11,7 +11,7 @@
int main() {
{
//source
char* source = "print null;";
const char* source = "print null;";
//test init & quit
Toy_Lexer lexer;
@@ -24,7 +24,7 @@ int main() {
{
//source
char* source = "print null;";
const char* source = "print null;";
//test parsing
Toy_Lexer lexer;
@@ -36,17 +36,17 @@ int main() {
//inspect the node
if (node == NULL) {
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode is null" TOY_CC_RESET);
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode is null\n" TOY_CC_RESET);
return -1;
}
if (node->type != TOY_AST_NODE_UNARY || node->unary.opcode != TOY_OP_PRINT) {
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode is not a unary print instruction" TOY_CC_RESET);
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode is not a unary print instruction\n" TOY_CC_RESET);
return -1;
}
if (node->unary.child->type != TOY_AST_NODE_LITERAL || !TOY_IS_NULL(node->unary.child->atomic.literal)) {
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode to be printed is not a null literal" TOY_CC_RESET);
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode to be printed is not a null literal\n" TOY_CC_RESET);
return -1;
}
@@ -58,7 +58,7 @@ int main() {
{
//get the source file
size_t size = 0;
char* source = Toy_readFile("scripts/parser_sample_code.toy", &size);
const char* source = (const char*)Toy_readFile("scripts/parser_sample_code.toy", &size);
//test parsing a chunk of junk (valgrind will find leaks)
Toy_Lexer lexer;
@@ -70,7 +70,7 @@ int main() {
while (node != NULL) {
if (node->type == TOY_AST_NODE_ERROR) {
fprintf(stderr, TOY_CC_ERROR "ERROR: Error node detected" TOY_CC_RESET);
fprintf(stderr, TOY_CC_ERROR "ERROR: Error node detected\n" TOY_CC_RESET);
return -1;
}
@@ -83,6 +83,82 @@ int main() {
free((void*)source);
}
{
//test parsing of escaped characters
const char* source = "print \"\\\"\";"; //NOTE: this string goes through two layers of escaping
//test parsing
Toy_Lexer lexer;
Toy_Parser parser;
Toy_initLexer(&lexer, source);
Toy_initParser(&parser, &lexer);
Toy_ASTNode* node = Toy_scanParser(&parser);
//inspect the node
if (node == NULL) {
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode is null\n" TOY_CC_RESET);
return -1;
}
if (node->type != TOY_AST_NODE_UNARY || node->unary.opcode != TOY_OP_PRINT) {
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode is not a unary print instruction\n" TOY_CC_RESET);
return -1;
}
if (node->unary.child->type != TOY_AST_NODE_LITERAL || !TOY_IS_STRING(node->unary.child->atomic.literal)) {
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode to be printed is not a string literal\n" TOY_CC_RESET);
return -1;
}
if (!Toy_equalsRefStringCString(TOY_AS_STRING(node->unary.child->atomic.literal), "\"")) {
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode to be printed is not an escaped character, found: %s\n" TOY_CC_RESET, Toy_toCString(TOY_AS_STRING(node->unary.child->atomic.literal)));
return -1;
}
//cleanup
Toy_freeASTNode(node);
Toy_freeParser(&parser);
}
{
//test parsing of underscored numbers
const char* source = "print 1_000_000;";
//test parsing
Toy_Lexer lexer;
Toy_Parser parser;
Toy_initLexer(&lexer, source);
Toy_initParser(&parser, &lexer);
Toy_ASTNode* node = Toy_scanParser(&parser);
//inspect the node
if (node == NULL) {
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode is null\n" TOY_CC_RESET);
return -1;
}
if (node->type != TOY_AST_NODE_UNARY || node->unary.opcode != TOY_OP_PRINT) {
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode is not a unary print instruction\n" TOY_CC_RESET);
return -1;
}
if (node->unary.child->type != TOY_AST_NODE_LITERAL || !TOY_IS_INTEGER(node->unary.child->atomic.literal)) {
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode to be printed is not a string literal\n" TOY_CC_RESET);
return -1;
}
if (TOY_AS_INTEGER(node->unary.child->atomic.literal) != 1000000) {
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode to be printed is not the correct value, found: %d\n" TOY_CC_RESET, TOY_AS_INTEGER(node->unary.child->atomic.literal));
return -1;
}
//cleanup
Toy_freeASTNode(node);
Toy_freeParser(&parser);
}
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
return 0;
}

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