Compare commits

..

33 Commits

Author SHA1 Message Date
Kayne Ruse 6fa224fa7b Hooks can't be dict keys, tweaked Toy_readFile 2023-02-18 16:47:38 +00:00
Kayne Ruse 8a68d864e6 Opaque type check added 2023-02-18 15:21:49 +00:00
Kayne Ruse 49f240ea07 Minor tweak 2023-02-18 12:15:23 +00:00
Kayne Ruse 3acbd7447a Merge remote-tracking branch 'refs/remotes/origin/main' 2023-02-18 11:57:22 +00:00
Kayne Ruse 6f126e6daa Minor tweaks and renames, as I'm documenting 2023-02-18 11:56:18 +00:00
Kayne Ruse 2adb9d9158 Tweaked lib runner API 2023-02-16 22:04:47 +00:00
Kayne Ruse 1668dca255 Tweaked some APIs, hid some functions I don't want in the API 2023-02-16 13:06:07 +00:00
Kayne Ruse 501ff6fff4 Chased a ghost for a few hours 2023-02-14 18:55:24 +00:00
Kayne Ruse 3845627fe5 Added release build to MSVC 2023-02-14 18:03:04 +00:00
Kayne Ruse cdae03bd54 String and identifier making fixed for MSVC, just in case 2023-02-14 17:38:10 +00:00
Kayne Ruse 7b501b71b5 commandLine now initializes with default values 2023-02-14 17:00:16 +00:00
Kayne Ruse 913738a4d1 Tweaked the runner test, should be orders of magnitude faster 2023-02-14 16:16:48 +00:00
Kayne Ruse 3312a38c7c Updated memusage tool 2023-02-14 16:05:43 +00:00
Kayne Ruse 71b57fd42c Fixed scripts for distribution 2023-02-14 10:35:08 +00:00
Kayne Ruse 453afbab41 Fixed a stupid bug in MSVC 2023-02-14 10:24:43 +00:00
Kayne Ruse 57af5a6d59 Tweaked some scripts 2023-02-14 09:21:22 +00:00
Kayne Ruse 0737b2a483 Dropped underscore functions in favour of UFCS 2023-02-14 08:37:31 +00:00
Kayne Ruse eae96d6403 Corrected the order of arguments to Toy_callLiteralFn() 2023-02-14 08:00:35 +00:00
Kayne Ruse b55b8e879e Added -n option to diable print newline 2023-02-13 15:51:38 +00:00
Kayne Ruse 1ed114b80d Allow for stmt to have empty clauses, resolved #58 2023-02-13 14:45:24 +00:00
Kayne Ruse eb8e522bf2 Merged standard and timer, resolved #48 2023-02-13 13:58:41 +00:00
Kayne Ruse 16b71ba6f4 Implemented quicksort in _sort() 2023-02-13 13:31:58 +00:00
Kayne Ruse 9725f3c6a3 Patched some very obscure bugs 2023-02-12 16:54:44 +00:00
Kayne Ruse 8653a2663f Added _indexOf 2023-02-12 14:32:26 +00:00
Kayne Ruse ab2cd5dc93 Removed lib timer properly, see #62 2023-02-12 14:19:14 +00:00
Kayne Ruse 724804a78a Playing with level.toy 2023-02-11 15:27:23 +00:00
Kayne Ruse 77a128e0f7 Added the -t option to the repl 2023-02-11 14:51:19 +00:00
Kayne Ruse 5343e1054d Straightened out file extensions 2023-02-11 14:26:55 +00:00
Kayne Ruse 3930ec0477 Tweaked README.md 2023-02-11 06:48:16 +00:00
Kayne Ruse 996744d7ec Resolved #59 2023-02-11 05:10:32 +00:00
Kayne Ruse c00b32017b Dummied out lib timer 2023-02-11 01:42:44 +00:00
Kayne Ruse 457014d577 Added MSVC build support, likely broke tests 2023-02-11 00:49:21 +00:00
Kayne Ruse be4cbf1ad6 Pack 'em up! 2023-02-10 21:53:38 +00:00
70 changed files with 2940 additions and 2680 deletions
+4 -3
View File
@@ -1,6 +1,4 @@
#Editor generated files
*.sln
*.vcproj
*.suo
*.ncb
*.user
@@ -13,7 +11,9 @@ Out/
release/
debug/
out/
bin/
.cache/
.vs/
#Project generated files
*.db
@@ -22,9 +22,10 @@ out/
*.exe
*.meta
*.log
out
*.out
*.stackdump
*.tb
*.filters
#Shell files
*.bat
+3 -1
View File
@@ -23,7 +23,9 @@ Special thanks to http://craftinginterpreters.com/ for their fantastic book that
For Windows(mingw32 & cygwin), Linux and MacOS, simply run `make` in the root directory.
Note: MacOS is not officially supported (no machines for testing), but we'll do our best!
For Windows(MSVC), Visual Studio project files are included.
Note: MacOS and Windows(MSVC) are not officially supported, but we'll do our best!
## Tools
+150
View File
@@ -0,0 +1,150 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<ProjectGuid>{97F823E5-3AB8-47EF-B142-C15DD7CADF76}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IgnoreImportLibrary>false</IgnoreImportLibrary>
<OutDir>$(SolutionDir)out\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(SolutionDir)out\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<Optimization>Disabled</Optimization>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Link>
<AdditionalDependencies>Toy.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)out\$(Configuration)</AdditionalLibraryDirectories>
</Link>
<ClCompile>
<AdditionalIncludeDirectories>C:\Users\kayne\Desktop\Toy\source;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard_C>stdc17</LanguageStandard_C>
<PreprocessorDefinitions>
</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<LanguageStandard_C>stdc17</LanguageStandard_C>
<PreprocessorDefinitions>
</PreprocessorDefinitions>
<AdditionalIncludeDirectories>C:\Users\kayne\Desktop\Toy\source;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>$(SolutionDir)out\$(Configuration)</AdditionalLibraryDirectories>
<AdditionalDependencies>Toy.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="repl\lib_about.c" />
<ClCompile Include="repl\lib_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_runner.h" />
<ClInclude Include="repl\lib_standard.h" />
<ClInclude Include="repl\repl_tools.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+159
View File
@@ -0,0 +1,159 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<ProjectGuid>{26360002-CC2A-469A-9B28-BA0C1AF41657}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>$(SolutionDir)out\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(SolutionDir)out\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;TOY_EXPORTS;TOY_EXPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<Optimization>Disabled</Optimization>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;TOY_EXPORTS;TOY_EXPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PreprocessorDefinitions>TOY_EXPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<LanguageStandard_C>stdc17</LanguageStandard_C>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<LanguageStandard_C>stdc17</LanguageStandard_C>
<PreprocessorDefinitions>TOY_EXPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="source\toy_ast_node.c" />
<ClCompile Include="source\toy_builtin.c" />
<ClCompile Include="source\toy_common.c" />
<ClCompile Include="source\toy_compiler.c" />
<ClCompile Include="source\toy_interpreter.c" />
<ClCompile Include="source\toy_keyword_types.c" />
<ClCompile Include="source\toy_lexer.c" />
<ClCompile Include="source\toy_literal.c" />
<ClCompile Include="source\toy_literal_array.c" />
<ClCompile Include="source\toy_literal_dictionary.c" />
<ClCompile Include="source\toy_memory.c" />
<ClCompile Include="source\toy_parser.c" />
<ClCompile Include="source\toy_refstring.c" />
<ClCompile Include="source\toy_scope.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="source\toy_ast_node.h" />
<ClInclude Include="source\toy_builtin.h" />
<ClInclude Include="source\toy_common.h" />
<ClInclude Include="source\toy_compiler.h" />
<ClInclude Include="source\toy_console_colors.h" />
<ClInclude Include="source\toy_interpreter.h" />
<ClInclude Include="source\toy_keyword_types.h" />
<ClInclude Include="source\toy_lexer.h" />
<ClInclude Include="source\toy_literal.h" />
<ClInclude Include="source\toy_literal_array.h" />
<ClInclude Include="source\toy_literal_dictionary.h" />
<ClInclude Include="source\toy_memory.h" />
<ClInclude Include="source\toy_opcodes.h" />
<ClInclude Include="source\toy_parser.h" />
<ClInclude Include="source\toy_refstring.h" />
<ClInclude Include="source\toy_scope.h" />
<ClInclude Include="source\toy_token_types.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+44
View File
@@ -0,0 +1,44 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.4.33213.308
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Toy", "Toy.vcxproj", "{26360002-CC2A-469A-9B28-BA0C1AF41657}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Repl", "Repl.vcxproj", "{97F823E5-3AB8-47EF-B142-C15DD7CADF76}"
ProjectSection(ProjectDependencies) = postProject
{26360002-CC2A-469A-9B28-BA0C1AF41657} = {26360002-CC2A-469A-9B28-BA0C1AF41657}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{26360002-CC2A-469A-9B28-BA0C1AF41657}.Debug|x64.ActiveCfg = Debug|x64
{26360002-CC2A-469A-9B28-BA0C1AF41657}.Debug|x64.Build.0 = Debug|x64
{26360002-CC2A-469A-9B28-BA0C1AF41657}.Debug|x86.ActiveCfg = Debug|Win32
{26360002-CC2A-469A-9B28-BA0C1AF41657}.Debug|x86.Build.0 = Debug|Win32
{26360002-CC2A-469A-9B28-BA0C1AF41657}.Release|x64.ActiveCfg = Release|x64
{26360002-CC2A-469A-9B28-BA0C1AF41657}.Release|x64.Build.0 = Release|x64
{26360002-CC2A-469A-9B28-BA0C1AF41657}.Release|x86.ActiveCfg = Release|Win32
{26360002-CC2A-469A-9B28-BA0C1AF41657}.Release|x86.Build.0 = Release|Win32
{97F823E5-3AB8-47EF-B142-C15DD7CADF76}.Debug|x64.ActiveCfg = Debug|x64
{97F823E5-3AB8-47EF-B142-C15DD7CADF76}.Debug|x64.Build.0 = Debug|x64
{97F823E5-3AB8-47EF-B142-C15DD7CADF76}.Debug|x86.ActiveCfg = Debug|Win32
{97F823E5-3AB8-47EF-B142-C15DD7CADF76}.Debug|x86.Build.0 = Debug|Win32
{97F823E5-3AB8-47EF-B142-C15DD7CADF76}.Release|x64.ActiveCfg = Release|x64
{97F823E5-3AB8-47EF-B142-C15DD7CADF76}.Release|x64.Build.0 = Release|x64
{97F823E5-3AB8-47EF-B142-C15DD7CADF76}.Release|x86.ActiveCfg = Release|Win32
{97F823E5-3AB8-47EF-B142-C15DD7CADF76}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7089F1AD-8EC0-4F27-AFD1-5FD43D91AABC}
EndGlobalSection
EndGlobal
+2 -2
View File
@@ -10,10 +10,10 @@ all: $(TOY_OUTDIR) repl
#repl builds
repl: $(TOY_OUTDIR) library
$(MAKE) -C repl
$(MAKE) -j8 -C repl
repl-static: $(TOY_OUTDIR) static
$(MAKE) -C repl
$(MAKE) -j8 -C repl
repl-release: clean $(TOY_OUTDIR) library-release
$(MAKE) -C repl release
-1468
View File
File diff suppressed because it is too large Load Diff
-6
View File
@@ -1,6 +0,0 @@
#pragma once
#include "toy_interpreter.h"
int Toy_hookCompound(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
+26 -26
View File
@@ -7,6 +7,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Toy_Runner {
Toy_Interpreter interpreter;
@@ -44,11 +45,11 @@ static int nativeLoadScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu
//use raw types - easier
const char* filePath = Toy_toCString(TOY_AS_STRING(filePathLiteral));
int filePathLength = Toy_lengthRefString(TOY_AS_STRING(filePathLiteral));
size_t filePathLength = Toy_lengthRefString(TOY_AS_STRING(filePathLiteral));
//load and compile the bytecode
size_t fileSize = 0;
const char* source = Toy_readFile(filePath, &fileSize);
const char* source = (const char*)Toy_readFile(filePath, &fileSize);
if (!source) {
interpreter->errorOutput("Failed to load source file\n");
@@ -138,7 +139,7 @@ static int nativeLoadScriptBytecode(Toy_Interpreter* interpreter, Toy_LiteralArr
//get the final real file path (concat) TODO: move this concat to refstring library
Toy_RefString* realDrive = Toy_copyRefString(TOY_AS_STRING(realDriveLiteral));
int realLength = Toy_lengthRefString(realDrive) + Toy_lengthRefString(path);
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));
@@ -159,7 +160,7 @@ static int nativeLoadScriptBytecode(Toy_Interpreter* interpreter, Toy_LiteralArr
}
//check for break-out attempts
for (int i = 0; i < realLength - 1; i++) {
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);
@@ -200,7 +201,7 @@ static int nativeLoadScriptBytecode(Toy_Interpreter* interpreter, Toy_LiteralArr
static int nativeRunScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _runScript\n");
interpreter->errorOutput("Incorrect number of arguments to runScript\n");
return -1;
}
@@ -213,7 +214,7 @@ static int nativeRunScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argum
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
interpreter->errorOutput("Unrecognized opaque literal in runScript\n");
return -1;
}
@@ -241,7 +242,7 @@ static int nativeRunScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argum
static int nativeGetScriptVar(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments to _getScriptVar\n");
interpreter->errorOutput("Incorrect number of arguments to getScriptVar\n");
return -1;
}
@@ -260,7 +261,7 @@ static int nativeGetScriptVar(Toy_Interpreter* interpreter, Toy_LiteralArray* ar
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
interpreter->errorOutput("Unrecognized opaque literal in getScriptVar\n");
return -1;
}
@@ -292,7 +293,7 @@ static int nativeGetScriptVar(Toy_Interpreter* interpreter, Toy_LiteralArray* ar
static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count < 2) {
interpreter->errorOutput("Incorrect number of arguments to _callScriptFn\n");
interpreter->errorOutput("Incorrect number of arguments to callScriptFn\n");
return -1;
}
@@ -309,7 +310,7 @@ static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* ar
Toy_LiteralArray rest;
Toy_initLiteralArray(&rest);
while (tmp.count) { //correct the order of the rest args
while (tmp.count > 0) { //correct the order of the rest args
Toy_Literal lit = Toy_popLiteralArray(&tmp);
Toy_pushLiteralArray(&rest, lit);
Toy_freeLiteral(lit);
@@ -317,7 +318,6 @@ static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* ar
Toy_freeLiteralArray(&tmp);
//get the runner object
Toy_Literal varName = Toy_popLiteralArray(arguments);
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
@@ -333,7 +333,7 @@ static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* ar
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
interpreter->errorOutput("Unrecognized opaque literal in callScriptFn\n");
return -1;
}
@@ -389,7 +389,7 @@ static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* ar
static int nativeResetScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _resetScript\n");
interpreter->errorOutput("Incorrect number of arguments to resetScript\n");
return -1;
}
@@ -402,7 +402,7 @@ static int nativeResetScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arg
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
interpreter->errorOutput("Unrecognized opaque literal in resetScript\n");
return -1;
}
@@ -425,7 +425,7 @@ static int nativeResetScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arg
static int nativeFreeScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _freeScript\n");
interpreter->errorOutput("Incorrect number of arguments to freeScript\n");
return -1;
}
@@ -438,7 +438,7 @@ static int nativeFreeScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _freeScript\n");
interpreter->errorOutput("Unrecognized opaque literal in freeScript\n");
return -1;
}
@@ -459,7 +459,7 @@ static int nativeFreeScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu
static int nativeCheckScriptDirty(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _runScript\n");
interpreter->errorOutput("Incorrect number of arguments to checkScriptDirty\n");
return -1;
}
@@ -472,7 +472,7 @@ static int nativeCheckScriptDirty(Toy_Interpreter* interpreter, Toy_LiteralArray
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
interpreter->errorOutput("Unrecognized opaque literal in checkScriptDirty\n");
return -1;
}
@@ -501,12 +501,12 @@ int Toy_hookRunner(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Lit
Natives natives[] = {
{"loadScript", nativeLoadScript},
{"loadScriptBytecode", nativeLoadScriptBytecode},
{"_runScript", nativeRunScript},
{"_getScriptVar", nativeGetScriptVar},
{"_callScriptFn", nativeCallScriptFn},
{"_resetScript", nativeResetScript},
{"_freeScript", nativeFreeScript},
{"_checkScriptDirty", nativeCheckScriptDirty},
{"runScript", nativeRunScript},
{"getScriptVar", nativeGetScriptVar},
{"callScriptFn", nativeCallScriptFn},
{"resetScript", nativeResetScript},
{"freeScript", nativeFreeScript},
{"checkScriptDirty", nativeCheckScriptDirty},
{NULL, NULL}
};
@@ -617,7 +617,7 @@ Toy_Literal Toy_getFilePathLiteral(Toy_Interpreter* interpreter, Toy_Literal* dr
//get the final real file path (concat) TODO: move this concat to refstring library
Toy_RefString* realDrive = Toy_copyRefString(TOY_AS_STRING(realDriveLiteral));
int realLength = Toy_lengthRefString(realDrive) + Toy_lengthRefString(path);
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));
@@ -630,7 +630,7 @@ Toy_Literal Toy_getFilePathLiteral(Toy_Interpreter* interpreter, Toy_Literal* dr
Toy_deleteRefString(drivePath);
//check for break-out attempts
for (int i = 0; i < realLength - 1; i++) {
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);
+4 -3
View File
@@ -1,13 +1,14 @@
#pragma once
#include "toy_common.h"
#include "toy_interpreter.h"
int Toy_hookRunner(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
//file system API - these need to be set by the host
void Toy_initDriveDictionary();
void Toy_freeDriveDictionary();
Toy_LiteralDictionary* Toy_getDriveDictionary();
TOY_API void Toy_initDriveDictionary();
TOY_API void Toy_freeDriveDictionary();
TOY_API Toy_LiteralDictionary* Toy_getDriveDictionary();
#define TOY_OPAQUE_TAG_RUNNER 100
+1539 -2
View File
File diff suppressed because it is too large Load Diff
-411
View File
@@ -1,411 +0,0 @@
#include "lib_timer.h"
#include "toy_memory.h"
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
//GOD DAMN IT: https://stackoverflow.com/questions/15846762/timeval-subtract-explanation
static int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y) {
//normallize
if (x->tv_usec > 999999) {
x->tv_sec += x->tv_usec / 1000000;
x->tv_usec %= 1000000;
}
if (y->tv_usec > 999999) {
y->tv_sec += y->tv_usec / 1000000;
y->tv_usec %= 1000000;
}
//calc
result->tv_sec = x->tv_sec - y->tv_sec;
if ((result->tv_usec = x->tv_usec - y->tv_usec) < 0) {
if (result->tv_sec != 0) { //only works far from 0
result->tv_usec += 1000000;
result->tv_sec--; // borrow
}
}
return result->tv_sec < 0 || (result->tv_sec == 0 && result->tv_usec < 0);
}
//god damn it
static struct timeval* diff(struct timeval* lhs, struct timeval* rhs) {
struct timeval* d = TOY_ALLOCATE(struct timeval, 1);
//I gave up, copied from SO
timeval_subtract(d, rhs, lhs);
return d;
}
//callbacks
static int nativeStartTimer(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 0) {
interpreter->errorOutput("Incorrect number of arguments to startTimer\n");
return -1;
}
//get the timeinfo from C
struct timeval* timeinfo = TOY_ALLOCATE(struct timeval, 1);
gettimeofday(timeinfo, NULL);
//wrap in an opaque literal for Toy
Toy_Literal timeLiteral = TOY_TO_OPAQUE_LITERAL(timeinfo, -1);
Toy_pushLiteralArray(&interpreter->stack, timeLiteral);
Toy_freeLiteral(timeLiteral);
return 1;
}
static int nativeStopTimer(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _stopTimer\n");
return -1;
}
//get the timeinfo from C
struct timeval timerStop;
gettimeofday(&timerStop, NULL);
//unwrap the opaque literal
Toy_Literal timeLiteral = Toy_popLiteralArray(arguments);
Toy_Literal timeLiteralIdn = timeLiteral;
if (TOY_IS_IDENTIFIER(timeLiteral) && Toy_parseIdentifierToValue(interpreter, &timeLiteral)) {
Toy_freeLiteral(timeLiteralIdn);
}
if (!TOY_IS_OPAQUE(timeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _stopTimer\n");
Toy_freeLiteral(timeLiteral);
return -1;
}
struct timeval* timerStart = TOY_AS_OPAQUE(timeLiteral);
//determine the difference, and wrap it
struct timeval* d = diff(timerStart, &timerStop);
Toy_Literal diffLiteral = TOY_TO_OPAQUE_LITERAL(d, -1);
Toy_pushLiteralArray(&interpreter->stack, diffLiteral);
//cleanup
Toy_freeLiteral(timeLiteral);
Toy_freeLiteral(diffLiteral);
return 1;
}
static int nativeCreateTimer(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments to createTimer\n");
return -1;
}
//get the args
Toy_Literal microsecondLiteral = Toy_popLiteralArray(arguments);
Toy_Literal secondLiteral = Toy_popLiteralArray(arguments);
Toy_Literal secondLiteralIdn = secondLiteral;
if (TOY_IS_IDENTIFIER(secondLiteral) && Toy_parseIdentifierToValue(interpreter, &secondLiteral)) {
Toy_freeLiteral(secondLiteralIdn);
}
Toy_Literal microsecondLiteralIdn = microsecondLiteral;
if (TOY_IS_IDENTIFIER(microsecondLiteral) && Toy_parseIdentifierToValue(interpreter, &microsecondLiteral)) {
Toy_freeLiteral(microsecondLiteralIdn);
}
if (!TOY_IS_INTEGER(secondLiteral) || !TOY_IS_INTEGER(microsecondLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to createTimer\n");
Toy_freeLiteral(secondLiteral);
Toy_freeLiteral(microsecondLiteral);
return -1;
}
if (TOY_AS_INTEGER(microsecondLiteral) <= -1000 * 1000 || TOY_AS_INTEGER(microsecondLiteral) >= 1000 * 1000 || (TOY_AS_INTEGER(secondLiteral) != 0 && TOY_AS_INTEGER(microsecondLiteral) < 0) ) {
interpreter->errorOutput("Microseconds out of range in createTimer\n");
Toy_freeLiteral(secondLiteral);
Toy_freeLiteral(microsecondLiteral);
return -1;
}
//get the timeinfo from toy
struct timeval* timeinfo = TOY_ALLOCATE(struct timeval, 1);
timeinfo->tv_sec = TOY_AS_INTEGER(secondLiteral);
timeinfo->tv_usec = TOY_AS_INTEGER(microsecondLiteral);
//wrap in an opaque literal for Toy
Toy_Literal timeLiteral = TOY_TO_OPAQUE_LITERAL(timeinfo, -1);
Toy_pushLiteralArray(&interpreter->stack, timeLiteral);
Toy_freeLiteral(timeLiteral);
Toy_freeLiteral(secondLiteral);
Toy_freeLiteral(microsecondLiteral);
return 1;
}
static int nativeGetTimerSeconds(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _getTimerSeconds\n");
return -1;
}
//unwrap the opaque literal
Toy_Literal timeLiteral = Toy_popLiteralArray(arguments);
Toy_Literal timeLiteralIdn = timeLiteral;
if (TOY_IS_IDENTIFIER(timeLiteral) && Toy_parseIdentifierToValue(interpreter, &timeLiteral)) {
Toy_freeLiteral(timeLiteralIdn);
}
if (!TOY_IS_OPAQUE(timeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _getTimerSeconds\n");
Toy_freeLiteral(timeLiteral);
return -1;
}
struct timeval* timer = TOY_AS_OPAQUE(timeLiteral);
//create the result literal
Toy_Literal result = TOY_TO_INTEGER_LITERAL(timer->tv_sec);
Toy_pushLiteralArray(&interpreter->stack, result);
//cleanup
Toy_freeLiteral(timeLiteral);
Toy_freeLiteral(result);
return 1;
}
static int nativeGetTimerMicroseconds(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _getTimerMicroseconds\n");
return -1;
}
//unwrap the opaque literal
Toy_Literal timeLiteral = Toy_popLiteralArray(arguments);
Toy_Literal timeLiteralIdn = timeLiteral;
if (TOY_IS_IDENTIFIER(timeLiteral) && Toy_parseIdentifierToValue(interpreter, &timeLiteral)) {
Toy_freeLiteral(timeLiteralIdn);
}
if (!TOY_IS_OPAQUE(timeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _getTimerMicroseconds\n");
Toy_freeLiteral(timeLiteral);
return -1;
}
struct timeval* timer = TOY_AS_OPAQUE(timeLiteral);
//create the result literal
Toy_Literal result = TOY_TO_INTEGER_LITERAL(timer->tv_usec);
Toy_pushLiteralArray(&interpreter->stack, result);
//cleanup
Toy_freeLiteral(timeLiteral);
Toy_freeLiteral(result);
return 1;
}
static int nativeCompareTimer(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments to _compareTimer\n");
return -1;
}
//unwrap the opaque literals
Toy_Literal rhsLiteral = Toy_popLiteralArray(arguments);
Toy_Literal lhsLiteral = Toy_popLiteralArray(arguments);
Toy_Literal lhsLiteralIdn = lhsLiteral;
if (TOY_IS_IDENTIFIER(lhsLiteral) && Toy_parseIdentifierToValue(interpreter, &lhsLiteral)) {
Toy_freeLiteral(lhsLiteralIdn);
}
Toy_Literal rhsLiteralIdn = rhsLiteral;
if (TOY_IS_IDENTIFIER(rhsLiteral) && Toy_parseIdentifierToValue(interpreter, &rhsLiteral)) {
Toy_freeLiteral(rhsLiteralIdn);
}
if (!TOY_IS_OPAQUE(lhsLiteral) || !TOY_IS_OPAQUE(rhsLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _compareTimer\n");
Toy_freeLiteral(lhsLiteral);
Toy_freeLiteral(rhsLiteral);
return -1;
}
struct timeval* lhsTimer = TOY_AS_OPAQUE(lhsLiteral);
struct timeval* rhsTimer = TOY_AS_OPAQUE(rhsLiteral);
//determine the difference, and wrap it
struct timeval* d = diff(lhsTimer, rhsTimer);
Toy_Literal diffLiteral = TOY_TO_OPAQUE_LITERAL(d, -1);
Toy_pushLiteralArray(&interpreter->stack, diffLiteral);
//cleanup
Toy_freeLiteral(lhsLiteral);
Toy_freeLiteral(rhsLiteral);
Toy_freeLiteral(diffLiteral);
return 1;
}
static int nativeTimerToString(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _timerToString\n");
return -1;
}
//unwrap in an opaque literal
Toy_Literal timeLiteral = Toy_popLiteralArray(arguments);
Toy_Literal timeLiteralIdn = timeLiteral;
if (TOY_IS_IDENTIFIER(timeLiteral) && Toy_parseIdentifierToValue(interpreter, &timeLiteral)) {
Toy_freeLiteral(timeLiteralIdn);
}
if (!TOY_IS_OPAQUE(timeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _timerToString\n");
Toy_freeLiteral(timeLiteral);
return -1;
}
struct timeval* timer = TOY_AS_OPAQUE(timeLiteral);
//create the string literal
Toy_Literal resultLiteral = TOY_TO_NULL_LITERAL;
if (timer->tv_sec == 0 && timer->tv_usec < 0) { //special case, for when the negative sign is encoded in the usec
char buffer[128];
snprintf(buffer, 128, "-%ld.%06ld", timer->tv_sec, -timer->tv_usec);
resultLiteral = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(buffer, strlen(buffer)));
}
else { //normal case
char buffer[128];
snprintf(buffer, 128, "%ld.%06ld", timer->tv_sec, timer->tv_usec);
resultLiteral = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(buffer, strlen(buffer)));
}
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
//cleanup
Toy_freeLiteral(timeLiteral);
Toy_freeLiteral(resultLiteral);
return 1;
}
static int nativeDestroyTimer(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _destroyTimer\n");
return -1;
}
//unwrap in an opaque literal
Toy_Literal timeLiteral = Toy_popLiteralArray(arguments);
Toy_Literal timeLiteralIdn = timeLiteral;
if (TOY_IS_IDENTIFIER(timeLiteral) && Toy_parseIdentifierToValue(interpreter, &timeLiteral)) {
Toy_freeLiteral(timeLiteralIdn);
}
if (!TOY_IS_OPAQUE(timeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _destroyTimer\n");
Toy_freeLiteral(timeLiteral);
return -1;
}
struct timeval* timer = TOY_AS_OPAQUE(timeLiteral);
TOY_FREE(struct timeval, timer);
Toy_freeLiteral(timeLiteral);
return 0;
}
//call the hook
typedef struct Natives {
char* name;
Toy_NativeFn fn;
} Natives;
int Toy_hookTimer(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
//build the natives list
Natives natives[] = {
{"startTimer", nativeStartTimer},
{"_stopTimer", nativeStopTimer},
{"createTimer", nativeCreateTimer},
{"_getTimerSeconds", nativeGetTimerSeconds},
{"_getTimerMicroseconds", nativeGetTimerMicroseconds},
{"_compareTimer", nativeCompareTimer},
{"_timerToString", nativeTimerToString},
{"_destroyTimer", nativeDestroyTimer},
{NULL, NULL}
};
//store the library in an aliased dictionary
if (!TOY_IS_NULL(alias)) {
//make sure the name isn't taken
if (Toy_isDelcaredScopeVariable(interpreter->scope, alias)) {
interpreter->errorOutput("Can't override an existing variable\n");
Toy_freeLiteral(alias);
return -1;
}
//create the dictionary to load up with functions
Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
Toy_initLiteralDictionary(dictionary);
//load the dict with functions
for (int i = 0; natives[i].name; i++) {
Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name));
Toy_Literal func = TOY_TO_FUNCTION_NATIVE_LITERAL(natives[i].fn);
Toy_setLiteralDictionary(dictionary, name, func);
Toy_freeLiteral(name);
Toy_freeLiteral(func);
}
//build the type
Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true);
Toy_Literal strType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true);
Toy_Literal fnType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FUNCTION_NATIVE, true);
TOY_TYPE_PUSH_SUBTYPE(&type, strType);
TOY_TYPE_PUSH_SUBTYPE(&type, fnType);
//set scope
Toy_Literal dict = TOY_TO_DICTIONARY_LITERAL(dictionary);
Toy_declareScopeVariable(interpreter->scope, alias, type);
Toy_setScopeVariable(interpreter->scope, alias, dict, false);
//cleanup
Toy_freeLiteral(dict);
Toy_freeLiteral(type);
return 0;
}
//default
for (int i = 0; natives[i].name; i++) {
Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn);
}
return 0;
}
-6
View File
@@ -1,6 +0,0 @@
#pragma once
#include "toy_interpreter.h"
int Toy_hookTimer(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
+67 -18
View File
@@ -1,8 +1,6 @@
#include "repl_tools.h"
#include "lib_about.h"
#include "lib_compound.h"
#include "lib_standard.h"
#include "lib_timer.h"
#include "lib_runner.h"
#include "toy_console_colors.h"
@@ -16,30 +14,30 @@
#include <stdlib.h>
#include <string.h>
void repl() {
#define INPUT_BUFFER_SIZE 2048
void repl(const char* initialInput) {
//repl does it's own thing for now
bool error = false;
const int size = 2048;
char input[size];
memset(input, 0, size);
char input[INPUT_BUFFER_SIZE];
memset(input, 0, INPUT_BUFFER_SIZE);
Toy_Interpreter interpreter; //persist the interpreter for the scopes
Toy_initInterpreter(&interpreter);
//inject the libs
Toy_injectNativeHook(&interpreter, "about", Toy_hookAbout);
Toy_injectNativeHook(&interpreter, "compound", Toy_hookCompound);
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
Toy_injectNativeHook(&interpreter, "timer", Toy_hookTimer);
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
for(;;) {
printf("> ");
//handle EOF for exits
if (!fgets(input, size, stdin)) {
break;
if (!initialInput) {
//handle EOF for exits
printf("> ");
if (!fgets(input, INPUT_BUFFER_SIZE, stdin)) {
break;
}
}
//escape the repl (length of 5 to accomodate the newline)
@@ -52,8 +50,8 @@ void repl() {
Toy_Parser parser;
Toy_Compiler compiler;
Toy_initLexer(&lexer, input);
Toy_private_setComments(&lexer, false); //BUGFIX: disable comments here
Toy_initLexer(&lexer, initialInput ? initialInput : input);
Toy_private_setComments(&lexer, initialInput != NULL); //BUGFIX: disable comments here
Toy_initParser(&parser, &lexer);
Toy_initCompiler(&compiler);
@@ -77,7 +75,7 @@ void repl() {
if (!error) {
//get the bytecode dump
int size = 0;
size_t size = 0;
unsigned char* tb = Toy_collateCompiler(&compiler, &size);
//run the bytecode
@@ -88,6 +86,15 @@ void repl() {
Toy_freeCompiler(&compiler);
Toy_freeParser(&parser);
error = false;
if (initialInput) {
free((void*)initialInput);
initialInput = NULL;
if (interpreter.panic) {
break;
}
}
}
Toy_freeInterpreter(&interpreter);
@@ -131,6 +138,14 @@ int main(int argc, const char* argv[]) {
//run source file
if (Toy_commandLine.sourcefile) {
//only works on toy files
const char* s = strrchr(Toy_commandLine.sourcefile, '.');
if (!s || strcmp(s, ".toy")) {
fprintf(stderr, TOY_CC_ERROR "Bad file extension passed to %s (expected '.toy', found '%s')" TOY_CC_RESET, argv[0], s);
return -1;
}
//run the source file
Toy_runSourceFile(Toy_commandLine.sourcefile);
//lib cleanup
@@ -151,8 +166,21 @@ int main(int argc, const char* argv[]) {
//compile source file
if (Toy_commandLine.compilefile && Toy_commandLine.outfile) {
//only works on toy and tb files
const char* c = strrchr(Toy_commandLine.compilefile, '.');
if (!c || strcmp(c, ".toy")) {
fprintf(stderr, TOY_CC_ERROR "Bad file extension passed to %s (expected '.toy', found '%s')" TOY_CC_RESET, argv[0], c);
return -1;
}
const char* o = strrchr(Toy_commandLine.outfile, '.');
if (!o || strcmp(o, ".tb")) {
fprintf(stderr, TOY_CC_ERROR "Bad file extension passed to %s (expected '.tb', found '%s')" TOY_CC_RESET, argv[0], o);
return -1;
}
//compile and save
size_t size = 0;
const char* source = Toy_readFile(Toy_commandLine.compilefile, &size);
const char* source = (const char*)Toy_readFile(Toy_commandLine.compilefile, &size);
if (!source) {
return 1;
}
@@ -166,6 +194,14 @@ int main(int argc, const char* argv[]) {
//run binary
if (Toy_commandLine.binaryfile) {
//only works on tb files
const char* c = strrchr(Toy_commandLine.binaryfile, '.');
if (!c || strcmp(c, ".tb")) {
fprintf(stderr, TOY_CC_ERROR "Bad file extension passed to %s (expected '.tb', found '%s')" TOY_CC_RESET, argv[0], c); //this one is never seen
return -1;
}
//run the binary file
Toy_runBinaryFile(Toy_commandLine.binaryfile);
//lib cleanup
@@ -174,7 +210,20 @@ int main(int argc, const char* argv[]) {
return 0;
}
repl();
const char* initialSource = NULL;
if (Toy_commandLine.initialfile) {
//only works on toy files
const char* s = strrchr(Toy_commandLine.initialfile, '.');
if (!s || strcmp(s, ".toy")) {
fprintf(stderr, TOY_CC_ERROR "Bad file extension passed to %s (expected '.toy', found '%s')" TOY_CC_RESET, argv[0], s);
return -1;
}
size_t size;
initialSource = (const char*)Toy_readFile(Toy_commandLine.initialfile, &size);
}
repl(initialSource);
//lib cleanup
Toy_freeDriveDictionary();
+8 -12
View File
@@ -1,8 +1,6 @@
#include "repl_tools.h"
#include "lib_about.h"
#include "lib_compound.h"
#include "lib_standard.h"
#include "lib_timer.h"
#include "lib_runner.h"
#include "toy_console_colors.h"
@@ -16,7 +14,7 @@
#include <stdlib.h>
//IO functions
const char* Toy_readFile(const char* path, size_t* fileSize) {
const unsigned char* Toy_readFile(const char* path, size_t* fileSize) {
FILE* file = fopen(path, "rb");
if (file == NULL) {
@@ -28,14 +26,14 @@ const char* Toy_readFile(const char* path, size_t* fileSize) {
*fileSize = ftell(file);
rewind(file);
char* buffer = (char*)malloc(*fileSize + 1);
unsigned char* buffer = (unsigned char*)malloc(*fileSize + 1);
if (buffer == NULL) {
fprintf(stderr, TOY_CC_ERROR "Not enough memory to read \"%s\"\n" TOY_CC_RESET, path);
return NULL;
}
size_t bytesRead = fread(buffer, sizeof(char), *fileSize, file);
size_t bytesRead = fread(buffer, sizeof(unsigned char), *fileSize, file);
buffer[*fileSize] = '\0'; //NOTE: fread doesn't append this
@@ -57,7 +55,7 @@ int Toy_writeFile(const char* path, const unsigned char* bytes, size_t size) {
return -1;
}
int written = fwrite(bytes, size, 1, file);
size_t written = fwrite(bytes, size, 1, file);
if (written != 1) {
fprintf(stderr, TOY_CC_ERROR "Could not write file \"%s\"\n" TOY_CC_RESET, path);
@@ -96,7 +94,7 @@ const unsigned char* Toy_compileString(const char* source, size_t* size) {
}
//get the bytecode dump
const unsigned char* tb = Toy_collateCompiler(&compiler, (int*)(size));
const unsigned char* tb = Toy_collateCompiler(&compiler, size);
//cleanup
Toy_freeCompiler(&compiler);
@@ -113,18 +111,16 @@ void Toy_runBinary(const unsigned char* tb, size_t size) {
//inject the libs
Toy_injectNativeHook(&interpreter, "about", Toy_hookAbout);
Toy_injectNativeHook(&interpreter, "compound", Toy_hookCompound);
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
Toy_injectNativeHook(&interpreter, "timer", Toy_hookTimer);
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
Toy_runInterpreter(&interpreter, tb, size);
Toy_runInterpreter(&interpreter, tb, (int)size);
Toy_freeInterpreter(&interpreter);
}
void Toy_runBinaryFile(const char* fname) {
size_t size = 0; //not used
const unsigned char* tb = (const unsigned char*)Toy_readFile(fname, &size);
const unsigned char* tb = Toy_readFile(fname, &size);
if (!tb) {
return;
}
@@ -144,7 +140,7 @@ void Toy_runSource(const char* source) {
void Toy_runSourceFile(const char* fname) {
size_t size = 0; //not used
const char* source = Toy_readFile(fname, &size);
const char* source = (const char*)Toy_readFile(fname, &size);
if (!source) {
return;
}
+1 -1
View File
@@ -2,7 +2,7 @@
#include "toy_common.h"
const char* Toy_readFile(const char* path, size_t* fileSize);
const unsigned char* Toy_readFile(const char* path, size_t* fileSize);
int Toy_writeFile(const char* path, const unsigned char* bytes, size_t size);
const unsigned char* Toy_compileString(const char* source, size_t* size);
+1 -1
View File
@@ -17,5 +17,5 @@ fn fib(n : int) {
for (var i = 0; i < 40; i++) {
var res = fib(i);
print string i + ": " + string res + "\n";
print string i + ": " + string res;
}
+2 -1
View File
@@ -1,3 +1,4 @@
//WARNING: please think twice before using this in a test
fn fib(n : int) {
if (n < 2) return n;
return fib(n-1) + fib(n-2);
@@ -5,5 +6,5 @@ fn fib(n : int) {
for (var i = 0; i < 20; i++) {
var res = fib(i);
print string i + ": " + string res + "\n";
print string i + ": " + string res;
}
+44 -15
View File
@@ -1,19 +1,36 @@
/*
How to run this program:
toyrepl -n -t scripts/level.toy
How to move around:
move(up);
move(down);
move(left);
move(right);
*/
//constants
var WIDTH: int const = 10;
var HEIGHT: int const = 10;
var WIDTH: int const = 12;
var HEIGHT: int const = 12;
//WIDTH * HEIGHT in size
var tiles: [[int]] const = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1],
[1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1],
[1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1],
[1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] //BUG: map is twisted along this diagonal
];
var tileset: [int: string] const = [
@@ -22,8 +39,8 @@ var tileset: [int: string] const = [
];
//variables
var posX: int = 5;
var posY: int = 5;
var posX: int = 4;
var posY: int = 4;
//functions
fn draw() {
@@ -42,7 +59,7 @@ fn draw() {
print "\n";
}
fn move(xrel: int, yrel: int) {
fn moveRelative(xrel: int, yrel: int) {
if (xrel > 1 || xrel < -1 || yrel > 1 || yrel < -1 || (xrel != 0 && yrel != 0)) {
print "too fast!\n";
return;
@@ -59,3 +76,15 @@ fn move(xrel: int, yrel: int) {
draw();
}
//wrap for easy use
var up: [int] const = [0, -1];
var down: [int] const = [0, 1];
var left: [int] const = [-1, 0];
var right: [int] const = [1, 0];
fn move(dir: [int] const) {
return moveRelative(dir[0], dir[1]);
}
//initial display
move([0, 0]);
+3 -3
View File
@@ -1,5 +1,5 @@
//number of iterations
var SIZE: int const = 260;
var SIZE: int const = 100;
//lookup table
var lookup = [
@@ -29,7 +29,7 @@ for (var i = 0; i < SIZE -1; i++) {
prev += " ";
}
prev += "*"; //initial
print prev + "\n";
print prev;
//run
for (var iteration = 0; iteration < SIZE -1; iteration++) {
@@ -44,6 +44,6 @@ for (var iteration = 0; iteration < SIZE -1; iteration++) {
//right
output += (lookup[prev[SIZE-2]][prev[SIZE-1]][" "]);
print output + "\n";
print output;
prev = output;
}
-10
View File
@@ -1,10 +0,0 @@
var xrel: int = 0;
var yrel: int = 0;
if (xrel > 1 || xrel < -1 || yrel > 1 || yrel < -1) {
print "outside";
}
else {
print "inside";
}
+12
View File
@@ -135,6 +135,10 @@ static void freeASTNodeCustom(Toy_ASTNode* node, bool freeSelf) {
Toy_freeLiteral(node->import.identifier);
Toy_freeLiteral(node->import.alias);
break;
case TOY_AST_NODE_PASS:
//EMPTY
break;
}
if (freeSelf) {
@@ -383,3 +387,11 @@ void Toy_emitASTNodeImport(Toy_ASTNode** nodeHandle, Toy_Literal identifier, Toy
*nodeHandle = tmp;
}
void Toy_emitASTNodePass(Toy_ASTNode** nodeHandle) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
tmp->type = TOY_AST_NODE_PASS;
*nodeHandle = tmp;
}
+4
View File
@@ -34,6 +34,7 @@ typedef enum Toy_ASTNodeType {
TOY_AST_NODE_PREFIX_DECREMENT, //decrement a variable
TOY_AST_NODE_POSTFIX_DECREMENT, //decrement a variable
TOY_AST_NODE_IMPORT, //import a library
TOY_AST_NODE_PASS, //for doing nothing
} Toy_ASTNodeType;
//literals
@@ -238,6 +239,9 @@ typedef struct Toy_NodeImport {
Toy_Literal alias;
} Toy_NodeImport;
//for doing nothing
void Toy_emitASTNodePass(Toy_ASTNode** nodeHandle);
union Toy_private_node {
Toy_ASTNodeType type;
Toy_NodeLiteral atomic;
+1
View File
@@ -4,6 +4,7 @@
#include "toy_literal.h"
#include <stdio.h>
#include <string.h>
//static math utils, copied from the interpreter
static Toy_Literal addition(Toy_Interpreter* interpreter, Toy_Literal lhs, Toy_Literal rhs) {
+30 -18
View File
@@ -15,23 +15,22 @@ STATIC_ASSERT(sizeof(unsigned char) == 1);
STATIC_ASSERT(sizeof(unsigned short) == 2);
STATIC_ASSERT(sizeof(unsigned int) == 4);
#ifndef TOY_EXPORT
//declare the singleton
Toy_CommandLine Toy_commandLine;
//declare the singleton with default values
Toy_CommandLine Toy_commandLine = {
.error = false,
.help = false,
.version = false,
.binaryfile = NULL,
.sourcefile = NULL,
.compilefile = NULL,
.outfile = "out.tb",
.source = NULL,
.initialfile = NULL,
.enablePrintNewline = true,
.verbose = false
};
void Toy_initCommandLine(int argc, const char* argv[]) {
//default values
Toy_commandLine.error = false;
Toy_commandLine.help = false;
Toy_commandLine.version = false;
Toy_commandLine.binaryfile = NULL;
Toy_commandLine.sourcefile = NULL;
Toy_commandLine.compilefile = NULL;
Toy_commandLine.outfile = "out.tb";
Toy_commandLine.source = NULL;
Toy_commandLine.verbose = false;
for (int i = 1; i < argc; i++) { //start at 1 to skip the program name
Toy_commandLine.error = true; //error state by default, set to false by successful flags
@@ -81,6 +80,19 @@ void Toy_initCommandLine(int argc, const char* argv[]) {
continue;
}
if ((!strcmp(argv[i], "-t") || !strcmp(argv[i], "--initial")) && i + 1 < argc) {
Toy_commandLine.initialfile = (char*)argv[i + 1];
i++;
Toy_commandLine.error = false;
continue;
}
if (!strcmp(argv[i], "-n")) {
Toy_commandLine.enablePrintNewline = false;
Toy_commandLine.error = false;
continue;
}
//option without a flag + ending in .tb = binary input
if (i < argc) {
if (strncmp(&(argv[i][strlen(argv[i]) - 3]), ".tb", 3) == 0) {
@@ -96,7 +108,7 @@ void Toy_initCommandLine(int argc, const char* argv[]) {
}
void Toy_usageCommandLine(int argc, const char* argv[]) {
printf("Usage: %s [<file.tb> | -h | -v | [-d][-f file | -i source | -c file [-o outfile]]]\n\n", argv[0]);
printf("Usage: %s [ file.tb | -h | -v | -d | -f file.toy | -i source | -c file.toy -o out.tb | -t file.toy ]\n\n", argv[0]);
}
void Toy_helpCommandLine(int argc, const char* argv[]) {
@@ -110,6 +122,8 @@ void Toy_helpCommandLine(int argc, const char* argv[]) {
printf("-i\t| --input source\tParse, compile and execute this given string of source code.\n\n");
printf("-c\t| --compile filename\tParse and compile the specified source file into an output file.\n\n");
printf("-o\t| --output outfile\tName of the output file built with --compile (default: out.tb).\n\n");
printf("-t\t| --initial filename\tStart the repl as normal, after first running the given file.\n\n");
printf("-n\t|\t\t\tDisable the newline character at the end of the print statement.\n\n");
}
void Toy_copyrightCommandLine(int argc, const char* argv[]) {
@@ -121,5 +135,3 @@ 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("3. This notice may not be removed or altered from any source distribution.\n\n");
}
#endif
+21 -13
View File
@@ -5,23 +5,29 @@
#include <stdint.h>
#define TOY_VERSION_MAJOR 0
#define TOY_VERSION_MINOR 8
#define TOY_VERSION_MINOR 9
#define TOY_VERSION_PATCH 2
#define TOY_VERSION_BUILD __DATE__ " " __TIME__
//platform-specific specifications
#if defined(__linux__)
//platform/compiler-specific instructions
#if defined(__linux__) || defined(__MINGW32__) || defined(__GNUC__)
#define TOY_API extern
#elif defined(_WIN32) || defined(WIN32)
#define TOY_API
#elif defined(_MSC_VER)
#ifndef TOY_EXPORT
#define TOY_API __declspec(dllimport)
#else
#define TOY_API __declspec(dllexport)
#endif
#else
#define TOY_API
#define TOY_API extern
#endif
#ifndef TOY_EXPORT
//for processing the command line arguments
typedef struct {
bool error;
@@ -32,14 +38,16 @@ typedef struct {
char* compilefile;
char* outfile; //defaults to out.tb
char* source;
char* initialfile;
bool enablePrintNewline;
bool verbose;
} Toy_CommandLine;
extern Toy_CommandLine Toy_commandLine;
//these are intended for the repl only, despite using the api prefix
TOY_API Toy_CommandLine Toy_commandLine;
void Toy_initCommandLine(int argc, const char* argv[]);
TOY_API void Toy_initCommandLine(int argc, const char* argv[]);
void Toy_usageCommandLine(int argc, const char* argv[]);
void Toy_helpCommandLine(int argc, const char* argv[]);
void Toy_copyrightCommandLine(int argc, const char* argv[]);
#endif
TOY_API void Toy_usageCommandLine(int argc, const char* argv[]);
TOY_API void Toy_helpCommandLine(int argc, const char* argv[]);
TOY_API void Toy_copyrightCommandLine(int argc, const char* argv[]);
+21 -6
View File
@@ -9,6 +9,7 @@
#include "toy_console_colors.h"
#include <stdio.h>
#include <string.h>
void Toy_initCompiler(Toy_Compiler* compiler) {
Toy_initLiteralArray(&compiler->literalCache);
@@ -302,6 +303,12 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
//special case for when indexing and assigning
if (override != TOY_OP_EOF && node->binary.opcode >= TOY_OP_VAR_ASSIGN && node->binary.opcode <= TOY_OP_VAR_MODULO_ASSIGN) {
Toy_writeCompilerWithJumps(compiler, node->binary.right, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
//Special case if there's an index on both sides of the sign, just set it as indexing
if (node->binary.left->type == TOY_AST_NODE_BINARY && node->binary.right->type == TOY_AST_NODE_BINARY && node->binary.left->binary.opcode == TOY_OP_INDEX && node->binary.right->binary.opcode == TOY_OP_INDEX) {
compiler->bytecode[compiler->count++] = (unsigned char)TOY_OP_INDEX;
}
compiler->bytecode[compiler->count++] = (unsigned char)TOY_OP_INDEX_ASSIGN; //1 byte WARNING: enum trickery
compiler->bytecode[compiler->count++] = (unsigned char)node->binary.opcode; //1 byte
return TOY_OP_EOF;
@@ -315,7 +322,7 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
//return this if...
Toy_Opcode ret = Toy_writeCompilerWithJumps(compiler, node->binary.right, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
if (node->binary.opcode == TOY_OP_INDEX && rootNode->type == TOY_AST_NODE_BINARY && (rootNode->binary.opcode >= TOY_OP_VAR_ASSIGN && rootNode->binary.opcode <= TOY_OP_VAR_MODULO_ASSIGN)) { //range-based check for assignment type
if (node->binary.opcode == TOY_OP_INDEX && rootNode->type == TOY_AST_NODE_BINARY && (rootNode->binary.opcode >= TOY_OP_VAR_ASSIGN && rootNode->binary.opcode <= TOY_OP_VAR_MODULO_ASSIGN) && rootNode->binary.right != node) { //range-based check for assignment type; make sure the index is on the left of the assignment symbol
return TOY_OP_INDEX_ASSIGN_INTERMEDIATE;
}
@@ -959,6 +966,11 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
return TOY_OP_INDEX_ASSIGN; //override binary's instruction IF it is assign
}
break;
case TOY_AST_NODE_PASS: {
return TOY_OP_PASS;
}
break;
}
return TOY_OP_EOF;
@@ -970,6 +982,8 @@ void Toy_writeCompiler(Toy_Compiler* compiler, Toy_ASTNode* node) {
if (op != TOY_OP_EOF) {//compensate for indexing & dot notation being screwy
compiler->bytecode[compiler->count++] = (unsigned char)op; //1 byte
}
//TODO: could free up AST Nodes
}
void Toy_freeCompiler(Toy_Compiler* compiler) {
@@ -978,6 +992,7 @@ void Toy_freeCompiler(Toy_Compiler* compiler) {
compiler->bytecode = NULL;
compiler->capacity = 0;
compiler->count = 0;
compiler->panic = false;
}
static void emitByte(unsigned char** collationPtr, int* capacityPtr, int* countPtr, unsigned char byte) {
@@ -1025,7 +1040,7 @@ static void emitFloat(unsigned char** collationPtr, int* capacityPtr, int* count
}
//return the result
static unsigned char* collateCompilerHeaderOpt(Toy_Compiler* compiler, int* size, bool embedHeader) {
static unsigned char* collateCompilerHeaderOpt(Toy_Compiler* compiler, size_t* size, bool embedHeader) {
if (compiler->panic) {
fprintf(stderr, TOY_CC_ERROR "[internal] Can't collate a panicked compiler\n" TOY_CC_RESET);
return NULL;
@@ -1167,17 +1182,17 @@ static unsigned char* collateCompilerHeaderOpt(Toy_Compiler* compiler, int* size
case TOY_LITERAL_FUNCTION_INTERMEDIATE: {
//extract the compiler
Toy_Literal fn = compiler->literalCache.literals[i];
void* fnCompiler = TOY_AS_FUNCTION(fn).bytecode; //store the compiler here for now
void* fnCompiler = TOY_AS_FUNCTION(fn).inner.bytecode; //store the compiler here for now
//collate the function into bytecode (without header)
int size = 0;
size_t size = 0;
unsigned char* bytes = collateCompilerHeaderOpt((Toy_Compiler*)fnCompiler, &size, false);
//emit how long this section is, +1 for ending mark
Toy_emitShort(&fnCollation, &fnCapacity, &fnCount, (unsigned short)size + 1);
//write the fn to the fn collation
for (int i = 0; i < size; i++) {
for (size_t i = 0; i < size; i++) {
emitByte(&fnCollation, &fnCapacity, &fnCount, bytes[i]);
}
@@ -1285,6 +1300,6 @@ static unsigned char* collateCompilerHeaderOpt(Toy_Compiler* compiler, int* size
}
//the whole point of the compiler is to alter bytecode, so leave it as non-const
unsigned char* Toy_collateCompiler(Toy_Compiler* compiler, int* size) {
unsigned char* Toy_collateCompiler(Toy_Compiler* compiler, size_t* size) {
return collateCompilerHeaderOpt(compiler, size, true);
}
+1 -1
View File
@@ -19,4 +19,4 @@ TOY_API void Toy_writeCompiler(Toy_Compiler* compiler, Toy_ASTNode* node);
TOY_API void Toy_freeCompiler(Toy_Compiler* compiler);
//embed the header, data section, code section, function section, etc.
TOY_API unsigned char* Toy_collateCompiler(Toy_Compiler* compiler, int* size);
TOY_API unsigned char* Toy_collateCompiler(Toy_Compiler* compiler, size_t* size);
+36 -2
View File
@@ -2,6 +2,9 @@
//NOTE: you need both font AND background for these to work
//platform/compiler-specific instructions
#if defined(__linux__) || defined(__MINGW32__) || defined(__GNUC__)
//fonts color
#define TOY_CC_FONT_BLACK "\033[30;"
#define TOY_CC_FONT_RED "\033[31;"
@@ -25,6 +28,37 @@
//useful
#define TOY_CC_NOTICE TOY_CC_FONT_GREEN TOY_CC_BACK_BLACK
#define TOY_CC_WARN TOY_CC_FONT_YELLOW TOY_CC_BACK_BLACK
#define TOY_CC_ERROR TOY_CC_FONT_RED TOY_CC_BACK_BLACK
#define TOY_CC_WARN TOY_CC_FONT_YELLOW TOY_CC_BACK_BLACK
#define TOY_CC_ERROR TOY_CC_FONT_RED TOY_CC_BACK_BLACK
#define TOY_CC_RESET "\033[0m"
#else
//fonts color
#define TOY_CC_FONT_BLACK
#define TOY_CC_FONT_RED
#define TOY_CC_FONT_GREEN
#define TOY_CC_FONT_YELLOW
#define TOY_CC_FONT_BLUE
#define TOY_CC_FONT_PURPLE
#define TOY_CC_FONT_DGREEN
#define TOY_CC_FONT_WHITE
#define TOY_CC_FONT_CYAN
//background color
#define TOY_CC_BACK_BLACK
#define TOY_CC_BACK_RED
#define TOY_CC_BACK_GREEN
#define TOY_CC_BACK_YELLOW
#define TOY_CC_BACK_BLUE
#define TOY_CC_BACK_PURPLE
#define TOY_CC_BACK_DGREEN
#define TOY_CC_BACK_WHITE
//useful
#define TOY_CC_NOTICE TOY_CC_FONT_GREEN TOY_CC_BACK_BLACK
#define TOY_CC_WARN TOY_CC_FONT_YELLOW TOY_CC_BACK_BLACK
#define TOY_CC_ERROR TOY_CC_FONT_RED TOY_CC_BACK_BLACK
#define TOY_CC_RESET
#endif
+57 -77
View File
@@ -12,14 +12,16 @@
#include <string.h>
static void printWrapper(const char* output) {
printf("%s", output);
// printf("\n"); //default new line
if (Toy_commandLine.enablePrintNewline) {
printf("%s\n", output);
}
else {
printf("%s", output);
}
}
static void assertWrapper(const char* output) {
fprintf(stderr, TOY_CC_ERROR "Assertion failure: ");
fprintf(stderr, "%s", output);
fprintf(stderr, "\n" TOY_CC_RESET); //default new line
fprintf(stderr, TOY_CC_ERROR "Assertion failure: %s\n" TOY_CC_RESET, output);
}
static void errorWrapper(const char* output) {
@@ -33,8 +35,7 @@ bool Toy_injectNativeFn(Toy_Interpreter* interpreter, const char* name, Toy_Nati
return false;
}
int identifierLength = strlen(name);
Toy_Literal identifier = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefStringLength(name, identifierLength));
Toy_Literal identifier = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString(name));
//make sure the name isn't taken
if (Toy_existsLiteralDictionary(&interpreter->scope->variables, identifier)) {
@@ -1085,6 +1086,8 @@ static bool execFalseJump(Toy_Interpreter* interpreter) {
static void execInterpreter(Toy_Interpreter*);
static void readInterpreterSections(Toy_Interpreter* interpreter);
//expect stack: identifier, arg1, arg2, arg3..., stackSize
//also supports identifier & arg1 to be other way around (looseFirstArgument)
static bool execFnCall(Toy_Interpreter* interpreter, bool looseFirstArgument) {
//BUGFIX: depth check - don't drown!
if (interpreter->depth >= 200) {
@@ -1121,24 +1124,7 @@ static bool execFnCall(Toy_Interpreter* interpreter, bool looseFirstArgument) {
Toy_freeLiteral(lit);
}
//let's screw with the fn name, too
if (looseFirstArgument) {
if (!TOY_IS_IDENTIFIER(identifier)) {
interpreter->errorOutput("Bad literal passed as a function identifier\n");
Toy_freeLiteral(identifier);
Toy_freeLiteral(stackSize);
Toy_freeLiteralArray(&arguments);
return false;
}
int length = TOY_AS_IDENTIFIER(identifier)->length + 1;
char buffer[TOY_MAX_STRING_LENGTH];
snprintf(buffer, TOY_MAX_STRING_LENGTH, "_%s", Toy_toCString(TOY_AS_IDENTIFIER(identifier))); //prepend an underscore
Toy_freeLiteral(identifier);
identifier = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefStringLength(buffer, length));
}
//get the function literal
Toy_Literal func = identifier;
if (!Toy_parseIdentifierToValue(interpreter, &func)) {
@@ -1148,30 +1134,7 @@ static bool execFnCall(Toy_Interpreter* interpreter, bool looseFirstArgument) {
return false;
}
//check for side-loaded native functions
if (TOY_IS_FUNCTION_NATIVE(func)) {
//reverse the order to the correct order
Toy_LiteralArray correct;
Toy_initLiteralArray(&correct);
while(arguments.count) {
Toy_Literal lit = Toy_popLiteralArray(&arguments);
Toy_pushLiteralArray(&correct, lit);
Toy_freeLiteral(lit);
}
Toy_freeLiteralArray(&arguments);
//call the native function
TOY_AS_FUNCTION_NATIVE(func)(interpreter, &correct);
Toy_freeLiteralArray(&correct);
Toy_freeLiteral(stackSize);
Toy_freeLiteral(identifier);
return true;
}
if (!TOY_IS_FUNCTION(func)) {
if (!TOY_IS_FUNCTION(func) && !TOY_IS_FUNCTION_NATIVE(func)) {
interpreter->errorOutput("Function not found: ");
Toy_printLiteralCustom(identifier, interpreter->errorOutput);
interpreter->errorOutput("\n");
@@ -1182,7 +1145,18 @@ static bool execFnCall(Toy_Interpreter* interpreter, bool looseFirstArgument) {
return false;
}
bool ret = Toy_callLiteralFn(interpreter, func, &arguments, &interpreter->stack);
//BUGFIX: correct the argument order
Toy_LiteralArray correct;
Toy_initLiteralArray(&correct);
while (arguments.count > 0) {
Toy_Literal lit = Toy_popLiteralArray(&arguments);
Toy_pushLiteralArray(&correct, lit);
Toy_freeLiteral(lit);
}
//call the function literal
bool ret = Toy_callLiteralFn(interpreter, func, &correct, &interpreter->stack);
if (!ret) {
interpreter->errorOutput("Error encountered in function \"");
@@ -1190,6 +1164,7 @@ static bool execFnCall(Toy_Interpreter* interpreter, bool looseFirstArgument) {
interpreter->errorOutput("\"\n");
}
Toy_freeLiteralArray(&correct);
Toy_freeLiteralArray(&arguments);
Toy_freeLiteral(func);
Toy_freeLiteral(stackSize);
@@ -1198,25 +1173,17 @@ static bool execFnCall(Toy_Interpreter* interpreter, bool looseFirstArgument) {
return ret;
}
//expects arguments in correct order
bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_LiteralArray* arguments, Toy_LiteralArray* returns) {
//check for side-loaded native functions
if (TOY_IS_FUNCTION_NATIVE(func)) {
//reverse the order to the correct order
Toy_LiteralArray correct;
Toy_initLiteralArray(&correct);
while(arguments->count) {
Toy_Literal lit = Toy_popLiteralArray(arguments);
Toy_pushLiteralArray(&correct, lit);
Toy_freeLiteral(lit);
}
//TODO: parse out identifier values, see issue #64
//call the native function
int returnsCount = TOY_AS_FUNCTION_NATIVE(func)(interpreter, &correct);
int returnsCount = TOY_AS_FUNCTION_NATIVE(func)(interpreter, arguments);
if (returnsCount < 0) {
interpreter->errorOutput("Unknown error from native function\n");
Toy_freeLiteralArray(&correct);
return false;
}
@@ -1238,13 +1205,12 @@ bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_Liter
}
Toy_freeLiteralArray(&returnsFromInner);
Toy_freeLiteralArray(&correct);
return true;
}
//normal Toy function
if (!TOY_IS_FUNCTION(func)) {
interpreter->errorOutput("Function required in Toy_callLiteralFn()\n");
interpreter->errorOutput("Function literal required in Toy_callLiteralFn()\n");
return false;
}
@@ -1254,8 +1220,8 @@ bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_Liter
//init the inner interpreter manually
Toy_initLiteralArray(&inner.literalCache);
inner.scope = Toy_pushScope(func.as.function.scope);
inner.bytecode = TOY_AS_FUNCTION(func).bytecode;
inner.length = TOY_AS_FUNCTION(func).length;
inner.bytecode = TOY_AS_FUNCTION(func).inner.bytecode;
inner.length = TOY_AS_FUNCTION_BYTECODE_LENGTH(func);
inner.count = 0;
inner.codeStart = -1;
inner.depth = interpreter->depth + 1;
@@ -1292,6 +1258,9 @@ bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_Liter
return false;
}
//BUGFIX: access the arguments from the beginning
int argumentIndex = 0;
//contents is the indexes of identifier & type
for (int i = 0; i < paramArray->count - (TOY_IS_NULL(restParam) ? 0 : 2); i += 2) { //don't count the rest parameter, if present
//declare and define each entry in the scope
@@ -1307,7 +1276,11 @@ bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_Liter
return false;
}
Toy_Literal arg = Toy_popLiteralArray(arguments);
//access the arguments in order
Toy_Literal arg = TOY_TO_NULL_LITERAL;
if (argumentIndex < arguments->count) {
arg = Toy_copyLiteral(arguments->literals[argumentIndex++]);
}
Toy_Literal argIdn = arg;
if (TOY_IS_IDENTIFIER(arg) && Toy_parseIdentifierToValue(interpreter, &arg)) {
@@ -1334,8 +1307,9 @@ bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_Liter
Toy_LiteralArray rest;
Toy_initLiteralArray(&rest);
while (arguments->count > 0) {
Toy_Literal lit = Toy_popLiteralArray(arguments);
//access the arguments in order
while (argumentIndex < arguments->count) {
Toy_Literal lit = Toy_copyLiteral(arguments->literals[argumentIndex++]);
Toy_pushLiteralArray(&rest, lit);
Toy_freeLiteral(lit);
}
@@ -1442,6 +1416,9 @@ bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_Liter
Toy_freeLiteralArray(&inner.stack);
Toy_freeLiteralArray(&inner.literalCache);
//BUGFIX: this function needs to eat the arguments
Toy_freeLiteralArray(arguments);
//actual bytecode persists until next call
return true;
}
@@ -1507,7 +1484,7 @@ static bool execImport(Toy_Interpreter* interpreter) {
if (!Toy_existsLiteralDictionary(interpreter->hooks, identifier)) {
interpreter->errorOutput("Unknown library name in import statement: ");
Toy_printLiteralCustom(identifier, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
interpreter->errorOutput("\n");
Toy_freeLiteral(alias);
Toy_freeLiteral(identifier);
@@ -1827,6 +1804,10 @@ static void execInterpreter(Toy_Interpreter* interpreter) {
while(opcode != TOY_OP_EOF && opcode != TOY_OP_SECTION_END && !interpreter->panic) {
switch(opcode) {
case TOY_OP_PASS:
//DO NOTHING
break;
case TOY_OP_ASSERT:
if (!execAssert(interpreter)) {
return;
@@ -2335,7 +2316,6 @@ static void readInterpreterSections(Toy_Interpreter* interpreter) {
//change the type to normal
interpreter->literalCache.literals[i] = TOY_TO_FUNCTION_LITERAL(bytes, size);
TOY_AS_FUNCTION(interpreter->literalCache.literals[i]).scope = NULL;
}
}
@@ -2356,7 +2336,7 @@ void Toy_initInterpreter(Toy_Interpreter* interpreter) {
Toy_resetInterpreter(interpreter);
}
void Toy_runInterpreter(Toy_Interpreter* interpreter, const unsigned char* bytecode, int length) {
void Toy_runInterpreter(Toy_Interpreter* interpreter, const unsigned char* bytecode, size_t length) {
//initialize here instead of initInterpreter()
Toy_initLiteralArray(&interpreter->literalCache);
interpreter->bytecode = NULL;
@@ -2445,12 +2425,12 @@ void Toy_resetInterpreter(Toy_Interpreter* interpreter) {
interpreter->scope = Toy_pushScope(NULL);
//globally available functions
Toy_injectNativeFn(interpreter, "_set", Toy_private_set);
Toy_injectNativeFn(interpreter, "_get", Toy_private_get);
Toy_injectNativeFn(interpreter, "_push", Toy_private_push);
Toy_injectNativeFn(interpreter, "_pop", Toy_private_pop);
Toy_injectNativeFn(interpreter, "_length", Toy_private_length);
Toy_injectNativeFn(interpreter, "_clear", Toy_private_clear);
Toy_injectNativeFn(interpreter, "set", Toy_private_set);
Toy_injectNativeFn(interpreter, "get", Toy_private_get);
Toy_injectNativeFn(interpreter, "push", Toy_private_push);
Toy_injectNativeFn(interpreter, "pop", Toy_private_pop);
Toy_injectNativeFn(interpreter, "length", Toy_private_length);
Toy_injectNativeFn(interpreter, "clear", Toy_private_clear);
}
void Toy_freeInterpreter(Toy_Interpreter* interpreter) {
+1 -3
View File
@@ -6,8 +6,6 @@
#include "toy_literal_dictionary.h"
#include "toy_scope.h"
typedef void (*Toy_PrintFn)(const char*);
//the interpreter acts depending on the bytecode instructions
typedef struct Toy_Interpreter {
//input
@@ -48,6 +46,6 @@ TOY_API void Toy_setInterpreterError(Toy_Interpreter* interpreter, Toy_PrintFn e
//main access
TOY_API void Toy_initInterpreter(Toy_Interpreter* interpreter); //start of program
TOY_API void Toy_runInterpreter(Toy_Interpreter* interpreter, const unsigned char* bytecode, int length); //run the code
TOY_API void Toy_runInterpreter(Toy_Interpreter* interpreter, const unsigned char* bytecode, size_t length); //run the code
TOY_API void Toy_resetInterpreter(Toy_Interpreter* interpreter); //use this to reset the interpreter's environment between runs
TOY_API void Toy_freeInterpreter(Toy_Interpreter* interpreter); //end of program
+8 -8
View File
@@ -117,7 +117,7 @@ static Toy_Token makeErrorToken(Toy_Lexer* lexer, char* msg) {
#ifndef TOY_EXPORT
if (Toy_commandLine.verbose) {
printf("err:");
Toy_printToken(&token);
Toy_private_printToken(&token);
}
#endif
@@ -136,7 +136,7 @@ static Toy_Token makeToken(Toy_Lexer* lexer, Toy_TokenType type) {
//BUG #10: this shows TOKEN_EOF twice due to the overarching structure of the program - can't be fixed
if (Toy_commandLine.verbose) {
printf("tok:");
Toy_printToken(&token);
Toy_private_printToken(&token);
}
#endif
@@ -168,7 +168,7 @@ static Toy_Token makeIntegerOrFloat(Toy_Lexer* lexer) {
} else {
printf("flt:");
}
Toy_printToken(&token);
Toy_private_printToken(&token);
}
#endif
@@ -221,7 +221,7 @@ static Toy_Token makeString(Toy_Lexer* lexer, char terminator) {
#ifndef TOY_EXPORT
if (Toy_commandLine.verbose) {
printf("str:");
Toy_printToken(&token);
Toy_private_printToken(&token);
}
#endif
@@ -248,7 +248,7 @@ static Toy_Token makeKeywordOrIdentifier(Toy_Lexer* lexer) {
#ifndef TOY_EXPORT
if (Toy_commandLine.verbose) {
printf("kwd:");
Toy_printToken(&token);
Toy_private_printToken(&token);
}
#endif
@@ -267,7 +267,7 @@ static Toy_Token makeKeywordOrIdentifier(Toy_Lexer* lexer) {
#ifndef TOY_EXPORT
if (Toy_commandLine.verbose) {
printf("idf:");
Toy_printToken(&token);
Toy_private_printToken(&token);
}
#endif
@@ -281,7 +281,7 @@ void Toy_initLexer(Toy_Lexer* lexer, const char* source) {
lexer->source = source;
}
Toy_Token Toy_scanLexer(Toy_Lexer* lexer) {
Toy_Token Toy_private_scanLexer(Toy_Lexer* lexer) {
eatWhitespace(lexer);
lexer->start = lexer->current;
@@ -352,7 +352,7 @@ static void trim(char** s, int* l) { //all this to remove a newline?
}
//for debugging
void Toy_printToken(Toy_Token* token) {
void Toy_private_printToken(Toy_Token* token) {
if (token->type == TOY_TOKEN_ERROR) {
printf(TOY_CC_ERROR "Error\t%d\t%.*s\n" TOY_CC_RESET, token->line, token->length, token->lexeme);
return;
+3 -3
View File
@@ -21,9 +21,9 @@ typedef struct {
} Toy_Token;
TOY_API void Toy_initLexer(Toy_Lexer* lexer, const char* source);
Toy_Token Toy_scanLexer(Toy_Lexer* lexer);
TOY_API Toy_Token Toy_private_scanLexer(Toy_Lexer* lexer);
//for debugging
void Toy_printToken(Toy_Token* token);
TOY_API void Toy_private_printToken(Toy_Token* token);
void Toy_private_setComments(Toy_Lexer* lexer, bool enabled);
TOY_API void Toy_private_setComments(Toy_Lexer* lexer, bool enabled);
+13 -11
View File
@@ -8,6 +8,7 @@
#include "toy_console_colors.h"
#include <stdio.h>
#include <string.h>
//hash util functions
static unsigned int hashString(const char* string, int length) {
@@ -58,7 +59,7 @@ void Toy_freeLiteral(Toy_Literal literal) {
if (TOY_IS_FUNCTION(literal)) {
Toy_popScope(TOY_AS_FUNCTION(literal).scope);
TOY_AS_FUNCTION(literal).scope = NULL;
TOY_FREE_ARRAY(unsigned char, TOY_AS_FUNCTION(literal).bytecode, TOY_AS_FUNCTION(literal).length);
TOY_FREE_ARRAY(unsigned char, TOY_AS_FUNCTION(literal).inner.bytecode, TOY_AS_FUNCTION_BYTECODE_LENGTH(literal));
}
if (TOY_IS_TYPE(literal)) {
@@ -84,11 +85,11 @@ bool Toy_private_isTruthy(Toy_Literal x) {
}
Toy_Literal Toy_private_toStringLiteral(Toy_RefString* ptr) {
return ((Toy_Literal){TOY_LITERAL_STRING, { .string.ptr = ptr }});
return ((Toy_Literal){{ .string = { .ptr = ptr }},TOY_LITERAL_STRING, 0});
}
Toy_Literal Toy_private_toIdentifierLiteral(Toy_RefString* ptr) {
return ((Toy_Literal){TOY_LITERAL_IDENTIFIER,{ .identifier.ptr = ptr, .identifier.hash = hashString(Toy_toCString(ptr), Toy_lengthRefString(ptr)) }});
return ((Toy_Literal){{ .identifier = { .ptr = ptr, .hash = hashString(Toy_toCString(ptr), Toy_lengthRefString(ptr)) }},TOY_LITERAL_IDENTIFIER, 0});
}
Toy_Literal* Toy_private_typePushSubtype(Toy_Literal* lit, Toy_Literal subtype) {
@@ -145,17 +146,18 @@ Toy_Literal Toy_copyLiteral(Toy_Literal original) {
}
case TOY_LITERAL_FUNCTION: {
unsigned char* buffer = TOY_ALLOCATE(unsigned char, TOY_AS_FUNCTION(original).length);
memcpy(buffer, TOY_AS_FUNCTION(original).bytecode, TOY_AS_FUNCTION(original).length);
unsigned char* buffer = TOY_ALLOCATE(unsigned char, TOY_AS_FUNCTION_BYTECODE_LENGTH(original));
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(original).length);
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);
return literal;
}
case TOY_LITERAL_IDENTIFIER: {
return TOY_TO_IDENTIFIER_LITERAL(Toy_copyRefString(TOY_AS_IDENTIFIER(original)));
//NOTE: could optimise this by copying the hash manually, but it's a very small increase in performance
return TOY_TO_IDENTIFIER_LITERAL(Toy_copyRefString(TOY_AS_IDENTIFIER(original)));
}
case TOY_LITERAL_TYPE: {
@@ -404,20 +406,20 @@ int Toy_hashLiteral(Toy_Literal lit) {
case TOY_LITERAL_FUNCTION:
case TOY_LITERAL_FUNCTION_NATIVE:
case TOY_LITERAL_FUNCTION_HOOK:
return 0; //can't hash these
return -1; //can't hash these
case TOY_LITERAL_IDENTIFIER:
return TOY_HASH_I(lit); //pre-computed
case TOY_LITERAL_TYPE:
return TOY_AS_TYPE(lit).typeOf; //nothing else I can do
return -1; //not much i can really do
case TOY_LITERAL_OPAQUE:
case TOY_LITERAL_ANY:
return -1;
default:
//should never bee seen
//should never be seen
fprintf(stderr, TOY_CC_ERROR "[internal] Unrecognized literal type in hash: %d\n" TOY_CC_RESET, lit.type);
return 0;
}
@@ -453,7 +455,7 @@ void Toy_printLiteral(Toy_Literal literal) {
Toy_printLiteralCustom(literal, stdoutWrapper);
}
void Toy_printLiteralCustom(Toy_Literal literal, void (printFn)(const char*)) {
void Toy_printLiteralCustom(Toy_Literal literal, Toy_PrintFn printFn) {
switch(literal.type) {
case TOY_LITERAL_NULL:
printFn("null");
+50 -44
View File
@@ -10,8 +10,7 @@ struct Toy_Interpreter;
struct Toy_LiteralArray;
typedef int (*Toy_NativeFn)(struct Toy_Interpreter* interpreter, struct Toy_LiteralArray* arguments);
typedef int (*Toy_HookFn)(struct Toy_Interpreter* interpreter, struct Toy_Literal identifier, struct Toy_Literal alias);
#include <string.h>
typedef void (*Toy_PrintFn)(const char*);
typedef enum {
TOY_LITERAL_NULL,
@@ -39,45 +38,49 @@ typedef enum {
} Toy_LiteralType;
typedef struct Toy_Literal {
Toy_LiteralType type;
union {
bool boolean;
int integer;
float number;
bool boolean; //1
int integer; //4
float number;//4
struct {
Toy_RefString* ptr;
Toy_RefString* ptr; //8
//string hash?
} string;
} string; //8
void* array;
void* dictionary;
void* array; //8
void* dictionary; //8
struct {
void* bytecode;
Toy_NativeFn native; //already a pointer
Toy_HookFn hook; //already a pointer
void* scope;
int length;
} function;
union {
void* bytecode; //8
Toy_NativeFn native; //8
Toy_HookFn hook; //8
} inner; //8
void* scope; //8
} function; //16
struct { //for variable names
Toy_RefString* ptr;
int hash;
} identifier;
Toy_RefString* ptr; //8
int hash; //4
} identifier; //16
struct {
Toy_LiteralType typeOf;
bool constant;
void* subtypes; //for nested types caused by compounds
int capacity;
int count;
} type;
void* subtypes; //8
Toy_LiteralType typeOf; //4
unsigned char capacity; //1
unsigned char count; //1
bool constant; //1
} type; //16
struct {
void* ptr;
int tag;
} opaque;
} as;
void* ptr; //8
int tag; //4
} opaque; //16
} as; //16
Toy_LiteralType type; //4
int bytecodeLength; //4 - shenanigans with byte alignment reduces the size of Toy_Literal
} Toy_Literal;
#define TOY_IS_NULL(value) ((value).type == TOY_LITERAL_NULL)
@@ -101,34 +104,36 @@ typedef struct Toy_Literal {
#define TOY_AS_ARRAY(value) ((Toy_LiteralArray*)((value).as.array))
#define TOY_AS_DICTIONARY(value) ((Toy_LiteralDictionary*)((value).as.dictionary))
#define TOY_AS_FUNCTION(value) ((value).as.function)
#define TOY_AS_FUNCTION_NATIVE(value) ((value).as.function.native)
#define TOY_AS_FUNCTION_HOOK(value) ((value).as.function.hook)
#define TOY_AS_FUNCTION_NATIVE(value) ((value).as.function.inner.native)
#define TOY_AS_FUNCTION_HOOK(value) ((value).as.function.inner.hook)
#define TOY_AS_IDENTIFIER(value) ((value).as.identifier.ptr)
#define TOY_AS_TYPE(value) ((value).as.type)
#define TOY_AS_OPAQUE(value) ((value).as.opaque.ptr)
#define TOY_TO_NULL_LITERAL ((Toy_Literal){TOY_LITERAL_NULL, { .integer = 0 }})
#define TOY_TO_BOOLEAN_LITERAL(value) ((Toy_Literal){TOY_LITERAL_BOOLEAN, { .boolean = value }})
#define TOY_TO_INTEGER_LITERAL(value) ((Toy_Literal){TOY_LITERAL_INTEGER, { .integer = value }})
#define TOY_TO_FLOAT_LITERAL(value) ((Toy_Literal){TOY_LITERAL_FLOAT, { .number = value }})
#define TOY_TO_NULL_LITERAL ((Toy_Literal){{ .integer = 0 }, TOY_LITERAL_NULL, 0})
#define TOY_TO_BOOLEAN_LITERAL(value) ((Toy_Literal){{ .boolean = value }, TOY_LITERAL_BOOLEAN, 0})
#define TOY_TO_INTEGER_LITERAL(value) ((Toy_Literal){{ .integer = value }, TOY_LITERAL_INTEGER, 0})
#define TOY_TO_FLOAT_LITERAL(value) ((Toy_Literal){{ .number = value }, TOY_LITERAL_FLOAT, 0})
#define TOY_TO_STRING_LITERAL(value) Toy_private_toStringLiteral(value)
#define TOY_TO_ARRAY_LITERAL(value) ((Toy_Literal){TOY_LITERAL_ARRAY, { .array = value }})
#define TOY_TO_DICTIONARY_LITERAL(value) ((Toy_Literal){TOY_LITERAL_DICTIONARY, { .dictionary = value }})
#define TOY_TO_FUNCTION_LITERAL(value, l) ((Toy_Literal){TOY_LITERAL_FUNCTION, { .function.bytecode = value, .function.scope = NULL, .function.length = l }})
#define TOY_TO_FUNCTION_NATIVE_LITERAL(value) ((Toy_Literal){TOY_LITERAL_FUNCTION_NATIVE, { .function.native = value, .function.scope = NULL, .function.length = 0 }})
#define TOY_TO_FUNCTION_HOOK_LITERAL(value) ((Toy_Literal){TOY_LITERAL_FUNCTION_HOOK, { .function.hook = value, .function.scope = NULL, .function.length = 0 }})
#define TOY_TO_ARRAY_LITERAL(value) ((Toy_Literal){{ .array = value }, TOY_LITERAL_ARRAY, 0})
#define TOY_TO_DICTIONARY_LITERAL(value) ((Toy_Literal){{ .dictionary = value }, TOY_LITERAL_DICTIONARY, 0})
#define TOY_TO_FUNCTION_LITERAL(value, l) ((Toy_Literal){{ .function = { .inner = { .bytecode = value }, .scope = NULL }}, TOY_LITERAL_FUNCTION, l})
#define TOY_TO_FUNCTION_NATIVE_LITERAL(value) ((Toy_Literal){{ .function = { .inner = { .native = value }, .scope = NULL }}, TOY_LITERAL_FUNCTION_NATIVE, 0})
#define TOY_TO_FUNCTION_HOOK_LITERAL(value) ((Toy_Literal){{ .function = { .inner = { .hook = value }, .scope = NULL }}, TOY_LITERAL_FUNCTION_HOOK, 0})
#define TOY_TO_IDENTIFIER_LITERAL(value) Toy_private_toIdentifierLiteral(value)
#define TOY_TO_TYPE_LITERAL(value, c) ((Toy_Literal){ TOY_LITERAL_TYPE, { .type.typeOf = value, .type.constant = c, .type.subtypes = NULL, .type.capacity = 0, .type.count = 0 }})
#define TOY_TO_OPAQUE_LITERAL(value, t) ((Toy_Literal){ TOY_LITERAL_OPAQUE, { .opaque.ptr = value, .opaque.tag = t }})
#define TOY_TO_TYPE_LITERAL(value, c) ((Toy_Literal){{ .type = { .typeOf = value, .constant = c, .subtypes = NULL, .capacity = 0, .count = 0 }}, TOY_LITERAL_TYPE, 0})
#define TOY_TO_OPAQUE_LITERAL(value, t) ((Toy_Literal){{ .opaque = { .ptr = value, .tag = t }}, TOY_LITERAL_OPAQUE, 0})
//BUGFIX: For blank indexing
#define TOY_IS_INDEX_BLANK(value) ((value).type == TOY_LITERAL_INDEX_BLANK)
#define TOY_TO_INDEX_BLANK_LITERAL ((Toy_Literal){TOY_LITERAL_INDEX_BLANK, { .integer = 0 }})
#define TOY_TO_INDEX_BLANK_LITERAL ((Toy_Literal){{ .integer = 0 }, TOY_LITERAL_INDEX_BLANK, 0})
TOY_API void Toy_freeLiteral(Toy_Literal literal);
#define TOY_IS_TRUTHY(x) Toy_private_isTruthy(x)
#define TOY_AS_FUNCTION_BYTECODE_LENGTH(lit) ((lit).bytecodeLength)
#define TOY_MAX_STRING_LENGTH 4096
#define TOY_HASH_I(lit) ((lit).as.identifier.hash)
#define TOY_TYPE_PUSH_SUBTYPE(lit, subtype) Toy_private_typePushSubtype(lit, subtype)
@@ -145,5 +150,6 @@ TOY_API Toy_Literal Toy_copyLiteral(Toy_Literal original);
TOY_API bool Toy_literalsAreEqual(Toy_Literal lhs, Toy_Literal rhs);
TOY_API int Toy_hashLiteral(Toy_Literal lit);
//not thread-safe
TOY_API void Toy_printLiteral(Toy_Literal literal);
TOY_API void Toy_printLiteralCustom(Toy_Literal literal, void (printFn)(const char*));
TOY_API void Toy_printLiteralCustom(Toy_Literal literal, Toy_PrintFn);
+2
View File
@@ -18,3 +18,5 @@ TOY_API bool Toy_setLiteralArray(Toy_LiteralArray* array, Toy_Literal index, Toy
TOY_API Toy_Literal Toy_getLiteralArray(Toy_LiteralArray* array, Toy_Literal index);
int Toy_findLiteralIndex(Toy_LiteralArray* array, Toy_Literal literal);
//TODO: add a function to get the capacity & count
+18 -18
View File
@@ -7,7 +7,7 @@
#include <stdio.h>
//util functions
static void setEntryValues(Toy_private_entry* entry, Toy_Literal key, Toy_Literal value) {
static void setEntryValues(Toy_private_dictionary_entry* entry, Toy_Literal key, Toy_Literal value) {
//much simpler now
Toy_freeLiteral(entry->key);
entry->key = Toy_copyLiteral(key);
@@ -16,7 +16,7 @@ static void setEntryValues(Toy_private_entry* entry, Toy_Literal key, Toy_Litera
entry->value = Toy_copyLiteral(value);
}
static Toy_private_entry* getEntryArray(Toy_private_entry* array, int capacity, Toy_Literal key, unsigned int hash, bool mustExist) {
static Toy_private_dictionary_entry* getEntryArray(Toy_private_dictionary_entry* array, int capacity, Toy_Literal key, unsigned int hash, bool mustExist) {
//find "key", starting at index
unsigned int index = hash % capacity;
unsigned int start = index;
@@ -26,7 +26,7 @@ static Toy_private_entry* getEntryArray(Toy_private_entry* array, int capacity,
//literal probing and collision checking
while (index != start) { //WARNING: this is the only function allowed to retrieve an entry from the array
Toy_private_entry* entry = &array[index];
Toy_private_dictionary_entry* entry = &array[index];
if (TOY_IS_NULL(entry->key)) { //if key is empty, it's either empty or tombstone
if (TOY_IS_NULL(entry->value) && !mustExist) {
@@ -46,9 +46,9 @@ static Toy_private_entry* getEntryArray(Toy_private_entry* array, int capacity,
return NULL;
}
static void adjustEntryCapacity(Toy_private_entry** dictionaryHandle, int oldCapacity, int capacity) {
static void adjustEntryCapacity(Toy_private_dictionary_entry** dictionaryHandle, int oldCapacity, int capacity) {
//new entry space
Toy_private_entry* newEntries = TOY_ALLOCATE(Toy_private_entry, capacity);
Toy_private_dictionary_entry* newEntries = TOY_ALLOCATE(Toy_private_dictionary_entry, capacity);
for (int i = 0; i < capacity; i++) {
newEntries[i].key = TOY_TO_NULL_LITERAL;
@@ -62,19 +62,19 @@ static void adjustEntryCapacity(Toy_private_entry** dictionaryHandle, int oldCap
}
//place the key and value in the new array (reusing string memory)
Toy_private_entry* entry = getEntryArray(newEntries, capacity, TOY_TO_NULL_LITERAL, Toy_hashLiteral((*dictionaryHandle)[i].key), false);
Toy_private_dictionary_entry* entry = getEntryArray(newEntries, capacity, TOY_TO_NULL_LITERAL, Toy_hashLiteral((*dictionaryHandle)[i].key), false);
entry->key = (*dictionaryHandle)[i].key;
entry->value = (*dictionaryHandle)[i].value;
}
//clear the old array
TOY_FREE_ARRAY(Toy_private_entry, *dictionaryHandle, oldCapacity);
TOY_FREE_ARRAY(Toy_private_dictionary_entry, *dictionaryHandle, oldCapacity);
*dictionaryHandle = newEntries;
}
static bool setEntryArray(Toy_private_entry** dictionaryHandle, int* capacityPtr, int contains, Toy_Literal key, Toy_Literal value, int hash) {
static bool setEntryArray(Toy_private_dictionary_entry** dictionaryHandle, int* capacityPtr, int contains, Toy_Literal key, Toy_Literal value, int hash) {
//expand array if needed
if (contains + 1 > *capacityPtr * TOY_DICTIONARY_MAX_LOAD) {
int oldCapacity = *capacityPtr;
@@ -82,7 +82,7 @@ static bool setEntryArray(Toy_private_entry** dictionaryHandle, int* capacityPtr
adjustEntryCapacity(dictionaryHandle, oldCapacity, *capacityPtr); //custom rather than automatic reallocation
}
Toy_private_entry* entry = getEntryArray(*dictionaryHandle, *capacityPtr, key, hash, false);
Toy_private_dictionary_entry* entry = getEntryArray(*dictionaryHandle, *capacityPtr, key, hash, false);
//true = contains increase
if (TOY_IS_NULL(entry->key)) {
@@ -97,14 +97,14 @@ static bool setEntryArray(Toy_private_entry** dictionaryHandle, int* capacityPtr
return false;
}
static void freeEntry(Toy_private_entry* entry) {
static void freeEntry(Toy_private_dictionary_entry* entry) {
Toy_freeLiteral(entry->key);
Toy_freeLiteral(entry->value);
entry->key = TOY_TO_NULL_LITERAL;
entry->value = TOY_TO_NULL_LITERAL;
}
static void freeEntryArray(Toy_private_entry* array, int capacity) {
static void freeEntryArray(Toy_private_dictionary_entry* array, int capacity) {
if (array == NULL) {
return;
}
@@ -115,7 +115,7 @@ static void freeEntryArray(Toy_private_entry* array, int capacity) {
}
}
TOY_FREE_ARRAY(Toy_private_entry, array, capacity);
TOY_FREE_ARRAY(Toy_private_dictionary_entry, array, capacity);
}
//exposed functions
@@ -141,7 +141,7 @@ void Toy_setLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key
}
//BUGFIX: Can't hash a function
if (TOY_IS_FUNCTION(key) || TOY_IS_FUNCTION_NATIVE(key)) {
if (TOY_IS_FUNCTION(key) || TOY_IS_FUNCTION_NATIVE(key) || TOY_IS_FUNCTION_HOOK(key)) {
fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have function keys (set)\n" TOY_CC_RESET);
return;
}
@@ -166,7 +166,7 @@ Toy_Literal Toy_getLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Lite
}
//BUGFIX: Can't hash a function
if (TOY_IS_FUNCTION(key) || TOY_IS_FUNCTION_NATIVE(key)) {
if (TOY_IS_FUNCTION(key) || TOY_IS_FUNCTION_NATIVE(key) || TOY_IS_FUNCTION_HOOK(key)) {
fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have function keys (get)\n" TOY_CC_RESET);
return TOY_TO_NULL_LITERAL;
}
@@ -176,7 +176,7 @@ Toy_Literal Toy_getLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Lite
return TOY_TO_NULL_LITERAL;
}
Toy_private_entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, Toy_hashLiteral(key), true);
Toy_private_dictionary_entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, Toy_hashLiteral(key), true);
if (entry != NULL) {
return Toy_copyLiteral(entry->value);
@@ -193,7 +193,7 @@ void Toy_removeLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal
}
//BUGFIX: Can't hash a function
if (TOY_IS_FUNCTION(key) || TOY_IS_FUNCTION_NATIVE(key)) {
if (TOY_IS_FUNCTION(key) || TOY_IS_FUNCTION_NATIVE(key) || TOY_IS_FUNCTION_HOOK(key)) {
fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have function keys (remove)\n" TOY_CC_RESET);
return;
}
@@ -203,7 +203,7 @@ void Toy_removeLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal
return;
}
Toy_private_entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, Toy_hashLiteral(key), true);
Toy_private_dictionary_entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, Toy_hashLiteral(key), true);
if (entry != NULL) {
freeEntry(entry);
@@ -214,6 +214,6 @@ void Toy_removeLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal
bool Toy_existsLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key) {
//null & not tombstoned
Toy_private_entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, Toy_hashLiteral(key), false);
Toy_private_dictionary_entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, Toy_hashLiteral(key), false);
return !(TOY_IS_NULL(entry->key) && TOY_IS_NULL(entry->value));
}
+3 -3
View File
@@ -7,13 +7,13 @@
//TODO: benchmark this
#define TOY_DICTIONARY_MAX_LOAD 0.75
typedef struct Toy_private_entry {
typedef struct Toy_private_dictionary_entry {
Toy_Literal key;
Toy_Literal value;
} Toy_private_entry;
} Toy_private_dictionary_entry;
typedef struct Toy_LiteralDictionary {
Toy_private_entry* entries;
Toy_private_dictionary_entry* entries;
int capacity;
int count;
int contains; //count + tombstones, for internal use
+2 -3
View File
@@ -15,15 +15,14 @@ void* Toy_private_defaultMemoryAllocator(void* pointer, size_t oldSize, size_t n
if (newSize == 0) {
free(pointer);
return NULL;
}
void* mem = realloc(pointer, newSize);
if (mem == NULL) {
fprintf(stderr, TOY_CC_ERROR "[internal] Memory allocation error (requested %d, replacing %d)\n" TOY_CC_RESET, (int)newSize, (int)oldSize);
exit(-1);
fprintf(stderr, TOY_CC_ERROR "[internal] Memory allocation error (requested %zu, replacing %zu)\n" TOY_CC_RESET, newSize, oldSize);
return NULL;
}
return mem;
+11 -8
View File
@@ -2,16 +2,19 @@
#include "toy_common.h"
#define TOY_ALLOCATE(type, count) ((type*)Toy_reallocate(NULL, 0, sizeof(type) * (count)))
#define TOY_FREE(type, pointer) Toy_reallocate(pointer, sizeof(type), 0)
#define TOY_GROW_CAPACITY(capacity) ((capacity) < 8 ? 8 : (capacity) * 2)
#define TOY_GROW_CAPACITY_FAST(capacity) ((capacity) < 32 ? 32 : (capacity) * 2)
#define TOY_GROW_ARRAY(type, pointer, oldCount, count) (type*)Toy_reallocate((type*)pointer, sizeof(type) * (oldCount), sizeof(type) * (count))
#define TOY_SHRINK_ARRAY(type, pointer, oldCount, count) (type*)Toy_reallocate((type*)pointer, sizeof(type) * (oldCount), sizeof(type) * (count))
#define TOY_FREE_ARRAY(type, pointer, oldCount) Toy_reallocate((type*)pointer, sizeof(type) * (oldCount), 0)
#define TOY_GROW_CAPACITY(capacity) ((capacity) < 8 ? 8 : (capacity) * 2)
#define TOY_GROW_CAPACITY_FAST(capacity) ((capacity) < 32 ? 32 : (capacity) * 2)
#define TOY_ALLOCATE(type, count) ((type*)Toy_reallocate(NULL, 0, sizeof(type) * (count)))
#define TOY_FREE(type, pointer) Toy_reallocate(pointer, sizeof(type), 0)
#define TOY_FREE_ARRAY(type, pointer, oldCount) Toy_reallocate((type*)pointer, sizeof(type) * (oldCount), 0)
#define TOY_GROW_ARRAY(type, pointer, oldCount, count) (type*)Toy_reallocate((type*)pointer, sizeof(type) * (oldCount), sizeof(type) * (count))
#define TOY_SHRINK_ARRAY(type, pointer, oldCount, count) (type*)Toy_reallocate((type*)pointer, sizeof(type) * (oldCount), sizeof(type) * (count))
//implementation details
void* Toy_reallocate(void* pointer, size_t oldSize, size_t newSize);
TOY_API void* Toy_reallocate(void* pointer, size_t oldSize, size_t newSize);
//assign the memory allocator
typedef void* (*Toy_MemoryAllocatorFn)(void* pointer, size_t oldSize, size_t newSize);
+3
View File
@@ -3,6 +3,9 @@
typedef enum Toy_Opcode {
TOY_OP_EOF,
//do nothing
TOY_OP_PASS,
//basic statements
TOY_OP_ASSERT,
TOY_OP_PRINT,
+29 -6
View File
@@ -32,7 +32,7 @@ static void error(Toy_Parser* parser, Toy_Token token, const char* message) {
static void advance(Toy_Parser* parser) {
parser->previous = parser->current;
parser->current = Toy_scanLexer(parser->lexer);
parser->current = Toy_private_scanLexer(parser->lexer);
if (parser->current.type == TOY_TOKEN_ERROR) {
error(parser, parser->current, "Toy_Lexer error");
@@ -1350,13 +1350,36 @@ static void forStmt(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
//read the clauses
consume(parser, TOY_TOKEN_PAREN_LEFT, "Expected '(' at beginning of for clause");
declaration(parser, &preClause); //allow defining variables in the pre-clause
//check the pre-clause
if (parser->current.type != TOY_TOKEN_SEMICOLON) {
declaration(parser, &preClause); //allow defining variables in the pre-clause
}
else {
consume(parser, TOY_TOKEN_SEMICOLON, "Expected ';' after empty declaration of for clause");
Toy_emitASTNodePass(&preClause);
}
parsePrecedence(parser, &condition, PREC_TERNARY);
consume(parser, TOY_TOKEN_SEMICOLON, "Expected ';' after condition of for clause");
//check the condition clause
if (parser->current.type != TOY_TOKEN_SEMICOLON) {
parsePrecedence(parser, &condition, PREC_TERNARY);
consume(parser, TOY_TOKEN_SEMICOLON, "Expected ';' after condition of for clause");
}
else {
consume(parser, TOY_TOKEN_SEMICOLON, "Expected ';' after empty condition of for clause");
//empty clause defaults to forever
Toy_Literal f = TOY_TO_BOOLEAN_LITERAL(true);
Toy_emitASTNodeLiteral(&condition, f);
}
parsePrecedence(parser, &postClause, PREC_ASSIGNMENT);
consume(parser, TOY_TOKEN_PAREN_RIGHT, "Expected ')' at end of for clause");
//check the postfix clause
if (parser->current.type != TOY_TOKEN_PAREN_RIGHT) {
parsePrecedence(parser, &postClause, PREC_ASSIGNMENT);
consume(parser, TOY_TOKEN_PAREN_RIGHT, "Expected ')' at end of for clause");
}
else {
consume(parser, TOY_TOKEN_PAREN_RIGHT, "Expected ')' after empty increment of for clause");
Toy_emitASTNodePass(&postClause);
}
//read the path
declaration(parser, &thenPath);
-2
View File
@@ -1,7 +1,5 @@
#include "toy_refstring.h"
#include <string.h>
//memory allocation
extern void* Toy_private_defaultMemoryAllocator(void* pointer, size_t oldSize, size_t newSize);
static Toy_RefStringAllocatorFn allocate = Toy_private_defaultMemoryAllocator;
+17 -13
View File
@@ -1,11 +1,12 @@
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include "toy_common.h"
#include <string.h>
//memory allocation hook
typedef void* (*Toy_RefStringAllocatorFn)(void* pointer, size_t oldSize, size_t newSize);
void Toy_setRefStringAllocatorFn(Toy_RefStringAllocatorFn);
TOY_API void Toy_setRefStringAllocatorFn(Toy_RefStringAllocatorFn);
//the RefString structure
typedef struct Toy_RefString {
@@ -15,13 +16,16 @@ typedef struct Toy_RefString {
} Toy_RefString;
//API
Toy_RefString* Toy_createRefString(const char* cstring);
Toy_RefString* Toy_createRefStringLength(const char* cstring, size_t length);
void Toy_deleteRefString(Toy_RefString* refString);
int Toy_countRefString(Toy_RefString* refString);
size_t Toy_lengthRefString(Toy_RefString* refString);
Toy_RefString* Toy_copyRefString(Toy_RefString* refString);
Toy_RefString* Toy_deepCopyRefString(Toy_RefString* refString);
const char* Toy_toCString(Toy_RefString* refString);
bool Toy_equalsRefString(Toy_RefString* lhs, Toy_RefString* rhs);
bool Toy_equalsRefStringCString(Toy_RefString* lhs, char* cstring);
TOY_API Toy_RefString* Toy_createRefString(const char* cstring);
TOY_API Toy_RefString* Toy_createRefStringLength(const char* cstring, size_t length);
TOY_API void Toy_deleteRefString(Toy_RefString* refString);
TOY_API int Toy_countRefString(Toy_RefString* refString);
TOY_API size_t Toy_lengthRefString(Toy_RefString* refString);
TOY_API Toy_RefString* Toy_copyRefString(Toy_RefString* refString);
TOY_API Toy_RefString* Toy_deepCopyRefString(Toy_RefString* refString);
TOY_API const char* Toy_toCString(Toy_RefString* refString);
TOY_API bool Toy_equalsRefString(Toy_RefString* lhs, Toy_RefString* rhs);
TOY_API bool Toy_equalsRefStringCString(Toy_RefString* lhs, char* cstring);
//TODO: merge refstring memory
+7 -3
View File
@@ -126,7 +126,7 @@ static bool checkType(Toy_Literal typeLiteral, Toy_Literal original, Toy_Literal
}
//find the internal child of original that matches this child of value
Toy_private_entry* ptr = NULL;
Toy_private_dictionary_entry* ptr = NULL;
for (int j = 0; j < TOY_AS_DICTIONARY(original)->capacity; j++) {
if (Toy_literalsAreEqual(TOY_AS_DICTIONARY(original)->entries[j].key, TOY_AS_DICTIONARY(value)->entries[i].key)) {
@@ -159,6 +159,10 @@ static bool checkType(Toy_Literal typeLiteral, Toy_Literal original, Toy_Literal
return false;
}
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_OPAQUE && !TOY_IS_OPAQUE(value)) {
return false;
}
return true;
}
@@ -185,7 +189,7 @@ Toy_Scope* Toy_popScope(Toy_Scope* scope) {
Toy_Scope* ret = scope->ancestor;
//BUGFIX: when freeing a scope, free the function's scopes manually
//BUGFIX: when freeing a scope, free the functions' scopes manually - I *think* this is related to the closure hack-in
for (int i = 0; i < scope->variables.capacity; i++) {
//handle keys, just in case
if (TOY_IS_FUNCTION(scope->variables.entries[i].key)) {
@@ -286,7 +290,7 @@ bool Toy_setScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal value,
}
//actually assign
Toy_setLiteralDictionary(&scope->variables, key, value);
Toy_setLiteralDictionary(&scope->variables, key, value); //key & value are copied here
Toy_freeLiteral(typeLiteral);
Toy_freeLiteral(original);
+9 -8
View File
@@ -1,5 +1,6 @@
#pragma once
#include "toy_literal.h"
#include "toy_literal_array.h"
#include "toy_literal_dictionary.h"
@@ -10,16 +11,16 @@ typedef struct Toy_Scope {
int references; //how many scopes point here
} Toy_Scope;
Toy_Scope* Toy_pushScope(Toy_Scope* scope);
Toy_Scope* Toy_popScope(Toy_Scope* scope);
Toy_Scope* Toy_copyScope(Toy_Scope* original);
TOY_API Toy_Scope* Toy_pushScope(Toy_Scope* scope);
TOY_API Toy_Scope* Toy_popScope(Toy_Scope* scope);
TOY_API Toy_Scope* Toy_copyScope(Toy_Scope* original);
//returns false if error
bool Toy_declareScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal type);
bool Toy_isDelcaredScopeVariable(Toy_Scope* scope, Toy_Literal key);
TOY_API bool Toy_declareScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal type);
TOY_API bool Toy_isDelcaredScopeVariable(Toy_Scope* scope, Toy_Literal key);
//return false if undefined
bool Toy_setScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal value, bool constCheck);
bool Toy_getScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal* value);
TOY_API bool Toy_setScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal value, bool constCheck);
TOY_API bool Toy_getScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal* value);
Toy_Literal Toy_getScopeType(Toy_Scope* scope, Toy_Literal key);
TOY_API Toy_Literal Toy_getScopeType(Toy_Scope* scope, Toy_Literal key);
+17 -17
View File
@@ -2,11 +2,11 @@
var a = [1, 2, 3];
var b = [4, 5, 6];
assert _length(a) == _length(b), "a and b lengths are wrong";
assert length(a) == length(b), "a and b lengths are wrong";
var acc = 0;
for (var i = 0; i < _length(a); i++) {
acc += _get(a, i) * _get(b, i);
for (var i = 0; i < length(a); i++) {
acc += get(a, i) * get(b, i);
}
assert acc == 32, "dot product failed";
@@ -15,38 +15,38 @@ assert acc == 32, "dot product failed";
//assume the args are matrices
fn matrix(first, second) {
//get the matrix size
var l1 = _length(first); //rows
var l2 = _length(_get(first, 0)); //cols
var l1 = length(first); //rows
var l2 = length(get(first, 0)); //cols
var l3 = _length(second); //rows
var l4 = _length(_get(second, 0)); //cols
var l3 = length(second); //rows
var l4 = length(get(second, 0)); //cols
//pre-allocate the matrix
var row = [];
for (var j = 0; j < l4; j++) {
_push(row, 0);
push(row, 0);
}
var result = [];
for (var i = 0; i < l1; i++) {
_push(result, row);
push(result, row);
}
//assign the values
for (var i = 0; i < _length(first); i++) {
for (var i = 0; i < length(first); i++) {
//select each element of "first"
var firstElement = _get(first, i);
var firstElement = get(first, i);
//for each element of second
for (var i2 = 0; i2 < _length(second); i2++) {
for (var j2 = 0; j2 < _length(_get(second, 0)); j2++) {
for (var i2 = 0; i2 < length(second); i2++) {
for (var j2 = 0; j2 < length(get(second, 0)); j2++) {
var val = _get(_get(first, i), i2) * _get(_get(second, i2), j2);
var val = get(get(first, i), i2) * get(get(second, i2), j2);
//TODO: needs better notation than this tmpRow variable
var tmpRow = _get(result, i);
_set(tmpRow, j2, val);
_set(result, i, tmpRow);
var tmpRow = get(result, i);
set(tmpRow, j2, val);
set(result, i, tmpRow);
//result[ i ][ j2 ] += first[i][i2] * second[i2][j2]
}
+1 -1
View File
@@ -9,7 +9,7 @@ It appears to be a compiler issue, see issue #38 for more info.
*/
fn _getValue(self) {
fn getValue(self) {
return self;
}
+3 -3
View File
@@ -1,10 +1,10 @@
//test function chaining with the dot operator
fn _identity(self) {
fn identity(self) {
return self;
}
fn _check(self) {
fn check(self) {
assert self == 42, "dot chaining failed";
return self;
}
@@ -20,7 +20,7 @@ val
//test the value is actually altered
fn _increment(self) {
fn increment(self) {
return self + 1;
}
+1 -1
View File
@@ -1,5 +1,5 @@
fn _add(self, inc) {
fn add(self, inc) {
return self + inc;
}
+1 -1
View File
@@ -63,7 +63,7 @@ extra("one", "two", "three", "four", "five", "six", "seven");
//test underscore functions
fn _example(self, a, b, c) {
fn example(self, a, b, c) {
assert a == "a", "underscore failed (a)";
assert b == "b", "underscore failed (b)";
assert c == "c", "underscore failed (c)";
@@ -0,0 +1,15 @@
/*
This ensures that when indexing on both sides of an assignment,
it works correctly.
*/
var a = [1, 2, 3];
var b = [4, 5, 6];
a[1] = b[1];
assert a == [1, 5, 3], "index assignment both failed";
print "All good";
@@ -0,0 +1,19 @@
/*
Compiler note:
This is also to test a specific element in the compiler.
It ensures that when doing indexing and assignment in one statement,
the index is NOT on the right. If it is, then it is treated like a normal
assignment.
*/
//polyfill the _insert function
var a = [1, 2, 3];
var b = a[1];
assert b == 2, "index assignment left failed";
print "All good";
-280
View File
@@ -1,280 +0,0 @@
import compound;
//test concat
{
//test array concat
{
var a = [1, 2, 3];
var b = [4, 5, 6];
var c = a.concat(b).concat(b);
assert c == [1, 2, 3, 4, 5, 6, 4, 5, 6], "array.concat() failed";
}
//test dictionary concat
{
var a = ["one" : 1, "two": 2, "three": 3];
var b = ["four" : 4, "five": 5, "six": 6];
var c = a.concat(b);
assert c.length() == 6, "dictionary.concat().length() failed";
assert c == ["one" : 1, "two": 2, "three": 3, "four" : 4, "five": 5, "six": 6], "dictionary.concat() comparison failed";
}
//test dictionary concat with clashing keys
{
var a = ["one" : 1, "two": 2, "three": 3, "random": 1];
var b = ["four" : 4, "five": 5, "six": 6, "random": 2];
var c = a.concat(b);
assert c["random"] == 1, "dictionary.concat() clashing keys failed";
}
//test string concat
{
var a = "foo";
var b = "bar";
var c = a.concat(b);
assert c == "foobar", "string.concat() failed";
}
}
//test containsKey
{
var d = ["one": 1, "two": 2];
assert d.containsKey("one") == true, "dictionary.containsKey() == true failed";
assert d.containsKey("three") == false, "dictionary.containsKey() == false failed";
}
//test containsValue
{
var a = [1, 2, 3];
var d = ["one": 1, "two": 2];
assert a.containsValue(1) == true, "array.containsValue() == true failed";
assert a.containsValue(5) == false, "array.containsValue() == false failed";
assert d.containsValue(1) == true, "dictionary.containsValue() == true failed";
assert d.containsValue(3) == false, "dictionary.containsValue() == false failed";
}
//test every
{
var a = [1, 2, 3];
var d = ["one": 1, "two": 2];
var counter = 0;
fn f(k, v) {
counter++;
return v;
}
assert a.every(f) == true, "array.every() == true failed";
assert d.every(f) == true, "dictionary.every() == true failed";
assert counter == 5, "Unexpected number of calls for _every() == true";
counter = 0;
a[1] = false;
d["two"] = false;
assert a.every(f) == false, "array.every() == false failed";
assert d.every(f) == false, "dictionary.every() == false failed";
assert counter == 4, "Unexpected number of calls for _every() == false";
}
//test filter
{
var a = [1, 2, 3, 4];
var d = ["one": 1, "two": 2, "three": 3, "four": 4];
fn f(k, v) {
return v % 2 == 0;
}
assert a.filter(f) == [2, 4], "array.filter() failed";
assert d.filter(f) == ["two": 2, "four": 4], "dictionary.filter() failed";
}
//test forEach
{
var counter = 0;
fn p(k, v) {
counter++;
print string k + ": " + string v;
}
var a = ["a", "b"];
var d = ["foo": 1, "bar": 2, "bazz": 3, "fizz": 4];
a.forEach(p);
assert counter == 2, "forEach ran an unusual number of times";
counter = 0;
d.forEach(p);
assert counter == 4, "forEach ran an unusual number of times";
}
//test getKeys
{
var d = ["foo": 1, "bar": 2];
var a = d.getKeys();
assert a.length() == 2, "_getKeys() length failed";
//NOTE: dependant on hash algorithm
assert a == ["bar", "foo"], "_getKeys() result failed";
}
//test getValues
{
var d = ["foo": 1, "bar": 2];
var a = d.getValues();
assert a.length() == 2, "_getValues() length failed";
//NOTE: dependant on hash algorithm
assert a == [2, 1], "_getValues() result failed";
}
//test map
{
//test map with toy functions
{
fn increment(k, v) {
return v + 1;
}
var a = [1, 2, 3];
var d = ["four": 4, "five": 5, "six": 6];
assert a.map(increment).map(increment).map(increment) == [4,5,6], "array.map() failed";
assert d.map(increment).map(increment).map(increment) == [8,9,7], "dictionary.map() failed";
}
//test map with native functions
{
//TODO: write some native functions for use with map
}
}
//test reduce
{
var a = [1, 2, 3, 4];
var d = ["one": 1, "two": 2, "three": 3, "four": 4];
fn f(acc, k, v) {
return acc + v;
}
assert a.reduce(0, f) == 10, "array.reduce() failed";
assert d.reduce(0, f) == 10, "dictionary.reduce() failed";
}
//test some
{
var a = [false, false, false];
var d = ["one": false, "two": false];
var counter = 0;
fn f(k, v) {
counter++;
return v;
}
assert a.some(f) == false, "array.some() == false failed";
assert d.some(f) == false, "dictionary.some() == false failed";
assert counter == 5, "Unexpected number of calls for _some() == false";
counter = 0;
a[1] = true;
d["two"] = true;
assert a.some(f) == true, "array.some() == true failed";
assert d.some(f) == true, "dictionary.some() == true failed";
assert counter == 4, "Unexpected number of calls for _some() == true";
}
//test toLower
{
assert "Hello World".toLower() == "hello world", "_toLower() failed";
}
//test toString
{
var a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
var s = a.toString();
assert s == "[[1,2,3],[4,5,6],[7,8,9]]", "array._toString() failed";
}
//test toUpper
{
assert "Hello World".toUpper() == "HELLO WORLD", "_toUpper() failed";
}
//test trim defaults
{
{
//test a bunch
fn test(s, pass) {
var result = s.trim();
assert result == pass, "_trim(" + result + ") failed";
}
test("hello world", "hello world");
test(" hello world", "hello world");
test("hello world ", "hello world");
test(" hello world ", "hello world");
test(" hello world", "hello world");
test("hello world ", "hello world");
test(" hello world ", "hello world");
test(" hello world", "hello world");
test("hello world ", "hello world");
test(" hello world ", "hello world");
//one for goot luck
assert " hello world ".trim() == "hello world", "hello world.trim() failed";
}
//test trim custom values
{
var chars = "heliod";
assert "hello world".trim(chars) == " wor", "custom _trim() failed";
}
//test trimBegin() & trimEnd()
assert " foo ".trimBegin() == "foo ", "string.trimBegin() failed";
assert " foo ".trimEnd() == " foo", "string.trimBegin() failed";
}
print "All good";
-40
View File
@@ -1,40 +0,0 @@
//test this logic for memory leaks
{
import compound;
import timer;
fn start(k, v) {
return startTimer();
}
fn check(k, v) {
var l = v.stopTimer();
print l.timerToString();
l.destroyTimer();
return v;
}
fn destroy(k, v) {
v.destroyTimer();
}
var arr = [1];
arr
.map(start)
.map(check)
.map(check)
.map(check)
.map(check)
.map(check)
.map(check)
.map(check)
.map(check)
.map(check)
.map(check)
.map(destroy)
;
}
print "All good";
Binary file not shown.
+318 -4
View File
@@ -1,9 +1,323 @@
//test the standard library
{
import standard;
import standard;
//test clock
{
//this depends on external factors, so only check the length
assert clock().length() == 24, "clock() import failed";
assert clock().length() == 24, "clock().length() failed";
}
//test concat
{
//test array concat
{
var a = [1, 2, 3];
var b = [4, 5, 6];
var c = a.concat(b).concat(b);
assert c == [1, 2, 3, 4, 5, 6, 4, 5, 6], "array.concat() failed";
}
//test dictionary concat
{
var a = ["one" : 1, "two": 2, "three": 3];
var b = ["four" : 4, "five": 5, "six": 6];
var c = a.concat(b);
assert c.length() == 6, "dictionary.concat().length() failed";
assert c == ["one" : 1, "two": 2, "three": 3, "four" : 4, "five": 5, "six": 6], "dictionary.concat() comparison failed";
}
//test dictionary concat with clashing keys
{
var a = ["one" : 1, "two": 2, "three": 3, "random": 1];
var b = ["four" : 4, "five": 5, "six": 6, "random": 2];
var c = a.concat(b);
assert c["random"] == 1, "dictionary.concat() clashing keys failed";
}
//test string concat
{
var a = "foo";
var b = "bar";
var c = a.concat(b);
assert c == "foobar", "string.concat() failed";
}
}
//test containsKey
{
var d = ["one": 1, "two": 2];
assert d.containsKey("one") == true, "dictionary.containsKey() == true failed";
assert d.containsKey("three") == false, "dictionary.containsKey() == false failed";
}
//test containsValue
{
var a = [1, 2, 3];
var d = ["one": 1, "two": 2];
assert a.containsValue(1) == true, "array.containsValue() == true failed";
assert a.containsValue(5) == false, "array.containsValue() == false failed";
assert d.containsValue(1) == true, "dictionary.containsValue() == true failed";
assert d.containsValue(3) == false, "dictionary.containsValue() == false failed";
}
//test every
{
var a = [1, 2, 3];
var d = ["one": 1, "two": 2];
var counter = 0;
fn f(k, v) {
counter++;
return v;
}
assert a.every(f) == true, "array.every() == true failed";
assert d.every(f) == true, "dictionary.every() == true failed";
assert counter == 5, "Unexpected number of calls for _every() == true";
counter = 0;
a[1] = false;
d["two"] = false;
assert a.every(f) == false, "array.every() == false failed";
assert d.every(f) == false, "dictionary.every() == false failed";
assert counter == 4, "Unexpected number of calls for _every() == false";
}
//test filter
{
var a = [1, 2, 3, 4];
var d = ["one": 1, "two": 2, "three": 3, "four": 4];
fn f(k, v) {
return v % 2 == 0;
}
assert a.filter(f) == [2, 4], "array.filter() failed";
assert d.filter(f) == ["two": 2, "four": 4], "dictionary.filter() failed";
}
//test forEach
{
var counter = 0;
fn p(k, v) {
counter++;
print string k + ": " + string v;
}
var a = ["a", "b"];
var d = ["foo": 1, "bar": 2, "bazz": 3, "fizz": 4];
a.forEach(p);
assert counter == 2, "forEach ran an unusual number of times";
counter = 0;
d.forEach(p);
assert counter == 4, "forEach ran an unusual number of times";
}
//test getKeys
{
var d = ["foo": 1, "bar": 2];
var a = d.getKeys();
assert a.length() == 2, "_getKeys() length failed";
//NOTE: dependant on hash algorithm
assert a == ["bar", "foo"], "_getKeys() result failed";
}
//test getValues
{
var d = ["foo": 1, "bar": 2];
var a = d.getValues();
assert a.length() == 2, "_getValues() length failed";
//NOTE: dependant on hash algorithm
assert a == [2, 1], "_getValues() result failed";
}
//test indexOf
{
var a = [1, 2, 42, 3];
//results are zero-indexed
assert a.indexOf(42) == 2, "_indexOf() failed";
assert a.indexOf(4) == null, "_indexOf() == null failed";
}
//test map
{
//test map with toy functions
{
fn increment(k, v) {
return v + 1;
}
var a = [1, 2, 3];
var d = ["four": 4, "five": 5, "six": 6];
assert a.map(increment).map(increment).map(increment) == [4,5,6], "array.map() failed";
assert d.map(increment).map(increment).map(increment) == [8,9,7], "dictionary.map() failed";
}
//test map with native functions
{
//TODO: write some native functions for use with map
}
}
//test reduce
{
var a = [1, 2, 3, 4];
var d = ["one": 1, "two": 2, "three": 3, "four": 4];
fn f(acc, k, v) {
return acc + v;
}
assert a.reduce(0, f) == 10, "array.reduce() failed";
assert d.reduce(0, f) == 10, "dictionary.reduce() failed";
}
//test some
{
var a = [false, false, false];
var d = ["one": false, "two": false];
var counter = 0;
fn f(k, v) {
counter++;
return v;
}
assert a.some(f) == false, "array.some() == false failed";
assert d.some(f) == false, "dictionary.some() == false failed";
assert counter == 5, "Unexpected number of calls for _some() == false";
counter = 0;
a[1] = true;
d["two"] = true;
assert a.some(f) == true, "array.some() == true failed";
assert d.some(f) == true, "dictionary.some() == true failed";
assert counter == 4, "Unexpected number of calls for _some() == true";
}
//test sort
{
fn less(a, b) {
return a < b;
}
fn greater(a, b) {
return a > b;
}
var a = [7, 2, 1, 8, 6, 3, 5, 4];
var b = [7, 2, 1, 4, 6, 3, 5, 8];
var c = [1, 2, 3, 4, 5, 6, 7, 8];
var d = [7, 2, 1, 8, 6, 3, 5, 4];
a = a.sort(less);
b = b.sort(less);
c = c.sort(less);
d = d.sort(greater);
assert a == [1, 2, 3, 4, 5, 6, 7, 8], "array.sort(less) failed";
assert b == [1, 2, 3, 4, 5, 6, 7, 8], "array.sort(less) with pivot high failed";
assert c == [1, 2, 3, 4, 5, 6, 7, 8], "array.sort(less) pre-sorted array failed";
assert d == [8, 7, 6, 5, 4, 3, 2, 1], "array.sort(greater) failed";
}
//test toLower
{
assert "Hello World".toLower() == "hello world", "_toLower() failed";
}
//test toString
{
var a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
var s = a.toString();
assert s == "[[1,2,3],[4,5,6],[7,8,9]]", "array._toString() failed";
}
//test toUpper
{
assert "Hello World".toUpper() == "HELLO WORLD", "_toUpper() failed";
}
//test trim defaults
{
{
//test a bunch
fn test(s, pass) {
var result = s.trim();
assert result == pass, "_trim(" + result + ") failed";
}
test("hello world", "hello world");
test(" hello world", "hello world");
test("hello world ", "hello world");
test(" hello world ", "hello world");
test(" hello world", "hello world");
test("hello world ", "hello world");
test(" hello world ", "hello world");
test(" hello world", "hello world");
test("hello world ", "hello world");
test(" hello world ", "hello world");
//one for goot luck
assert " hello world ".trim() == "hello world", "hello world.trim() failed";
}
//test trim custom values
{
var chars = "heliod";
assert "hello world".trim(chars) == " wor", "custom _trim() failed";
}
//test trimBegin() & trimEnd()
assert " foo ".trimBegin() == "foo ", "string.trimBegin() failed";
assert " foo ".trimEnd() == " foo", "string.trimBegin() failed";
}
+39 -39
View File
@@ -3,41 +3,41 @@
//test arrays without types
var array = [];
assert _length(array) == 0, "_length failed with array";
assert length(array) == 0, "length failed with array";
_push(array, 1);
_push(array, 2);
_push(array, 3);
_push(array, 4);
_push(array, "foo");
push(array, 1);
push(array, 2);
push(array, 3);
push(array, 4);
push(array, "foo");
assert _length(array) == 5, "_push failed with array";
assert _pop(array) == "foo", "_pop failed with array";
assert length(array) == 5, "push failed with array";
assert pop(array) == "foo", "pop failed with array";
_set(array, 2, "bar");
assert array == [1, 2, "bar", 4], "_set failed with array";
assert _get(array, 3) == 4, "_get failed with array";
set(array, 2, "bar");
assert array == [1, 2, "bar", 4], "set failed with array";
assert get(array, 3) == 4, "get failed with array";
//test dictionaries without types
var dict = [:];
_set(dict, "key", "value");
_set(dict, 1, 2);
set(dict, "key", "value");
set(dict, 1, 2);
assert dict == ["key":"value", 1:2], "_set failed with dictionaries";
assert _get(dict, "key") == "value", "_get failed with dictionaries";
assert dict == ["key":"value", 1:2], "set failed with dictionaries";
assert get(dict, "key") == "value", "get failed with dictionaries";
//test _length
assert _length(array) == 4 && _length(dict) == 2, "_length failed with array or dictionaries";
//test length
assert length(array) == 4 && length(dict) == 2, "length failed with array or dictionaries";
//test clear
_clear(array);
_clear(dict);
clear(array);
clear(dict);
assert _length(array) == 0 && _length(dict) == 0, "_clear failed with array or dictionaries";
assert length(array) == 0 && length(dict) == 0, "clear failed with array or dictionaries";
}
@@ -45,46 +45,46 @@
//test arrays with types
var array: [int] = [];
assert _length(array) == 0, "_length failed with array (+ types)";
assert length(array) == 0, "length failed with array (+ types)";
_push(array, 1);
_push(array, 2);
_push(array, 3);
_push(array, 4);
_push(array, 10);
push(array, 1);
push(array, 2);
push(array, 3);
push(array, 4);
push(array, 10);
assert _length(array) == 5, "_push or failed with array (+ types)";
assert _pop(array) == 10, "_pop failed with array (+ types)";
assert length(array) == 5, "push or failed with array (+ types)";
assert pop(array) == 10, "pop failed with array (+ types)";
_set(array, 2, 70);
assert array == [1, 2, 70, 4], "_set failed with array (+ types)";
assert _get(array, 3) == 4, "_get failed with array (+ types)";
set(array, 2, 70);
assert array == [1, 2, 70, 4], "set failed with array (+ types)";
assert get(array, 3) == 4, "get failed with array (+ types)";
//test dictionaries with types
var dict: [string : string] = [:];
_set(dict, "key", "value");
set(dict, "key", "value");
assert dict == ["key":"value"], "_set failed with dictionaries (+ types)";
assert _get(dict, "key") == "value", "_get failed with dictionaries (+ types)";
assert dict == ["key":"value"], "set failed with dictionaries (+ types)";
assert get(dict, "key") == "value", "get failed with dictionaries (+ types)";
//test length with types
assert _length(array) == 4 && _length(dict) == 1, "_length failed with array or dictionaries (+ types)";
assert length(array) == 4 && length(dict) == 1, "length failed with array or dictionaries (+ types)";
//test clear with types
_clear(array);
_clear(dict);
clear(array);
clear(dict);
assert _length(array) == 0 && _length(dict) == 0, "_clear failed with array or dictionaries (+ types)";
assert length(array) == 0 && length(dict) == 0, "clear failed with array or dictionaries (+ types)";
}
{
var str = "hello world";
assert _length(str) == 11, "_length failed with string";
assert length(str) == 11, "length failed with string";
}
+22
View File
@@ -0,0 +1,22 @@
//polyfill the insert function
fn insert(self, k, v) {
var tmp1 = v;
var tmp2;
for (var i = k; i < self.length(); i++) {
tmp2 = self[i];
self[i] = tmp1;
tmp1 = tmp2;
}
self.push(tmp1);
return self;
}
var a = [1, 2, 3];
a = a.insert(1, 42);
assert a == [1, 42, 2, 3], "polyfill insert failed";
print "All good";
+23
View File
@@ -0,0 +1,23 @@
//polyfill the remove function
fn remove(self, k) {
var result = [];
for (var i = 0; i <= k - 1; i++) {
result.push( self[i] );
}
for (var i = k + 1; i < self.length(); i++) {
result.push( self[i] );
}
return result;
}
var a = [1, 2, 3];
assert a.remove(0) == [2, 3], "polyfill remove(start) failed";
assert a.remove(1) == [1, 3], "polyfill remove(middle) failed";
assert a.remove(2) == [1, 2], "polyfill remove(end) failed";
print "All good";
+15 -6
View File
@@ -1,12 +1,21 @@
fn fib(n : int) {
if (n < 2) {
return n;
}
//memoize the fib function
var memo: [int : int] = [:];
return fib(n-1) + fib(n-2);
fn fib(n : int) {
if (n < 2) {
return n;
}
var result = memo[n];
if (result == null) {
result = fib(n-1) + fib(n-2);
memo[n] = result;
}
return result;
}
for (var i = 0; i < 20; i++) {
for (var i = 0; i < 40; i++) {
var res = fib(i);
print string i + ": " + string res;
}
+26 -26
View File
@@ -20,14 +20,14 @@ static void noPrintFn(const char* output) {
}
void error(char* msg) {
printf("%s", msg);
printf("%s\n", msg);
exit(-1);
}
int main() {
{
size_t size = 0;
const char* source = Toy_readFile("scripts/call-from-host.toy", &size);
const char* source = (const char*)Toy_readFile("scripts/call-from-host.toy", &size);
const unsigned char* tb = Toy_compileString(source, &size);
free((void*)source);
@@ -41,7 +41,7 @@ int main() {
//test answer
{
interpreter.printOutput("Testing answer\n");
interpreter.printOutput("Testing answer");
Toy_LiteralArray arguments;
Toy_initLiteralArray(&arguments);
@@ -52,15 +52,15 @@ int main() {
//check the results
if (arguments.count != 0) {
error("Arguments has the wrong number of members\n");
error("Arguments has the wrong number of members");
}
if (returns.count != 1) {
error("Returns has the wrong number of members\n");
error("Returns has the wrong number of members");
}
if (!TOY_IS_INTEGER(returns.literals[0]) || TOY_AS_INTEGER(returns.literals[0]) != 42) {
error("Returned value is incorrect\n");
error("Returned value is incorrect");
}
Toy_freeLiteralArray(&arguments);
@@ -69,7 +69,7 @@ int main() {
//test identity
{
interpreter.printOutput("Testing identity\n");
interpreter.printOutput("Testing identity");
Toy_LiteralArray arguments;
Toy_initLiteralArray(&arguments);
@@ -85,17 +85,17 @@ int main() {
//check the results
if (arguments.count != 0) {
error("Arguments has the wrong number of members\n");
error("Arguments has the wrong number of members");
}
if (returns.count != 1) {
error("Returns has the wrong number of members\n");
error("Returns has the wrong number of members");
}
float epsilon = 0.1; //because floats are evil
if (!TOY_IS_FLOAT(returns.literals[0]) || fabs(TOY_AS_FLOAT(returns.literals[0]) - pi) > epsilon) {
error("Returned value is incorrect\n");
error("Returned value is incorrect");
}
Toy_freeLiteralArray(&arguments);
@@ -104,7 +104,7 @@ int main() {
//test makeCounter (closures)
{
interpreter.printOutput("Testing makeCounter (closures)\n");
interpreter.printOutput("Testing makeCounter (closures)");
Toy_LiteralArray arguments;
Toy_initLiteralArray(&arguments);
@@ -115,11 +115,11 @@ int main() {
//check the results
if (arguments.count != 0) {
error("Arguments has the wrong number of members\n");
error("Arguments has the wrong number of members");
}
if (returns.count != 1) {
error("Returns has the wrong number of members\n");
error("Returns has the wrong number of members");
}
//grab the resulting literal
@@ -139,15 +139,15 @@ int main() {
//check the results
if (arguments.count != 0) {
error("Arguments (1) has the wrong number of members\n");
error("Arguments (1) has the wrong number of members");
}
if (returns.count != 1) {
error("Returns (1) has the wrong number of members\n");
error("Returns (1) has the wrong number of members");
}
if (!TOY_IS_INTEGER(returns.literals[0]) || TOY_AS_INTEGER(returns.literals[0]) != 1) {
error("Returned value (1) is incorrect\n");
error("Returned value (1) is incorrect");
}
Toy_freeLiteralArray(&arguments);
@@ -164,15 +164,15 @@ int main() {
//check the results
if (arguments.count != 0) {
error("Arguments (2) has the wrong number of members\n");
error("Arguments (2) has the wrong number of members");
}
if (returns.count != 1) {
error("Returns (2) has the wrong number of members\n");
error("Returns (2) has the wrong number of members");
}
if (!TOY_IS_INTEGER(returns.literals[0]) || TOY_AS_INTEGER(returns.literals[0]) != 2) {
error("Returned value (2) is incorrect\n");
error("Returned value (2) is incorrect");
}
Toy_freeLiteralArray(&arguments);
@@ -189,15 +189,15 @@ int main() {
//check the results
if (arguments.count != 0) {
error("Arguments (3) has the wrong number of members\n");
error("Arguments (3) has the wrong number of members");
}
if (returns.count != 1) {
error("Returns (3) has the wrong number of members\n");
error("Returns (3) has the wrong number of members");
}
if (!TOY_IS_INTEGER(returns.literals[0]) || TOY_AS_INTEGER(returns.literals[0]) != 3) {
error("Returned value (3) is incorrect\n");
error("Returned value (3) is incorrect");
}
Toy_freeLiteralArray(&arguments);
@@ -209,7 +209,7 @@ int main() {
//test assertion failure
{
interpreter.printOutput("Testing assertion failure\n");
interpreter.printOutput("Testing assertion failure");
Toy_setInterpreterAssert(&interpreter, noPrintFn);
@@ -222,15 +222,15 @@ int main() {
//check the results
if (arguments.count != 0) {
error("Arguments has the wrong number of members\n");
error("Arguments has the wrong number of members");
}
if (returns.count != 1 || !TOY_IS_NULL(returns.literals[0])) {
error("Returns has the wrong number of members\n");
error("Returns has the wrong number of members");
}
if (!ret) {
error("Assertion gives the wrong return value\n");
error("Assertion gives the wrong return value");
}
Toy_freeLiteralArray(&arguments);
+3 -3
View File
@@ -39,7 +39,7 @@ int main() {
Toy_writeCompiler(&compiler, node);
//collate
int size = 0;
size_t size = 0;
unsigned char* bytecode = Toy_collateCompiler(&compiler, &size);
//cleanup
@@ -52,7 +52,7 @@ int main() {
{
//source
size_t sourceLength = 0;
const char* source = Toy_readFile("scripts/compiler_sample_code.toy", &sourceLength);
const char* source = (const char*)Toy_readFile("scripts/compiler_sample_code.toy", &sourceLength);
//test basic compilation & collation
Toy_Lexer lexer;
@@ -78,7 +78,7 @@ int main() {
}
//collate
int size = 0;
size_t size = 0;
unsigned char* bytecode = Toy_collateCompiler(&compiler, &size);
//cleanup
+6 -2
View File
@@ -53,7 +53,7 @@ void runSourceCustom(const char* source) {
void runSourceFileCustom(const char* fname) {
size_t size = 0; //not used
const char* source = Toy_readFile(fname, &size);
const char* source = (const char*)Toy_readFile(fname, &size);
runSourceCustom(source);
free((void*)source);
}
@@ -87,7 +87,7 @@ int main() {
Toy_writeCompiler(&compiler, node);
//collate
int size = 0;
size_t size = 0;
const unsigned char* bytecode = Toy_collateCompiler(&compiler, &size);
//NOTE: suppress print output for testing
@@ -117,6 +117,8 @@ int main() {
"dottify-bugfix.toy",
"functions.toy",
"index-arrays.toy",
"index-assignment-both-bugfix.toy",
"index-assignment-left-bugfix.toy",
"index-dictionaries.toy",
"index-strings.toy",
"jumps.toy",
@@ -128,6 +130,8 @@ int main() {
"native-functions.toy",
"or-chaining-bugfix.toy",
"panic-within-functions.toy",
"polyfill-insert.toy",
"polyfill-remove.toy",
"ternary-expressions.toy",
"types.toy",
NULL
+4 -4
View File
@@ -15,10 +15,10 @@ int main() {
Toy_initLexer(&lexer, source);
//get each token
Toy_Token print = Toy_scanLexer(&lexer);
Toy_Token null = Toy_scanLexer(&lexer);
Toy_Token semi = Toy_scanLexer(&lexer);
Toy_Token eof = Toy_scanLexer(&lexer);
Toy_Token print = Toy_private_scanLexer(&lexer);
Toy_Token null = Toy_private_scanLexer(&lexer);
Toy_Token semi = Toy_private_scanLexer(&lexer);
Toy_Token eof = Toy_private_scanLexer(&lexer);
//test each token is correct
if (strncmp(print.lexeme, "print", print.length)) {
+3 -9
View File
@@ -14,10 +14,8 @@
#include "../repl/repl_tools.h"
#include "../repl/lib_about.h"
#include "../repl/lib_compound.h"
#include "../repl/lib_runner.h"
#include "../repl/lib_standard.h"
#include "../repl/lib_timer.h"
//supress the print output
static void noPrintFn(const char* output) {
@@ -64,9 +62,7 @@ void runBinaryQuietly(const unsigned char* tb, size_t size) {
//inject the libs
Toy_injectNativeHook(&interpreter, "about", Toy_hookAbout);
Toy_injectNativeHook(&interpreter, "compound", Toy_hookCompound);
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
Toy_injectNativeHook(&interpreter, "timer", Toy_hookTimer);
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
Toy_runInterpreter(&interpreter, tb, size);
@@ -96,10 +92,8 @@ int main() {
Payload payloads[] = {
{"interactions.toy", "standard", Toy_hookStandard}, //interactions needs standard
{"about.toy", "about", Toy_hookAbout},
{"compound.toy", "compound", Toy_hookCompound},
{"runner.toy", "runner", Toy_hookRunner},
{"standard.toy", "standard", Toy_hookStandard},
{"timer.toy", "timer", Toy_hookTimer},
{"runner.toy", "runner", Toy_hookRunner},
{NULL, NULL, NULL}
};
@@ -111,7 +105,7 @@ int main() {
//compile the source
size_t size = 0;
const char* source = Toy_readFile(fname, &size);
const char* source = (const char*)Toy_readFile(fname, &size);
if (!source) {
printf(TOY_CC_ERROR "Failed to load file: %s\n" TOY_CC_RESET, fname);
failedAsserts++;
@@ -146,7 +140,7 @@ int main() {
//compile the source
size_t size = 0;
const char* source = Toy_readFile(fname, &size);
const char* source = (const char*)Toy_readFile(fname, &size);
if (!source) {
printf(TOY_CC_ERROR "Failed to load file: %s\n" TOY_CC_RESET, fname);
failedAsserts++;
+2 -2
View File
@@ -50,7 +50,7 @@ const unsigned char* compileStringCustom(const char* source, size_t* size) {
}
//get the bytecode dump
const unsigned char* tb = Toy_collateCompiler(&compiler, (int*)(size));
const unsigned char* tb = Toy_collateCompiler(&compiler, size);
//cleanup
Toy_freeCompiler(&compiler);
@@ -84,7 +84,7 @@ void runSourceCustom(const char* source) {
void runSourceFileCustom(const char* fname) {
size_t size = 0; //not used
const char* source = Toy_readFile(fname, &size);
const char* source = (const char*)Toy_readFile(fname, &size);
runSourceCustom(source);
free((void*)source);
}
+1 -1
View File
@@ -68,7 +68,7 @@ static int consume(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
int main() {
{
size_t size = 0;
const char* source = Toy_readFile("scripts/opaque-data-type.toy", &size);
const char* source = (const char*)Toy_readFile("scripts/opaque-data-type.toy", &size);
const unsigned char* tb = Toy_compileString(source, &size);
free((void*)source);
+1 -1
View File
@@ -58,7 +58,7 @@ int main() {
{
//get the source file
size_t size = 0;
const char* source = Toy_readFile("scripts/parser_sample_code.toy", &size);
const char* source = (const char*)Toy_readFile("scripts/parser_sample_code.toy", &size);
//test parsing a chunk of junk (valgrind will find leaks)
Toy_Lexer lexer;
+4 -1
View File
@@ -39,11 +39,14 @@ static void* trackerAllocator(void* pointer, size_t oldSize, size_t newSize) {
return mem;
}
int main(int argc, char* argv[]) {
int main(int argc, const char* argv[]) {
if (argc <= 1) {
return -1;
}
//not used, except for print
Toy_initCommandLine(argc, argv);
//setup for runner
Toy_initDriveDictionary();