Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cce8ae1ea3 | |||
| ce54912232 | |||
| 23b55fc360 | |||
| 62fe86f99b | |||
| 401de578a5 | |||
| fb4258f9df | |||
| f885fdaf4c | |||
| cfec1b6911 | |||
| a63bdaef1c | |||
| 3783c94064 | |||
| d292b33184 | |||
| 64944c24f6 | |||
| 604604e8bc | |||
| 67e49b7477 | |||
| 967963c9d7 | |||
| 9b469e6eb0 | |||
| f8094fa17e | |||
| 8714c56c3e | |||
| 9faaa311e0 | |||
| f5ba1181c0 | |||
| b06b2d9485 | |||
| e3e9ca7ece | |||
| 81fe278c96 | |||
| 027d093e21 | |||
| 2eaf7fc71a | |||
| c43310f316 | |||
| 6e07c5f2f4 | |||
| 7690dce3f6 | |||
| 1ed1993489 | |||
| 9b5327b83d | |||
| 10dbe8f8f1 | |||
| 9e4ad7a9a5 | |||
| 5317a12383 | |||
| 35bfa1b9f1 | |||
| 7f692b4cb4 | |||
| 0cef0abdb5 | |||
| 6ba42b5a9b | |||
| 3cb62274c9 | |||
| 60b561d809 | |||
| 70b2dcd829 | |||
| 0955b3ff38 | |||
| 4137935468 | |||
| ebeabcb9d4 | |||
| 4d33a9473a | |||
| 61e3cdba82 | |||
| 3b7d2be87e | |||
| fa175203c9 | |||
| b4a3e9b42b | |||
| 6347778ead |
+25
-21
@@ -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
@@ -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
|
||||
@@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "toy_interpreter.h"
|
||||
|
||||
int Toy_hookAbout(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
|
||||
+1152
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "toy_interpreter.h"
|
||||
|
||||
int Toy_hookMath(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
|
||||
+1
-1
@@ -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>
|
||||
|
||||
|
||||
+261
-110
@@ -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)) {
|
||||
@@ -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);
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "toy_interpreter.h"
|
||||
|
||||
int Toy_hookToyVersionInfo(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
|
||||
+1
-1
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import standard;
|
||||
var array = [42];
|
||||
|
||||
var result = null;
|
||||
|
||||
//problematic line
|
||||
result = max(0, array[0]);
|
||||
|
||||
assert result == 42, "Indexing in argument list failed";
|
||||
|
||||
|
||||
print "All good";
|
||||
+3
-3
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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->binary.left = *nodeHandle;
|
||||
tmp->binary.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->binary.left = *nodeHandle;
|
||||
tmp->binary.right = rhs;
|
||||
|
||||
*nodeHandle = tmp;
|
||||
}
|
||||
|
||||
void Toy_emitASTNodePrefixIncrement(Toy_ASTNode** nodeHandle, Toy_Literal identifier) {
|
||||
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+62
-6
@@ -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
|
||||
}
|
||||
@@ -917,6 +925,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
File diff suppressed because it is too large
Load Diff
+3
-3
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
+2
-2
@@ -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))
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
@@ -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";
|
||||
}
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
var array = [
|
||||
1, 2, 3,
|
||||
4, 5, 6,
|
||||
7, 8, 9, //explicitly leave a trailing comma
|
||||
];
|
||||
|
||||
|
||||
print "All good";
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "toy_drive_system.h"
|
||||
#include "drive_system.h"
|
||||
|
||||
#include "toy_console_colors.h"
|
||||
|
||||
|
||||
+11
-3
@@ -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,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}
|
||||
};
|
||||
|
||||
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,550 @@
|
||||
/*
|
||||
* disassembler.c
|
||||
*
|
||||
* Created on: 10 ago. 2023
|
||||
* Original Author: egonzalez
|
||||
*
|
||||
* 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.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][2] = {
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_EOF
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_PASS
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_ASSERT
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_PRINT
|
||||
{ DIS_ARG_BYTE, DIS_ARG_NONE }, // DIS_OP_LITERAL
|
||||
{ DIS_ARG_WORD, DIS_ARG_NONE }, // DIS_OP_LITERAL_LONG
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_LITERAL_RAW
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_NEGATE
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_ADDITION
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_SUBTRACTION
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_MULTIPLICATION
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_DIVISION
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_MODULO
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_GROUPING_BEGIN
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_GROUPING_END
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_SCOPE_BEGIN
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_SCOPE_END
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_TYPE_DECL_removed
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_TYPE_DECL_LONG_removed
|
||||
{ DIS_ARG_BYTE, DIS_ARG_BYTE }, // DIS_OP_VAR_DECL
|
||||
{ DIS_ARG_WORD, DIS_ARG_WORD }, // DIS_OP_VAR_DECL_LONG
|
||||
{ DIS_ARG_BYTE, DIS_ARG_BYTE }, // DIS_OP_FN_DECL
|
||||
{ DIS_ARG_WORD, DIS_ARG_WORD }, // DIS_OP_FN_DECL_LONG
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_VAR_ASSIGN
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_VAR_ADDITION_ASSIGN
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_VAR_SUBTRACTION_ASSIGN
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_VAR_MULTIPLICATION_ASSIGN
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_VAR_DIVISION_ASSIGN
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_VAR_MODULO_ASSIGN
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_TYPE_CAST
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_TYPE_OF
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_IMPORT
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_EXPORT_removed
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_INDEX
|
||||
{ DIS_ARG_BYTE, DIS_ARG_NONE }, // DIS_OP_INDEX_ASSIGN
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_INDEX_ASSIGN_INTERMEDIATE
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_DOT
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_COMPARE_EQUAL
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_COMPARE_NOT_EQUAL
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_COMPARE_LESS
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_COMPARE_LESS_EQUAL
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_COMPARE_GREATER
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_COMPARE_GREATER_EQUAL
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_INVERT
|
||||
{ DIS_ARG_WORD, DIS_ARG_NONE }, // DIS_OP_AND
|
||||
{ DIS_ARG_WORD, DIS_ARG_NONE }, // DIS_OP_OR
|
||||
{ DIS_ARG_WORD, DIS_ARG_NONE }, // DIS_OP_JUMP
|
||||
{ DIS_ARG_WORD, DIS_ARG_NONE }, // DIS_OP_IF_FALSE_JUMP
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_FN_CALL
|
||||
{ DIS_ARG_WORD, DIS_ARG_NONE }, // DIS_OP_FN_RETURN
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_POP_STACK
|
||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_TERNARY
|
||||
};
|
||||
|
||||
typedef struct dis_program_s {
|
||||
uint8_t *program;
|
||||
uint32_t len;
|
||||
uint32_t pc;
|
||||
} dis_program_t;
|
||||
|
||||
typedef struct dis_func_op_s {
|
||||
uint32_t start;
|
||||
uint32_t end;
|
||||
} dis_func_op_t;
|
||||
|
||||
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)->len = 0;
|
||||
(*prg)->pc = 0;
|
||||
}
|
||||
|
||||
static void dis_disassembler_deinit(dis_program_t **prg) {
|
||||
free((*prg)->program);
|
||||
free((*prg));
|
||||
}
|
||||
|
||||
static uint8_t dis_load_file(const char *filename, dis_program_t **prg) {
|
||||
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;
|
||||
printf("\nFile: %s\nSize: %zu\n", filename, fsize);
|
||||
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dis_read_header(dis_program_t **prg) {
|
||||
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));
|
||||
printf("[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) \
|
||||
switch (OP_ARGS[opcode][n]) { \
|
||||
case DIS_ARG_NONE: \
|
||||
break; \
|
||||
case DIS_ARG_BYTE: \
|
||||
uint = readByte((*prg)->program, &pc); \
|
||||
printf(" b(%d)", uint); \
|
||||
break; \
|
||||
case DIS_ARG_WORD: \
|
||||
uint = readWord((*prg)->program, &pc);\
|
||||
printf(" w(%d)", uint); \
|
||||
break; \
|
||||
case DIS_ARG_INTEGER: \
|
||||
intg = readInt((*prg)->program, &pc); \
|
||||
printf(" i(%d)", intg); \
|
||||
break; \
|
||||
case DIS_ARG_FLOAT: \
|
||||
flt = readFloat((*prg)->program, &pc); \
|
||||
printf(" f(%f)", flt); \
|
||||
break; \
|
||||
case DIS_ARG_STRING: \
|
||||
str = readString((*prg)->program, &pc); \
|
||||
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) {
|
||||
uint8_t opcode;
|
||||
uint32_t uint;
|
||||
int32_t intg;
|
||||
float flt;
|
||||
char *str;
|
||||
|
||||
//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);
|
||||
SPC(spaces);
|
||||
printf("| [args literal %d, rets literal %d]", args, rets);
|
||||
}
|
||||
|
||||
while (pc < len) {
|
||||
opcode = (*prg)->program[pc];
|
||||
printf("\n");
|
||||
SPC(spaces);
|
||||
printf("| [ %05d ](%03d) ", pc++, opcode);
|
||||
dis_print_opcode(opcode);
|
||||
|
||||
if (opcode > DIS_OP_END_OPCODES)
|
||||
continue;
|
||||
|
||||
S_OP(0);
|
||||
S_OP(1);
|
||||
}
|
||||
}
|
||||
|
||||
#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) {
|
||||
uint32_t literal_count = 0;
|
||||
uint8_t literal_type[65536];
|
||||
|
||||
const unsigned short literalCount = readWord((*prg)->program, pc);
|
||||
|
||||
printf("\n");
|
||||
SPC(spaces);
|
||||
printf("| ( Reading %d literals )\n", literalCount);
|
||||
|
||||
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);
|
||||
SPC(spaces);
|
||||
printf("| | [%d] ( null )\n", i);
|
||||
break;
|
||||
|
||||
case DIS_LITERAL_BOOLEAN: {
|
||||
const bool b = readByte((*prg)->program, pc);
|
||||
LIT_ADD(DIS_LITERAL_BOOLEAN, literal_type, literal_count);
|
||||
SPC(spaces);
|
||||
printf("| | [%d] ( boolean %s )\n", i, b ? "true" : "false");
|
||||
}
|
||||
break;
|
||||
|
||||
case DIS_LITERAL_INTEGER: {
|
||||
const int d = readInt((*prg)->program, pc);
|
||||
LIT_ADD(DIS_LITERAL_INTEGER, literal_type, literal_count);
|
||||
SPC(spaces);
|
||||
printf("| | [%d] ( integer %d )\n", i, d);
|
||||
}
|
||||
break;
|
||||
|
||||
case DIS_LITERAL_FLOAT: {
|
||||
const float f = readFloat((*prg)->program, pc);
|
||||
LIT_ADD(DIS_LITERAL_FLOAT, literal_type, literal_count);
|
||||
SPC(spaces);
|
||||
printf("| | [%d] ( float %f )\n", i, f);
|
||||
}
|
||||
break;
|
||||
|
||||
case DIS_LITERAL_STRING: {
|
||||
const char *s = readString((*prg)->program, pc);
|
||||
LIT_ADD(DIS_LITERAL_STRING, literal_type, literal_count);
|
||||
SPC(spaces);
|
||||
printf("| | [%d] ( string \"%s\" )\n", i, s);
|
||||
}
|
||||
break;
|
||||
|
||||
case DIS_LITERAL_ARRAY_INTERMEDIATE:
|
||||
case DIS_LITERAL_ARRAY: {
|
||||
unsigned short length = readWord((*prg)->program, pc);
|
||||
SPC(spaces);
|
||||
printf("| | [%d] ( array ", i);
|
||||
for (int i = 0; i < length; i++) {
|
||||
int index = readWord((*prg)->program, pc);
|
||||
printf("%d ", index);
|
||||
LIT_ADD(DIS_LITERAL_NULL, literal_type, literal_count);
|
||||
if (!(i % 15) && i != 0) {
|
||||
printf("\n");
|
||||
SPC(spaces);
|
||||
printf("| | ");
|
||||
}
|
||||
}
|
||||
printf(")\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);
|
||||
SPC(spaces);
|
||||
printf("| | [%d] ( dictionary ", i);
|
||||
for (int i = 0; i < length / 2; i++) {
|
||||
int key = readWord((*prg)->program, pc);
|
||||
int val = readWord((*prg)->program, pc);
|
||||
printf("(key: %d, val:%d) ", key, val);
|
||||
if(!(i % 5) && i != 0){
|
||||
printf("\n");
|
||||
SPC(spaces);
|
||||
printf("| | ");
|
||||
}
|
||||
}
|
||||
printf(")\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);
|
||||
SPC(spaces);
|
||||
printf("| | [%d] ( function index: %d )\n", i, index);
|
||||
}
|
||||
break;
|
||||
|
||||
case DIS_LITERAL_IDENTIFIER: {
|
||||
const char *str = readString((*prg)->program, pc);
|
||||
LIT_ADD(DIS_LITERAL_IDENTIFIER, literal_type, literal_count);
|
||||
SPC(spaces);
|
||||
printf("| | [%d] ( identifier %s )\n", i, str);
|
||||
}
|
||||
break;
|
||||
|
||||
case DIS_LITERAL_TYPE:
|
||||
case DIS_LITERAL_TYPE_INTERMEDIATE: {
|
||||
uint8_t literalType = readByte((*prg)->program, pc);
|
||||
uint8_t constant = readByte((*prg)->program, pc);
|
||||
SPC(spaces);
|
||||
printf("| | [%d] ( type %s: %d)\n", i, (LIT_STR[literalType] + 12), constant);
|
||||
if (literalType == DIS_LITERAL_ARRAY) {
|
||||
uint16_t vt = readWord((*prg)->program, pc);
|
||||
SPC(spaces);
|
||||
printf("| | | ( subtype: %d)\n", vt);
|
||||
}
|
||||
|
||||
if (literalType == DIS_LITERAL_DICTIONARY) {
|
||||
uint8_t kt = readWord((*prg)->program, pc);
|
||||
uint8_t vt = readWord((*prg)->program, pc);
|
||||
SPC(spaces);
|
||||
printf("| | | ( subtype: [%d, %d] )\n", kt, vt);
|
||||
}
|
||||
LIT_ADD(literalType, literal_type, literal_count);
|
||||
}
|
||||
break;
|
||||
|
||||
case DIS_LITERAL_INDEX_BLANK:
|
||||
LIT_ADD(DIS_LITERAL_INDEX_BLANK, literal_type, literal_count);
|
||||
SPC(spaces);
|
||||
printf("| | [%d] ( blank )\n", i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
consumeByte(DIS_OP_SECTION_END, (*prg)->program, pc);
|
||||
|
||||
int functionCount = readWord((*prg)->program, pc);
|
||||
int functionSize = readWord((*prg)->program, pc);
|
||||
|
||||
if (functionCount) {
|
||||
SPC(spaces);
|
||||
printf("| | \n");
|
||||
SPC(spaces);
|
||||
printf("| | ( fun count: %d, total size: %d )\n", functionCount, functionSize);
|
||||
|
||||
uint32_t fcnt = 0;
|
||||
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;
|
||||
|
||||
SPC(spaces);
|
||||
printf("| | |\n");
|
||||
SPC(spaces);
|
||||
printf("| | | ( fun %d [ start: %d, end: %d ] )", fcnt, fpc_start, fpc_end);
|
||||
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);
|
||||
SPC(spaces);
|
||||
printf("| | |\n");
|
||||
SPC(spaces + 4);
|
||||
printf("| ------ CODE ------");
|
||||
dis_disassemble_section(prg, fpc_start, fpc_end, spaces + 4, true);
|
||||
printf("\n");
|
||||
SPC(spaces + 4);
|
||||
printf("| ---- END CODE ----\n");
|
||||
|
||||
fcnt++;
|
||||
*pc += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
consumeByte(DIS_OP_SECTION_END, (*prg)->program, pc);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void disassemble(const char *filename) {
|
||||
dis_program_t *prg;
|
||||
|
||||
dis_disassembler_init(&prg);
|
||||
if (dis_load_file(filename, &prg))
|
||||
exit(1);
|
||||
|
||||
dis_read_header(&prg);
|
||||
|
||||
consumeByte(DIS_OP_SECTION_END, prg->program, &(prg->pc));
|
||||
|
||||
printf("\n| ---- LITERALS ----");
|
||||
dis_read_interpreter_sections(&prg, &(prg->pc), 0);
|
||||
printf("| -- END LITERALS --\n|");
|
||||
|
||||
printf("\n| ---- PROGRAM ----");
|
||||
dis_disassemble_section(&prg, prg->pc, prg->len, 0, false);
|
||||
printf("\n| -- END PROGRAM --");
|
||||
|
||||
printf("\n\n");
|
||||
dis_disassembler_deinit(&prg);
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
#ifndef DISASSEMBLER_H_
|
||||
#define DISASSEMBLER_H_
|
||||
|
||||
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, // for more than 256 literals in a chunk
|
||||
DIS_OP_LITERAL_RAW, // forcibly get the raw value of the literal
|
||||
|
||||
// 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, // declare a variable to be used (as a literal)
|
||||
DIS_OP_VAR_DECL_LONG, // declare a variable to be used (as a long literal)
|
||||
|
||||
DIS_OP_FN_DECL, // declare a function to be used (as a literal)
|
||||
DIS_OP_FN_DECL_LONG, // declare a function to be used (as a long literal)
|
||||
|
||||
DIS_OP_VAR_ASSIGN, // assign to a literal
|
||||
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, // temporarily change a type of an atomic value
|
||||
DIS_OP_TYPE_OF, // get the type of a variable
|
||||
|
||||
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, // for booleans
|
||||
|
||||
// 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);
|
||||
|
||||
#endif /* DISASSEMBLER_H_ */
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "disassembler.h"
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
disassemble(argv[1]);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -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))
|
||||
OUTNAME=
|
||||
OUT=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)
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user