Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 18b59c9e84 | |||
| d3eb31d964 | |||
| 07f4a98b95 | |||
| 0949fd6ff9 | |||
| 03e5096f10 | |||
| bb81b8c474 | |||
| cf6db57787 | |||
| 17f0e4476b | |||
| 1095e1a885 | |||
| 2edfbbe3ef | |||
| 4b83f1f0d6 | |||
| e2fa1cf2e8 | |||
| a04d2c4816 | |||
| f2f8aed23a | |||
| 68ed52b347 | |||
| 88dac53ae0 |
+4
-2
@@ -115,13 +115,15 @@
|
|||||||
<ClCompile>
|
<ClCompile>
|
||||||
<AdditionalIncludeDirectories>$(SolutionDir)/source;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(SolutionDir)/source;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<LanguageStandard_C>stdc17</LanguageStandard_C>
|
<LanguageStandard_C>stdc17</LanguageStandard_C>
|
||||||
<PreprocessorDefinitions>LIB_RUNNER_EXPORT</PreprocessorDefinitions>
|
<PreprocessorDefinitions>
|
||||||
|
</PreprocessorDefinitions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<LanguageStandard_C>stdc17</LanguageStandard_C>
|
<LanguageStandard_C>stdc17</LanguageStandard_C>
|
||||||
<PreprocessorDefinitions>LIB_RUNNER_EXPORT</PreprocessorDefinitions>
|
<PreprocessorDefinitions>
|
||||||
|
</PreprocessorDefinitions>
|
||||||
<AdditionalIncludeDirectories>$(SolutionDir)/source;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(SolutionDir)/source;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
|
|||||||
@@ -123,6 +123,7 @@
|
|||||||
<ClCompile Include="source\toy_builtin.c" />
|
<ClCompile Include="source\toy_builtin.c" />
|
||||||
<ClCompile Include="source\toy_common.c" />
|
<ClCompile Include="source\toy_common.c" />
|
||||||
<ClCompile Include="source\toy_compiler.c" />
|
<ClCompile Include="source\toy_compiler.c" />
|
||||||
|
<ClCompile Include="source\toy_drive_system.c" />
|
||||||
<ClCompile Include="source\toy_interpreter.c" />
|
<ClCompile Include="source\toy_interpreter.c" />
|
||||||
<ClCompile Include="source\toy_keyword_types.c" />
|
<ClCompile Include="source\toy_keyword_types.c" />
|
||||||
<ClCompile Include="source\toy_lexer.c" />
|
<ClCompile Include="source\toy_lexer.c" />
|
||||||
@@ -131,15 +132,18 @@
|
|||||||
<ClCompile Include="source\toy_literal_dictionary.c" />
|
<ClCompile Include="source\toy_literal_dictionary.c" />
|
||||||
<ClCompile Include="source\toy_memory.c" />
|
<ClCompile Include="source\toy_memory.c" />
|
||||||
<ClCompile Include="source\toy_parser.c" />
|
<ClCompile Include="source\toy_parser.c" />
|
||||||
|
<ClCompile Include="source\toy_reffunction.c" />
|
||||||
<ClCompile Include="source\toy_refstring.c" />
|
<ClCompile Include="source\toy_refstring.c" />
|
||||||
<ClCompile Include="source\toy_scope.c" />
|
<ClCompile Include="source\toy_scope.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="source\toy.h" />
|
||||||
<ClInclude Include="source\toy_ast_node.h" />
|
<ClInclude Include="source\toy_ast_node.h" />
|
||||||
<ClInclude Include="source\toy_builtin.h" />
|
<ClInclude Include="source\toy_builtin.h" />
|
||||||
<ClInclude Include="source\toy_common.h" />
|
<ClInclude Include="source\toy_common.h" />
|
||||||
<ClInclude Include="source\toy_compiler.h" />
|
<ClInclude Include="source\toy_compiler.h" />
|
||||||
<ClInclude Include="source\toy_console_colors.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_interpreter.h" />
|
||||||
<ClInclude Include="source\toy_keyword_types.h" />
|
<ClInclude Include="source\toy_keyword_types.h" />
|
||||||
<ClInclude Include="source\toy_lexer.h" />
|
<ClInclude Include="source\toy_lexer.h" />
|
||||||
@@ -149,6 +153,7 @@
|
|||||||
<ClInclude Include="source\toy_memory.h" />
|
<ClInclude Include="source\toy_memory.h" />
|
||||||
<ClInclude Include="source\toy_opcodes.h" />
|
<ClInclude Include="source\toy_opcodes.h" />
|
||||||
<ClInclude Include="source\toy_parser.h" />
|
<ClInclude Include="source\toy_parser.h" />
|
||||||
|
<ClInclude Include="source\toy_reffunction.h" />
|
||||||
<ClInclude Include="source\toy_refstring.h" />
|
<ClInclude Include="source\toy_refstring.h" />
|
||||||
<ClInclude Include="source\toy_scope.h" />
|
<ClInclude Include="source\toy_scope.h" />
|
||||||
<ClInclude Include="source\toy_token_types.h" />
|
<ClInclude Include="source\toy_token_types.h" />
|
||||||
|
|||||||
@@ -28,10 +28,10 @@ library: $(TOY_OUTDIR)
|
|||||||
static: $(TOY_OUTDIR)
|
static: $(TOY_OUTDIR)
|
||||||
$(MAKE) -j8 -C source static
|
$(MAKE) -j8 -C source static
|
||||||
|
|
||||||
library-release: $(TOY_OUTDIR)
|
library-release: clean $(TOY_OUTDIR)
|
||||||
$(MAKE) -j8 -C source library-release
|
$(MAKE) -j8 -C source library-release
|
||||||
|
|
||||||
static-release: $(TOY_OUTDIR)
|
static-release: clean $(TOY_OUTDIR)
|
||||||
$(MAKE) -j8 -C source static-release
|
$(MAKE) -j8 -C source static-release
|
||||||
|
|
||||||
#utils
|
#utils
|
||||||
|
|||||||
+10
-145
@@ -1,13 +1,12 @@
|
|||||||
#include "lib_runner.h"
|
#include "lib_runner.h"
|
||||||
|
|
||||||
#include "toy_memory.h"
|
#include "toy_memory.h"
|
||||||
|
#include "toy_drive_system.h"
|
||||||
#include "toy_interpreter.h"
|
#include "toy_interpreter.h"
|
||||||
|
|
||||||
#include "repl_tools.h"
|
#include "repl_tools.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
typedef struct Toy_Runner {
|
typedef struct Toy_Runner {
|
||||||
Toy_Interpreter interpreter;
|
Toy_Interpreter interpreter;
|
||||||
@@ -38,7 +37,7 @@ static int nativeLoadScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_Literal filePathLiteral = Toy_getFilePathLiteral(interpreter, &drivePathLiteral);
|
Toy_Literal filePathLiteral = Toy_getDrivePathLiteral(interpreter, &drivePathLiteral);
|
||||||
|
|
||||||
if (TOY_IS_NULL(filePathLiteral)) {
|
if (TOY_IS_NULL(filePathLiteral)) {
|
||||||
Toy_freeLiteral(filePathLiteral);
|
Toy_freeLiteral(filePathLiteral);
|
||||||
@@ -113,70 +112,19 @@ static int nativeLoadScriptBytecode(Toy_Interpreter* interpreter, Toy_LiteralArr
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_RefString* drivePath = Toy_copyRefString(TOY_AS_STRING(drivePathLiteral));
|
Toy_Literal filePathLiteral = Toy_getDrivePathLiteral(interpreter, &drivePathLiteral);
|
||||||
|
|
||||||
//get the drive and path as a string (can't trust that pesky strtok - custom split) TODO: move this to refstring library
|
if (TOY_IS_NULL(filePathLiteral)) {
|
||||||
size_t driveLength = 0;
|
Toy_freeLiteral(filePathLiteral);
|
||||||
while (Toy_toCString(drivePath)[driveLength] != ':') {
|
|
||||||
if (driveLength >= Toy_lengthRefString(drivePath)) {
|
|
||||||
interpreter->errorOutput("Incorrect drive path format given to loadScriptBytecode\n");
|
|
||||||
Toy_deleteRefString(drivePath);
|
|
||||||
Toy_freeLiteral(drivePathLiteral);
|
Toy_freeLiteral(drivePathLiteral);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
driveLength++;
|
|
||||||
}
|
|
||||||
|
|
||||||
Toy_RefString* drive = Toy_createRefStringLength(Toy_toCString(drivePath), driveLength);
|
|
||||||
Toy_RefString* path = Toy_createRefStringLength( &Toy_toCString(drivePath)[driveLength + 1], Toy_lengthRefString(drivePath) - driveLength );
|
|
||||||
|
|
||||||
//get the real drive file path
|
|
||||||
Toy_Literal driveLiteral = TOY_TO_STRING_LITERAL(drive); //NOTE: driveLiteral takes ownership of the refString
|
|
||||||
Toy_Literal realDriveLiteral = Toy_getLiteralDictionary(Toy_getDriveDictionary(), driveLiteral);
|
|
||||||
|
|
||||||
if (!TOY_IS_STRING(realDriveLiteral)) {
|
|
||||||
interpreter->errorOutput("Incorrect literal type found for drive: ");
|
|
||||||
Toy_printLiteralCustom(realDriveLiteral, interpreter->errorOutput);
|
|
||||||
interpreter->errorOutput("\n");
|
|
||||||
Toy_freeLiteral(realDriveLiteral);
|
|
||||||
Toy_freeLiteral(driveLiteral);
|
|
||||||
Toy_deleteRefString(path);
|
|
||||||
Toy_deleteRefString(drivePath);
|
|
||||||
Toy_freeLiteral(drivePathLiteral);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//get the final real file path (concat) TODO: move this concat to refstring library
|
|
||||||
Toy_RefString* realDrive = Toy_copyRefString(TOY_AS_STRING(realDriveLiteral));
|
|
||||||
size_t realLength = Toy_lengthRefString(realDrive) + Toy_lengthRefString(path);
|
|
||||||
|
|
||||||
char* filePath = TOY_ALLOCATE(char, realLength + 1); //+1 for null
|
|
||||||
snprintf(filePath, realLength, "%s%s", Toy_toCString(realDrive), Toy_toCString(path));
|
|
||||||
|
|
||||||
//clean up the drivepath stuff
|
|
||||||
Toy_deleteRefString(realDrive);
|
|
||||||
Toy_freeLiteral(realDriveLiteral);
|
|
||||||
Toy_freeLiteral(driveLiteral);
|
|
||||||
Toy_deleteRefString(path);
|
|
||||||
Toy_deleteRefString(drivePath);
|
|
||||||
Toy_freeLiteral(drivePathLiteral);
|
Toy_freeLiteral(drivePathLiteral);
|
||||||
|
|
||||||
//check for file extensions
|
//use raw types - easier
|
||||||
if (!(filePath[realLength - 4] == '.' && filePath[realLength - 3] == 't' && filePath[realLength - 2] == 'b')) {
|
const char* filePath = Toy_toCString(TOY_AS_STRING(filePathLiteral));
|
||||||
interpreter->errorOutput("Bad binary file extension (expected .tb)\n");
|
size_t filePathLength = Toy_lengthRefString(TOY_AS_STRING(filePathLiteral));
|
||||||
TOY_FREE_ARRAY(char, filePath, realLength);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//check for break-out attempts
|
|
||||||
for (size_t i = 0; i < realLength - 1; i++) {
|
|
||||||
if (filePath[i] == '.' && filePath[i + 1] == '.') {
|
|
||||||
interpreter->errorOutput("Parent directory access not allowed\n");
|
|
||||||
TOY_FREE_ARRAY(char, filePath, realLength);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//load the bytecode
|
//load the bytecode
|
||||||
size_t fileSize = 0;
|
size_t fileSize = 0;
|
||||||
@@ -203,7 +151,8 @@ static int nativeLoadScriptBytecode(Toy_Interpreter* interpreter, Toy_LiteralArr
|
|||||||
Toy_Literal runnerLiteral = TOY_TO_OPAQUE_LITERAL(runner, TOY_OPAQUE_TAG_RUNNER);
|
Toy_Literal runnerLiteral = TOY_TO_OPAQUE_LITERAL(runner, TOY_OPAQUE_TAG_RUNNER);
|
||||||
Toy_pushLiteralArray(&interpreter->stack, runnerLiteral);
|
Toy_pushLiteralArray(&interpreter->stack, runnerLiteral);
|
||||||
|
|
||||||
TOY_FREE_ARRAY(char, filePath, realLength);
|
//free the drive path
|
||||||
|
Toy_freeLiteral(filePathLiteral);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -602,87 +551,3 @@ int Toy_hookRunner(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Lit
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//file system API
|
|
||||||
static Toy_LiteralDictionary Toy_driveDictionary;
|
|
||||||
|
|
||||||
void Toy_initDriveDictionary() {
|
|
||||||
Toy_initLiteralDictionary(&Toy_driveDictionary);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Toy_freeDriveDictionary() {
|
|
||||||
Toy_freeLiteralDictionary(&Toy_driveDictionary);
|
|
||||||
}
|
|
||||||
|
|
||||||
Toy_LiteralDictionary* Toy_getDriveDictionary() {
|
|
||||||
return &Toy_driveDictionary;
|
|
||||||
}
|
|
||||||
|
|
||||||
Toy_Literal Toy_getFilePathLiteral(Toy_Interpreter* interpreter, Toy_Literal* drivePathLiteral) {
|
|
||||||
//check argument types
|
|
||||||
if (!TOY_IS_STRING(*drivePathLiteral)) {
|
|
||||||
interpreter->errorOutput("Incorrect argument type passed to Toy_getFilePathLiteral\n");
|
|
||||||
return TOY_TO_NULL_LITERAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Toy_RefString* drivePath = Toy_copyRefString(TOY_AS_STRING(*drivePathLiteral));
|
|
||||||
|
|
||||||
//get the drive and path as a string (can't trust that pesky strtok - custom split) TODO: move this to refstring library
|
|
||||||
size_t driveLength = 0;
|
|
||||||
while (Toy_toCString(drivePath)[driveLength] != ':') {
|
|
||||||
if (driveLength >= Toy_lengthRefString(drivePath)) {
|
|
||||||
interpreter->errorOutput("Incorrect drive path format given to Toy_getFilePathLiteral\n");
|
|
||||||
|
|
||||||
return TOY_TO_NULL_LITERAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
driveLength++;
|
|
||||||
}
|
|
||||||
|
|
||||||
Toy_RefString* drive = Toy_createRefStringLength(Toy_toCString(drivePath), driveLength);
|
|
||||||
Toy_RefString* path = Toy_createRefStringLength( &Toy_toCString(drivePath)[driveLength + 1], Toy_lengthRefString(drivePath) - driveLength );
|
|
||||||
|
|
||||||
//get the real drive file path
|
|
||||||
Toy_Literal driveLiteral = TOY_TO_STRING_LITERAL(drive); //NOTE: driveLiteral takes ownership of the refString
|
|
||||||
Toy_Literal realDriveLiteral = Toy_getLiteralDictionary(Toy_getDriveDictionary(), driveLiteral);
|
|
||||||
|
|
||||||
if (!TOY_IS_STRING(realDriveLiteral)) {
|
|
||||||
interpreter->errorOutput("Incorrect literal type found for drive: ");
|
|
||||||
Toy_printLiteralCustom(realDriveLiteral, interpreter->errorOutput);
|
|
||||||
interpreter->errorOutput("\n");
|
|
||||||
Toy_freeLiteral(realDriveLiteral);
|
|
||||||
Toy_freeLiteral(driveLiteral);
|
|
||||||
Toy_deleteRefString(path);
|
|
||||||
Toy_deleteRefString(drivePath);
|
|
||||||
|
|
||||||
return TOY_TO_NULL_LITERAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
//get the final real file path (concat) TODO: move this concat to refstring library
|
|
||||||
Toy_RefString* realDrive = Toy_copyRefString(TOY_AS_STRING(realDriveLiteral));
|
|
||||||
size_t realLength = Toy_lengthRefString(realDrive) + Toy_lengthRefString(path);
|
|
||||||
|
|
||||||
char* filePath = TOY_ALLOCATE(char, realLength + 1); //+1 for null
|
|
||||||
snprintf(filePath, realLength, "%s%s", Toy_toCString(realDrive), Toy_toCString(path));
|
|
||||||
|
|
||||||
//clean up the drivepath stuff
|
|
||||||
Toy_deleteRefString(realDrive);
|
|
||||||
Toy_freeLiteral(realDriveLiteral);
|
|
||||||
Toy_freeLiteral(driveLiteral);
|
|
||||||
Toy_deleteRefString(path);
|
|
||||||
Toy_deleteRefString(drivePath);
|
|
||||||
|
|
||||||
//check for break-out attempts
|
|
||||||
for (size_t i = 0; i < realLength - 1; i++) {
|
|
||||||
if (filePath[i] == '.' && filePath[i + 1] == '.') {
|
|
||||||
interpreter->errorOutput("Parent directory access not allowed\n");
|
|
||||||
TOY_FREE_ARRAY(char, filePath, realLength + 1);
|
|
||||||
return TOY_TO_NULL_LITERAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Toy_Literal result = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(filePath, realLength));
|
|
||||||
|
|
||||||
TOY_FREE_ARRAY(char, filePath, realLength + 1);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -1,35 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "toy_common.h"
|
|
||||||
#include "toy_interpreter.h"
|
#include "toy_interpreter.h"
|
||||||
|
|
||||||
int Toy_hookRunner(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
|
int Toy_hookRunner(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
|
||||||
|
|
||||||
#define TOY_OPAQUE_TAG_RUNNER 100
|
#define TOY_OPAQUE_TAG_RUNNER 100
|
||||||
|
|
||||||
//platform/compiler-specific instructions - because MSVC + Box Engine are dumber than a bag of rocks
|
|
||||||
#if defined(__linux__) || defined(__MINGW32__) || defined(__GNUC__)
|
|
||||||
|
|
||||||
#define LIB_RUNNER_API extern
|
|
||||||
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
|
|
||||||
#ifndef LIB_RUNNER_EXPORT
|
|
||||||
#define LIB_RUNNER_API __declspec(dllimport)
|
|
||||||
#else
|
|
||||||
#define LIB_RUNNER_API __declspec(dllexport)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define LIB_RUNNER_API extern
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//file system API - these need to be set by the host
|
|
||||||
LIB_RUNNER_API void Toy_initDriveDictionary();
|
|
||||||
LIB_RUNNER_API void Toy_freeDriveDictionary();
|
|
||||||
LIB_RUNNER_API Toy_LiteralDictionary* Toy_getDriveDictionary();
|
|
||||||
|
|
||||||
//file system API - for use with other libs
|
|
||||||
LIB_RUNNER_API Toy_Literal Toy_getFilePathLiteral(Toy_Interpreter* interpreter, Toy_Literal* drivePathLiteral);
|
|
||||||
|
|||||||
+8
-18
@@ -6,10 +6,7 @@
|
|||||||
|
|
||||||
#include "toy_console_colors.h"
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
#include "toy_lexer.h"
|
#include "toy.h"
|
||||||
#include "toy_parser.h"
|
|
||||||
#include "toy_compiler.h"
|
|
||||||
#include "toy_interpreter.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -106,16 +103,9 @@ void repl(const char* initialInput) {
|
|||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
Toy_initCommandLine(argc, argv);
|
Toy_initCommandLine(argc, argv);
|
||||||
|
|
||||||
//lib setup (hacky - only really for this program)
|
//setup the drive system (for filesystem access)
|
||||||
Toy_initDriveDictionary();
|
Toy_initDriveSystem();
|
||||||
|
Toy_setDrivePath("scripts", "scripts");
|
||||||
Toy_Literal driveLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("scripts"));
|
|
||||||
Toy_Literal pathLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("scripts"));
|
|
||||||
|
|
||||||
Toy_setLiteralDictionary(Toy_getDriveDictionary(), driveLiteral, pathLiteral);
|
|
||||||
|
|
||||||
Toy_freeLiteral(driveLiteral);
|
|
||||||
Toy_freeLiteral(pathLiteral);
|
|
||||||
|
|
||||||
//command line specific actions
|
//command line specific actions
|
||||||
if (Toy_commandLine.error) {
|
if (Toy_commandLine.error) {
|
||||||
@@ -151,7 +141,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
Toy_runSourceFile(Toy_commandLine.sourcefile);
|
Toy_runSourceFile(Toy_commandLine.sourcefile);
|
||||||
|
|
||||||
//lib cleanup
|
//lib cleanup
|
||||||
Toy_freeDriveDictionary();
|
Toy_freeDriveSystem();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -161,7 +151,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
Toy_runSource(Toy_commandLine.source);
|
Toy_runSource(Toy_commandLine.source);
|
||||||
|
|
||||||
//lib cleanup
|
//lib cleanup
|
||||||
Toy_freeDriveDictionary();
|
Toy_freeDriveSystem();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -207,7 +197,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
Toy_runBinaryFile(Toy_commandLine.binaryfile);
|
Toy_runBinaryFile(Toy_commandLine.binaryfile);
|
||||||
|
|
||||||
//lib cleanup
|
//lib cleanup
|
||||||
Toy_freeDriveDictionary();
|
Toy_freeDriveSystem();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -228,7 +218,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
repl(initialSource);
|
repl(initialSource);
|
||||||
|
|
||||||
//lib cleanup
|
//lib cleanup
|
||||||
Toy_freeDriveDictionary();
|
Toy_freeDriveSystem();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -78,10 +78,10 @@ const unsigned char* Toy_compileString(const char* source, size_t* size) {
|
|||||||
Toy_initParser(&parser, &lexer);
|
Toy_initParser(&parser, &lexer);
|
||||||
Toy_initCompiler(&compiler);
|
Toy_initCompiler(&compiler);
|
||||||
|
|
||||||
//run the parser until the end of the source
|
//step 1 - run the parser until the end of the source
|
||||||
Toy_ASTNode* node = Toy_scanParser(&parser);
|
Toy_ASTNode* node = Toy_scanParser(&parser);
|
||||||
while(node != NULL) {
|
while(node != NULL) {
|
||||||
//pack up and leave
|
//on error, pack up and leave
|
||||||
if (node->type == TOY_AST_NODE_ERROR) {
|
if (node->type == TOY_AST_NODE_ERROR) {
|
||||||
Toy_freeASTNode(node);
|
Toy_freeASTNode(node);
|
||||||
Toy_freeCompiler(&compiler);
|
Toy_freeCompiler(&compiler);
|
||||||
@@ -94,7 +94,7 @@ const unsigned char* Toy_compileString(const char* source, size_t* size) {
|
|||||||
node = Toy_scanParser(&parser);
|
node = Toy_scanParser(&parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
//get the bytecode dump
|
//step 2 - get the bytecode dump
|
||||||
const unsigned char* tb = Toy_collateCompiler(&compiler, size);
|
const unsigned char* tb = Toy_collateCompiler(&compiler, size);
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
C 0.002s 1
|
||||||
|
JS 0.064s 32
|
||||||
|
Py3 0.070s 35
|
||||||
|
Toy 0.430s 215
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
//functions be local in C
|
||||||
|
int sum(int n) {
|
||||||
|
if (n < 2) {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return n + sum(n - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//the test case (C)
|
||||||
|
void test_sum(int key, int val) {
|
||||||
|
const int result = sum(val);
|
||||||
|
printf("%d: %d\n", key, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
for (int i = 0; i <= 10; i++) {
|
||||||
|
test_sum(i, i * 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
//the test case (js)
|
||||||
|
function test_sum(key, val) {
|
||||||
|
function sum(n) {
|
||||||
|
if (n < 2) {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return n + sum(n - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = sum(val);
|
||||||
|
console.log(`${key}: ${result}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i <= 10; i++) {
|
||||||
|
test_sum(i, i * 1000);
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import sys
|
||||||
|
sys.setrecursionlimit(11000)
|
||||||
|
|
||||||
|
#the test case (python)
|
||||||
|
def test_sum(key: int, val: int):
|
||||||
|
def sum(n: int):
|
||||||
|
if n < 2:
|
||||||
|
return n
|
||||||
|
|
||||||
|
return n + sum(n - 1)
|
||||||
|
|
||||||
|
result: int = sum(val)
|
||||||
|
print(str(key) + ": " + str(result))
|
||||||
|
|
||||||
|
for i in range(0, 10):
|
||||||
|
test_sum(i, i * 1000)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
//the test case (toy)
|
||||||
|
fn test_sum(key: int, val: int) {
|
||||||
|
fn sum(n: int) {
|
||||||
|
if (n < 2) {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return n + sum(n - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
var result: int const = sum(val);
|
||||||
|
print string key + ": " + string result;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i: int = 0; i <= 10; i++) {
|
||||||
|
test_sum(i, i * 1000);
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/* toy.h - A Toy Programming Language
|
||||||
|
|
||||||
|
If you're looking how to use Toy directly, try https://toylang.com/
|
||||||
|
Otherwise, these headers may help learn how Toy works internally.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* utilities - these define a bunch of useful macros based on platform.
|
||||||
|
|
||||||
|
The most important one is `TOY_API`, which highlights functions intended for the end user.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "toy_common.h"
|
||||||
|
#include "toy_console_colors.h"
|
||||||
|
#include "toy_memory.h"
|
||||||
|
#include "toy_drive_system.h"
|
||||||
|
|
||||||
|
/* core pipeline - from source to execution
|
||||||
|
|
||||||
|
Each step is as follows:
|
||||||
|
|
||||||
|
source -> lexer -> token
|
||||||
|
token -> parser -> AST
|
||||||
|
AST -> compiler -> bytecode
|
||||||
|
bytecode -> interpreter -> result
|
||||||
|
|
||||||
|
I should note that the parser -> compiler phase is actually made up of two steps - the write step
|
||||||
|
and the collate step. See `Toy_compileString()` in `repl/repl_tools.c` for an example of how to compile
|
||||||
|
properly.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "toy_lexer.h"
|
||||||
|
#include "toy_parser.h"
|
||||||
|
#include "toy_compiler.h"
|
||||||
|
#include "toy_interpreter.h"
|
||||||
|
|
||||||
|
/* building block structures - the basic units of operation
|
||||||
|
|
||||||
|
Literals represent any value within the language, including some internal ones that you never see.
|
||||||
|
Literal Arrays are literally arrays within memory, and are the most heavily used structure in Toy.
|
||||||
|
Literal Dictionaries are unordered key-value hashmaps, that use a running strategy for collisions.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "toy_literal.h"
|
||||||
|
#include "toy_literal_array.h"
|
||||||
|
#include "toy_literal_dictionary.h"
|
||||||
|
|
||||||
|
/* other components - you probably won't use these directly, but they're a good learning opportunity.
|
||||||
|
|
||||||
|
`Toy_Scope` holds the variables of a specific scope within Toy - be it a script, a function, a block, etc.
|
||||||
|
Scopes are also where the type system lives at runtime. They use identifier literals as keys, exclusively.
|
||||||
|
|
||||||
|
`Toy_RefString` is a utility class that wraps traditional C strings, making them less memory intensive and
|
||||||
|
faster to copy and move. In reality, since strings are considered immutable, multiple variables can point
|
||||||
|
to the same string to save memory, and you can just create a new one of these vars pointing to the original
|
||||||
|
rather than copying entirely for a speed boost. This module has it's own memory allocator system that is
|
||||||
|
plugged into the main memory allocator.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "toy_scope.h"
|
||||||
|
#include "toy_refstring.h"
|
||||||
|
|
||||||
+5
-1
@@ -4,7 +4,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
//test variable sizes based on platform
|
//test variable sizes based on platform - see issue #35
|
||||||
#define STATIC_ASSERT(test_for_true) static_assert((test_for_true), "(" #test_for_true ") failed")
|
#define STATIC_ASSERT(test_for_true) static_assert((test_for_true), "(" #test_for_true ") failed")
|
||||||
|
|
||||||
STATIC_ASSERT(sizeof(char) == 1);
|
STATIC_ASSERT(sizeof(char) == 1);
|
||||||
@@ -15,6 +15,8 @@ STATIC_ASSERT(sizeof(unsigned char) == 1);
|
|||||||
STATIC_ASSERT(sizeof(unsigned short) == 2);
|
STATIC_ASSERT(sizeof(unsigned short) == 2);
|
||||||
STATIC_ASSERT(sizeof(unsigned int) == 4);
|
STATIC_ASSERT(sizeof(unsigned int) == 4);
|
||||||
|
|
||||||
|
#ifndef TOY_DISABLE_REPL
|
||||||
|
|
||||||
//declare the singleton with default values
|
//declare the singleton with default values
|
||||||
Toy_CommandLine Toy_commandLine = {
|
Toy_CommandLine Toy_commandLine = {
|
||||||
.error = false,
|
.error = false,
|
||||||
@@ -134,3 +136,5 @@ void Toy_copyrightCommandLine(int argc, const char* argv[]) {
|
|||||||
printf("2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\n\n");
|
printf("2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\n\n");
|
||||||
printf("3. This notice may not be removed or altered from any source distribution.\n\n");
|
printf("3. This notice may not be removed or altered from any source distribution.\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
+6
-2
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
#define TOY_VERSION_MAJOR 1
|
#define TOY_VERSION_MAJOR 1
|
||||||
#define TOY_VERSION_MINOR 1
|
#define TOY_VERSION_MINOR 1
|
||||||
#define TOY_VERSION_PATCH 1
|
#define TOY_VERSION_PATCH 3
|
||||||
#define TOY_VERSION_BUILD __DATE__ " " __TIME__
|
#define TOY_VERSION_BUILD __DATE__ " " __TIME__
|
||||||
|
|
||||||
//platform/compiler-specific instructions
|
//platform/compiler-specific instructions
|
||||||
@@ -28,7 +28,9 @@
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//for processing the command line arguments
|
#ifndef TOY_DISABLE_REPL
|
||||||
|
|
||||||
|
//for processing the command line arguments in the repl
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool error;
|
bool error;
|
||||||
bool help;
|
bool help;
|
||||||
@@ -51,3 +53,5 @@ TOY_API void Toy_initCommandLine(int argc, const char* argv[]);
|
|||||||
TOY_API void Toy_usageCommandLine(int argc, const char* argv[]);
|
TOY_API void Toy_usageCommandLine(int argc, const char* argv[]);
|
||||||
TOY_API void Toy_helpCommandLine(int argc, const char* argv[]);
|
TOY_API void Toy_helpCommandLine(int argc, const char* argv[]);
|
||||||
TOY_API void Toy_copyrightCommandLine(int argc, const char* argv[]);
|
TOY_API void Toy_copyrightCommandLine(int argc, const char* argv[]);
|
||||||
|
|
||||||
|
#endif
|
||||||
+32
-5
@@ -331,9 +331,37 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
|
|||||||
return node->binary.opcode;
|
return node->binary.opcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret != TOY_OP_EOF && (node->binary.opcode == TOY_OP_VAR_ASSIGN || node->binary.opcode == TOY_OP_AND || node->binary.opcode == TOY_OP_OR || (node->binary.opcode >= TOY_OP_COMPARE_EQUAL && node->binary.opcode <= TOY_OP_INVERT))) {
|
//untangle in these cases - (WTF, are you serious?)
|
||||||
|
if (ret != TOY_OP_EOF) {
|
||||||
|
switch(node->binary.opcode) {
|
||||||
|
case TOY_OP_NEGATE:
|
||||||
|
case TOY_OP_ADDITION:
|
||||||
|
case TOY_OP_SUBTRACTION:
|
||||||
|
case TOY_OP_MULTIPLICATION:
|
||||||
|
case TOY_OP_DIVISION:
|
||||||
|
case TOY_OP_MODULO:
|
||||||
|
case TOY_OP_VAR_ASSIGN:
|
||||||
|
case TOY_OP_VAR_ADDITION_ASSIGN:
|
||||||
|
case TOY_OP_VAR_SUBTRACTION_ASSIGN:
|
||||||
|
case TOY_OP_VAR_MULTIPLICATION_ASSIGN:
|
||||||
|
case TOY_OP_VAR_DIVISION_ASSIGN:
|
||||||
|
case TOY_OP_VAR_MODULO_ASSIGN:
|
||||||
|
case TOY_OP_COMPARE_EQUAL:
|
||||||
|
case TOY_OP_COMPARE_NOT_EQUAL:
|
||||||
|
case TOY_OP_COMPARE_LESS:
|
||||||
|
case TOY_OP_COMPARE_LESS_EQUAL:
|
||||||
|
case TOY_OP_COMPARE_GREATER:
|
||||||
|
case TOY_OP_COMPARE_GREATER_EQUAL:
|
||||||
|
case TOY_OP_INVERT:
|
||||||
|
case TOY_OP_AND:
|
||||||
|
case TOY_OP_OR:
|
||||||
|
//place the rhs result before the outer instruction
|
||||||
compiler->bytecode[compiler->count++] = (unsigned char)ret; //1 byte
|
compiler->bytecode[compiler->count++] = (unsigned char)ret; //1 byte
|
||||||
ret = TOY_OP_EOF; //untangle in this case
|
ret = TOY_OP_EOF;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
compiler->bytecode[compiler->count++] = (unsigned char)node->binary.opcode; //1 byte
|
compiler->bytecode[compiler->count++] = (unsigned char)node->binary.opcode; //1 byte
|
||||||
@@ -490,8 +518,7 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
|
|||||||
}
|
}
|
||||||
|
|
||||||
//create the function in the literal cache (by storing the compiler object)
|
//create the function in the literal cache (by storing the compiler object)
|
||||||
Toy_Literal fnLiteral = TOY_TO_FUNCTION_LITERAL(fnCompiler, 0);
|
Toy_Literal fnLiteral = ((Toy_Literal){ .as = { .generic = fnCompiler }, .type = TOY_LITERAL_FUNCTION_INTERMEDIATE});
|
||||||
fnLiteral.type = TOY_LITERAL_FUNCTION_INTERMEDIATE; //NOTE: changing type
|
|
||||||
|
|
||||||
//push the name
|
//push the name
|
||||||
int identifierIndex = Toy_findLiteralIndex(&compiler->literalCache, node->fnDecl.identifier);
|
int identifierIndex = Toy_findLiteralIndex(&compiler->literalCache, node->fnDecl.identifier);
|
||||||
@@ -1182,7 +1209,7 @@ static unsigned char* collateCompilerHeaderOpt(Toy_Compiler* compiler, size_t* s
|
|||||||
case TOY_LITERAL_FUNCTION_INTERMEDIATE: {
|
case TOY_LITERAL_FUNCTION_INTERMEDIATE: {
|
||||||
//extract the compiler
|
//extract the compiler
|
||||||
Toy_Literal fn = compiler->literalCache.literals[i];
|
Toy_Literal fn = compiler->literalCache.literals[i];
|
||||||
void* fnCompiler = TOY_AS_FUNCTION(fn).inner.bytecode; //store the compiler here for now
|
void* fnCompiler = fn.as.generic; //store the compiler here for now
|
||||||
|
|
||||||
//collate the function into bytecode (without header)
|
//collate the function into bytecode (without header)
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
#include "toy_drive_system.h"
|
||||||
|
|
||||||
|
#include "toy_memory.h"
|
||||||
|
#include "toy_literal_dictionary.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
//file system API
|
||||||
|
static Toy_LiteralDictionary driveDictionary;
|
||||||
|
|
||||||
|
void Toy_initDriveSystem() {
|
||||||
|
Toy_initLiteralDictionary(&driveDictionary);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Toy_freeDriveSystem() {
|
||||||
|
Toy_freeLiteralDictionary(&driveDictionary);
|
||||||
|
}
|
||||||
|
|
||||||
|
TOY_API void Toy_setDrivePath(char* drive, char* path) {
|
||||||
|
Toy_Literal driveLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString(drive));
|
||||||
|
Toy_Literal pathLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString(path));
|
||||||
|
|
||||||
|
Toy_setLiteralDictionary(&driveDictionary, driveLiteral, pathLiteral);
|
||||||
|
|
||||||
|
Toy_freeLiteral(driveLiteral);
|
||||||
|
Toy_freeLiteral(pathLiteral);
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_Literal Toy_getDrivePathLiteral(Toy_Interpreter* interpreter, Toy_Literal* drivePathLiteral) {
|
||||||
|
//check argument types
|
||||||
|
if (!TOY_IS_STRING(*drivePathLiteral)) {
|
||||||
|
interpreter->errorOutput("Incorrect argument type passed to Toy_getDrivePathLiteral\n");
|
||||||
|
return TOY_TO_NULL_LITERAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_RefString* drivePath = Toy_copyRefString(TOY_AS_STRING(*drivePathLiteral));
|
||||||
|
|
||||||
|
//get the drive and path as a string (can't trust that pesky strtok - custom split) TODO: move this to refstring library
|
||||||
|
size_t driveLength = 0;
|
||||||
|
while (Toy_toCString(drivePath)[driveLength] != ':') {
|
||||||
|
if (driveLength >= Toy_lengthRefString(drivePath)) {
|
||||||
|
interpreter->errorOutput("Incorrect drive path format given to Toy_getDrivePathLiteral\n");
|
||||||
|
|
||||||
|
return TOY_TO_NULL_LITERAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
driveLength++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_RefString* drive = Toy_createRefStringLength(Toy_toCString(drivePath), driveLength);
|
||||||
|
Toy_RefString* filePath = Toy_createRefStringLength( &Toy_toCString(drivePath)[driveLength + 1], Toy_lengthRefString(drivePath) - driveLength );
|
||||||
|
|
||||||
|
//get the real drive file path
|
||||||
|
Toy_Literal driveLiteral = TOY_TO_STRING_LITERAL(drive); //NOTE: driveLiteral takes ownership of the refString
|
||||||
|
Toy_Literal pathLiteral = Toy_getLiteralDictionary(&driveDictionary, driveLiteral);
|
||||||
|
|
||||||
|
if (!TOY_IS_STRING(pathLiteral)) {
|
||||||
|
interpreter->errorOutput("Incorrect literal type found for drive: ");
|
||||||
|
Toy_printLiteralCustom(pathLiteral, interpreter->errorOutput);
|
||||||
|
interpreter->errorOutput("\n");
|
||||||
|
Toy_freeLiteral(driveLiteral);
|
||||||
|
Toy_freeLiteral(pathLiteral);
|
||||||
|
Toy_deleteRefString(filePath);
|
||||||
|
Toy_deleteRefString(drivePath);
|
||||||
|
|
||||||
|
return TOY_TO_NULL_LITERAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get the final real file path (concat) TODO: move this concat to refstring library
|
||||||
|
Toy_RefString* path = Toy_copyRefString(TOY_AS_STRING(pathLiteral));
|
||||||
|
size_t fileLength = Toy_lengthRefString(path) + Toy_lengthRefString(filePath);
|
||||||
|
|
||||||
|
char* file = TOY_ALLOCATE(char, fileLength + 1); //+1 for null
|
||||||
|
snprintf(file, fileLength, "%s%s", Toy_toCString(path), Toy_toCString(filePath));
|
||||||
|
|
||||||
|
//clean up the drive/path stuff
|
||||||
|
Toy_deleteRefString(drivePath);
|
||||||
|
Toy_deleteRefString(filePath);
|
||||||
|
Toy_deleteRefString(path);
|
||||||
|
Toy_freeLiteral(driveLiteral);
|
||||||
|
Toy_freeLiteral(pathLiteral);
|
||||||
|
|
||||||
|
//check for break-out attempts
|
||||||
|
for (size_t i = 0; i < fileLength - 1; i++) {
|
||||||
|
if (file[i] == '.' && file[i + 1] == '.') {
|
||||||
|
interpreter->errorOutput("Parent directory access not allowed\n");
|
||||||
|
TOY_FREE_ARRAY(char, file, fileLength + 1);
|
||||||
|
return TOY_TO_NULL_LITERAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_Literal result = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(file, fileLength));
|
||||||
|
|
||||||
|
TOY_FREE_ARRAY(char, file, fileLength + 1);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#include "toy_common.h"
|
||||||
|
|
||||||
|
#include "toy_literal.h"
|
||||||
|
#include "toy_interpreter.h"
|
||||||
|
|
||||||
|
//file system API - these need to be set by the host
|
||||||
|
TOY_API void Toy_initDriveSystem();
|
||||||
|
TOY_API void Toy_freeDriveSystem();
|
||||||
|
|
||||||
|
//file system API - for use with libs
|
||||||
|
TOY_API void Toy_setDrivePath(char* drive, char* path);
|
||||||
|
TOY_API Toy_Literal Toy_getDrivePathLiteral(Toy_Interpreter* interpreter, Toy_Literal* drivePathLiteral);
|
||||||
+21
-18
@@ -12,12 +12,17 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
static void printWrapper(const char* output) {
|
static void printWrapper(const char* output) {
|
||||||
|
//allow for disabling of newlines in the repl
|
||||||
|
#ifndef TOY_EXPORT
|
||||||
if (Toy_commandLine.enablePrintNewline) {
|
if (Toy_commandLine.enablePrintNewline) {
|
||||||
printf("%s\n", output);
|
printf("%s\n", output);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printf("%s", output);
|
printf("%s", output);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
printf("%s\n", output);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void assertWrapper(const char* output) {
|
static void assertWrapper(const char* output) {
|
||||||
@@ -1082,11 +1087,12 @@ static bool execAnd(Toy_Interpreter* interpreter) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TOY_IS_TRUTHY(lhs) && TOY_IS_TRUTHY(rhs)) {
|
//short-circuit support
|
||||||
Toy_pushLiteralArray(&interpreter->stack, TOY_TO_BOOLEAN_LITERAL(true));
|
if (!TOY_IS_TRUTHY(lhs)) {
|
||||||
|
Toy_pushLiteralArray(&interpreter->stack, lhs);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Toy_pushLiteralArray(&interpreter->stack, TOY_TO_BOOLEAN_LITERAL(false));
|
Toy_pushLiteralArray(&interpreter->stack, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_freeLiteral(lhs);
|
Toy_freeLiteral(lhs);
|
||||||
@@ -1115,11 +1121,12 @@ static bool execOr(Toy_Interpreter* interpreter) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TOY_IS_TRUTHY(lhs) || TOY_IS_TRUTHY(rhs)) {
|
//short-circuit support
|
||||||
Toy_pushLiteralArray(&interpreter->stack, TOY_TO_BOOLEAN_LITERAL(true));
|
if (TOY_IS_TRUTHY(lhs)) {
|
||||||
|
Toy_pushLiteralArray(&interpreter->stack, lhs);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Toy_pushLiteralArray(&interpreter->stack, TOY_TO_BOOLEAN_LITERAL(false));
|
Toy_pushLiteralArray(&interpreter->stack, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_freeLiteral(lhs);
|
Toy_freeLiteral(lhs);
|
||||||
@@ -1186,7 +1193,7 @@ static void readInterpreterSections(Toy_Interpreter* interpreter);
|
|||||||
//also supports identifier & arg1 to be other way around (looseFirstArgument)
|
//also supports identifier & arg1 to be other way around (looseFirstArgument)
|
||||||
static bool execFnCall(Toy_Interpreter* interpreter, bool looseFirstArgument) {
|
static bool execFnCall(Toy_Interpreter* interpreter, bool looseFirstArgument) {
|
||||||
//BUGFIX: depth check - don't drown!
|
//BUGFIX: depth check - don't drown!
|
||||||
if (interpreter->depth >= 200) {
|
if (interpreter->depth >= 1000 * 10) {
|
||||||
interpreter->errorOutput("Infinite recursion detected - panicking\n");
|
interpreter->errorOutput("Infinite recursion detected - panicking\n");
|
||||||
interpreter->panic = true;
|
interpreter->panic = true;
|
||||||
return false;
|
return false;
|
||||||
@@ -1316,8 +1323,8 @@ bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_Liter
|
|||||||
//init the inner interpreter manually
|
//init the inner interpreter manually
|
||||||
Toy_initLiteralArray(&inner.literalCache);
|
Toy_initLiteralArray(&inner.literalCache);
|
||||||
inner.scope = Toy_pushScope(func.as.function.scope);
|
inner.scope = Toy_pushScope(func.as.function.scope);
|
||||||
inner.bytecode = TOY_AS_FUNCTION(func).inner.bytecode;
|
inner.bytecode = ((Toy_RefFunction*)(TOY_AS_FUNCTION(func).inner.ptr))->data;
|
||||||
inner.length = TOY_AS_FUNCTION_BYTECODE_LENGTH(func);
|
inner.length = ((Toy_RefFunction*)(TOY_AS_FUNCTION(func).inner.ptr))->length;
|
||||||
inner.count = 0;
|
inner.count = 0;
|
||||||
inner.codeStart = -1;
|
inner.codeStart = -1;
|
||||||
inner.depth = interpreter->depth + 1;
|
inner.depth = interpreter->depth + 1;
|
||||||
@@ -2421,20 +2428,16 @@ static void readInterpreterSections(Toy_Interpreter* interpreter) {
|
|||||||
//get the size of the function
|
//get the size of the function
|
||||||
size_t size = (size_t)readShort(interpreter->bytecode, &interpreter->count);
|
size_t size = (size_t)readShort(interpreter->bytecode, &interpreter->count);
|
||||||
|
|
||||||
//read the function code (literal cache and all)
|
|
||||||
unsigned char* bytes = TOY_ALLOCATE(unsigned char, size);
|
|
||||||
memcpy(bytes, interpreter->bytecode + interpreter->count, size); //TODO: -1 for the ending mark
|
|
||||||
interpreter->count += size;
|
|
||||||
|
|
||||||
//assert that the last memory slot is function end
|
//assert that the last memory slot is function end
|
||||||
if (bytes[size - 1] != TOY_OP_FN_END) {
|
if (interpreter->bytecode[interpreter->count + size - 1] != TOY_OP_FN_END) {
|
||||||
interpreter->errorOutput("[internal] Failed to find function end");
|
interpreter->errorOutput("[internal] Failed to find function end");
|
||||||
TOY_FREE_ARRAY(unsigned char, bytes, size);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//change the type to normal
|
//copies internally, since functions can exist independant of literalCache
|
||||||
interpreter->literalCache.literals[i] = TOY_TO_FUNCTION_LITERAL(bytes, size);
|
interpreter->literalCache.literals[i] = TOY_TO_FUNCTION_LITERAL(Toy_createRefFunction(interpreter->bytecode + interpreter->count, size));
|
||||||
|
|
||||||
|
interpreter->count += size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ void Toy_freeLiteral(Toy_Literal literal) {
|
|||||||
if (TOY_IS_FUNCTION(literal)) {
|
if (TOY_IS_FUNCTION(literal)) {
|
||||||
Toy_popScope(TOY_AS_FUNCTION(literal).scope);
|
Toy_popScope(TOY_AS_FUNCTION(literal).scope);
|
||||||
TOY_AS_FUNCTION(literal).scope = NULL;
|
TOY_AS_FUNCTION(literal).scope = NULL;
|
||||||
TOY_FREE_ARRAY(unsigned char, TOY_AS_FUNCTION(literal).inner.bytecode, TOY_AS_FUNCTION_BYTECODE_LENGTH(literal));
|
Toy_deleteRefFunction((Toy_RefFunction*)(TOY_AS_FUNCTION(literal).inner.ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TOY_IS_TYPE(literal) && TOY_AS_TYPE(literal).capacity > 0) {
|
if (TOY_IS_TYPE(literal) && TOY_AS_TYPE(literal).capacity > 0) {
|
||||||
@@ -84,12 +84,8 @@ bool Toy_private_isTruthy(Toy_Literal x) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_Literal Toy_private_toStringLiteral(Toy_RefString* ptr) {
|
|
||||||
return ((Toy_Literal){{ .string = { .ptr = ptr }},TOY_LITERAL_STRING, 0});
|
|
||||||
}
|
|
||||||
|
|
||||||
Toy_Literal Toy_private_toIdentifierLiteral(Toy_RefString* ptr) {
|
Toy_Literal Toy_private_toIdentifierLiteral(Toy_RefString* ptr) {
|
||||||
return ((Toy_Literal){{ .identifier = { .ptr = ptr, .hash = hashString(Toy_toCString(ptr), Toy_lengthRefString(ptr)) }},TOY_LITERAL_IDENTIFIER, 0});
|
return ((Toy_Literal){{ .identifier = { .ptr = ptr, .hash = hashString(Toy_toCString(ptr), Toy_lengthRefString(ptr)) }},TOY_LITERAL_IDENTIFIER});
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_Literal* Toy_private_typePushSubtype(Toy_Literal* lit, Toy_Literal subtype) {
|
Toy_Literal* Toy_private_typePushSubtype(Toy_Literal* lit, Toy_Literal subtype) {
|
||||||
@@ -146,10 +142,8 @@ Toy_Literal Toy_copyLiteral(Toy_Literal original) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case TOY_LITERAL_FUNCTION: {
|
case TOY_LITERAL_FUNCTION: {
|
||||||
unsigned char* buffer = TOY_ALLOCATE(unsigned char, TOY_AS_FUNCTION_BYTECODE_LENGTH(original));
|
Toy_Literal literal = TOY_TO_FUNCTION_LITERAL(Toy_copyRefFunction( TOY_AS_FUNCTION(original).inner.ptr ));
|
||||||
memcpy(buffer, TOY_AS_FUNCTION(original).inner.bytecode, TOY_AS_FUNCTION_BYTECODE_LENGTH(original));
|
|
||||||
|
|
||||||
Toy_Literal literal = TOY_TO_FUNCTION_LITERAL(buffer, TOY_AS_FUNCTION_BYTECODE_LENGTH(original));
|
|
||||||
TOY_AS_FUNCTION(literal).scope = Toy_copyScope(TOY_AS_FUNCTION(original).scope);
|
TOY_AS_FUNCTION(literal).scope = Toy_copyScope(TOY_AS_FUNCTION(original).scope);
|
||||||
|
|
||||||
return literal;
|
return literal;
|
||||||
|
|||||||
+20
-18
@@ -3,6 +3,7 @@
|
|||||||
#include "toy_common.h"
|
#include "toy_common.h"
|
||||||
|
|
||||||
#include "toy_refstring.h"
|
#include "toy_refstring.h"
|
||||||
|
#include "toy_reffunction.h"
|
||||||
|
|
||||||
//forward delcare stuff
|
//forward delcare stuff
|
||||||
struct Toy_Literal;
|
struct Toy_Literal;
|
||||||
@@ -55,7 +56,7 @@ typedef struct Toy_Literal {
|
|||||||
|
|
||||||
struct {
|
struct {
|
||||||
union {
|
union {
|
||||||
void* bytecode; //8
|
Toy_RefFunction* ptr; //8
|
||||||
Toy_NativeFn native; //8
|
Toy_NativeFn native; //8
|
||||||
Toy_HookFn hook; //8
|
Toy_HookFn hook; //8
|
||||||
} inner; //8
|
} inner; //8
|
||||||
@@ -68,7 +69,6 @@ typedef struct Toy_Literal {
|
|||||||
} identifier; //16
|
} identifier; //16
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
|
||||||
struct Toy_Literal* subtypes; //8
|
struct Toy_Literal* subtypes; //8
|
||||||
Toy_LiteralType typeOf; //4
|
Toy_LiteralType typeOf; //4
|
||||||
unsigned char capacity; //1
|
unsigned char capacity; //1
|
||||||
@@ -80,10 +80,13 @@ typedef struct Toy_Literal {
|
|||||||
void* ptr; //8
|
void* ptr; //8
|
||||||
int tag; //4
|
int tag; //4
|
||||||
} opaque; //16
|
} opaque; //16
|
||||||
|
|
||||||
|
void* generic; //8
|
||||||
} as; //16
|
} as; //16
|
||||||
|
|
||||||
Toy_LiteralType type; //4
|
Toy_LiteralType type; //4
|
||||||
int bytecodeLength; //4 - shenanigans with byte alignment reduces the size of Toy_Literal
|
//4 - unused
|
||||||
|
//shenanigans with byte alignment reduces the size of Toy_Literal
|
||||||
} Toy_Literal;
|
} Toy_Literal;
|
||||||
|
|
||||||
#define TOY_IS_NULL(value) ((value).type == TOY_LITERAL_NULL)
|
#define TOY_IS_NULL(value) ((value).type == TOY_LITERAL_NULL)
|
||||||
@@ -113,29 +116,29 @@ typedef struct Toy_Literal {
|
|||||||
#define TOY_AS_TYPE(value) ((value).as.type)
|
#define TOY_AS_TYPE(value) ((value).as.type)
|
||||||
#define TOY_AS_OPAQUE(value) ((value).as.opaque.ptr)
|
#define TOY_AS_OPAQUE(value) ((value).as.opaque.ptr)
|
||||||
|
|
||||||
#define TOY_TO_NULL_LITERAL ((Toy_Literal){{ .integer = 0 }, TOY_LITERAL_NULL, 0})
|
#define TOY_TO_NULL_LITERAL ((Toy_Literal){{ .integer = 0 }, TOY_LITERAL_NULL})
|
||||||
#define TOY_TO_BOOLEAN_LITERAL(value) ((Toy_Literal){{ .boolean = value }, TOY_LITERAL_BOOLEAN, 0})
|
#define TOY_TO_BOOLEAN_LITERAL(value) ((Toy_Literal){{ .boolean = value }, TOY_LITERAL_BOOLEAN})
|
||||||
#define TOY_TO_INTEGER_LITERAL(value) ((Toy_Literal){{ .integer = value }, TOY_LITERAL_INTEGER, 0})
|
#define TOY_TO_INTEGER_LITERAL(value) ((Toy_Literal){{ .integer = value }, TOY_LITERAL_INTEGER})
|
||||||
#define TOY_TO_FLOAT_LITERAL(value) ((Toy_Literal){{ .number = value }, TOY_LITERAL_FLOAT, 0})
|
#define TOY_TO_FLOAT_LITERAL(value) ((Toy_Literal){{ .number = value }, TOY_LITERAL_FLOAT})
|
||||||
#define TOY_TO_STRING_LITERAL(value) Toy_private_toStringLiteral(value)
|
#define TOY_TO_STRING_LITERAL(value) ((Toy_Literal){{ .string = { .ptr = value }},TOY_LITERAL_STRING})
|
||||||
#define TOY_TO_ARRAY_LITERAL(value) ((Toy_Literal){{ .array = value }, TOY_LITERAL_ARRAY, 0})
|
#define TOY_TO_ARRAY_LITERAL(value) ((Toy_Literal){{ .array = value }, TOY_LITERAL_ARRAY})
|
||||||
#define TOY_TO_DICTIONARY_LITERAL(value) ((Toy_Literal){{ .dictionary = value }, TOY_LITERAL_DICTIONARY, 0})
|
#define TOY_TO_DICTIONARY_LITERAL(value) ((Toy_Literal){{ .dictionary = value }, TOY_LITERAL_DICTIONARY})
|
||||||
#define TOY_TO_FUNCTION_LITERAL(value, l) ((Toy_Literal){{ .function = { .inner = { .bytecode = value }, .scope = NULL }}, TOY_LITERAL_FUNCTION, l})
|
#define TOY_TO_FUNCTION_LITERAL(value) ((Toy_Literal){{ .function = { .inner = { .ptr = value }, .scope = NULL }}, TOY_LITERAL_FUNCTION})
|
||||||
#define TOY_TO_FUNCTION_NATIVE_LITERAL(value) ((Toy_Literal){{ .function = { .inner = { .native = value }, .scope = NULL }}, TOY_LITERAL_FUNCTION_NATIVE, 0})
|
#define TOY_TO_FUNCTION_NATIVE_LITERAL(value) ((Toy_Literal){{ .function = { .inner = { .native = value }, .scope = NULL }}, TOY_LITERAL_FUNCTION_NATIVE})
|
||||||
#define TOY_TO_FUNCTION_HOOK_LITERAL(value) ((Toy_Literal){{ .function = { .inner = { .hook = value }, .scope = NULL }}, TOY_LITERAL_FUNCTION_HOOK, 0})
|
#define TOY_TO_FUNCTION_HOOK_LITERAL(value) ((Toy_Literal){{ .function = { .inner = { .hook = value }, .scope = NULL }}, TOY_LITERAL_FUNCTION_HOOK})
|
||||||
#define TOY_TO_IDENTIFIER_LITERAL(value) Toy_private_toIdentifierLiteral(value)
|
#define TOY_TO_IDENTIFIER_LITERAL(value) Toy_private_toIdentifierLiteral(value)
|
||||||
#define TOY_TO_TYPE_LITERAL(value, c) ((Toy_Literal){{ .type = { .typeOf = value, .constant = c, .subtypes = NULL, .capacity = 0, .count = 0 }}, TOY_LITERAL_TYPE, 0})
|
#define TOY_TO_TYPE_LITERAL(value, c) ((Toy_Literal){{ .type = { .typeOf = value, .constant = c, .subtypes = NULL, .capacity = 0, .count = 0 }}, TOY_LITERAL_TYPE})
|
||||||
#define TOY_TO_OPAQUE_LITERAL(value, t) ((Toy_Literal){{ .opaque = { .ptr = value, .tag = t }}, TOY_LITERAL_OPAQUE, 0})
|
#define TOY_TO_OPAQUE_LITERAL(value, t) ((Toy_Literal){{ .opaque = { .ptr = value, .tag = t }}, TOY_LITERAL_OPAQUE})
|
||||||
|
|
||||||
//BUGFIX: For blank indexing
|
//BUGFIX: For blank indexing
|
||||||
#define TOY_IS_INDEX_BLANK(value) ((value).type == TOY_LITERAL_INDEX_BLANK)
|
#define TOY_IS_INDEX_BLANK(value) ((value).type == TOY_LITERAL_INDEX_BLANK)
|
||||||
#define TOY_TO_INDEX_BLANK_LITERAL ((Toy_Literal){{ .integer = 0 }, TOY_LITERAL_INDEX_BLANK, 0})
|
#define TOY_TO_INDEX_BLANK_LITERAL ((Toy_Literal){{ .integer = 0 }, TOY_LITERAL_INDEX_BLANK})
|
||||||
|
|
||||||
TOY_API void Toy_freeLiteral(Toy_Literal literal);
|
TOY_API void Toy_freeLiteral(Toy_Literal literal);
|
||||||
|
|
||||||
#define TOY_IS_TRUTHY(x) Toy_private_isTruthy(x)
|
#define TOY_IS_TRUTHY(x) Toy_private_isTruthy(x)
|
||||||
|
|
||||||
#define TOY_AS_FUNCTION_BYTECODE_LENGTH(lit) ((lit).bytecodeLength)
|
#define TOY_AS_FUNCTION_BYTECODE_LENGTH(lit) (Toy_lengthRefFunction((lit).inner.ptr))
|
||||||
|
|
||||||
#define TOY_MAX_STRING_LENGTH 4096
|
#define TOY_MAX_STRING_LENGTH 4096
|
||||||
#define TOY_HASH_I(lit) ((lit).as.identifier.hash)
|
#define TOY_HASH_I(lit) ((lit).as.identifier.hash)
|
||||||
@@ -144,7 +147,6 @@ TOY_API void Toy_freeLiteral(Toy_Literal literal);
|
|||||||
|
|
||||||
//BUGFIX: macros are not functions
|
//BUGFIX: macros are not functions
|
||||||
TOY_API bool Toy_private_isTruthy(Toy_Literal x);
|
TOY_API bool Toy_private_isTruthy(Toy_Literal x);
|
||||||
TOY_API Toy_Literal Toy_private_toStringLiteral(Toy_RefString* ptr);
|
|
||||||
TOY_API Toy_Literal Toy_private_toIdentifierLiteral(Toy_RefString* ptr);
|
TOY_API Toy_Literal Toy_private_toIdentifierLiteral(Toy_RefString* ptr);
|
||||||
TOY_API Toy_Literal* Toy_private_typePushSubtype(Toy_Literal* lit, Toy_Literal subtype);
|
TOY_API Toy_Literal* Toy_private_typePushSubtype(Toy_Literal* lit, Toy_Literal subtype);
|
||||||
|
|
||||||
|
|||||||
+36
-15
@@ -367,73 +367,73 @@ static Toy_Opcode binary(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
|
|||||||
|
|
||||||
//assignment
|
//assignment
|
||||||
case TOY_TOKEN_ASSIGN: {
|
case TOY_TOKEN_ASSIGN: {
|
||||||
parsePrecedence(parser, nodeHandle, PREC_ASSIGNMENT);
|
parsePrecedence(parser, nodeHandle, PREC_ASSIGNMENT + 1);
|
||||||
return TOY_OP_VAR_ASSIGN;
|
return TOY_OP_VAR_ASSIGN;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_PLUS_ASSIGN: {
|
case TOY_TOKEN_PLUS_ASSIGN: {
|
||||||
parsePrecedence(parser, nodeHandle, PREC_ASSIGNMENT);
|
parsePrecedence(parser, nodeHandle, PREC_ASSIGNMENT + 1);
|
||||||
return TOY_OP_VAR_ADDITION_ASSIGN;
|
return TOY_OP_VAR_ADDITION_ASSIGN;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_MINUS_ASSIGN: {
|
case TOY_TOKEN_MINUS_ASSIGN: {
|
||||||
parsePrecedence(parser, nodeHandle, PREC_ASSIGNMENT);
|
parsePrecedence(parser, nodeHandle, PREC_ASSIGNMENT + 1);
|
||||||
return TOY_OP_VAR_SUBTRACTION_ASSIGN;
|
return TOY_OP_VAR_SUBTRACTION_ASSIGN;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_MULTIPLY_ASSIGN: {
|
case TOY_TOKEN_MULTIPLY_ASSIGN: {
|
||||||
parsePrecedence(parser, nodeHandle, PREC_ASSIGNMENT);
|
parsePrecedence(parser, nodeHandle, PREC_ASSIGNMENT + 1);
|
||||||
return TOY_OP_VAR_MULTIPLICATION_ASSIGN;
|
return TOY_OP_VAR_MULTIPLICATION_ASSIGN;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_DIVIDE_ASSIGN: {
|
case TOY_TOKEN_DIVIDE_ASSIGN: {
|
||||||
parsePrecedence(parser, nodeHandle, PREC_ASSIGNMENT);
|
parsePrecedence(parser, nodeHandle, PREC_ASSIGNMENT + 1);
|
||||||
return TOY_OP_VAR_DIVISION_ASSIGN;
|
return TOY_OP_VAR_DIVISION_ASSIGN;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_MODULO_ASSIGN: {
|
case TOY_TOKEN_MODULO_ASSIGN: {
|
||||||
parsePrecedence(parser, nodeHandle, PREC_ASSIGNMENT);
|
parsePrecedence(parser, nodeHandle, PREC_ASSIGNMENT + 1);
|
||||||
return TOY_OP_VAR_MODULO_ASSIGN;
|
return TOY_OP_VAR_MODULO_ASSIGN;
|
||||||
}
|
}
|
||||||
|
|
||||||
//comparison
|
//comparison
|
||||||
case TOY_TOKEN_EQUAL: {
|
case TOY_TOKEN_EQUAL: {
|
||||||
parsePrecedence(parser, nodeHandle, PREC_COMPARISON);
|
parsePrecedence(parser, nodeHandle, PREC_COMPARISON + 1);
|
||||||
return TOY_OP_COMPARE_EQUAL;
|
return TOY_OP_COMPARE_EQUAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_NOT_EQUAL: {
|
case TOY_TOKEN_NOT_EQUAL: {
|
||||||
parsePrecedence(parser, nodeHandle, PREC_COMPARISON);
|
parsePrecedence(parser, nodeHandle, PREC_COMPARISON + 1);
|
||||||
return TOY_OP_COMPARE_NOT_EQUAL;
|
return TOY_OP_COMPARE_NOT_EQUAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_LESS: {
|
case TOY_TOKEN_LESS: {
|
||||||
parsePrecedence(parser, nodeHandle, PREC_COMPARISON);
|
parsePrecedence(parser, nodeHandle, PREC_COMPARISON + 1);
|
||||||
return TOY_OP_COMPARE_LESS;
|
return TOY_OP_COMPARE_LESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_LESS_EQUAL: {
|
case TOY_TOKEN_LESS_EQUAL: {
|
||||||
parsePrecedence(parser, nodeHandle, PREC_COMPARISON);
|
parsePrecedence(parser, nodeHandle, PREC_COMPARISON + 1);
|
||||||
return TOY_OP_COMPARE_LESS_EQUAL;
|
return TOY_OP_COMPARE_LESS_EQUAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_GREATER: {
|
case TOY_TOKEN_GREATER: {
|
||||||
parsePrecedence(parser, nodeHandle, PREC_COMPARISON);
|
parsePrecedence(parser, nodeHandle, PREC_COMPARISON + 1);
|
||||||
return TOY_OP_COMPARE_GREATER;
|
return TOY_OP_COMPARE_GREATER;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_GREATER_EQUAL: {
|
case TOY_TOKEN_GREATER_EQUAL: {
|
||||||
parsePrecedence(parser, nodeHandle, PREC_COMPARISON);
|
parsePrecedence(parser, nodeHandle, PREC_COMPARISON + 1);
|
||||||
return TOY_OP_COMPARE_GREATER_EQUAL;
|
return TOY_OP_COMPARE_GREATER_EQUAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_AND: {
|
case TOY_TOKEN_AND: {
|
||||||
parsePrecedence(parser, nodeHandle, PREC_AND);
|
parsePrecedence(parser, nodeHandle, PREC_AND + 1);
|
||||||
return TOY_OP_AND;
|
return TOY_OP_AND;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_OR: {
|
case TOY_TOKEN_OR: {
|
||||||
parsePrecedence(parser, nodeHandle, PREC_OR);
|
parsePrecedence(parser, nodeHandle, PREC_OR + 1);
|
||||||
return TOY_OP_OR;
|
return TOY_OP_OR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -658,7 +658,7 @@ static Toy_Opcode castingInfix(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TOY_TOKEN_LITERAL_STRING:
|
case TOY_TOKEN_LITERAL_STRING:
|
||||||
atomic(parser, nodeHandle);
|
string(parser, nodeHandle);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -739,6 +739,27 @@ static Toy_Opcode decrementInfix(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Toy_Opcode fnCall(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
|
static Toy_Opcode fnCall(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
|
||||||
|
//wait - is the previous token a type? this should be casting instead
|
||||||
|
if (parser->previous.type >= TOY_TOKEN_NULL && parser->previous.type <= TOY_TOKEN_ANY) {
|
||||||
|
//casting type
|
||||||
|
Toy_ASTNode* lhsNode = NULL;
|
||||||
|
castingPrefix(parser, &lhsNode);
|
||||||
|
advance(parser);
|
||||||
|
|
||||||
|
//casting value
|
||||||
|
Toy_ASTNode* rhsNode = NULL;
|
||||||
|
grouping(parser, &rhsNode);
|
||||||
|
|
||||||
|
//emit the cast node
|
||||||
|
|
||||||
|
Toy_emitASTNodeBinary(&lhsNode, rhsNode, TOY_OP_TYPE_CAST);
|
||||||
|
|
||||||
|
//pass it off to the caller
|
||||||
|
*nodeHandle = lhsNode;
|
||||||
|
|
||||||
|
return TOY_OP_GROUPING_BEGIN; //dummy value
|
||||||
|
}
|
||||||
|
|
||||||
advance(parser); //skip the left paren
|
advance(parser); //skip the left paren
|
||||||
|
|
||||||
//binary() is an infix rule - so only get the RHS of the operator
|
//binary() is an infix rule - so only get the RHS of the operator
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
#include "toy_reffunction.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
//memory allocation
|
||||||
|
extern void* Toy_private_defaultMemoryAllocator(void* pointer, size_t oldSize, size_t newSize);
|
||||||
|
static Toy_RefFunctionAllocatorFn allocate = Toy_private_defaultMemoryAllocator;
|
||||||
|
|
||||||
|
void Toy_setRefFunctionAllocatorFn(Toy_RefFunctionAllocatorFn allocator) {
|
||||||
|
allocate = allocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
//API
|
||||||
|
Toy_RefFunction* Toy_createRefFunction(const void* data, size_t length) {
|
||||||
|
//allocate the memory area (including metadata space)
|
||||||
|
Toy_RefFunction* refFunction = allocate(NULL, 0, sizeof(size_t) + sizeof(int) + sizeof(char) * length);
|
||||||
|
|
||||||
|
if (refFunction == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//set the data
|
||||||
|
refFunction->refCount = 1;
|
||||||
|
refFunction->length = length;
|
||||||
|
memcpy(refFunction->data, data, refFunction->length);
|
||||||
|
|
||||||
|
return refFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Toy_deleteRefFunction(Toy_RefFunction* refFunction) {
|
||||||
|
//decrement, then check
|
||||||
|
refFunction->refCount--;
|
||||||
|
if (refFunction->refCount <= 0) {
|
||||||
|
allocate(refFunction, sizeof(size_t) + sizeof(int) + sizeof(char) * (refFunction->length + 1), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Toy_countRefFunction(Toy_RefFunction* refFunction) {
|
||||||
|
return refFunction->refCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Toy_lengthRefFunction(Toy_RefFunction* refFunction) {
|
||||||
|
return refFunction->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_RefFunction* Toy_copyRefFunction(Toy_RefFunction* refFunction) {
|
||||||
|
//Cheaty McCheater Face
|
||||||
|
refFunction->refCount++;
|
||||||
|
return refFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_RefFunction* Toy_deepCopyRefFunction(Toy_RefFunction* refFunction) {
|
||||||
|
//create a new function, with a new refCount
|
||||||
|
return Toy_createRefFunction(refFunction->data, refFunction->length);
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "toy_common.h"
|
||||||
|
|
||||||
|
//memory allocation hook
|
||||||
|
typedef void* (*Toy_RefFunctionAllocatorFn)(void* pointer, size_t oldSize, size_t newSize);
|
||||||
|
TOY_API void Toy_setRefFunctionAllocatorFn(Toy_RefFunctionAllocatorFn);
|
||||||
|
|
||||||
|
//the RefFunction structure
|
||||||
|
typedef struct Toy_RefFunction {
|
||||||
|
size_t length;
|
||||||
|
int refCount;
|
||||||
|
unsigned char data[];
|
||||||
|
} Toy_RefFunction;
|
||||||
|
|
||||||
|
//API
|
||||||
|
TOY_API Toy_RefFunction* Toy_createRefFunction(const void* data, size_t length);
|
||||||
|
TOY_API void Toy_deleteRefFunction(Toy_RefFunction* refFunction);
|
||||||
|
TOY_API int Toy_countRefFunction(Toy_RefFunction* refFunction);
|
||||||
|
TOY_API size_t Toy_lengthRefFunction(Toy_RefFunction* refFunction);
|
||||||
|
TOY_API Toy_RefFunction* Toy_copyRefFunction(Toy_RefFunction* refFunction);
|
||||||
|
TOY_API Toy_RefFunction* Toy_deepCopyRefFunction(Toy_RefFunction* refFunction);
|
||||||
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
var s = "42";
|
||||||
|
var t = "69";
|
||||||
|
|
||||||
|
assert int (s + t) - 1 == 4268, "casting parentheses failed";
|
||||||
|
|
||||||
|
|
||||||
|
print "All good";
|
||||||
@@ -23,5 +23,8 @@ assert !false, "!false";
|
|||||||
var c = false;
|
var c = false;
|
||||||
assert !c, "!c";
|
assert !c, "!c";
|
||||||
|
|
||||||
|
//test multiple comparisons
|
||||||
|
assert 1 == 2 == false, "Left-accociative equality failed";
|
||||||
|
|
||||||
|
|
||||||
print "All good";
|
print "All good";
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
var days = [
|
||||||
|
"sunday",
|
||||||
|
"monday",
|
||||||
|
"tuesday",
|
||||||
|
"wednesday",
|
||||||
|
"thursday",
|
||||||
|
"friday",
|
||||||
|
"saturday"
|
||||||
|
];
|
||||||
|
|
||||||
|
var rng = 10; //for chosen at random
|
||||||
|
|
||||||
|
|
||||||
|
var index = rng % days.length();
|
||||||
|
|
||||||
|
assert index == 3, "dot modulo bugfix failed";
|
||||||
|
|
||||||
|
rng %= days.length();
|
||||||
|
|
||||||
|
assert rng == 3, "dot modulo assign bugfix failed";
|
||||||
|
|
||||||
|
|
||||||
|
print "All good";
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
//explicitly support && and || short circuits
|
||||||
|
|
||||||
|
assert 1 && 2 == 2, "&& short-circuit failed";
|
||||||
|
|
||||||
|
assert 1 || 2 == 1, "|| short-circuit failed";
|
||||||
|
|
||||||
|
|
||||||
|
print "All good";
|
||||||
|
|
||||||
@@ -108,12 +108,14 @@ int main() {
|
|||||||
//run each file in tests/scripts/
|
//run each file in tests/scripts/
|
||||||
const char* filenames[] = {
|
const char* filenames[] = {
|
||||||
"arithmetic.toy",
|
"arithmetic.toy",
|
||||||
|
"casting-parentheses-bugfix.toy",
|
||||||
"casting.toy",
|
"casting.toy",
|
||||||
"coercions.toy",
|
"coercions.toy",
|
||||||
"comparisons.toy",
|
"comparisons.toy",
|
||||||
"dot-and-matrix.toy",
|
"dot-and-matrix.toy",
|
||||||
"dot-assignments-bugfix.toy",
|
"dot-assignments-bugfix.toy",
|
||||||
"dot-chaining.toy",
|
"dot-chaining.toy",
|
||||||
|
"dot-modulo-bugfix.toy",
|
||||||
"dottify-bugfix.toy",
|
"dottify-bugfix.toy",
|
||||||
"functions.toy",
|
"functions.toy",
|
||||||
"index-arrays.toy",
|
"index-arrays.toy",
|
||||||
@@ -132,6 +134,7 @@ int main() {
|
|||||||
"panic-within-functions.toy",
|
"panic-within-functions.toy",
|
||||||
"polyfill-insert.toy",
|
"polyfill-insert.toy",
|
||||||
"polyfill-remove.toy",
|
"polyfill-remove.toy",
|
||||||
|
"short-circuiting-support.toy",
|
||||||
"ternary-expressions.toy",
|
"ternary-expressions.toy",
|
||||||
"types.toy",
|
"types.toy",
|
||||||
NULL
|
NULL
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "toy_console_colors.h"
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
#include "toy_memory.h"
|
#include "toy_memory.h"
|
||||||
|
#include "toy_drive_system.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -63,15 +64,9 @@ typedef struct Payload {
|
|||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
//setup the runner filesystem (hacky)
|
//setup the runner filesystem (hacky)
|
||||||
Toy_initDriveDictionary();
|
Toy_initDriveSystem();
|
||||||
|
|
||||||
Toy_Literal driveLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("scripts"));
|
Toy_setDrivePath("scripts", "scripts");
|
||||||
Toy_Literal pathLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("scripts"));
|
|
||||||
|
|
||||||
Toy_setLiteralDictionary(Toy_getDriveDictionary(), driveLiteral, pathLiteral);
|
|
||||||
|
|
||||||
Toy_freeLiteral(driveLiteral);
|
|
||||||
Toy_freeLiteral(pathLiteral);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
//run each file in test/scripts
|
//run each file in test/scripts
|
||||||
@@ -113,7 +108,7 @@ int main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//lib cleanup
|
//lib cleanup
|
||||||
Toy_freeDriveDictionary();
|
Toy_freeDriveSystem();
|
||||||
|
|
||||||
if (!failedAsserts) {
|
if (!failedAsserts) {
|
||||||
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||||
|
|||||||
Reference in New Issue
Block a user