Compare commits

...

77 Commits

Author SHA1 Message Date
Kayne Ruse b602e2ff87 Tweaked build trigger 2024-09-22 15:04:27 +10:00
Kayne Ruse 0b99eb7b0c Bumped patch version 2024-09-22 14:45:04 +10:00
Kayne Ruse 2505cedc79 Update README.md 2024-09-22 14:43:20 +10:00
Kayne Ruse d7035a59c8 Updated CI 2024-08-11 21:25:11 +10:00
Kayne Ruse ea584d8950 Fixed the failing build on mingw
Squashed commit of the following:

commit c48929d25a84331ca8bd1b27be2c6aa4f3b4db12
Author: Kayne Ruse <kayneruse@gmail.com>
Date:   Fri Aug 9 23:12:49 2024 +1000

    Update c-cpp.yml

    I'm only going a little bit nuts.

commit 3f65882bdc75f1712c9a3c9d2ddf0e53a27ce4b9
Author: Kayne Ruse <kayneruse@gmail.com>
Date:   Fri Aug 9 22:49:18 2024 +1000

    Update c-cpp.yml

    It would be great if this was documented better.

commit d3abeda7c2776bb2e82ca635cd659967afa6ad75
Author: Kayne Ruse <kayneruse@gmail.com>
Date:   Fri Aug 9 21:40:39 2024 +1000

    Bumped license date

commit 17bbce9d7ca212064bc95e467933c5602a89fb4c
Author: Kayne Ruse <kayneruse@gmail.com>
Date:   Fri Aug 9 21:33:57 2024 +1000

    Fixed the failing build on mingw

    There seems to be persistent issues with different compilers
    displaying the values of size_t, so I simply cast it to an integer.

commit 843a76d0ac44328776f8ecf83a66caa7ea7fdef6
Author: Kayne Ruse <kayneruse@gmail.com>
Date:   Fri Aug 9 21:17:17 2024 +1000

    Updated CI

commit 08cd89c58d8d028438b9f83a60f5dd9265cc3465
Author: Kayne Ruse <kayneruse@gmail.com>
Date:   Fri Aug 9 21:09:03 2024 +1000

    Why did that fail last time?
2024-08-09 23:25:56 +10:00
Kayne Ruse 2ce9a0cf42 Fixed an AST bug 2024-07-20 16:27:07 +10:00
Kayne Ruse b77f0fb50d Merge pull request #117 from hiperiondev/main
Add prefix in function for label code
2023-09-01 23:36:58 +10:00
hiperiondev edb5a52562 Add prefix in function for label code 2023-08-29 22:41:52 -03:00
Kayne Ruse 9dc9316853 Merge pull request #116 from hiperiondev/main
Correct format
2023-08-29 13:07:22 +10:00
hiperiondev a864a1a226 Correct format 2023-08-28 23:57:46 -03:00
Kayne Ruse c645026620 Merge pull request #115 from hiperiondev/main
Add disassemblre group option
2023-08-29 12:50:56 +10:00
hiperiondev a9ccd65da1 Add disassemblre group option 2023-08-28 23:46:02 -03:00
Kayne Ruse 0da5201829 Merge pull request #114 from hiperiondev/main
Correct disassembler
2023-08-24 21:43:15 +10:00
hiperiondev 6be29ed8c5 Add implicit fn return 2023-08-23 20:48:06 -03:00
hiperiondev 6341d3337f Correct disassembler 2023-08-23 12:37:28 -03:00
Kayne Ruse d4f952eafc Merge pull request #110 from hiperiondev/main
Add disassembler alternative format
2023-08-23 22:09:33 +10:00
hiperiondev d5bc07d3b3 Add header reference 2023-08-23 08:36:27 -03:00
hiperiondev 5a851f6fbe Rename 2023-08-22 20:35:22 -03:00
hiperiondev d8c6a3ec27 Correct memory leak 2023-08-22 20:21:43 -03:00
hiperiondev b5883e248b Correct format 2023-08-22 19:45:14 -03:00
hiperiondev 52048f2466 Correct literal format 2023-08-22 19:31:06 -03:00
hiperiondev 6b8e95d250 Add disassembler alternative format 2023-08-22 18:23:27 -03:00
Ratstail91 5721edc2d1 Tweaked disassembler pretty printing, because I'm bored 2023-08-22 07:27:36 +10:00
Ratstail91 db52c13613 Removed extra scope around for loop body blocks, resolved #107 2023-08-22 01:11:49 +10:00
Ratstail91 7290efe069 Tweaked valgrind test
@add00 you'll want to merge these and test them
2023-08-22 00:43:48 +10:00
Ratstail91 0cf92bdeae Added contributors to the README, removed a binary that was accidentally committed 2023-08-19 06:53:34 +10:00
Kayne Ruse 4c9a2e5378 Merge pull request #106 from hiperiondev/main
Disassembler: Some optimizations
2023-08-15 03:57:29 +10:00
hiperiondev 1e11e9eea7 Start independent code from PC zero. Add hierarchical notation for function index. Add guard for end literals. Some presentation formats. 2023-08-14 14:46:07 -03:00
Kayne Ruse cce8ae1ea3 Added disassembler, thanks @hiperiondev, bumped minor version 2023-08-14 23:06:05 +10:00
Kayne Ruse ce54912232 Removed an extra pair of SCOPE_BEGIN and SCOPE_END from function bytecode
This should reduce the memory footprint a bit
2023-08-14 22:17:33 +10:00
Kayne Ruse 23b55fc360 Fixed execFnDecl accidentally modifying the literalCache for a moment, resolved #105 2023-08-14 10:47:10 +10:00
Kayne Ruse 62fe86f99b Fixed indexing in argument lists, resolved #102 2023-08-09 02:25:07 +10:00
Ratstail91 401de578a5 Short circuitable operators are extremely loose 2023-08-06 04:53:46 +10:00
Kayne Ruse fb4258f9df Fixed broken test 2023-08-06 04:38:55 +10:00
Ratstail91 f885fdaf4c Short circuits are now functioning correctly, resolved #73 2023-08-06 04:28:02 +10:00
Kayne Ruse cfec1b6911 Added int to float coercions to function args and returns, when specified 2023-08-06 02:17:32 +10:00
Kayne Ruse a63bdaef1c Merge remote-tracking branch 'refs/remotes/origin/main' 2023-08-04 18:43:32 +10:00
Kayne Ruse 3783c94064 Allow trailing commas when writing a compound 2023-08-04 18:43:07 +10:00
Ratstail91 d292b33184 Tweaked types to stop MSVC complaining 2023-08-04 18:24:54 +10:00
Kayne Ruse 64944c24f6 Snipped some duplicate code, resolved #97 2023-08-04 14:52:01 +10:00
Kayne Ruse 604604e8bc Two opcodes weren't being used, resolved #98 2023-08-04 14:51:08 +10:00
Kayne Ruse 67e49b7477 Fixed the way an identifier was handled, resolved #99 2023-08-04 14:45:07 +10:00
Kayne Ruse 967963c9d7 Fixed a spelling mistake 2023-08-03 15:22:06 +10:00
Kayne Ruse 9b469e6eb0 Merge pull request #94 from Add00/main
Adding a math library to toy
2023-08-03 01:40:19 +10:00
Add00 f8094fa17e Added hyperbolic and additional comparisons 2023-08-02 11:25:27 -04:00
Add00 8714c56c3e Implemented feedback 2023-08-02 08:39:50 -04:00
Add00 9faaa311e0 Fixed Memory Leak 2023-08-01 17:50:20 -04:00
Add00 f5ba1181c0 Added arc versions of trigonometric functions 2023-08-01 13:41:55 -04:00
Add00 b06b2d9485 test cases and additional functions 2023-08-01 09:04:37 -04:00
Add00 e3e9ca7ece Added math library 2023-07-31 23:31:12 -04:00
Add00 81fe278c96 Added partial cos and sine implementations 2023-07-31 19:02:55 -04:00
Add00 027d093e21 Added math constants for pi and e 2023-07-31 13:56:06 -04:00
Add00 2eaf7fc71a Merge branch 'main' of https://github.com/Add00/Toy 2023-07-31 13:16:01 -04:00
Add00 c43310f316 Code clean up 2023-07-31 13:13:10 -04:00
Add00 6e07c5f2f4 Merge branch 'Ratstail91:main' into main 2023-07-31 13:11:06 -04:00
Ratstail91 7690dce3f6 Fixed casting and grouping 2023-07-31 17:26:07 +10:00
Ratstail91 1ed1993489 Whoops, lets try that again. 2023-07-31 16:55:27 +10:00
Ratstail91 9b5327b83d Merge bug 2023-07-31 16:22:04 +10:00
Ratstail91 10dbe8f8f1 Fixed casting + grouping, resolved #67 2023-07-31 16:20:45 +10:00
Ratstail91 9e4ad7a9a5 Fixed casting + grouping, resolved #67 2023-07-31 16:17:33 +10:00
Add00 5317a12383 Added radian and degree conversion functions. 2023-07-30 23:17:43 -04:00
Ratstail91 35bfa1b9f1 Tweak, these were annoying me 2023-07-31 12:06:04 +10:00
Kayne Ruse 7f692b4cb4 Renamed the about library to toy_version_info library, resovled #81 2023-07-31 11:15:10 +10:00
Kayne Ruse 0cef0abdb5 Adjusted the layout of nativeClamp() and nativeLerp(), thanks Add00! 2023-07-31 04:51:40 +10:00
Kayne Ruse 6ba42b5a9b Merge pull request #93 from Add00/main
Adding clamp and lerp functions to standard library
2023-07-31 04:12:15 +10:00
Add00 3cb62274c9 Fixed merge issue 2023-07-30 13:21:42 -04:00
Add00 60b561d809 Merge branch 'Ratstail91:main' into main 2023-07-30 13:16:57 -04:00
Add00 70b2dcd829 Added clamp and lerp functions to standard library 2023-07-30 13:15:39 -04:00
Ratstail91 0955b3ff38 Tweak to the MSVC build 2023-07-31 02:04:27 +10:00
Kayne Ruse 4137935468 Added sign() and normalize() to standard lib 2023-07-30 17:46:00 +10:00
Kayne Ruse ebeabcb9d4 Reordered some functions for clarity, caught a bug or two 2023-07-28 02:42:57 +10:00
Kayne Ruse 4d33a9473a Added tools/changing-of-the-guard.cpp, resolved #89
A present for @hyperiondev - just run this in the 'includes/' directory.

It's easier than changing things by hand.
2023-07-28 01:09:58 +10:00
Kayne Ruse 61e3cdba82 Fixed a potential linker issue 2023-07-26 08:13:05 +10:00
Ratstail91 3b7d2be87e Discovered and fixed a misplaced macro 2023-07-26 01:44:15 +10:00
Kayne Ruse fa175203c9 Tweaked docs 2023-07-26 01:08:54 +10:00
Kayne Ruse b4a3e9b42b Renamed drive system files, see #88 2023-07-26 00:53:41 +10:00
Kayne Ruse 6347778ead Moved drive system to repl, resolved #88 2023-07-26 00:46:47 +10:00
57 changed files with 4491 additions and 689 deletions
@@ -1,17 +1,26 @@
name: Comprehensive Tests
name: Continuous Integration v1.x
#trigger when these occur
on:
push:
branches: [ "main", "dev" ]
branches:
- v1
pull_request:
branches: [ "main" ]
types:
- opened
- edited
- reopened
branches:
- v1
workflow_dispatch:
#testing the CI workflows under multiple supported conditions
jobs:
test-valgrind:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: install valgrind
run: sudo apt install valgrind
- name: make test (valgrind)
@@ -21,7 +30,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: make test (sanitized)
run: make test-sanitized
@@ -29,6 +38,6 @@ jobs:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: make test (mingw32)
run: make test
+56 -32
View File
@@ -1,35 +1,59 @@
#Editor generated files
*.suo
*.ncb
*.user
compile_commands.json
# Prerequisites
*.d
#Directories
Release/
Debug/
Out/
release/
debug/
out/
bin/
.cache/
.vs/
#Project generated files
*.db
# Object files
*.o
*.a
*.so
*.dll
*.exe
*.meta
*.log
*.out
*.stackdump
*.tb
*.filters
[Dd]ocs/
*.ko
*.obj
*.elf
#Shell files
*.bat
*.sh
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
.cproject
.project
.settings/
temp/
Release/
out/
+1 -1
View File
@@ -1,6 +1,6 @@
# License
Copyright (c) 2020-2023 Kayne Ruse, KR Game Studios
Copyright (c) 2020-2024 Kayne Ruse, KR Game Studios
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
+12 -2
View File
@@ -2,7 +2,7 @@
<image src="toylogo.png" />
</p>
# Toy
# Toy v1
The Toy programming language is an imperative bytecode-intermediate embedded scripting language. It isn't intended to operate on its own, but rather as part of another program, the "host". This process is intended to allow a decent amount of easy customisation by the host's end user, by exposing logic in script files. Alternatively, binary files in a custom format can be used as well.
@@ -35,6 +35,8 @@ Run `make install-tools` to install a number of tools, including:
* VSCode syntax highlighting
Other tools such as a disassembler are available, as well - simply run `make` in the correct directory.
## Syntax
```
@@ -69,8 +71,16 @@ print tally(); //3
This source code is covered by the zlib license (see [LICENSE.md](LICENSE.md)).
# Contributions
@hiperiondev - Disassembler, porting support and feedback
@add00 - Library support
@gruelingpine185 - Unofficial MacOS support
@solar-mist - Minor bugfixes
Unnamed Individuals - Feedback
# Patrons via Patreon
* Seth A. Robinson
Special thanks to http://craftinginterpreters.com/ for their fantastic book that set me on this path.
Special thanks to http://craftinginterpreters.com/ for their fantastic book that set me on this path.
+25 -21
View File
@@ -71,12 +71,12 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IgnoreImportLibrary>false</IgnoreImportLibrary>
<OutDir>$(SolutionDir)out\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
<OutDir>$(SolutionDir)out\</OutDir>
<IntDir>$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(SolutionDir)out\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
<OutDir>$(SolutionDir)out\</OutDir>
<IntDir>$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
@@ -110,7 +110,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Link>
<AdditionalDependencies>Toy.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)out\$(Configuration)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>$(SolutionDir)out</AdditionalLibraryDirectories>
</Link>
<ClCompile>
<AdditionalIncludeDirectories>$(SolutionDir)/source;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@@ -125,30 +125,34 @@
<AdditionalIncludeDirectories>$(SolutionDir)/source;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>$(SolutionDir)out\$(Configuration)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>$(SolutionDir)out</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>
<ItemGroup>
<ClCompile Include="repl\drive_system.c" />
<ClCompile Include="repl\lib_math.c" />
<ClCompile Include="repl\lib_random.c" />
<ClCompile Include="repl\lib_runner.c" />
<ClCompile Include="repl\lib_standard.c" />
<ClCompile Include="repl\lib_toy_version_info.c" />
<ClCompile Include="repl\repl_main.c" />
<ClCompile Include="repl\repl_tools.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="repl\drive_system.h" />
<ClInclude Include="repl\lib_math.h" />
<ClInclude Include="repl\lib_random.h" />
<ClInclude Include="repl\lib_runner.h" />
<ClInclude Include="repl\lib_standard.h" />
<ClInclude Include="repl\lib_toy_version_info.h" />
<ClInclude Include="repl\repl_tools.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
+6 -10
View File
@@ -71,12 +71,12 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>$(SolutionDir)out\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
<IntDir>$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(SolutionDir)out\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
<IntDir>$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
@@ -114,9 +114,8 @@
<LanguageStandard_C>stdc17</LanguageStandard_C>
</ClCompile>
<PostBuildEvent>
<Command>del "$(OutDir)$(ProjectName).exp"
del "$(OutDir)$(ProjectName).pdb"
</Command>
<Command>
</Command>
</PostBuildEvent>
<Link>
<OutputFile>$(Outdir)$(TargetName)$(TargetExt)</OutputFile>
@@ -131,9 +130,8 @@ del "$(OutDir)$(ProjectName).pdb"
<PreprocessorDefinitions>TOY_EXPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<PostBuildEvent>
<Command>del "$(OutDir)$(ProjectName).exp"
del "$(OutDir)$(ProjectName).pdb"
</Command>
<Command>
</Command>
</PostBuildEvent>
<Link>
<OutputFile>$(Outdir)$(TargetName)$(TargetExt)</OutputFile>
@@ -147,7 +145,6 @@ del "$(OutDir)$(ProjectName).pdb"
<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" />
@@ -167,7 +164,6 @@ del "$(OutDir)$(ProjectName).pdb"
<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" />
@@ -1,4 +1,4 @@
#include "toy_drive_system.h"
#include "drive_system.h"
#include "toy_memory.h"
#include "toy_literal_dictionary.h"
@@ -18,7 +18,7 @@ void Toy_freeDriveSystem() {
Toy_freeLiteralDictionary(&driveDictionary);
}
TOY_API void Toy_setDrivePath(char* drive, char* path) {
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));
@@ -1,14 +1,14 @@
#pragma once
/*!
# toy_drive_system.h
# drive_system.h
When accessing the file system through toy (such as with the runner library), it's best practice to utilize Toy's built-in drive system - this system (tries to) prevent malicious accessing of files outside of the designated folders. It does this by causing an error when a script tries to access a parent directory.
When accessing the file system through Toy (such as with the runner library), it's best practice to utilize the drive system - this system (tries to) prevent malicious accessing of files outside of the designated folders. It does this by causing an error when a script tries to access a parent directory.
To use the drive system, first you must designate specific folders which can be accessed, like so:
```c
#include "toy_drive_system.h"
#include "drive_system.h"
int main(int argc, char* argv[]) {
//the drive system uses a LiteralDictionary, which must be initialized with this
-5
View File
@@ -1,5 +0,0 @@
#pragma once
#include "toy_interpreter.h"
int Toy_hookAbout(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
+1152
View File
File diff suppressed because it is too large Load Diff
+5
View File
@@ -0,0 +1,5 @@
#pragma once
#include "toy_interpreter.h"
int Toy_hookMath(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
+1 -1
View File
@@ -1,10 +1,10 @@
#include "lib_runner.h"
#include "toy_memory.h"
#include "toy_drive_system.h"
#include "toy_interpreter.h"
#include "repl_tools.h"
#include "drive_system.h"
#include <stdlib.h>
+264 -113
View File
@@ -47,11 +47,6 @@ static int nativeHash(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
Toy_freeLiteral(selfLiteralIdn);
}
if (TOY_IS_IDENTIFIER(selfLiteral)) {
Toy_freeLiteral(selfLiteral);
return -1;
}
Toy_Literal result = TOY_TO_INTEGER_LITERAL(Toy_hashLiteral(selfLiteral));
Toy_pushLiteralArray(&interpreter->stack, result);
@@ -77,11 +72,6 @@ static int nativeAbs(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
Toy_freeLiteral(selfLiteralIdn);
}
if (TOY_IS_IDENTIFIER(selfLiteral)) {
Toy_freeLiteral(selfLiteral);
return -1;
}
if (!(TOY_IS_INTEGER(selfLiteral) || TOY_IS_FLOAT(selfLiteral))) {
interpreter->errorOutput("Incorrect argument type passed to abs\n");
Toy_freeLiteral(selfLiteral);
@@ -120,11 +110,6 @@ static int nativeCeil(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
Toy_freeLiteral(selfLiteralIdn);
}
if (TOY_IS_IDENTIFIER(selfLiteral)) {
Toy_freeLiteral(selfLiteral);
return -1;
}
if (!(TOY_IS_INTEGER(selfLiteral) || TOY_IS_FLOAT(selfLiteral))) {
interpreter->errorOutput("Incorrect argument type passed to ceil\n");
Toy_freeLiteral(selfLiteral);
@@ -164,11 +149,6 @@ static int nativeFloor(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments
Toy_freeLiteral(selfLiteralIdn);
}
if (TOY_IS_IDENTIFIER(selfLiteral)) {
Toy_freeLiteral(selfLiteral);
return -1;
}
if (!(TOY_IS_INTEGER(selfLiteral) || TOY_IS_FLOAT(selfLiteral))) {
interpreter->errorOutput("Incorrect argument type passed to floor\n");
Toy_freeLiteral(selfLiteral);
@@ -208,11 +188,6 @@ static int nativeMax(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
Toy_freeLiteral(selfLiteralIdn);
}
if (TOY_IS_IDENTIFIER(selfLiteral)) {
Toy_freeLiteral(selfLiteral);
return -1;
}
if (!(TOY_IS_INTEGER(selfLiteral) || TOY_IS_FLOAT(selfLiteral))) {
interpreter->errorOutput("Incorrect argument type passed to max\n");
Toy_freeLiteral(selfLiteral);
@@ -227,11 +202,11 @@ static int nativeMax(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
//cooerce if needed
if (TOY_IS_INTEGER(resultLiteral) && TOY_IS_FLOAT(selfLiteral)) {
resultLiteral = TOY_TO_FLOAT_LITERAL( TOY_AS_INTEGER(resultLiteral) );
resultLiteral = TOY_TO_FLOAT_LITERAL( (float)TOY_AS_INTEGER(resultLiteral) );
}
if (TOY_IS_FLOAT(resultLiteral) && TOY_IS_INTEGER(selfLiteral)) {
selfLiteral = TOY_TO_FLOAT_LITERAL( TOY_AS_INTEGER(selfLiteral) );
selfLiteral = TOY_TO_FLOAT_LITERAL( (float)TOY_AS_INTEGER(selfLiteral) );
}
//compare
@@ -269,11 +244,6 @@ static int nativeMin(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
Toy_freeLiteral(selfLiteralIdn);
}
if (TOY_IS_IDENTIFIER(selfLiteral)) {
Toy_freeLiteral(selfLiteral);
return -1;
}
if (!(TOY_IS_INTEGER(selfLiteral) || TOY_IS_FLOAT(selfLiteral))) {
interpreter->errorOutput("Incorrect argument type passed to min\n");
Toy_freeLiteral(selfLiteral);
@@ -288,11 +258,11 @@ static int nativeMin(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
//cooerce if needed
if (TOY_IS_INTEGER(resultLiteral) && TOY_IS_FLOAT(selfLiteral)) {
resultLiteral = TOY_TO_FLOAT_LITERAL( TOY_AS_INTEGER(resultLiteral) );
resultLiteral = TOY_TO_FLOAT_LITERAL( (float)TOY_AS_INTEGER(resultLiteral) );
}
if (TOY_IS_FLOAT(resultLiteral) && TOY_IS_INTEGER(selfLiteral)) {
selfLiteral = TOY_TO_FLOAT_LITERAL( TOY_AS_INTEGER(selfLiteral) );
selfLiteral = TOY_TO_FLOAT_LITERAL( (float)TOY_AS_INTEGER(selfLiteral) );
}
//compare
@@ -330,11 +300,6 @@ static int nativeRound(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments
Toy_freeLiteral(selfLiteralIdn);
}
if (TOY_IS_IDENTIFIER(selfLiteral)) {
Toy_freeLiteral(selfLiteral);
return -1;
}
if (!(TOY_IS_INTEGER(selfLiteral) || TOY_IS_FLOAT(selfLiteral))) {
interpreter->errorOutput("Incorrect argument type passed to round\n");
Toy_freeLiteral(selfLiteral);
@@ -365,6 +330,259 @@ static int nativeRound(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments
return 1;
}
static int nativeSign(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to sign\n");
return -1;
}
//get the self
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
//parse to value if needed
Toy_Literal selfLiteralIdn = selfLiteral;
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
Toy_freeLiteral(selfLiteralIdn);
}
if (!(TOY_IS_INTEGER(selfLiteral) || TOY_IS_FLOAT(selfLiteral))) {
interpreter->errorOutput("Incorrect argument type passed to sign\n");
Toy_freeLiteral(selfLiteral);
return -1;
}
Toy_Literal resultLiteral = TOY_TO_NULL_LITERAL;
if (TOY_IS_INTEGER(selfLiteral)) {
if (TOY_AS_INTEGER(selfLiteral) < 0) {
resultLiteral = TOY_TO_INTEGER_LITERAL(-1);
}
else {
resultLiteral = TOY_TO_INTEGER_LITERAL(1);
}
}
if (TOY_IS_FLOAT(selfLiteral)) {
if (TOY_AS_FLOAT(selfLiteral) < 0) {
resultLiteral = TOY_TO_INTEGER_LITERAL(-1);
}
else {
resultLiteral = TOY_TO_INTEGER_LITERAL(1);
}
}
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
Toy_freeLiteral(resultLiteral);
Toy_freeLiteral(selfLiteral);
return 1;
}
static int nativeNormalize(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//NOTE: this is identical to `sign`, except it returns 0 when the argument is 0.
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to normalize\n");
return -1;
}
//get the self
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
//parse to value if needed
Toy_Literal selfLiteralIdn = selfLiteral;
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
Toy_freeLiteral(selfLiteralIdn);
}
if (!(TOY_IS_INTEGER(selfLiteral) || TOY_IS_FLOAT(selfLiteral))) {
interpreter->errorOutput("Incorrect argument type passed to normalize\n");
Toy_freeLiteral(selfLiteral);
return -1;
}
Toy_Literal resultLiteral = TOY_TO_NULL_LITERAL;
if (TOY_IS_INTEGER(selfLiteral)) {
if (TOY_AS_INTEGER(selfLiteral) < 0) {
resultLiteral = TOY_TO_INTEGER_LITERAL(-1);
}
else if (TOY_AS_INTEGER(selfLiteral) > 0) {
resultLiteral = TOY_TO_INTEGER_LITERAL(1);
}
else {
resultLiteral = TOY_TO_INTEGER_LITERAL(0);
}
}
if (TOY_IS_FLOAT(selfLiteral)) {
if (TOY_AS_FLOAT(selfLiteral) < 0) {
resultLiteral = TOY_TO_INTEGER_LITERAL(-1);
}
else if (TOY_AS_FLOAT(selfLiteral) > 0) {
resultLiteral = TOY_TO_INTEGER_LITERAL(1);
}
else {
resultLiteral = TOY_TO_INTEGER_LITERAL(0);
}
}
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
Toy_freeLiteral(resultLiteral);
Toy_freeLiteral(selfLiteral);
return 1;
}
static int nativeClamp(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 3) {
interpreter->errorOutput("Incorrect number of arguments to clamp\n");
return -1;
}
//get the arguments
Toy_Literal maxLiteral = Toy_popLiteralArray(arguments);
Toy_Literal minLiteral = Toy_popLiteralArray(arguments);
Toy_Literal valueLiteral = Toy_popLiteralArray(arguments);
//parse the arguments (if they're identifiers)
Toy_Literal valueLiteralIdn = valueLiteral;
if (TOY_IS_IDENTIFIER(valueLiteral) && Toy_parseIdentifierToValue(interpreter, &valueLiteral)) {
Toy_freeLiteral(valueLiteralIdn);
}
Toy_Literal minLiteralIdn = minLiteral;
if (TOY_IS_IDENTIFIER(minLiteral) && Toy_parseIdentifierToValue(interpreter, &minLiteral)) {
Toy_freeLiteral(minLiteralIdn);
}
Toy_Literal maxLiteralIdn = maxLiteral;
if (TOY_IS_IDENTIFIER(maxLiteral) && Toy_parseIdentifierToValue(interpreter, &maxLiteral)) {
Toy_freeLiteral(maxLiteralIdn);
}
//check the types
if (!(TOY_IS_INTEGER(valueLiteral) || TOY_IS_FLOAT(valueLiteral))) {
interpreter->errorOutput("Incorrect argument type passed to clamp\n");
Toy_freeLiteral(valueLiteral);
Toy_freeLiteral(minLiteral);
Toy_freeLiteral(maxLiteral);
return -1;
}
if (!(TOY_IS_INTEGER(minLiteral) || TOY_IS_FLOAT(minLiteral))) {
interpreter->errorOutput("Incorrect argument type passed to clamp\n");
Toy_freeLiteral(valueLiteral);
Toy_freeLiteral(minLiteral);
Toy_freeLiteral(maxLiteral);
return -1;
}
if (!(TOY_IS_INTEGER(maxLiteral) || TOY_IS_FLOAT(maxLiteral))) {
interpreter->errorOutput("Incorrect argument type passed to clamp\n");
Toy_freeLiteral(valueLiteral);
Toy_freeLiteral(minLiteral);
Toy_freeLiteral(maxLiteral);
return -1;
}
// cast ints to floats to handle all types of numbers
float value = TOY_IS_INTEGER(valueLiteral)? TOY_AS_INTEGER(valueLiteral) : TOY_AS_FLOAT(valueLiteral);
float min = TOY_IS_INTEGER(minLiteral)? TOY_AS_INTEGER(minLiteral) : TOY_AS_FLOAT(minLiteral);
float max = TOY_IS_INTEGER(maxLiteral)? TOY_AS_INTEGER(maxLiteral) : TOY_AS_FLOAT(maxLiteral);
//determine which literal to return (this way, we retain the original type)
if (min > value) {
Toy_pushLiteralArray(&interpreter->stack, minLiteral);
}
else if (max < value) {
Toy_pushLiteralArray(&interpreter->stack, maxLiteral);
}
else {
Toy_pushLiteralArray(&interpreter->stack, valueLiteral);
}
Toy_freeLiteral(valueLiteral);
Toy_freeLiteral(minLiteral);
Toy_freeLiteral(maxLiteral);
return 1;
}
static int nativeLerp(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 3) {
interpreter->errorOutput("Incorrect number of arguments to lerp\n");
return -1;
}
//get the arguments
Toy_Literal amountLiteral = Toy_popLiteralArray(arguments);
Toy_Literal endLiteral = Toy_popLiteralArray(arguments);
Toy_Literal startLiteral = Toy_popLiteralArray(arguments);
//parse the arguments (if they're identifiers)
Toy_Literal startLiteralIdn = startLiteral;
if (TOY_IS_IDENTIFIER(startLiteral) && Toy_parseIdentifierToValue(interpreter, &startLiteral)) {
Toy_freeLiteral(startLiteralIdn);
}
Toy_Literal endLiteralIdn = endLiteral;
if (TOY_IS_IDENTIFIER(endLiteral) && Toy_parseIdentifierToValue(interpreter, &endLiteral)) {
Toy_freeLiteral(endLiteralIdn);
}
Toy_Literal amountLiteralIdn = amountLiteral;
if (TOY_IS_IDENTIFIER(amountLiteral) && Toy_parseIdentifierToValue(interpreter, &amountLiteral)) {
Toy_freeLiteral(amountLiteralIdn);
}
//check the argument types
if (!(TOY_IS_INTEGER(startLiteral) || TOY_IS_FLOAT(startLiteral))) {
interpreter->errorOutput("Incorrect argument type passed to lerp\n");
Toy_freeLiteral(startLiteral);
Toy_freeLiteral(endLiteral);
Toy_freeLiteral(amountLiteral);
return -1;
}
if (!(TOY_IS_INTEGER(endLiteral) || TOY_IS_FLOAT(endLiteral))) {
interpreter->errorOutput("Incorrect argument type passed to lerp\n");
Toy_freeLiteral(startLiteral);
Toy_freeLiteral(endLiteral);
Toy_freeLiteral(amountLiteral);
return -1;
}
if (!(TOY_IS_INTEGER(amountLiteral) || TOY_IS_FLOAT(amountLiteral))) {
interpreter->errorOutput("Incorrect argument type passed to lerp\n");
Toy_freeLiteral(startLiteral);
Toy_freeLiteral(endLiteral);
Toy_freeLiteral(amountLiteral);
return -1;
}
// cast ints to floats to handle all types of numbers
float start = TOY_IS_INTEGER(startLiteral)? TOY_AS_INTEGER(startLiteral) : TOY_AS_FLOAT(startLiteral);
float end = TOY_IS_INTEGER(endLiteral)? TOY_AS_INTEGER(endLiteral) : TOY_AS_FLOAT(endLiteral);
float amount = TOY_IS_INTEGER(amountLiteral)? TOY_AS_INTEGER(amountLiteral) : TOY_AS_FLOAT(amountLiteral);
//calculate the result
float result = start + amount * (end - start);
//return the result
Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result);
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
//cleanup
Toy_freeLiteral(resultLiteral);
Toy_freeLiteral(startLiteral);
Toy_freeLiteral(endLiteral);
Toy_freeLiteral(amountLiteral);
return 1;
}
static int nativeConcat(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 2) {
@@ -387,12 +605,6 @@ static int nativeConcat(Toy_Interpreter* interpreter, Toy_LiteralArray* argument
Toy_freeLiteral(otherLiteralIdn);
}
if (TOY_IS_IDENTIFIER(selfLiteral) || TOY_IS_IDENTIFIER(otherLiteral)) {
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(otherLiteral);
return -1;
}
//for each self type
if (TOY_IS_ARRAY(selfLiteral)) {
if (!TOY_IS_ARRAY(otherLiteral)) {
@@ -449,7 +661,7 @@ static int nativeConcat(Toy_Interpreter* interpreter, Toy_LiteralArray* argument
}
//get the combined length for the new string
size_t length = TOY_AS_STRING(selfLiteral)->length + TOY_AS_STRING(otherLiteral)->length + 1;
size_t length = TOY_AS_STRING(selfLiteral)->length + TOY_AS_STRING(otherLiteral)->length;
if (length > TOY_MAX_STRING_LENGTH) {
interpreter->errorOutput("Can't concatenate these strings, result is too long (error found in concat)\n");
@@ -459,8 +671,8 @@ static int nativeConcat(Toy_Interpreter* interpreter, Toy_LiteralArray* argument
}
//allocate the space and generate
char* buffer = TOY_ALLOCATE(char, length);
snprintf(buffer, length, "%s%s", Toy_toCString(TOY_AS_STRING(selfLiteral)), Toy_toCString(TOY_AS_STRING(otherLiteral)));
char* buffer = TOY_ALLOCATE(char, length + 1);
snprintf(buffer, length + 1, "%s%s", Toy_toCString(TOY_AS_STRING(selfLiteral)), Toy_toCString(TOY_AS_STRING(otherLiteral)));
Toy_Literal result = TOY_TO_STRING_LITERAL(Toy_createRefString(buffer));
@@ -503,12 +715,6 @@ static int nativeContainsKey(Toy_Interpreter* interpreter, Toy_LiteralArray* arg
Toy_freeLiteral(keyLiteralIdn);
}
if (TOY_IS_IDENTIFIER(selfLiteral) || TOY_IS_IDENTIFIER(keyLiteral)) {
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(keyLiteral);
return -1;
}
//check type
if (!(/* TOY_IS_ARRAY(selfLiteral) || */ TOY_IS_DICTIONARY(selfLiteral) )) {
interpreter->errorOutput("Incorrect argument type passed to containsKey\n");
@@ -554,12 +760,6 @@ static int nativeContainsValue(Toy_Interpreter* interpreter, Toy_LiteralArray* a
Toy_freeLiteral(valueLiteralIdn);
}
if (TOY_IS_IDENTIFIER(selfLiteral) || TOY_IS_IDENTIFIER(valueLiteral)) {
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(valueLiteral);
return -1;
}
//check type
if (!( TOY_IS_ARRAY(selfLiteral) || TOY_IS_DICTIONARY(selfLiteral) )) {
interpreter->errorOutput("Incorrect argument type passed to containsValue\n");
@@ -630,12 +830,6 @@ static int nativeEvery(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments
Toy_freeLiteral(fnLiteralIdn);
}
if (TOY_IS_IDENTIFIER(selfLiteral) || TOY_IS_IDENTIFIER(fnLiteral)) {
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(fnLiteral);
return -1;
}
//check type
if (!( TOY_IS_ARRAY(selfLiteral) || TOY_IS_DICTIONARY(selfLiteral) ) || !( TOY_IS_FUNCTION(fnLiteral) || TOY_IS_FUNCTION_NATIVE(fnLiteral) )) {
interpreter->errorOutput("Incorrect argument type passed to every\n");
@@ -752,12 +946,6 @@ static int nativeFilter(Toy_Interpreter* interpreter, Toy_LiteralArray* argument
Toy_freeLiteral(fnLiteralIdn);
}
if (TOY_IS_IDENTIFIER(selfLiteral) || TOY_IS_IDENTIFIER(fnLiteral)) {
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(fnLiteral);
return -1;
}
//check type
if (!( TOY_IS_ARRAY(selfLiteral) || TOY_IS_DICTIONARY(selfLiteral) ) || !( TOY_IS_FUNCTION(fnLiteral) || TOY_IS_FUNCTION_NATIVE(fnLiteral) )) {
interpreter->errorOutput("Incorrect argument type passed to filter\n");
@@ -872,12 +1060,6 @@ static int nativeForEach(Toy_Interpreter* interpreter, Toy_LiteralArray* argumen
Toy_freeLiteral(fnLiteralIdn);
}
if (TOY_IS_IDENTIFIER(selfLiteral) || TOY_IS_IDENTIFIER(fnLiteral)) {
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(fnLiteral);
return -1;
}
//check type
if (!( TOY_IS_ARRAY(selfLiteral) || TOY_IS_DICTIONARY(selfLiteral) ) || !( TOY_IS_FUNCTION(fnLiteral) || TOY_IS_FUNCTION_NATIVE(fnLiteral) )) {
interpreter->errorOutput("Incorrect argument type passed to forEach\n");
@@ -950,11 +1132,6 @@ static int nativeGetKeys(Toy_Interpreter* interpreter, Toy_LiteralArray* argumen
Toy_freeLiteral(selfLiteralIdn);
}
if (TOY_IS_IDENTIFIER(selfLiteral)) {
Toy_freeLiteral(selfLiteral);
return -1;
}
//check type
if (!TOY_IS_DICTIONARY(selfLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to getKeys\n");
@@ -1000,11 +1177,6 @@ static int nativeGetValues(Toy_Interpreter* interpreter, Toy_LiteralArray* argum
Toy_freeLiteral(selfLiteralIdn);
}
if (TOY_IS_IDENTIFIER(selfLiteral)) {
Toy_freeLiteral(selfLiteral);
return -1;
}
//check type
if (!TOY_IS_DICTIONARY(selfLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to getValues\n");
@@ -1057,12 +1229,6 @@ static int nativeIndexOf(Toy_Interpreter* interpreter, Toy_LiteralArray* argumen
Toy_freeLiteral(valueLiteralIdn);
}
if (TOY_IS_IDENTIFIER(selfLiteral) || TOY_IS_IDENTIFIER(valueLiteral)) {
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(valueLiteral);
return -1;
}
//check type
if (!TOY_IS_ARRAY(selfLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to indexOf\n");
@@ -1110,12 +1276,6 @@ static int nativeMap(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
Toy_freeLiteral(fnLiteralIdn);
}
if (TOY_IS_IDENTIFIER(selfLiteral) || TOY_IS_IDENTIFIER(fnLiteral)) {
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(fnLiteral);
return -1;
}
//check type
if (!( TOY_IS_ARRAY(selfLiteral) || TOY_IS_DICTIONARY(selfLiteral) ) || !( TOY_IS_FUNCTION(fnLiteral) || TOY_IS_FUNCTION_NATIVE(fnLiteral) )) {
interpreter->errorOutput("Incorrect argument type passed to map\n");
@@ -1225,13 +1385,6 @@ static int nativeReduce(Toy_Interpreter* interpreter, Toy_LiteralArray* argument
Toy_freeLiteral(fnLiteralIdn);
}
if (TOY_IS_IDENTIFIER(selfLiteral) || TOY_IS_IDENTIFIER(defaultLiteral) || TOY_IS_IDENTIFIER(fnLiteral)) {
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(defaultLiteral);
Toy_freeLiteral(fnLiteral);
return -1;
}
//check type
if (!( TOY_IS_ARRAY(selfLiteral) || TOY_IS_DICTIONARY(selfLiteral) ) || !( TOY_IS_FUNCTION(fnLiteral) || TOY_IS_FUNCTION_NATIVE(fnLiteral) )) {
interpreter->errorOutput("Incorrect argument type passed to reduce\n");
@@ -1327,12 +1480,6 @@ static int nativeSome(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
Toy_freeLiteral(fnLiteralIdn);
}
if (TOY_IS_IDENTIFIER(selfLiteral) || TOY_IS_IDENTIFIER(fnLiteral)) {
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(fnLiteral);
return -1;
}
//check type
if (!( TOY_IS_ARRAY(selfLiteral) || TOY_IS_DICTIONARY(selfLiteral) ) || !( TOY_IS_FUNCTION(fnLiteral) || TOY_IS_FUNCTION_NATIVE(fnLiteral) )) {
interpreter->errorOutput("Incorrect argument type passed to some\n");
@@ -1997,6 +2144,10 @@ int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_L
{"max", nativeMax},
{"min", nativeMin},
{"round", nativeRound},
{"sign", nativeSign},
{"normalize", nativeNormalize},
{"clamp", nativeClamp},
{"lerp", nativeLerp},
//compound utils
{"concat", nativeConcat}, //array, dictionary, string
@@ -1,23 +1,23 @@
#include "lib_about.h"
#include "lib_toy_version_info.h"
#include "toy_memory.h"
int Toy_hookAbout(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
//the about keys
int Toy_hookToyVersionInfo(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
//the info 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
//the info 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
//the info 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);
+5
View File
@@ -0,0 +1,5 @@
#pragma once
#include "toy_interpreter.h"
int Toy_hookToyVersionInfo(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
+1 -1
View File
@@ -2,7 +2,7 @@ CC=gcc
IDIR+=. ../source
CFLAGS+=$(addprefix -I,$(IDIR)) -g -Wall -W -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable
LIBS+=-ltoy
LIBS+=-ltoy -lm
ODIR = obj
SRC = $(wildcard *.c)
+5 -2
View File
@@ -1,8 +1,10 @@
#include "repl_tools.h"
#include "lib_about.h"
#include "drive_system.h"
#include "lib_toy_version_info.h"
#include "lib_standard.h"
#include "lib_random.h"
#include "lib_runner.h"
#include "lib_math.h"
#include "toy_console_colors.h"
@@ -25,10 +27,11 @@ void repl(const char* initialInput) {
Toy_initInterpreter(&interpreter);
//inject the libs
Toy_injectNativeHook(&interpreter, "about", Toy_hookAbout);
Toy_injectNativeHook(&interpreter, "toy_version_info", Toy_hookToyVersionInfo);
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
Toy_injectNativeHook(&interpreter, "random", Toy_hookRandom);
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
Toy_injectNativeHook(&interpreter, "math", Toy_hookMath);
for(;;) {
if (!initialInput) {
+5 -3
View File
@@ -1,8 +1,9 @@
#include "repl_tools.h"
#include "lib_about.h"
#include "lib_toy_version_info.h"
#include "lib_standard.h"
#include "lib_random.h"
#include "lib_runner.h"
#include "lib_math.h"
#include "toy_console_colors.h"
@@ -111,10 +112,11 @@ void Toy_runBinary(const unsigned char* tb, size_t size) {
Toy_initInterpreter(&interpreter);
//inject the libs
Toy_injectNativeHook(&interpreter, "about", Toy_hookAbout);
Toy_injectNativeHook(&interpreter, "toy_version_info", Toy_hookToyVersionInfo);
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
Toy_injectNativeHook(&interpreter, "random", Toy_hookRandom);
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
Toy_injectNativeHook(&interpreter, "math", Toy_hookMath);
Toy_runInterpreter(&interpreter, tb, (int)size);
Toy_freeInterpreter(&interpreter);
@@ -159,7 +161,7 @@ static unsigned char readByte(const unsigned char* tb, int* count) {
static const char* readString(const unsigned char* tb, int* count) {
const unsigned char* ret = tb + *count;
*count += strlen((char*)ret) + 1; //+1 for null character
*count += (int)strlen((char*)ret) + 1; //+1 for null character
return (const char*)ret;
}
+1 -1
View File
@@ -46,7 +46,7 @@ const unsigned char* Toy_compileString(const char* source, size_t* size);
This function takes a bytecode array of `size` size, and executes it. The libraries available to the code are currently:
* lib_about
* lib_toy_version_info
* lib_standard
* lib_random
* lib_runner
+13
View File
@@ -0,0 +1,13 @@
fn f() {
//
}
fn g() {
fn i() {
//
}
}
fn h() {
//
}
+3 -3
View File
@@ -11,14 +11,14 @@ OBJ = $(addprefix $(ODIR)/,$(SRC:.c=.o))
OUTNAME=toy
ifeq ($(findstring CYGWIN, $(shell uname)),CYGWIN)
LIBLINE =-Wl,--out-implib=../$(TOY_OUTDIR)/lib$(OUTNAME).dll.a -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--whole-archive $(OBJ) -Wl,--no-whole-archive
LIBLINE=-Wl,-rpath,. -Wl,--out-implib=../$(TOY_OUTDIR)/lib$(OUTNAME).dll.a -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--whole-archive $(OBJ) -Wl,--no-whole-archive
OUT=../$(TOY_OUTDIR)/$(OUTNAME).dll
else ifeq ($(shell uname),Linux)
LIBLINE=-Wl,--out-implib=../$(TOY_OUTDIR)/lib$(OUTNAME).a -Wl,--whole-archive $(OBJ) -Wl,--no-whole-archive
LIBLINE=-Wl,-rpath,. -Wl,--out-implib=../$(TOY_OUTDIR)/lib$(OUTNAME).a -Wl,--whole-archive $(OBJ) -Wl,--no-whole-archive
OUT=../$(TOY_OUTDIR)/lib$(OUTNAME).so
CFLAGS += -fPIC
else ifeq ($(OS),Windows_NT)
LIBLINE =-Wl,--out-implib=../$(TOY_OUTDIR)/lib$(OUTNAME).dll.a -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--whole-archive $(OBJ) -Wl,--no-whole-archive
LIBLINE=-Wl,-rpath,. -Wl,--out-implib=../$(TOY_OUTDIR)/lib$(OUTNAME).dll.a -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--whole-archive $(OBJ) -Wl,--no-whole-archive
OUT=../$(TOY_OUTDIR)/$(OUTNAME).dll
else ifeq ($(shell uname),Darwin)
LIBLINE = $(OBJ)
-2
View File
@@ -17,13 +17,11 @@ The most important macro is `TOY_API`, which specifies functions intended for th
* [toy_common.h](toy_common_h.md)
* [toy_console_colors.h](toy_console_colors_h.md)
* [toy_memory.h](toy_memory_h.md)
* [toy_drive_system.h](toy_drive_system_h.md)
!*/
#include "toy_common.h"
#include "toy_console_colors.h"
#include "toy_memory.h"
#include "toy_drive_system.h"
/*!
## Core Pipeline
+30
View File
@@ -124,6 +124,16 @@ static void freeASTNodeCustom(Toy_ASTNode* node, bool freeSelf) {
//NO-OP
break;
case TOY_AST_NODE_AND:
Toy_freeASTNode(node->pathAnd.left);
Toy_freeASTNode(node->pathAnd.right);
break;
case TOY_AST_NODE_OR:
Toy_freeASTNode(node->pathOr.left);
Toy_freeASTNode(node->pathOr.right);
break;
case TOY_AST_NODE_PREFIX_INCREMENT:
Toy_freeLiteral(node->prefixIncrement.identifier);
break;
@@ -348,6 +358,26 @@ void Toy_emitASTNodeContinue(Toy_ASTNode** nodeHandle) {
*nodeHandle = tmp;
}
void Toy_emitASTNodeAnd(Toy_ASTNode** nodeHandle, Toy_ASTNode* rhs) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
tmp->type = TOY_AST_NODE_AND;
tmp->pathAnd.left = *nodeHandle;
tmp->pathAnd.right = rhs;
*nodeHandle = tmp;
}
void Toy_emitASTNodeOr(Toy_ASTNode** nodeHandle, Toy_ASTNode* rhs) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
tmp->type = TOY_AST_NODE_OR;
tmp->pathOr.left = *nodeHandle;
tmp->pathOr.right = rhs;
*nodeHandle = tmp;
}
void Toy_emitASTNodePrefixIncrement(Toy_ASTNode** nodeHandle, Toy_Literal identifier) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
+22
View File
@@ -29,6 +29,8 @@ typedef enum Toy_ASTNodeType {
TOY_AST_NODE_FOR, //for control flow
TOY_AST_NODE_BREAK, //for control flow
TOY_AST_NODE_CONTINUE, //for control flow
TOY_AST_NODE_AND, //for control flow
TOY_AST_NODE_OR, //for control flow
TOY_AST_NODE_PREFIX_INCREMENT, //increment a variable
TOY_AST_NODE_POSTFIX_INCREMENT, //increment a variable
TOY_AST_NODE_PREFIX_DECREMENT, //decrement a variable
@@ -204,6 +206,24 @@ typedef struct Toy_NodeContinue {
Toy_ASTNodeType type;
} Toy_NodeContinue;
//and operator
void Toy_emitASTNodeAnd(Toy_ASTNode** nodeHandle, Toy_ASTNode* rhs); //handled node becomes lhs
typedef struct Toy_NodeAnd {
Toy_ASTNodeType type;
Toy_ASTNode* left;
Toy_ASTNode* right;
} Toy_NodeAnd;
//or operator
void Toy_emitASTNodeOr(Toy_ASTNode** nodeHandle, Toy_ASTNode* rhs); //handled node becomes lhs
typedef struct Toy_NodeOr {
Toy_ASTNodeType type;
Toy_ASTNode* left;
Toy_ASTNode* right;
} Toy_NodeOr;
//pre-post increment/decrement
void Toy_emitASTNodePrefixIncrement(Toy_ASTNode** nodeHandle, Toy_Literal identifier);
void Toy_emitASTNodePrefixDecrement(Toy_ASTNode** nodeHandle, Toy_Literal identifier);
@@ -263,6 +283,8 @@ union Toy_private_node {
Toy_NodeFor pathFor;
Toy_NodeBreak pathBreak;
Toy_NodeContinue pathContinue;
Toy_NodeAnd pathAnd;
Toy_NodeOr pathOr;
Toy_NodePrefixIncrement prefixIncrement;
Toy_NodePrefixDecrement prefixDecrement;
Toy_NodePostfixIncrement postfixIncrement;
+2 -2
View File
@@ -54,7 +54,7 @@ The current minor version of Toy. This value is embedded into the bytecode, and
This value MUST fit into an unsigned char.
!*/
#define TOY_VERSION_MINOR 2
#define TOY_VERSION_MINOR 3
/*!
### TOY_VERSION_PATCH
@@ -64,7 +64,7 @@ The current patch version of Toy. This value is embedded into the bytecode.
This value MUST fit into an unsigned char.
!*/
#define TOY_VERSION_PATCH 0
#define TOY_VERSION_PATCH 2
/*!
### TOY_VERSION_BUILD
+75 -11
View File
@@ -318,6 +318,12 @@ bool checkNodeInTree(Toy_ASTNode* tree, Toy_ASTNode* node) {
case TOY_AST_NODE_FOR:
return checkNodeInTree(tree->pathFor.preClause, node) || checkNodeInTree(tree->pathFor.condition, node) || checkNodeInTree(tree->pathFor.postClause, node) || checkNodeInTree(tree->pathFor.thenPath, node);
case TOY_AST_NODE_AND:
return checkNodeInTree(tree->pathAnd.left, node) || checkNodeInTree(tree->pathAnd.right, node);
case TOY_AST_NODE_OR:
return checkNodeInTree(tree->pathOr.left, node) || checkNodeInTree(tree->pathOr.right, node);
case TOY_AST_NODE_ERROR:
case TOY_AST_NODE_LITERAL:
case TOY_AST_NODE_BREAK:
@@ -429,8 +435,6 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
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;
@@ -583,9 +587,13 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
Toy_initCompiler(fnCompiler);
Toy_writeCompiler(fnCompiler, node->fnDecl.arguments); //can be empty, but not NULL
Toy_writeCompiler(fnCompiler, node->fnDecl.returns); //can be empty, but not NULL
Toy_Opcode override = Toy_writeCompilerWithJumps(fnCompiler, node->fnDecl.block, NULL, NULL, -4, rootNode); //can be empty, but not NULL
if (override != TOY_OP_EOF) {//compensate for indexing & dot notation being screwy
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
//BUGFIX: copied from TOY_AST_NODE_BLOCK, omitting the SCOPE_BEGIN and SCOPE_END opcodes (might squeeze a few bytes out of the interpreter's scopes by declaring one less)
for (int i = 0; i < node->fnDecl.block->block.count; i++) {
Toy_Opcode override = Toy_writeCompilerWithJumps(fnCompiler, &(node->fnDecl.block->block.nodes[i]), NULL, NULL, -4, &(node->fnDecl.block->block.nodes[i]));
if (override != TOY_OP_EOF) {//compensate for indexing & dot notation being screwy
fnCompiler->bytecode[fnCompiler->count++] = (unsigned char)override; //1 byte
}
}
//adopt the panic state if anything happened
@@ -645,7 +653,7 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
for (int i = 0; i < node->fnCall.arguments->fnCollection.count; i++) { //reverse order, to count from the beginning in the interpreter
//sub-calls
if (node->fnCall.arguments->fnCollection.nodes[i].type != TOY_AST_NODE_LITERAL) {
Toy_Opcode override = Toy_writeCompilerWithJumps(compiler, &node->fnCall.arguments->fnCollection.nodes[i], breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
Toy_Opcode override = Toy_writeCompilerWithJumps(compiler, &node->fnCall.arguments->fnCollection.nodes[i], breakAddressesPtr, continueAddressesPtr, jumpOffsets, node); //BUGFIX: use node as rootNode, to allow indexing within argument lists
if (override != TOY_OP_EOF) {//compensate for indexing & dot notation being screwy
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
}
@@ -833,12 +841,20 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
compiler->count += sizeof(unsigned short); //2 bytes
//write the body
compiler->bytecode[compiler->count++] = TOY_OP_SCOPE_BEGIN; //1 byte
bool closeScope = false;
if (node->pathFor.thenPath->type != TOY_AST_NODE_BLOCK) {
compiler->bytecode[compiler->count++] = TOY_OP_SCOPE_BEGIN; //1 byte
closeScope = true;
}
override = Toy_writeCompilerWithJumps(compiler, node->pathFor.thenPath, &breakAddresses, &continueAddresses, jumpOffsets, rootNode);
if (override != TOY_OP_EOF) {//compensate for indexing & dot notation being screwy
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
}
compiler->bytecode[compiler->count++] = TOY_OP_SCOPE_END; //1 byte
if (closeScope) {
compiler->bytecode[compiler->count++] = TOY_OP_SCOPE_END; //1 byte
}
//for-breaks actually jump to the bottom
int jumpToIncrement = compiler->count;
@@ -849,6 +865,9 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
}
//BUGFIX: clear the stack after each loop
compiler->bytecode[compiler->count++] = TOY_OP_POP_STACK; //1 byte
compiler->bytecode[compiler->count++] = TOY_OP_JUMP; //1 byte
unsigned short tmpVal = jumpToStart + jumpOffsets;
memcpy(compiler->bytecode + compiler->count, &tmpVal, sizeof(tmpVal));
@@ -872,9 +891,6 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
memcpy(compiler->bytecode + point, &tmpVal, sizeof(tmpVal));
}
//clear the stack after use
compiler->bytecode[compiler->count++] = TOY_OP_POP_STACK; //1 byte
//cleanup
Toy_freeLiteralArray(&breakAddresses);
Toy_freeLiteralArray(&continueAddresses);
@@ -917,6 +933,54 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
}
break;
case TOY_AST_NODE_AND: {
//process the lhs
Toy_Opcode override = Toy_writeCompilerWithJumps(compiler, node->pathAnd.left, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
if (override != TOY_OP_EOF) {//compensate for indexing & dot notation being screwy
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
}
//insert the AND opcode to signal a possible jump
compiler->bytecode[compiler->count++] = TOY_OP_AND; //1 byte
int jumpToEnd = compiler->count;
compiler->count += sizeof(unsigned short); //2 bytes
//process the rhs
override = Toy_writeCompilerWithJumps(compiler, node->pathAnd.right, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
if (override != TOY_OP_EOF) {//compensate for indexing & dot notation being screwy
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
}
//set the spot to jump to, to proceed
unsigned short tmpVal = compiler->count + jumpOffsets;
memcpy(compiler->bytecode + jumpToEnd, &tmpVal, sizeof(tmpVal));
}
break;
case TOY_AST_NODE_OR: {
//process the lhs
Toy_Opcode override = Toy_writeCompilerWithJumps(compiler, node->pathOr.left, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
if (override != TOY_OP_EOF) {//compensate for indexing & dot notation being screwy
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
}
//insert the AND opcode to signal a possible jump
compiler->bytecode[compiler->count++] = TOY_OP_OR; //1 byte
int jumpToEnd = compiler->count;
compiler->count += sizeof(unsigned short); //2 bytes
//process the rhs
override = Toy_writeCompilerWithJumps(compiler, node->pathOr.right, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
if (override != TOY_OP_EOF) {//compensate for indexing & dot notation being screwy
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
}
//set the spot to jump to, to proceed
unsigned short tmpVal = compiler->count + jumpOffsets;
memcpy(compiler->bytecode + jumpToEnd, &tmpVal, sizeof(tmpVal));
}
break;
case TOY_AST_NODE_FN_RETURN: {
//read each returned literal onto the stack, and return the number of values to return
for (int i = 0; i < node->returns.returns->fnCollection.count; i++) {
+449 -404
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -237,7 +237,7 @@ static Toy_Token makeKeywordOrIdentifier(Toy_Lexer* lexer) {
//scan for a keyword
for (int i = 0; Toy_keywordTypes[i].keyword; i++) {
if (strlen(Toy_keywordTypes[i].keyword) == (long unsigned int)(lexer->current - lexer->start) && !strncmp(Toy_keywordTypes[i].keyword, &lexer->source[lexer->start], lexer->current - lexer->start)) {
if (strlen(Toy_keywordTypes[i].keyword) == (size_t)(lexer->current - lexer->start) && !strncmp(Toy_keywordTypes[i].keyword, &lexer->source[lexer->start], lexer->current - lexer->start)) {
Toy_Token token;
token.type = Toy_keywordTypes[i].type;
@@ -317,10 +317,10 @@ Toy_Token Toy_private_scanLexer(Toy_Lexer* lexer) {
if (advance(lexer) != '&') {
return makeErrorToken(lexer, "Unexpected '&'");
} else {
return makeToken(lexer, TOY_TOKEN_AND);
return makeToken(lexer, TOY_TOKEN_AND_AND);
}
case '|': return makeToken(lexer, match(lexer, '|') ? TOY_TOKEN_OR : TOY_TOKEN_PIPE);
case '|': return makeToken(lexer, match(lexer, '|') ? TOY_TOKEN_OR_OR : TOY_TOKEN_PIPE);
case '?': return makeToken(lexer, TOY_TOKEN_QUESTION);
case ':': return makeToken(lexer, TOY_TOKEN_COLON);
+2 -2
View File
@@ -455,8 +455,8 @@ static void printToBuffer(const char* str) {
globalPrintBuffer = TOY_GROW_ARRAY(char, globalPrintBuffer, oldCapacity, globalPrintCapacity);
}
snprintf(globalPrintBuffer + globalPrintCount, strlen(str) + 1, "%s", str ? str : "\0");
globalPrintCount += strlen(str);
size_t total = snprintf(globalPrintBuffer + globalPrintCount, strlen(str) + 1, "%s", str ? str : "\0");
globalPrintCount += total;
}
//exposed functions
+1 -1
View File
@@ -22,7 +22,7 @@ void* Toy_private_defaultMemoryAllocator(void* pointer, size_t oldSize, size_t n
void* mem = realloc(pointer, newSize);
if (mem == NULL) {
fprintf(stderr, TOY_CC_ERROR "[internal] Memory allocation error (requested %zu, replacing %zu)\n" TOY_CC_RESET, newSize, oldSize);
fprintf(stderr, TOY_CC_ERROR "[internal] Memory allocation error (requested %d, replacing %d)\n" TOY_CC_RESET, (int)newSize, (int)oldSize);
return NULL;
}
+2 -2
View File
@@ -29,8 +29,8 @@ typedef enum Toy_Opcode {
TOY_OP_SCOPE_BEGIN,
TOY_OP_SCOPE_END,
TOY_OP_TYPE_DECL, //declare a type to be used (as a literal)
TOY_OP_TYPE_DECL_LONG, //declare a type to be used (as a long literal)
TOY_OP_TYPE_DECL_removed,
TOY_OP_TYPE_DECL_LONG_removed,
TOY_OP_VAR_DECL, //declare a variable to be used (as a literal)
TOY_OP_VAR_DECL_LONG, //declare a variable to be used (as a long literal)
+40 -27
View File
@@ -168,6 +168,10 @@ static Toy_Opcode compound(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
consume(parser, TOY_TOKEN_COMMA, "Expected ',' in array or dictionary");
}
if (match(parser, TOY_TOKEN_BRACKET_RIGHT)) { //allow for trailing commas
break;
}
iterations++;
Toy_ASTNode* left = NULL;
@@ -335,6 +339,28 @@ static Toy_Opcode grouping(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
}
}
static Toy_Opcode circuit(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
advance(parser);
//handle short-circuitable operators - && ||
switch (parser->previous.type) {
case TOY_TOKEN_AND_AND: {
parsePrecedence(parser, nodeHandle, PREC_AND + 1);
return TOY_OP_AND;
}
case TOY_TOKEN_OR_OR: {
parsePrecedence(parser, nodeHandle, PREC_OR + 1);
return TOY_OP_OR;
}
default: {
error(parser, parser->previous, "Unexpected token passed to grouping precedence rule");
return TOY_OP_EOF;
}
}
}
static Toy_Opcode binary(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
advance(parser);
@@ -428,16 +454,6 @@ static Toy_Opcode binary(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
return TOY_OP_COMPARE_GREATER_EQUAL;
}
case TOY_TOKEN_AND: {
parsePrecedence(parser, nodeHandle, PREC_AND + 1);
return TOY_OP_AND;
}
case TOY_TOKEN_OR: {
parsePrecedence(parser, nodeHandle, PREC_OR + 1);
return TOY_OP_OR;
}
default:
error(parser, parser->previous, "Unexpected token passed to binary precedence rule");
return TOY_OP_EOF;
@@ -750,23 +766,10 @@ 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);
parsePrecedence(parser, nodeHandle, PREC_CALL);
//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
return TOY_OP_TYPE_CAST; //opcode value
}
advance(parser); //skip the left paren
@@ -1011,8 +1014,8 @@ ParseRule parseRules[] = { //must match the token types
{NULL, binary, PREC_COMPARISON},// TOKEN_GREATER,
{NULL, binary, PREC_COMPARISON},// TOKEN_LESS_EQUAL,
{NULL, binary, PREC_COMPARISON},// TOKEN_GREATER_EQUAL,
{NULL, binary, PREC_AND},// TOKEN_AND,
{NULL, binary, PREC_OR},// TOKEN_OR,
{NULL, circuit, PREC_AND},// TOKEN_AND,
{NULL, circuit, PREC_OR},// TOKEN_OR,
//other operators
{NULL, question, PREC_TERNARY}, //TOKEN_QUESTION,
@@ -1294,6 +1297,16 @@ static void parsePrecedence(Toy_Parser* parser, Toy_ASTNode** nodeHandle, Preced
continue;
}
if (opcode == TOY_OP_AND) {
Toy_emitASTNodeAnd(nodeHandle, rhsNode);
continue;
}
if (opcode == TOY_OP_OR) {
Toy_emitASTNodeOr(nodeHandle, rhsNode);
continue;
}
Toy_emitASTNodeBinary(nodeHandle, rhsNode, opcode);
//optimise away the constants
+2 -2
View File
@@ -74,8 +74,8 @@ typedef enum Toy_TokenType {
TOY_TOKEN_GREATER,
TOY_TOKEN_LESS_EQUAL,
TOY_TOKEN_GREATER_EQUAL,
TOY_TOKEN_AND,
TOY_TOKEN_OR,
TOY_TOKEN_AND_AND,
TOY_TOKEN_OR_OR,
//other operators
TOY_TOKEN_QUESTION,
+3 -3
View File
@@ -2,9 +2,9 @@ CC=gcc
IDIR +=. ../source ../repl
CFLAGS +=$(addprefix -I,$(IDIR)) -g -Wall -W -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable
LIBS +=
LIBS +=-lm
ODIR = obj
TARGETS = $(wildcard ../source/*.c) $(wildcard ../repl/lib_*.c) ../repl/repl_tools.c
TARGETS = $(wildcard ../source/*.c) $(wildcard ../repl/lib_*.c) ../repl/repl_tools.c ../repl/drive_system.c
TESTS = $(wildcard test_*.c)
OBJ = $(addprefix $(ODIR)/,$(TARGETS:../source/%.c=%.o)) $(addprefix $(ODIR)/,$(TESTS:.c=.o))
@@ -15,7 +15,7 @@ all: $(OBJ) $(TESTS:%.c=../$(TOY_OUTDIR)/%.exe)
../$(TOY_OUTDIR)/%.exe: $(ODIR)/%.o
@$(CC) -o $@ $< $(TARGETS:../source/%.c=$(ODIR)/%.o) $(CFLAGS) $(LIBS)
ifeq ($(shell uname)$(DISABLE_VALGRIND),Linux)
valgrind --leak-check=full --track-origins=yes $@
valgrind --leak-check=full --track-origins=yes --show-leak-kinds=all $@
else
$@
endif
+16
View File
@@ -10,4 +10,20 @@
}
//test function coercion
{
fn f(arg: float) {
assert typeof arg == float, "argument coercion failed";
}
f(42);
fn g(): float {
return 42;
}
assert typeof g() == float, "return coercion failed";
}
print "All good";
+11
View File
@@ -0,0 +1,11 @@
//test for casting + grouping, see #67
{
assert string(10 % 4) == "2", "basic group casting failed";
assert string 4 == "4", "normal casting failed";
assert typeof string(10 % 4) == string, "group casting type failed";
}
print "All good";
@@ -0,0 +1,20 @@
fn max(lhs, rhs) {
if (lhs > rhs) {
return lhs;
}
else {
return rhs;
}
}
var array = [42];
var result = null;
//problematic line
result = max(0, array[0]);
assert result == 42, "Indexing in argument list failed";
print "All good";
+185
View File
@@ -0,0 +1,185 @@
import math;
// test pow
{
assert pow(5, 3) == 125, "pow(5, 3) failed";
assert pow(-5, 3) == -125, "pow(-5, 3) failed";
assert pow(-5.5, 3) == -166.375, "pow(-5.5, 3) failed";
assert pow(0, 1) == 0.0, "pow(0, 1) failed";
assert pow(-0.0, 1) == -0.0, "pow(0, 1) failed";
}
// test sqrt
{
assert sqrt(25) == 5, "sqrt(25) failed";
assert sqrt(256.0) == 16, "sqrt(256.0) failed";
assert checkIsNaN(sqrt(-256.0)), "sqrt(-256.0) failed";
assert sqrt(1) == 1, "sqrt(1) failed";
assert sqrt(0) == 0, "sqrt(0) failed";
}
// test cbrt
{
assert cbrt(64) == 4, "cbrt(64) failed";
assert cbrt(4096.0) == 16, "cbrt(4096.0) failed";
assert cbrt(-64) == -4, "cbrt(-64) failed";
assert cbrt(1) == 1, "cbrt(1) failed";
assert cbrt(0) == 0, "cbrt(0) failed";
}
// test hypot
{
assert hypot(3, 4) == 5, "hypot(3, 4) failed";
}
// test toRad
{
assert toRadians(0) == 0, "toRadians(0) failed";
assert toRadians(180) == PI, "toRadians(180) failed";
assert toRadians(360) == 2 * PI, "toRadians(360) failed";
}
// test toDeg
{
assert toDegrees(0) == 0, "toDegrees(0) failed";
assert toDegrees(PI) == 180, "toDegrees(PI) failed";
assert toDegrees(2 * PI) == 360, "toDegrees(2*PI) failed";
}
// test sin
{
assert epsilionCompare(sin(PI), 0), "sin(PI) failed";
assert epsilionCompare(sin(PI / 2), 1), "sin(PI/2) failed";
assert epsilionCompare(sin(0), 0), "sin(0) failed";
}
// test cos
{
assert epsilionCompare(cos(PI), -1), "cos(PI) failed";
assert epsilionCompare(cos(PI / 2), 0), "cos(PI/2) failed";
assert epsilionCompare(cos(0), 1), "cos(0) failed";
}
// test tan
{
assert epsilionCompare(tan(PI), 0), "tan(PI) failed";
assert epsilionCompare(tan(PI / 4), 1), "tan(PI/4) failed";
assert epsilionCompare(tan(0), 0), "tan(0) failed";
}
// test asin
{
assert epsilionCompare(asin(1), 1.570796), "asin(1) failed";
assert epsilionCompare(asin(-0.5), -0.523599), "asin(-0.5) failed";
assert epsilionCompare(asin(0), 0), "asin(0) failed";
}
// test acos
{
assert epsilionCompare(acos(1), 0), "acos(1) failed";
assert epsilionCompare(acos(0.5), 1.047198), "acos(0.5) failed";
assert epsilionCompare(acos(0), 1.570796), "acos(0) failed";
}
// test atan
{
assert epsilionCompare(atan(1), 0.785398), "acos(1) failed";
assert epsilionCompare(atan(INFINITY), 1.570796), "atan(INFINITY) failed";
assert epsilionCompare(atan(0), 0), "atan(0) failed";
}
// test atan2
{
assert epsilionCompare(atans(0, 0), 0), "atan2(0, 0) failed";
assert epsilionCompare(atans(7, 0), 1.570796), "atans(7, 0) failed";
}
// test sinh
{
assert epsilionCompare(sinh(1), 1.175201), "sinh(1) failed";
assert epsilionCompare(sinh(-1), -1.175201), "sinh(-1) failed";
assert epsilionCompare(sinh(0), 0), "sinh(0) failed";
}
// test cosh
{
assert epsilionCompare(cosh(1), 1.543081), "cosh(1) failed";
assert epsilionCompare(cosh(-1), 1.543081), "cosh(-1) failed";
assert epsilionCompare(cosh(0), 1), "cosh(0) failed";
}
// test tanh
{
assert epsilionCompare(tanh(1), 0.761594), "tanh(1) failed";
assert epsilionCompare(tanh(-1), -0.761594), "tanh(-1) failed";
assert epsilionCompare(tanh(0), 0), "tanh(0) failed";
}
// test asinh
{
assert epsilionCompare(asinh(1), 0.881374), "asinh(1) failed";
assert epsilionCompare(asinh(-1), -0.881374), "asinh(-1) failed";
assert epsilionCompare(asinh(0), 0), "asinh(0) failed";
}
// test acosh
{
assert epsilionCompare(acosh(1), 0), "acosh(1) failed";
assert checkIsNaN(acosh(-1)) == true, "acosh(-1) failed";
assert checkIsNaN(acosh(0)) == true, "acosh(0) failed";
}
// test atanh
{
assert checkIsInfinite(atanh(1)) == true, "atanh(1) failed";
assert checkIsInfinite(atanh(-1)) == true, "atanh(-1) failed";
assert epsilionCompare(atanh(0), 0), "atanh(0) failed";
}
// test checkIsNaN
{
assert checkIsNaN(NAN) == true, "checkIsNaN(NAN) failed";
assert checkIsNaN(INFINITY) == false, "checkIsNaN(INFINITY) failed";
assert checkIsNaN(0.0) == false, "checkIsNaN(0.0) failed";
assert checkIsNaN(INFINITY - INFINITY) == true, "checkIsNaN(INFINITY - INFINITY) failed";
}
// test checkIsFinite
{
assert checkIsFinite(NAN) == false, "checkIsFinite(NAN) failed";
assert checkIsFinite(INFINITY) == false, "checkIsFinite(INFINITY) failed";
assert checkIsFinite(0.0) == true, "checkIsFinite(0.0) failed";
assert checkIsFinite(1) == true, "checkIsFinite(1) failed";
}
// test checkIsInfinite
{
assert checkIsInfinite(NAN) == false, "checkIsInfinite(NAN) failed";
assert checkIsInfinite(INFINITY) == true, "checkIsInfinite(INFINITY) failed";
assert checkIsInfinite(0.0) == false, "checkIsInfinite(0.0) failed";
assert checkIsInfinite(1) == false, "checkIsInfinite(1) failed";
}
// test epsilionCompare
{
assert epsilionCompare(1, 1) == true, "epsilionCompare(1, 1) failed";
assert epsilionCompare(1, 1.000001) == true, "epsilionCompare(1, 1.000001) failed";
assert epsilionCompare(1, 1.001) == false, "epsilionCompare(1, 1.001) failed";
assert epsilionCompare(0, 0) == true, "epsilionCompare(0, 0) failed";
}
+57
View File
@@ -101,6 +101,63 @@ import standard;
}
//test sign
{
assert sign(4) == 1, "sign(int) failed";
assert sign(-4) == -1, "sign(-int) failed";
assert sign(4.1) == 1, "sign(float) failed";
assert sign(-4.1) == -1, "sign(-float) failed";
assert sign(0) == 1, "sign(0) failed";
var x = 4.1;
assert x.sign() == 1, "var.sign() failed";
assert typeof sign(1.0) == int, "typeof sign() == int failed";
}
//test normalize
{
assert normalize(4) == 1, "normalize(int) failed";
assert normalize(-4) == -1, "normalize(-int) failed";
assert normalize(4.1) == 1, "normalize(float) failed";
assert normalize(-4.1) == -1, "normalize(-float) failed";
assert normalize(0) == 0, "normalize(0) failed";
var x = 4.1;
assert x.normalize() == 1, "var.normalize() failed";
assert typeof normalize(1.0) == int, "typeof normalize() == int failed";
}
//test clamp
{
assert clamp(1, 0, 5) == 1, "clamp(1, 0, 5) failed";
assert clamp(0, 1, 5) == 1, "clamp(0, 1, 5) failed";
assert clamp(10, 1, 5) == 5, "clamp(10, 1, 5) failed";
assert clamp(1.0, 0.0, 5.0) == 1, "clamp(1.0, 0.0, 5.0) failed";
assert clamp(0.0, 1.0, 5.0) == 1, "clamp(0.0, 1.0, 5.0) failed";
assert clamp(10.0, 1.0, 5.0) == 5, "clamp(10.0, 1.0, 5.0) failed";
assert typeof clamp(10, 1, 5) == int, "typeof clamp(10, 1, 5) == int failed";
assert typeof clamp(10.0, 1, 5) == int, "typeof clamp(10.0, 1, 5) == int failed";
assert typeof clamp(10, 1, 5.0) == float, "typeof clamp(10, 1, 5.0) == float failed";
}
//test lerp
{
assert lerp(0, 10, 0.5) == 5, "lerp 50% failed";
assert lerp(0, 10, 1.5) == 15, "lerp 150% failed";
assert typeof lerp(0, 10, 0) == float, "typeof lerp result failed";
}
//test concat
{
//test array concat
@@ -1,5 +1,5 @@
import about as about;
import about;
import toy_version_info as toy_version_info;
import toy_version_info;
assert author == "Kayne Ruse, KR Game Studios", "Author failed";
+14
View File
@@ -0,0 +1,14 @@
//These operators should short-circuit
assert (true && false) == false, "(true && false) == false failed";
assert (false && true) == false, "(false && true) == false failed";
assert (true || false) == true, "(true || false) == true failed";
assert (false || true) == true, "(false || true) == true failed";
//make sure the right value is being returned when chained
assert "a" && "b" && "c" == "c", "chained && failed";
assert "a" || "b" || "c" == "a", "chained || failed";
print "All good";
@@ -1,9 +0,0 @@
//explicitly support && and || short circuits
assert 1 && 2 == 2, "&& short-circuit failed";
assert 1 || 2 == 1, "|| short-circuit failed";
print "All good";
+8
View File
@@ -0,0 +1,8 @@
var array = [
1, 2, 3,
4, 5, 6,
7, 8, 9, //explicitly leave a trailing comma
];
print "All good";
+1 -1
View File
@@ -1,4 +1,4 @@
#include "toy_drive_system.h"
#include "drive_system.h"
#include "toy_console_colors.h"
+11 -3
View File
@@ -18,6 +18,7 @@ static void noPrintFn(const char* output) {
//NO OP
}
int failedAssertions = 0;
int ignoredAssertions = 0;
static void noAssertFn(const char* output) {
if (strncmp(output, "!ignore", 7) == 0) {
@@ -27,6 +28,7 @@ static void noAssertFn(const char* output) {
fprintf(stderr, TOY_CC_ERROR "Assertion failure: ");
fprintf(stderr, "%s", output);
fprintf(stderr, "\n" TOY_CC_RESET); //default new line
failedAssertions++;
}
}
@@ -119,6 +121,7 @@ int main() {
"dottify-bugfix.toy",
"function-within-function-bugfix.toy",
"functions.toy",
"group-casting-bugfix.toy",
"increment-postfix-bugfix.toy",
"index-arrays.toy",
"index-assignment-both-bugfix.toy",
@@ -126,6 +129,7 @@ int main() {
"index-assignment-left-bugfix.toy",
"index-dictionaries.toy",
"index-strings.toy",
"indexing-in-argument-list-bugfix.toy",
"jumps.toy",
"jumps-in-functions.toy",
"logicals.toy",
@@ -137,8 +141,9 @@ int main() {
"panic-within-functions.toy",
"polyfill-insert.toy",
"polyfill-remove.toy",
"short-circuiting-support.toy",
"short-circuit.toy",
"ternary-expressions.toy",
"trailing-comma-bugfix.toy",
"types.toy",
NULL
};
@@ -159,7 +164,10 @@ int main() {
return -1;
}
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
return 0;
if (failedAssertions == 0) {
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
}
return failedAssertions;
}
+6 -4
View File
@@ -6,18 +6,19 @@
#include "toy_console_colors.h"
#include "toy_memory.h"
#include "toy_drive_system.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../repl/repl_tools.h"
#include "../repl/drive_system.h"
#include "../repl/lib_about.h"
#include "../repl/lib_toy_version_info.h"
#include "../repl/lib_standard.h"
#include "../repl/lib_random.h"
#include "../repl/lib_runner.h"
#include "../repl/lib_standard.h"
#include "../repl/lib_math.h"
//supress the print output
static void noPrintFn(const char* output) {
@@ -72,10 +73,11 @@ int main() {
//run each file in test/scripts
Payload payloads[] = {
{"interactions.toy", "standard", Toy_hookStandard}, //interactions needs standard
{"about.toy", "about", Toy_hookAbout},
{"toy_version_info.toy", "toy_version_info", Toy_hookToyVersionInfo},
{"standard.toy", "standard", Toy_hookStandard},
{"runner.toy", "runner", Toy_hookRunner},
{"random.toy", "random", Toy_hookRandom},
{"math.toy", "math", Toy_hookMath},
{NULL, NULL, NULL}
};
+427
View File
@@ -0,0 +1,427 @@
/*
* Project: https://github.com/likle/cargs
* License: MIT
*/
#include <assert.h>
#include <cargs.h>
#include <memory.h>
#include <stdio.h>
#include <string.h>
#define CAG_OPTION_PRINT_DISTANCE 4
#define CAG_OPTION_PRINT_MIN_INDENTION 20
static void cag_option_print_value(const cag_option *option,
size_t *accessor_length, FILE *destination) {
if (option->value_name != NULL) {
*accessor_length += fprintf(destination, "=%s", option->value_name);
}
}
static void cag_option_print_letters(const cag_option *option, bool *first,
size_t *accessor_length, FILE *destination) {
const char *access_letter;
access_letter = option->access_letters;
if (access_letter != NULL) {
while (*access_letter) {
if (*first) {
*accessor_length += fprintf(destination, "-%c", *access_letter);
*first = false;
} else {
*accessor_length += fprintf(destination, ", -%c",
*access_letter);
}
++access_letter;
}
}
}
static void cag_option_print_name(const cag_option *option, bool *first,
size_t *accessor_length, FILE *destination) {
if (option->access_name != NULL) {
if (*first) {
*accessor_length += fprintf(destination, "--%s",
option->access_name);
} else {
*accessor_length += fprintf(destination, ", --%s",
option->access_name);
}
}
}
static size_t cag_option_get_print_indention(const cag_option *options,
size_t option_count) {
size_t option_index, indention, result;
const cag_option *option;
result = CAG_OPTION_PRINT_MIN_INDENTION;
for (option_index = 0; option_index < option_count; ++option_index) {
indention = CAG_OPTION_PRINT_DISTANCE;
option = &options[option_index];
if (option->access_letters != NULL && *option->access_letters) {
indention += strlen(option->access_letters) * 4 - 2;
if (option->access_name != NULL) {
indention += strlen(option->access_name) + 4;
}
} else if (option->access_name != NULL) {
indention += strlen(option->access_name) + 2;
}
if (option->value_name != NULL) {
indention += strlen(option->value_name) + 1;
}
if (indention > result) {
result = indention;
}
}
return result;
}
void cag_option_print(const cag_option *options, size_t option_count,
FILE *destination) {
size_t option_index, indention, i, accessor_length;
const cag_option *option;
bool first;
indention = cag_option_get_print_indention(options, option_count);
for (option_index = 0; option_index < option_count; ++option_index) {
option = &options[option_index];
accessor_length = 0;
first = true;
fputs(" ", destination);
cag_option_print_letters(option, &first, &accessor_length, destination);
cag_option_print_name(option, &first, &accessor_length, destination);
cag_option_print_value(option, &accessor_length, destination);
for (i = accessor_length; i < indention; ++i) {
fputs(" ", destination);
}
fputs(" ", destination);
fputs(option->description, destination);
fprintf(destination, "\n");
}
}
void cag_option_prepare(cag_option_context *context, const cag_option *options,
size_t option_count, int argc, char **argv) {
// This just initialized the values to the beginning of all the arguments.
context->options = options;
context->option_count = option_count;
context->argc = argc;
context->argv = argv;
context->index = 1;
context->inner_index = 0;
context->forced_end = false;
}
static const cag_option* cag_option_find_by_name(cag_option_context *context,
char *name, size_t name_size) {
const cag_option *option;
size_t i;
// We loop over all the available options and stop as soon as we have found
// one. We don't use any hash map table, since there won't be that many
// arguments anyway.
for (i = 0; i < context->option_count; ++i) {
option = &context->options[i];
// The option might not have an item name, we can just skip those.
if (option->access_name == NULL) {
continue;
}
// Try to compare the name of the access name. We can use the name_size or
// this comparison, since we are guaranteed to have null-terminated access
// names.
if (strncmp(option->access_name, name, name_size) == 0) {
return option;
}
}
return NULL;
}
static const cag_option* cag_option_find_by_letter(cag_option_context *context,
char letter) {
const cag_option *option;
size_t i;
// We loop over all the available options and stop as soon as we have found
// one. We don't use any look up table, since there won't be that many
// arguments anyway.
for (i = 0; i < context->option_count; ++i) {
option = &context->options[i];
// If this option doesn't have any access letters we will skip them.
if (option->access_letters == NULL) {
continue;
}
// Verify whether this option has the access letter in it's access letter
// string. If it does, then this is our option.
if (strchr(option->access_letters, letter) != NULL) {
return option;
}
}
return NULL;
}
static void cag_option_parse_value(cag_option_context *context,
const cag_option *option, char **c) {
// And now let's check whether this option is supposed to have a value, which
// is the case if there is a value name set. The value can be either submitted
// with a '=' sign or a space, which means we would have to jump over to the
// next argv index. This is somewhat ugly, but we do it to behave the same as
// the other option parsers.
if (option->value_name != NULL) {
if (**c == '=') {
context->value = ++(*c);
} else {
// If the next index is larger or equal to the argument count, then the
// parameter for this option is missing. The user will know about this,
// since the value pointer of the context will be NULL because we don't
// set it here in that case.
if (context->argc > context->index + 1) {
// We consider this argv to be the value, no matter what the contents
// are.
++context->index;
*c = context->argv[context->index];
context->value = *c;
}
}
// Move c to the end of the value, to not confuse the caller about our
// position.
while (**c) {
++(*c);
}
}
}
static void cag_option_parse_access_name(cag_option_context *context, char **c) {
const cag_option *option;
char *n;
// Now we need to extract the access name, which is any symbol up to a '=' or
// a '\0'.
n = *c;
while (**c && **c != '=') {
++*c;
}
// Now this will obviously always be true, but we are paranoid. Sometimes. It
// doesn't hurt to check.
assert(*c >= n);
// Figure out which option this name belongs to. This might return NULL if the
// name is not registered, which means the user supplied an unknown option. In
// that case we return true to indicate that we finished with this option. We
// have to skip the value parsing since we don't know whether the user thinks
// this option has one or not. Since we don't set any identifier specifically,
// it will remain '?' within the context.
option = cag_option_find_by_name(context, n, (size_t) (*c - n));
if (option == NULL) {
// Since this option is invalid, we will move on to the next index. There is
// nothing we can do about this.
++context->index;
return;
}
// We found an option and now we can specify the identifier within the
// context.
context->identifier = option->identifier;
// And now we try to parse the value. This function will also check whether
// this option is actually supposed to have a value.
cag_option_parse_value(context, option, c);
// And finally we move on to the next index.
++context->index;
}
static void cag_option_parse_access_letter(cag_option_context *context,
char **c) {
const cag_option *option;
char *n = *c;
char *v;
// Figure out which option this letter belongs to. This might return NULL if
// the letter is not registered, which means the user supplied an unknown
// option. In that case we return true to indicate that we finished with this
// option. We have to skip the value parsing since we don't know whether the
// user thinks this option has one or not. Since we don't set any identifier
// specifically, it will remain '?' within the context.
option = cag_option_find_by_letter(context, n[context->inner_index]);
if (option == NULL) {
++context->index;
context->inner_index = 0;
return;
}
// We found an option and now we can specify the identifier within the
// context.
context->identifier = option->identifier;
// And now we try to parse the value. This function will also check whether
// this option is actually supposed to have a value.
v = &n[++context->inner_index];
cag_option_parse_value(context, option, &v);
// Check whether we reached the end of this option argument.
if (*v == '\0') {
++context->index;
context->inner_index = 0;
}
}
static void cag_option_shift(cag_option_context *context, int start, int option,
int end) {
char *tmp;
int a_index, shift_index, shift_count, left_index, right_index;
shift_count = option - start;
// There is no shift is required if the start and the option have the same
// index.
if (shift_count == 0) {
return;
}
// Lets loop through the option strings first, which we will move towards the
// beginning.
for (a_index = option; a_index < end; ++a_index) {
// First remember the current option value, because we will have to save
// that later at the beginning.
tmp = context->argv[a_index];
// Let's loop over all option values and shift them one towards the end.
// This will override the option value we just stored temporarily.
for (shift_index = 0; shift_index < shift_count; ++shift_index) {
left_index = a_index - shift_index;
right_index = a_index - shift_index - 1;
context->argv[left_index] = context->argv[right_index];
}
// Now restore the saved option value at the beginning.
context->argv[a_index - shift_count] = tmp;
}
// The new index will be before all non-option values, in such a way that they
// all will be moved again in the next fetch call.
context->index = end - shift_count;
}
static bool cag_option_is_argument_string(const char *c) {
return *c == '-' && *(c + 1) != '\0';
}
static int cag_option_find_next(cag_option_context *context) {
int next_index, next_option_index;
char *c;
// Prepare to search the next option at the next index.
next_index = context->index;
next_option_index = next_index;
// Grab a pointer to the string and verify that it is not the end. If it is
// the end, we have to return false to indicate that we finished.
c = context->argv[next_option_index];
if (context->forced_end || c == NULL) {
return -1;
}
// Check whether it is a '-'. We need to find the next option - and an option
// always starts with a '-'. If there is a string "-\0", we don't consider it
// as an option neither.
while (!cag_option_is_argument_string(c)) {
c = context->argv[++next_option_index];
if (c == NULL) {
// We reached the end and did not find any argument anymore. Let's tell
// our caller that we reached the end.
return -1;
}
}
// Indicate that we found an option which can be processed. The index of the
// next option will be returned.
return next_option_index;
}
bool cag_option_fetch(cag_option_context *context) {
char *c;
int old_index, new_index;
// Reset our identifier to a question mark, which indicates an "unknown"
// option. The value is set to NULL, to make sure we are not carrying the
// parameter from the previous option to this one.
context->identifier = '?';
context->value = NULL;
// Check whether there are any options left to parse and remember the old
// index as well as the new index. In the end we will move the option junk to
// the beginning, so that non option arguments can be read.
old_index = context->index;
new_index = cag_option_find_next(context);
if (new_index >= 0) {
context->index = new_index;
} else {
return false;
}
// Grab a pointer to the beginning of the option. At this point, the next
// character must be a '-', since if it was not the prepare function would
// have returned false. We will skip that symbol and proceed.
c = context->argv[context->index];
assert(*c == '-');
++c;
// Check whether this is a long option, starting with a double "--".
if (*c == '-') {
++c;
// This might be a double "--" which indicates the end of options. If this
// is the case, we will not move to the next index. That ensures that
// another call to the fetch function will not skip the "--".
if (*c == '\0') {
context->forced_end = true;
} else {
// We parse now the access name. All information about it will be written
// to the context.
cag_option_parse_access_name(context, &c);
}
} else {
// This is no long option, so we can just parse an access letter.
cag_option_parse_access_letter(context, &c);
}
// Move the items so that the options come first followed by non-option
// arguments.
cag_option_shift(context, old_index, new_index, context->index);
return context->forced_end == false;
}
char cag_option_get(const cag_option_context *context) {
// We just return the identifier here.
return context->identifier;
}
const char* cag_option_get_value(const cag_option_context *context) {
// We just return the internal value pointer of the context.
return context->value;
}
int cag_option_get_index(const cag_option_context *context) {
// Either we point to a value item,
return context->index;
}
+169
View File
@@ -0,0 +1,169 @@
/*
* Project: https://github.com/likle/cargs
* License: MIT
*/
#ifndef CARGS_H_
#define CARGS_H_
/**
* This is a simple alternative cross-platform implementation of getopt, which
* is used to parse argument strings submitted to the executable (argc and argv
* which are received in the main function).
*/
#ifndef CAG_LIBRARY_H
#define CAG_LIBRARY_H
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#if defined(_WIN32) || defined(__CYGWIN__)
#define CAG_EXPORT __declspec(dllexport)
#define CAG_IMPORT __declspec(dllimport)
#elif __GNUC__ >= 4
#define CAG_EXPORT __attribute__((visibility("default")))
#define CAG_IMPORT __attribute__((visibility("default")))
#else
#define CAG_EXPORT
#define CAG_IMPORT
#endif
#if defined(CAG_SHARED)
#if defined(CAG_EXPORTS)
#define CAG_PUBLIC CAG_EXPORT
#else
#define CAG_PUBLIC CAG_IMPORT
#endif
#else
#define CAG_PUBLIC
#endif
#ifdef __cplusplus
extern "C" {
#endif
/**
* An option is used to describe a flag/argument option submitted when the
* program is run.
*/
typedef struct cag_option {
const char identifier;
const char *access_letters;
const char *access_name;
const char *value_name;
const char *description;
} cag_option;
/**
* A context is used to iterate over all options provided. It stores the parsing
* state.
*/
typedef struct cag_option_context {
const struct cag_option *options;
size_t option_count;
int argc;
char **argv;
int index;
int inner_index;
bool forced_end;
char identifier;
char *value;
} cag_option_context;
/**
* This is just a small macro which calculates the size of an array.
*/
#define CAG_ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
/**
* @brief Prints all options to the terminal.
*
* This function prints all options to the terminal. This can be used to
* generate the output for a "--help" option.
*
* @param options The options which will be printed.
* @param option_count The option count which will be printed.
* @param destination The destination where the output will be printed.
*/
CAG_PUBLIC void cag_option_print(const cag_option *options, size_t option_count,
FILE *destination);
/**
* @brief Prepare argument options context for parsing.
*
* This function prepares the context for iteration and initializes the context
* with the supplied options and arguments. After the context has been prepared,
* it can be used to fetch arguments from it.
*
* @param context The context which will be initialized.
* @param options The registered options which are available for the program.
* @param option_count The amount of options which are available for the
* program.
* @param argc The amount of arguments the user supplied in the main function.
* @param argv A pointer to the arguments of the main function.
*/
CAG_PUBLIC void cag_option_prepare(cag_option_context *context,
const cag_option *options, size_t option_count, int argc, char **argv);
/**
* @brief Fetches an option from the argument list.
*
* This function fetches a single option from the argument list. The context
* will be moved to that item. Information can be extracted from the context
* after the item has been fetched.
* The arguments will be re-ordered, which means that non-option arguments will
* be moved to the end of the argument list. After all options have been
* fetched, all non-option arguments will be positioned after the index of
* the context.
*
* @param context The context from which we will fetch the option.
* @return Returns true if there was another option or false if the end is
* reached.
*/
CAG_PUBLIC bool cag_option_fetch(cag_option_context *context);
/**
* @brief Gets the identifier of the option.
*
* This function gets the identifier of the option, which should be unique to
* this option and can be used to determine what kind of option this is.
*
* @param context The context from which the option was fetched.
* @return Returns the identifier of the option.
*/
CAG_PUBLIC char cag_option_get(const cag_option_context *context);
/**
* @brief Gets the value from the option.
*
* This function gets the value from the option, if any. If the option does not
* contain a value, this function will return NULL.
*
* @param context The context from which the option was fetched.
* @return Returns a pointer to the value or NULL if there is no value.
*/
CAG_PUBLIC const char* cag_option_get_value(const cag_option_context *context);
/**
* @brief Gets the current index of the context.
*
* This function gets the index within the argv arguments of the context. The
* context always points to the next item which it will inspect. This is
* particularly useful to inspect the original argument array, or to get
* non-option arguments after option fetching has finished.
*
* @param context The context from which the option was fetched.
* @return Returns the current index of the context.
*/
CAG_PUBLIC int cag_option_get_index(const cag_option_context *context);
#ifdef __cplusplus
} // extern "C"
#endif
#endif
#endif /* CARGS_H_ */
+949
View File
@@ -0,0 +1,949 @@
/*
* disassembler.c
*
* Created on: 10 ago. 2023
* Original Author: Emiliano Augusto Gonzalez (egonzalez . hiperion @ gmail . com)
*
* Further modified by Kayne Ruse, and added to the Toy Programming Language tool repository.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include "disassembler_utils.h"
#include "disassembler.h"
#define SPC(n) printf("%.*s", n, "| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |");
#define EP(x) [x] = #x
const char *OP_STR[] = {
EP(DIS_OP_EOF), //
EP(DIS_OP_PASS), //
EP(DIS_OP_ASSERT), //
EP(DIS_OP_PRINT), //
EP(DIS_OP_LITERAL), //
EP(DIS_OP_LITERAL_LONG), //
EP(DIS_OP_LITERAL_RAW), //
EP(DIS_OP_NEGATE), //
EP(DIS_OP_ADDITION), //
EP(DIS_OP_SUBTRACTION), //
EP(DIS_OP_MULTIPLICATION), //
EP(DIS_OP_DIVISION), //
EP(DIS_OP_MODULO), //
EP(DIS_OP_GROUPING_BEGIN), //
EP(DIS_OP_GROUPING_END), //
EP(DIS_OP_SCOPE_BEGIN), //
EP(DIS_OP_SCOPE_END), //
EP(DIS_OP_TYPE_DECL_removed), //
EP(DIS_OP_TYPE_DECL_LONG_removed), //
EP(DIS_OP_VAR_DECL), //
EP(DIS_OP_VAR_DECL_LONG), //
EP(DIS_OP_FN_DECL), //
EP(DIS_OP_FN_DECL_LONG), //
EP(DIS_OP_VAR_ASSIGN), //
EP(DIS_OP_VAR_ADDITION_ASSIGN), //
EP(DIS_OP_VAR_SUBTRACTION_ASSIGN), //
EP(DIS_OP_VAR_MULTIPLICATION_ASSIGN), //
EP(DIS_OP_VAR_DIVISION_ASSIGN), //
EP(DIS_OP_VAR_MODULO_ASSIGN), //
EP(DIS_OP_TYPE_CAST), //
EP(DIS_OP_TYPE_OF), //
EP(DIS_OP_IMPORT), //
EP(DIS_OP_EXPORT_removed), //
EP(DIS_OP_INDEX), //
EP(DIS_OP_INDEX_ASSIGN), //
EP(DIS_OP_INDEX_ASSIGN_INTERMEDIATE), //
EP(DIS_OP_DOT), //
EP(DIS_OP_COMPARE_EQUAL), //
EP(DIS_OP_COMPARE_NOT_EQUAL), //
EP(DIS_OP_COMPARE_LESS), //
EP(DIS_OP_COMPARE_LESS_EQUAL), //
EP(DIS_OP_COMPARE_GREATER), //
EP(DIS_OP_COMPARE_GREATER_EQUAL), //
EP(DIS_OP_INVERT), //
EP(DIS_OP_AND), //
EP(DIS_OP_OR), //
EP(DIS_OP_JUMP), //
EP(DIS_OP_IF_FALSE_JUMP), //
EP(DIS_OP_FN_CALL), //
EP(DIS_OP_FN_RETURN), //
EP(DIS_OP_POP_STACK), //
EP(DIS_OP_TERNARY), //
EP(DIS_OP_FN_END), //
};
const char *LIT_STR[] = {
EP(DIS_LITERAL_NULL), //
EP(DIS_LITERAL_BOOLEAN), //
EP(DIS_LITERAL_INTEGER), //
EP(DIS_LITERAL_FLOAT), //
EP(DIS_LITERAL_STRING), //
EP(DIS_LITERAL_ARRAY), //
EP(DIS_LITERAL_DICTIONARY), //
EP(DIS_LITERAL_FUNCTION), //
EP(DIS_LITERAL_IDENTIFIER), //
EP(DIS_LITERAL_TYPE), //
EP(DIS_LITERAL_OPAQUE), //
EP(DIS_LITERAL_ANY), //
EP(DIS_LITERAL_TYPE_INTERMEDIATE), //
EP(DIS_LITERAL_ARRAY_INTERMEDIATE), //
EP(DIS_LITERAL_DICTIONARY_INTERMEDIATE), //
EP(DIS_LITERAL_FUNCTION_INTERMEDIATE), //
EP(DIS_LITERAL_FUNCTION_ARG_REST), //
EP(DIS_LITERAL_FUNCTION_NATIVE), //
EP(DIS_LITERAL_FUNCTION_HOOK), //
EP(DIS_LITERAL_INDEX_BLANK), //
};
enum DIS_ARG_TYPE {
DIS_ARG_NONE, //
DIS_ARG_BYTE, //
DIS_ARG_WORD, //
DIS_ARG_INTEGER, //
DIS_ARG_FLOAT, //
DIS_ARG_STRING //
};
const uint8_t OP_ARGS[DIS_OP_END_OPCODES][3] = {
// | first arg | second arg | jump |
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_EOF
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_PASS
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_ASSERT
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_PRINT
{ DIS_ARG_BYTE, DIS_ARG_NONE, false }, // DIS_OP_LITERAL
{ DIS_ARG_WORD, DIS_ARG_NONE, false }, // DIS_OP_LITERAL_LONG
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_LITERAL_RAW
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_NEGATE
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_ADDITION
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_SUBTRACTION
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_MULTIPLICATION
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_DIVISION
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_MODULO
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_GROUPING_BEGIN
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_GROUPING_END
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_SCOPE_BEGIN
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_SCOPE_END
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_TYPE_DECL_removed
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_TYPE_DECL_LONG_removed
{ DIS_ARG_BYTE, DIS_ARG_BYTE, false }, // DIS_OP_VAR_DECL
{ DIS_ARG_WORD, DIS_ARG_WORD, false }, // DIS_OP_VAR_DECL_LONG
{ DIS_ARG_BYTE, DIS_ARG_BYTE, false }, // DIS_OP_FN_DECL
{ DIS_ARG_WORD, DIS_ARG_WORD, false }, // DIS_OP_FN_DECL_LONG
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_VAR_ASSIGN
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_VAR_ADDITION_ASSIGN
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_VAR_SUBTRACTION_ASSIGN
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_VAR_MULTIPLICATION_ASSIGN
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_VAR_DIVISION_ASSIGN
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_VAR_MODULO_ASSIGN
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_TYPE_CAST
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_TYPE_OF
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_IMPORT
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_EXPORT_removed
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_INDEX
{ DIS_ARG_BYTE, DIS_ARG_NONE, false }, // DIS_OP_INDEX_ASSIGN
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_INDEX_ASSIGN_INTERMEDIATE
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_DOT
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_COMPARE_EQUAL
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_COMPARE_NOT_EQUAL
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_COMPARE_LESS
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_COMPARE_LESS_EQUAL
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_COMPARE_GREATER
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_COMPARE_GREATER_EQUAL
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_INVERT
{ DIS_ARG_WORD, DIS_ARG_NONE, true }, // DIS_OP_AND
{ DIS_ARG_WORD, DIS_ARG_NONE, true }, // DIS_OP_OR
{ DIS_ARG_WORD, DIS_ARG_NONE, true }, // DIS_OP_JUMP
{ DIS_ARG_WORD, DIS_ARG_NONE, true }, // DIS_OP_IF_FALSE_JUMP
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_FN_CALL
{ DIS_ARG_WORD, DIS_ARG_NONE, false }, // DIS_OP_FN_RETURN
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_POP_STACK
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_TERNARY
};
typedef struct dis_program_s {
uint8_t *program;
uint32_t len;
uint32_t pc;
} dis_program_t;
typedef struct fun_code_s {
uint32_t start;
uint32_t len;
char *fun;
} fun_code_t;
typedef struct lit_s {
char *fun;
char *str;
} *lit_t;
uint32_t jump_label;
uint32_t function_queue_len = 0;
uint32_t lit_fn_queue_len = 0;
queue_node_t *function_queue_front = NULL;
queue_node_t *function_queue_rear = NULL;
queue_node_t *lit_fn_queue_front = NULL;
queue_node_t *lit_fn_queue_rear = NULL;
static void dis_print_opcode(uint8_t op);
static uint8_t readByte(const uint8_t *tb, uint32_t *count) {
uint8_t ret = *(uint8_t*) (tb + *count);
*count += 1;
return ret;
}
static uint16_t readWord(const uint8_t *tb, uint32_t *count) {
uint16_t ret = 0;
memcpy(&ret, tb + *count, 2);
*count += 2;
return ret;
}
static int32_t readInt(const uint8_t *tb, uint32_t *count) {
int ret = 0;
memcpy(&ret, tb + *count, 4);
*count += 4;
return ret;
}
static float readFloat(const uint8_t *tb, uint32_t *count) {
float ret = 0;
memcpy(&ret, tb + *count, 4);
*count += 4;
return ret;
}
static char* readString(const uint8_t *tb, uint32_t *count) {
const unsigned char *ret = tb + *count;
*count += strlen((char*) ret) + 1; //+1 for null character
return (char*) ret;
}
static void consumeByte(uint8_t byte, uint8_t *tb, uint32_t *count) {
if (byte != tb[*count]) {
printf("[internal] Failed to consume the correct byte (expected %u, found %u)\n", byte, tb[*count]);
exit(1);
}
*count += 1;
}
///////////////////////////////////////////////////////////////////////////////
static void dis_disassembler_init(dis_program_t **prg) {
(*prg) = malloc(sizeof(struct dis_program_s));
(*prg)->program = NULL;
(*prg)->len = 0;
(*prg)->pc = 0;
}
static void dis_disassembler_deinit(dis_program_t **prg) {
if((*prg)->program != NULL)
free((*prg)->program);
free((*prg));
}
static uint8_t dis_load_file(const char *filename, dis_program_t **prg, bool alt_fmt) {
FILE *f;
size_t fsize, bytes;
uint32_t count = 0;
uint8_t buf = 0;
f = fopen(filename, "r");
if (f == NULL) {
printf("Not able to open the file.\n");
return 1;
}
fseek(f, 0, SEEK_END);
fsize = ftell(f);
fseek(f, 0, SEEK_SET);
(*prg)->program = malloc(fsize * sizeof(uint8_t));
while ((bytes = fread(&buf, sizeof(uint8_t), 1, f)) == 1)
(*prg)->program[count++] = buf;
(*prg)->len = fsize;
if (!alt_fmt)
printf("\nFile: %s\nSize: %zu\n", filename, fsize);
else
printf("\n.comment File: %s, Size: %zu\n", filename, fsize);
fclose(f);
return 0;
}
static void dis_read_header(dis_program_t **prg, bool alt_fmt) {
const unsigned char major = readByte((*prg)->program, &((*prg)->pc));
const unsigned char minor = readByte((*prg)->program, &((*prg)->pc));
const unsigned char patch = readByte((*prg)->program, &((*prg)->pc));
const char *build = readString((*prg)->program, &((*prg)->pc));
if (!alt_fmt)
printf("[Header Version: %d.%d.%d (%s)]\n", major, minor, patch, build);
else
printf(".comment Header Version: %d.%d.%d (%s)\n", major, minor, patch, build);
}
static void dis_print_opcode(uint8_t op) {
if (op == 255) {
printf("SECTION_END");
return;
}
if (op < DIS_OP_END_OPCODES)
printf("%s", (OP_STR[op] + 7));
else
printf("(OP UNKNOWN [%c])", op);
}
///////////////////////////////////////////////////////////////////////////////
#define S_OP(n, p) \
switch (OP_ARGS[opcode][n]) { \
case DIS_ARG_NONE: \
break; \
case DIS_ARG_BYTE: \
uint = readByte((*prg)->program, &pc); \
if (p) printf(" b(%d)", uint); \
break; \
case DIS_ARG_WORD: \
uint = readWord((*prg)->program, &pc);\
if (p) printf(" w(%d)", uint); \
break; \
case DIS_ARG_INTEGER: \
intg = readInt((*prg)->program, &pc); \
if (p) printf(" i(%d)", intg); \
break; \
case DIS_ARG_FLOAT: \
flt = readFloat((*prg)->program, &pc); \
if (p) printf(" f(%f)", flt); \
break; \
case DIS_ARG_STRING: \
str = readString((*prg)->program, &pc); \
if (p) printf(" s(%s)", str); \
break; \
default: \
printf("ERROR, unknown argument type\n"); \
exit(1); \
}
static void dis_disassemble_section(dis_program_t **prg, uint32_t pc, uint32_t len, uint8_t spaces, bool is_function, options_t config) {
uint8_t opcode = 0;
uint16_t uint = 0;
int32_t intg = 0;
float flt = 0;
char *str = NULL;
// first 4 bytes of the program section within a function are actually specifying the parameter and return lists
if (is_function) {
printf("\n");
uint16_t args = readWord((*prg)->program, &pc);
uint16_t rets = readWord((*prg)->program, &pc);
if (!config.alt_format_flag) {
SPC(spaces);
printf("| ");
} else
printf(" .comment args:%d, rets:%d", args, rets);
}
uint32_t pc_start = pc;
uint32_t labels_qty = 0;
uint16_t *label_line = NULL;
uint32_t *label_id = NULL;
if (config.alt_format_flag) {
// first pass: search jump labels
label_line = malloc(sizeof(uint16_t));
label_id = malloc(sizeof(uint32_t));
while (pc < len) {
label_line = realloc(label_line, (labels_qty + 1) * sizeof(uint16_t));
label_id = realloc(label_id, (labels_qty + 1) * sizeof(uint32_t));
opcode = (*prg)->program[pc];
if (config.alt_format_flag && (opcode == 255 || opcode == 0)) {
++pc;
continue;
}
if (opcode > DIS_OP_END_OPCODES)
continue;
++pc;
S_OP(0, 0);
if (OP_ARGS[opcode][2]) {
label_line[labels_qty] = uint;
label_id[labels_qty] = jump_label++;
++labels_qty;
}
S_OP(1, 0);
}
pc = pc_start;
}
while (pc < len) {
opcode = (*prg)->program[pc];
if (config.alt_format_flag) {
for (uint32_t lbl = 0; lbl < labels_qty; lbl++) {
if (pc - pc_start == label_line[lbl]) {
printf("\nJL_%04d_:", label_id[lbl]);
break;
}
}
}
if (config.alt_format_flag && (opcode == 255 || opcode == 0)) {
++pc;
continue;
}
printf("\n");
if (!config.alt_format_flag) {
SPC(spaces);
printf("| ");
printf("[%05d](%03d) ", (pc++) - pc_start, opcode);
} else {
printf(" ");
pc++;
}
dis_print_opcode(opcode);
if (opcode >= DIS_OP_END_OPCODES)
continue;
if (config.alt_format_flag) {
if (OP_ARGS[opcode][2]) {
uint = readWord((*prg)->program, &pc);
for (uint32_t lbl = 0; lbl < labels_qty; lbl++) {
if (uint == label_line[lbl]) {
printf(" JL_%04d_", label_id[lbl]);
break;
}
}
} else
S_OP(0, 1);
} else
S_OP(0, 1);
S_OP(1, 1);
}
if (config.alt_format_flag) {
free(label_line);
free(label_id);
}
if (config.alt_format_flag && (*prg)->program[pc - 5] != DIS_OP_FN_RETURN)
printf("\n FN_RETURN w(0)");
}
#define LIT_ADD(a, b, c) b[c] = a; ++c;
static void dis_read_interpreter_sections(dis_program_t **prg, uint32_t *pc, uint8_t spaces, char *tree, options_t config) {
uint32_t literal_count = 0;
uint8_t literal_type[65536];
char *lit_str = NULL;
const unsigned short literalCount = readWord((*prg)->program, pc);
if(!config.group_flag)
printf("\n");
if (!config.alt_format_flag) {
SPC(spaces);
printf("| ");
printf(" ");
printf("--- ( Reading %d literals from cache ) ---\n", literalCount);
}
if (config.alt_format_flag)
lit_str = calloc(1, sizeof(char));
for (int i = 0; i < literalCount; i++) {
const unsigned char literalType = readByte((*prg)->program, pc);
switch (literalType) {
case DIS_LITERAL_NULL:
LIT_ADD(DIS_LITERAL_NULL, literal_type, literal_count);
if (!config.alt_format_flag) {
SPC(spaces);
printf("| | ");
printf("[%05d] ( null )\n", i);
} else {
str_append(&lit_str, " .lit NULL\n");
}
break;
case DIS_LITERAL_BOOLEAN: {
const bool b = readByte((*prg)->program, pc);
LIT_ADD(DIS_LITERAL_BOOLEAN, literal_type, literal_count);
if (!config.alt_format_flag) {
SPC(spaces);
printf("| | ");
printf("[%05d] ( boolean %s )\n", i, b ? "true" : "false");
} else {
char bs[10];
sprintf(bs, "%s\n", b ? "true" : "false");
str_append(&lit_str, " .lit BOOLEAN ");
str_append(&lit_str, bs);
}
}
break;
case DIS_LITERAL_INTEGER: {
const int d = readInt((*prg)->program, pc);
LIT_ADD(DIS_LITERAL_INTEGER, literal_type, literal_count);
if (!config.alt_format_flag) {
SPC(spaces);
printf("| | ");
printf("[%05d] ( integer %d )\n", i, d);
} else {
char ds[20];
sprintf(ds, "%d\n", d);
str_append(&lit_str, " .lit INTEGER ");
str_append(&lit_str, ds);
}
}
break;
case DIS_LITERAL_FLOAT: {
const float f = readFloat((*prg)->program, pc);
LIT_ADD(DIS_LITERAL_FLOAT, literal_type, literal_count);
if (!config.alt_format_flag) {
SPC(spaces);
printf("| | ");
printf("[%05d] ( float %f )\n", i, f);
} else {
char fs[20];
sprintf(fs, "%f\n", f);
str_append(&lit_str, " .lit FLOAT ");
str_append(&lit_str, fs);
}
}
break;
case DIS_LITERAL_STRING: {
const char *s = readString((*prg)->program, pc);
LIT_ADD(DIS_LITERAL_STRING, literal_type, literal_count);
if (!config.alt_format_flag) {
SPC(spaces);
printf("| | ");
printf("[%05d] ( string \"%s\" )\n", i, s);
} else {
str_append(&lit_str, " .lit STRING \"");
str_append(&lit_str, s);
str_append(&lit_str, "\"\n");
}
}
break;
case DIS_LITERAL_ARRAY_INTERMEDIATE:
case DIS_LITERAL_ARRAY: {
unsigned short length = readWord((*prg)->program, pc);
if (!config.alt_format_flag) {
SPC(spaces);
printf("| | ");
printf("[%05d] ( array ", i);
} else {
str_append(&lit_str, " .lit ARRAY ");
}
for (int i = 0; i < length; i++) {
int index = readWord((*prg)->program, pc);
if (!config.alt_format_flag) {
printf("%d ", index);
} else {
char ds[20];
sprintf(ds, "%d ", index);
str_append(&lit_str, ds);
}
LIT_ADD(DIS_LITERAL_NULL, literal_type, literal_count);
if (!(i % 15) && i != 0) {
if (!config.alt_format_flag) {
printf("\\\n");
SPC(spaces);
printf("| | ");
printf(" ");
} else {
str_append(&lit_str, "\\\n ");
}
}
}
if (!config.alt_format_flag) {
printf(")");
printf("\n");
} else {
str_append(&lit_str, "\n");
}
LIT_ADD(DIS_LITERAL_ARRAY, literal_type, literal_count);
}
break;
case DIS_LITERAL_DICTIONARY_INTERMEDIATE:
case DIS_LITERAL_DICTIONARY: {
unsigned short length = readWord((*prg)->program, pc);
if (!config.alt_format_flag) {
SPC(spaces);
printf("| | ");
printf("[%05d] ( dictionary ", i);
} else {
str_append(&lit_str, " .lit DICTIONARY ");
}
for (int i = 0; i < length / 2; i++) {
int key = readWord((*prg)->program, pc);
int val = readWord((*prg)->program, pc);
if (!config.alt_format_flag)
printf("(key: %d, val:%d) ", key, val);
else {
char s[100];
sprintf(s, "%d,%d ", key, val);
str_append(&lit_str, s);
}
if (!(i % 5) && i != 0) {
if (!config.alt_format_flag) {
printf("\\\n");
SPC(spaces);
printf("| | ");
printf(" ");
} else {
str_append(&lit_str, "\\\n ");
}
}
}
if (!config.alt_format_flag) {
printf(")");
printf("\n");
} else {
str_append(&lit_str, "\n");
}
LIT_ADD(DIS_LITERAL_DICTIONARY, literal_type, literal_count);
}
break;
case DIS_LITERAL_FUNCTION: {
unsigned short index = readWord((*prg)->program, pc);
LIT_ADD(DIS_LITERAL_FUNCTION_INTERMEDIATE, literal_type, literal_count);
if (!config.alt_format_flag) {
SPC(spaces);
printf("| | ");
printf("[%05d] ( function index: %d )\n", i, index);
} else {
char s[100];
sprintf(s, " .lit FUNCTION %d\n", index);
str_append(&lit_str, s);
}
}
break;
case DIS_LITERAL_IDENTIFIER: {
const char *str = readString((*prg)->program, pc);
LIT_ADD(DIS_LITERAL_IDENTIFIER, literal_type, literal_count);
if (!config.alt_format_flag) {
SPC(spaces);
printf("| | ");
printf("[%05d] ( identifier %s )\n", i, str);
} else {
str_append(&lit_str, " .lit IDENTIFIER ");
str_append(&lit_str, str);
str_append(&lit_str, "\n");
}
}
break;
case DIS_LITERAL_TYPE:
case DIS_LITERAL_TYPE_INTERMEDIATE: {
uint8_t literalType = readByte((*prg)->program, pc);
uint8_t constant = readByte((*prg)->program, pc);
if (!config.alt_format_flag) {
SPC(spaces);
printf("| | ");
printf("[%05d] ( type %s: %d)\n", i, (LIT_STR[literalType] + 12), constant);
} else {
char s[100];
sprintf(s, " .lit TYPE %s %d", (LIT_STR[literalType] + 12), constant);
str_append(&lit_str, s);
}
if (literalType == DIS_LITERAL_ARRAY) {
uint16_t vt = readWord((*prg)->program, pc);
if (!config.alt_format_flag) {
SPC(spaces);
printf("| | ");
printf("\n ( subtype: %d)\n", vt);
} else {
char s[100];
sprintf(s, " SUBTYPE %d\n", vt);
str_append(&lit_str, s);
}
} else
if (literalType == DIS_LITERAL_DICTIONARY) {
uint8_t kt = readWord((*prg)->program, pc);
uint8_t vt = readWord((*prg)->program, pc);
if (!config.alt_format_flag) {
SPC(spaces);
printf("| | ");
printf("\n ( subtype: [%d, %d] )\n\n\n", kt, vt);
} else {
char s[100];
sprintf(s, " SUBTYPE %d,%d\n", kt, vt);
str_append(&lit_str, s);
}
} else {
if (!config.alt_format_flag)
printf("\n");
else
str_append(&lit_str, "\n");
}
LIT_ADD(literalType, literal_type, literal_count);
}
break;
case DIS_LITERAL_INDEX_BLANK:
LIT_ADD(DIS_LITERAL_INDEX_BLANK, literal_type, literal_count);
if (!config.alt_format_flag) {
SPC(spaces);
printf("| | ");
printf("[%05d] ( blank )\n", i);
} else {
str_append(&lit_str, " .lit BLANK\n");
}
break;
}
}
if (!config.group_flag) {
printf(lit_str);
} else {
lit_t fn_str = (lit_t)(lit_fn_queue_rear->data);
fn_str->str = calloc(1, strlen(lit_str) + 1);
strcpy(fn_str->str, lit_str);
}
free(lit_str);
consumeByte(DIS_OP_SECTION_END, (*prg)->program, pc);
if (!config.alt_format_flag) {
SPC(spaces);
printf("| ");
printf("--- ( end literal section ) ---\n");
}
int functionCount = readWord((*prg)->program, pc);
int functionSize = readWord((*prg)->program, pc);
if (functionCount) {
if (!config.alt_format_flag) {
SPC(spaces);
printf("|\n");
SPC(spaces);
printf("| ");
printf("--- ( fn count: %d, total size: %d ) ---\n", functionCount, functionSize);
}
uint32_t fcnt = 0;
char tree_local[2048];
for (uint32_t i = 0; i < literal_count; i++) {
if (literal_type[i] == DIS_LITERAL_FUNCTION_INTERMEDIATE) {
size_t size = (size_t) readWord((*prg)->program, pc);
uint32_t fpc_start = *pc;
uint32_t fpc_end = *pc + size - 1;
tree_local[0] = '\0';
if (!config.alt_format_flag) {
sprintf(tree_local, "%s.%d", tree, fcnt);
if (tree_local[0] == '_')
memcpy(tree_local, tree_local + 1, strlen(tree_local));
} else {
sprintf(tree_local, "%s_%d", tree, fcnt);
if (tree_local[0] == '_')
memcpy(tree_local, tree_local + 1, strlen(tree_local));
}
if (!config.alt_format_flag) {
SPC(spaces);
printf("| |\n");
SPC(spaces);
printf("| | ");
printf("( fun %s [ start: %d, end: %d ] )", tree_local, fpc_start, fpc_end);
} else {
if (!config.group_flag)
printf("\nLIT_FUN_%s:", tree_local);
else {
lit_t new_lit = malloc(sizeof(struct lit_s));
new_lit->fun = calloc(1, strlen(tree_local) + 1);
strcpy(new_lit->fun, tree_local);
dis_enqueue((void*) new_lit, &lit_fn_queue_front, &lit_fn_queue_rear, &lit_fn_queue_len);
}
}
if ((*prg)->program[*pc + size - 1] != DIS_OP_FN_END) {
printf("\nERROR: Failed to find function end\n");
exit(1);
}
dis_read_interpreter_sections(prg, &fpc_start, spaces + 4, tree_local, config);
if (!config.alt_format_flag) {
SPC(spaces);
printf("| | |\n");
SPC(spaces + 4);
printf("| ");
printf("--- ( reading code for %s ) ---", tree_local);
dis_disassemble_section(prg, fpc_start, fpc_end, spaces + 4, true, config);
printf("\n");
SPC(spaces + 4);
printf("| ");
printf("--- ( end code section ) ---\n");
} else {
fun_code_t *fun = malloc(sizeof(struct fun_code_s));
fun->fun = malloc(strlen(tree_local) + 1);
strcpy(fun->fun, tree_local);
fun->start = fpc_start;
fun->len = fpc_end;
dis_enqueue((void*) fun, &function_queue_front, &function_queue_rear, &function_queue_len);
}
fcnt++;
*pc += size;
}
}
if (!config.alt_format_flag) {
SPC(spaces);
printf("|\n");
SPC(spaces);
printf("| ");
printf("--- ( end fn section ) ---\n");
}
}
consumeByte(DIS_OP_SECTION_END, (*prg)->program, pc);
}
///////////////////////////////////////////////////////////////////////////////
void disassemble(const char *filename, options_t config) {
dis_program_t *prg;
jump_label = 0;
dis_disassembler_init(&prg);
if (dis_load_file(filename, &prg, config.alt_format_flag)) {
dis_disassembler_deinit(&prg);
exit(1);
}
dis_read_header(&prg, config.alt_format_flag);
printf("\n.start MAIN\n");
consumeByte(DIS_OP_SECTION_END, prg->program, &(prg->pc));
if (!config.group_flag) {
if (config.alt_format_flag)
printf("\nLIT_MAIN:");
dis_read_interpreter_sections(&prg, &(prg->pc), 0, "", config);
if (!config.alt_format_flag) {
printf("|\n| ");
printf("--- ( reading main code ) ---");
} else
printf("\nMAIN:");
dis_disassemble_section(&prg, prg->pc, prg->len, 0, false, config);
if (!config.alt_format_flag) {
printf("\n| ");
printf("--- ( end main code section ) ---");
} else
printf("\n");
if (config.alt_format_flag) {
while (function_queue_front != NULL) {
fun_code_t *fun = (fun_code_t*) function_queue_front->data;
printf("\nFUN_%s:", fun->fun);
free(fun->fun);
dis_disassemble_section(&prg, fun->start, fun->len, 0, true, config);
dis_dequeue(&function_queue_front, &function_queue_rear, &function_queue_len);
printf("\n");
}
}
} else {
config.alt_format_flag = true;
lit_t new_lit = malloc(sizeof(struct lit_s));
new_lit->fun = calloc(1, 6 * sizeof(char));
strcpy(new_lit->fun, "MAIN");
dis_enqueue((void*) new_lit, &lit_fn_queue_front, &lit_fn_queue_rear, &lit_fn_queue_len);
dis_read_interpreter_sections(&prg, &(prg->pc), 0, "", config);
printf("\n");
while (lit_fn_queue_front != NULL) {
lit_t litf = (lit_t) lit_fn_queue_front->data;
if (!strcmp(litf->fun, "MAIN")) {
printf("MAIN:\n");
printf("%s", str_replace_substr_all(litf->str, ".lit FUNCTION ", ".lit FUNCTION (code=FUN_) "));
dis_disassemble_section(&prg, prg->pc, prg->len, 0, false, config);
free(litf->fun);
free(litf->str);
dis_dequeue(&lit_fn_queue_front, &lit_fn_queue_rear, &lit_fn_queue_len);
printf("\n\n");
continue;
}
printf("FUN_%s:\n", litf->fun);
char sbtr[strlen(litf->fun) + 19];
sprintf(sbtr, ".lit FUNCTION (code=FUN_%s_) ", litf->fun);
printf("%s", str_replace_substr_all(litf->str, ".lit FUNCTION ", sbtr));
queue_node_t *fqf = function_queue_front;
while (fqf != NULL) {
fun_code_t *fun = (fun_code_t*) fqf->data;
if (!strcmp(fun->fun, litf->fun)) {
dis_disassemble_section(&prg, fun->start, fun->len, 0, true, config);
break;
}
fqf = fqf->next;
}
free(litf->fun);
free(litf->str);
dis_dequeue(&lit_fn_queue_front, &lit_fn_queue_rear, &lit_fn_queue_len);
printf("\n\n");
}
while (function_queue_front != NULL) {
free(((fun_code_t*)(function_queue_front->data))->fun);
dis_dequeue(&function_queue_front, &function_queue_rear, &function_queue_len);
}
}
printf("\n");
dis_disassembler_deinit(&prg);
}
+133
View File
@@ -0,0 +1,133 @@
/*
* disassembler.c
*
* Created on: 10 ago. 2023
* Original Author: Emiliano Augusto Gonzalez (egonzalez . hiperion @ gmail . com)
*
* Further modified by Kayne Ruse, and added to the Toy Programming Language tool repository.
*/
#ifndef DISASSEMBLER_H_
#define DISASSEMBLER_H_
typedef struct options_s {
bool alt_format_flag;
bool group_flag;
} options_t;
typedef enum DIS_OPCODES {
DIS_OP_EOF, //
// do nothing
DIS_OP_PASS, //
// basic statements
DIS_OP_ASSERT, //
DIS_OP_PRINT, //
// data
DIS_OP_LITERAL, //
DIS_OP_LITERAL_LONG, //
DIS_OP_LITERAL_RAW, //
// arithmetic operators
DIS_OP_NEGATE, //
DIS_OP_ADDITION, //
DIS_OP_SUBTRACTION, //
DIS_OP_MULTIPLICATION, //
DIS_OP_DIVISION, //
DIS_OP_MODULO, //
DIS_OP_GROUPING_BEGIN, //
DIS_OP_GROUPING_END, //
// variable stuff
DIS_OP_SCOPE_BEGIN, //
DIS_OP_SCOPE_END, //
DIS_OP_TYPE_DECL_removed, // deprecated
DIS_OP_TYPE_DECL_LONG_removed, // deprecated
DIS_OP_VAR_DECL, //
DIS_OP_VAR_DECL_LONG, //
DIS_OP_FN_DECL, //
DIS_OP_FN_DECL_LONG, //
DIS_OP_VAR_ASSIGN, //
DIS_OP_VAR_ADDITION_ASSIGN, //
DIS_OP_VAR_SUBTRACTION_ASSIGN, //
DIS_OP_VAR_MULTIPLICATION_ASSIGN, //
DIS_OP_VAR_DIVISION_ASSIGN, //
DIS_OP_VAR_MODULO_ASSIGN, //
DIS_OP_TYPE_CAST, //
DIS_OP_TYPE_OF, //
DIS_OP_IMPORT, //
DIS_OP_EXPORT_removed, // deprecated
// for indexing
DIS_OP_INDEX, //
DIS_OP_INDEX_ASSIGN, //
DIS_OP_INDEX_ASSIGN_INTERMEDIATE, //
DIS_OP_DOT, //
// comparison of values
DIS_OP_COMPARE_EQUAL, //
DIS_OP_COMPARE_NOT_EQUAL, //
DIS_OP_COMPARE_LESS, //
DIS_OP_COMPARE_LESS_EQUAL, //
DIS_OP_COMPARE_GREATER, //
DIS_OP_COMPARE_GREATER_EQUAL, //
DIS_OP_INVERT, //
// logical operators
DIS_OP_AND, //
DIS_OP_OR, //
// jumps, and conditional jumps (absolute)
DIS_OP_JUMP, //
DIS_OP_IF_FALSE_JUMP, //
DIS_OP_FN_CALL, //
DIS_OP_FN_RETURN, //
// pop the stack at the end of a complex statement
DIS_OP_POP_STACK, //
//ternary shorthand
DIS_OP_TERNARY, //
//meta
DIS_OP_FN_END, // different from SECTION_END
DIS_OP_END_OPCODES, // mark for end opcodes list. Not valid opcode
DIS_OP_SECTION_END = 255,
} dis_opcode_t;
typedef enum DIS_LITERAL_TYPE {
DIS_LITERAL_NULL, //
DIS_LITERAL_BOOLEAN, //
DIS_LITERAL_INTEGER, //
DIS_LITERAL_FLOAT, //
DIS_LITERAL_STRING, //
DIS_LITERAL_ARRAY, //
DIS_LITERAL_DICTIONARY, //
DIS_LITERAL_FUNCTION, //
DIS_LITERAL_IDENTIFIER, //
DIS_LITERAL_TYPE, //
DIS_LITERAL_OPAQUE, //
DIS_LITERAL_ANY, //
// these are meta-level types - not for general use
DIS_LITERAL_TYPE_INTERMEDIATE, // used to process types in the compiler only
DIS_LITERAL_ARRAY_INTERMEDIATE, // used to process arrays in the compiler only
DIS_LITERAL_DICTIONARY_INTERMEDIATE, // used to process dictionaries in the compiler only
DIS_LITERAL_FUNCTION_INTERMEDIATE, // used to process functions in the compiler only
DIS_LITERAL_FUNCTION_ARG_REST, // used to process function rest parameters only
DIS_LITERAL_FUNCTION_NATIVE, // for handling native functions only
DIS_LITERAL_FUNCTION_HOOK, // for handling hook functions within literals only
DIS_LITERAL_INDEX_BLANK, // for blank indexing i.e. arr[:]
} dis_literal_type_t;
extern void disassemble(const char *filename, options_t config);
#endif /* DISASSEMBLER_H_ */
+92
View File
@@ -0,0 +1,92 @@
/*
* utils.c
*
* Created on: 10 ago. 2023
* Original Author: Emiliano Augusto Gonzalez (egonzalez . hiperion @ gmail . com)
*
* Further modified by Kayne Ruse, and added to the Toy Programming Language tool repository.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "disassembler_utils.h"
void dis_enqueue(void *x, queue_node_t **queue_front, queue_node_t **queue_rear, uint32_t *len) {
queue_node_t *temp;
temp = (queue_node_t*) malloc(sizeof(struct queue_node_s));
temp->data = x;
temp->next = NULL;
if ((*queue_front) == NULL && (*queue_rear) == NULL) {
(*queue_front) = (*queue_rear) = temp;
++(*len);
return;
}
(*queue_rear)->next = temp;
(*queue_rear) = temp;
++(*len);
}
void dis_dequeue(queue_node_t **queue_front, queue_node_t **queue_rear, uint32_t *len) {
struct queue_node_s *temp = (*queue_front);
if ((*queue_front) == NULL) {
printf("Error : QUEUE is empty!!");
return;
}
if ((*queue_front) == (*queue_rear))
(*queue_front) = (*queue_rear) = NULL;
else
(*queue_front) = (*queue_front)->next;
--(*len);
free(temp->data);
free(temp);
}
///
void str_append(char **str, const char *app) {
if ((*str) == NULL)
return;
*str = realloc(*str, (strlen(*str) + strlen(app) + 1) * sizeof(char));
memcpy((*str) + strlen(*str), app, strlen(app) + 1);
}
char* str_replace_substr_all(char *mainstr, char *substr, char *newstr) {
int lenmain, lensub, i, j, lennew, startindex = -1, c;
lenmain = strlen(mainstr);
lensub = strlen(substr);
lennew = strlen(newstr);
char *result = (char*) malloc(sizeof(char) * (lenmain + 200));
for (c = 0, i = 0; i < lenmain; i++) {
if (lenmain - i >= lensub && *(mainstr + i) == *(substr)) {
startindex = i;
for (j = 1; j < lensub; j++)
if (*(mainstr + i + j) != *(substr + j)) {
startindex = -1;
break;
}
if (startindex != -1) {
for (j = 0; j < lennew; j++, c++) {
*(result + c) = *(newstr + j);
}
i = i + lensub - 1;
} else {
*(result + c) = *(mainstr + i);
c++;
}
} else {
*(result + c) = *(mainstr + i);
c++;
}
}
*(result + c) = '\0';
return result;
}
+26
View File
@@ -0,0 +1,26 @@
/*
* utils.h
*
* Created on: 10 ago. 2023
* Original Author: Emiliano Augusto Gonzalez (egonzalez . hiperion @ gmail . com)
*
* Further modified by Kayne Ruse, and added to the Toy Programming Language tool repository.
*/
#ifndef UTILS_H_
#define UTILS_H_
#include <stdint.h>
typedef struct queue_node_s {
void *data;
struct queue_node_s *next;
} queue_node_t;
void dis_enqueue(void *x, queue_node_t **queue_front, queue_node_t **queue_rear, uint32_t *len);
void dis_dequeue(queue_node_t **queue_front, queue_node_t **queue_rear, uint32_t *len);
void str_append(char **str, const char *app);
char* str_replace_substr_all(char *mainstr, char *substr, char *newstr);
#endif /* UTILS_H_ */
+53
View File
@@ -0,0 +1,53 @@
#include <stdlib.h>
#include "cargs.h"
#include "disassembler.h"
static struct cag_option options[] = {
{
.identifier = 'a',
.access_letters = "a",
.access_name = NULL,
.value_name = NULL,
.description = "Alternate format"
}, {
.identifier = 'g',
.access_letters = "g",
.access_name = NULL,
.value_name = NULL,
.description = "Group literals with functions"
}, {
.identifier = 'h',
.access_letters = "h",
.access_name = "help",
.description = "Shows the command help"
}
};
int main(int argc, char *argv[]) {
char identifier;
cag_option_context context;
options_t config = { false, false };
cag_option_prepare(&context, options, CAG_ARRAY_SIZE(options), argc, argv);
while (cag_option_fetch(&context)) {
identifier = cag_option_get(&context);
switch (identifier) {
case 'a':
config.alt_format_flag = true;
break;
case 'g':
config.group_flag = true;
config.alt_format_flag = true;
break;
case 'h':
printf("Usage: disassembler [OPTION] file\n");
cag_option_print(options, CAG_ARRAY_SIZE(options), stdout);
return EXIT_SUCCESS;
}
}
disassemble(argv[context.index], config);
return EXIT_SUCCESS;
}
+27
View File
@@ -0,0 +1,27 @@
CC=gcc
IDIR+=.
CFLAGS+=$(addprefix -I,$(IDIR)) -g -Wall -W -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable
LIBS+=
ODIR = obj
SRC = $(wildcard *.c)
OBJ = $(addprefix $(ODIR)/,$(SRC:.c=.o))
OUTDIR=../../out
OUT=$(OUTDIR)/disassembler
all: $(OBJ)
$(CC) $(CFLAGS) -o $(OUT) $(OBJ) $(LIBS)
$(OBJ): | $(ODIR)
$(ODIR):
mkdir $(ODIR)
$(ODIR)/%.o: %.c
$(CC) -c -o $@ $< $(CFLAGS)
.PHONY: clean
clean:
$(RM) -r $(ODIR)
+73
View File
@@ -0,0 +1,73 @@
//changing of the guard - made for @hyperiondev's microcontrollers
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
std::string convert(std::string str) {
str = str.substr(str.find_last_of("\\/")+1);
std::transform(str.begin(), str.end(), str.begin(), ::toupper);
std::replace(str.begin(), str.end(), '.', '_');
return str;
}
std::string convertToGuardStart(std::string str) {
str = convert(str);
return "#ifndef " + str + "\n#define " + str + "\n";
}
std::string convertToGuardEnd(std::string str) {
str = convert(str);
return "\n#endif //" + str + "\n";
}
int main(int argc, char** argv) {
if (argc <= 1) {
return -1;
}
for (int fileCounter = 1; fileCounter < argc; fileCounter++) {
std::ifstream is; //input stream
std::string buffer; //store output file
//open
is.open(argv[fileCounter]);
if (!is.is_open()) {
return -1;
}
while (!is.eof()) {
std::string top; //I dislike C++
getline(is, top);
//check for pragma guard
if (top == "#pragma once") {
top = convertToGuardStart(argv[fileCounter]);
getline(is, buffer, '\0');
buffer += convertToGuardEnd(argv[fileCounter]);
}
else {
top += "\n";
getline(is, buffer, '\0');
}
buffer = top + buffer;
}
//finally
is.close();
std::ofstream os;
os.open(argv[fileCounter]);
if (!os.is_open()) {
return -1;
}
os << buffer;
os.close();
}
return 0;
}