Compare commits

..

48 Commits

Author SHA1 Message Date
Kayne Ruse d3df01c1c4 Updated .gitignore 2023-02-23 03:33:52 +11:00
Ratstail91 cdca6fa45c Fixed directory in solution file 2023-02-22 20:06:48 +11:00
Kayne Ruse 1dde9d8f29 Improved error message in set() and push()
The actual issue was that the type check wasn't catching the issue, so
it reached the scope before it was caught. Fixed it, anyway.
2023-02-20 13:04:35 +00:00
Kayne Ruse 7f0f17b6e0 Patched up failures from Toy_parseIdentifierToValue
I really don't like that function - it needs to be replaced.
2023-02-20 06:11:30 +00:00
Kayne Ruse 3507104121 Fixed indexAccess potentially going awry with bad inputs
There's always one or two that slip through
2023-02-20 05:28:25 +00:00
Kayne Ruse 87de634e30 Updated version number to 1.0.0 2023-02-20 02:08:42 +00:00
Kayne Ruse 6fa224fa7b Hooks can't be dict keys, tweaked Toy_readFile 2023-02-18 16:47:38 +00:00
Kayne Ruse 8a68d864e6 Opaque type check added 2023-02-18 15:21:49 +00:00
Kayne Ruse 49f240ea07 Minor tweak 2023-02-18 12:15:23 +00:00
Kayne Ruse 3acbd7447a Merge remote-tracking branch 'refs/remotes/origin/main' 2023-02-18 11:57:22 +00:00
Kayne Ruse 6f126e6daa Minor tweaks and renames, as I'm documenting 2023-02-18 11:56:18 +00:00
Kayne Ruse 2adb9d9158 Tweaked lib runner API 2023-02-16 22:04:47 +00:00
Kayne Ruse 1668dca255 Tweaked some APIs, hid some functions I don't want in the API 2023-02-16 13:06:07 +00:00
Kayne Ruse 501ff6fff4 Chased a ghost for a few hours 2023-02-14 18:55:24 +00:00
Kayne Ruse 3845627fe5 Added release build to MSVC 2023-02-14 18:03:04 +00:00
Kayne Ruse cdae03bd54 String and identifier making fixed for MSVC, just in case 2023-02-14 17:38:10 +00:00
Kayne Ruse 7b501b71b5 commandLine now initializes with default values 2023-02-14 17:00:16 +00:00
Kayne Ruse 913738a4d1 Tweaked the runner test, should be orders of magnitude faster 2023-02-14 16:16:48 +00:00
Kayne Ruse 3312a38c7c Updated memusage tool 2023-02-14 16:05:43 +00:00
Kayne Ruse 71b57fd42c Fixed scripts for distribution 2023-02-14 10:35:08 +00:00
Kayne Ruse 453afbab41 Fixed a stupid bug in MSVC 2023-02-14 10:24:43 +00:00
Kayne Ruse 57af5a6d59 Tweaked some scripts 2023-02-14 09:21:22 +00:00
Kayne Ruse 0737b2a483 Dropped underscore functions in favour of UFCS 2023-02-14 08:37:31 +00:00
Kayne Ruse eae96d6403 Corrected the order of arguments to Toy_callLiteralFn() 2023-02-14 08:00:35 +00:00
Kayne Ruse b55b8e879e Added -n option to diable print newline 2023-02-13 15:51:38 +00:00
Kayne Ruse 1ed114b80d Allow for stmt to have empty clauses, resolved #58 2023-02-13 14:45:24 +00:00
Kayne Ruse eb8e522bf2 Merged standard and timer, resolved #48 2023-02-13 13:58:41 +00:00
Kayne Ruse 16b71ba6f4 Implemented quicksort in _sort() 2023-02-13 13:31:58 +00:00
Kayne Ruse 9725f3c6a3 Patched some very obscure bugs 2023-02-12 16:54:44 +00:00
Kayne Ruse 8653a2663f Added _indexOf 2023-02-12 14:32:26 +00:00
Kayne Ruse ab2cd5dc93 Removed lib timer properly, see #62 2023-02-12 14:19:14 +00:00
Kayne Ruse 724804a78a Playing with level.toy 2023-02-11 15:27:23 +00:00
Kayne Ruse 77a128e0f7 Added the -t option to the repl 2023-02-11 14:51:19 +00:00
Kayne Ruse 5343e1054d Straightened out file extensions 2023-02-11 14:26:55 +00:00
Kayne Ruse 3930ec0477 Tweaked README.md 2023-02-11 06:48:16 +00:00
Kayne Ruse 996744d7ec Resolved #59 2023-02-11 05:10:32 +00:00
Kayne Ruse c00b32017b Dummied out lib timer 2023-02-11 01:42:44 +00:00
Kayne Ruse 457014d577 Added MSVC build support, likely broke tests 2023-02-11 00:49:21 +00:00
Kayne Ruse be4cbf1ad6 Pack 'em up! 2023-02-10 21:53:38 +00:00
Kayne Ruse aeb008c684 Fixed unary negation bug, removed newline from print 2023-02-10 18:38:25 +00:00
Kayne Ruse 53012dbce1 Added _filter() 2023-02-10 15:41:38 +00:00
Kayne Ruse 4fe57f9562 Added _containsKey() and _containsValue() 2023-02-10 15:27:39 +00:00
Kayne Ruse 3ba2e420ea Added _every() and _some() 2023-02-10 15:00:15 +00:00
Kayne Ruse c81a139c97 Now handles unterminated block comments without freezing 2023-02-10 12:26:38 +00:00
Kayne Ruse 66ea684a90 Disabled comments in the repl 2023-02-10 12:11:42 +00:00
Kayne Ruse a26a6a56d0 Patched a pre/postfix increment/decrement segfault 2023-02-10 11:49:59 +00:00
Kayne Ruse ee226ea426 Strengthened constness for cstrings and bytecode 2023-02-10 08:52:38 +00:00
Kayne Ruse 76a0290290 Removed export keyword from README.md 2023-02-09 17:46:28 +00:00
72 changed files with 3615 additions and 2261 deletions
+6 -3
View File
@@ -1,6 +1,4 @@
#Editor generated files #Editor generated files
*.sln
*.vcproj
*.suo *.suo
*.ncb *.ncb
*.user *.user
@@ -13,18 +11,23 @@ Out/
release/ release/
debug/ debug/
out/ out/
bin/
.cache/ .cache/
.vs/
#Project generated files #Project generated files
*.db *.db
*.o *.o
*.a *.a
*.so
*.dll
*.exe *.exe
*.meta *.meta
*.log *.log
out *.out
*.stackdump *.stackdump
*.tb *.tb
*.filters
#Shell files #Shell files
*.bat *.bat
+3 -4
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. 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 ## Tools
@@ -36,7 +38,6 @@ Run `make install-tools` to install a number of tools, including:
``` ```
import standard; //for a bunch of utility functions import standard; //for a bunch of utility functions
print "Hello world"; //"print" is a keyword print "Hello world"; //"print" is a keyword
var msg = "foobar"; //declare a variable like this var msg = "foobar"; //declare a variable like this
@@ -60,8 +61,6 @@ var tally = makeCounter();
print tally(); //1 print tally(); //1
print tally(); //2 print tally(); //2
print tally(); //3 print tally(); //3
export tally; //export this variable to the host program
``` ```
# License # License
+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>$(SolutionDir)/source;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard_C>stdc17</LanguageStandard_C>
<PreprocessorDefinitions>
</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<LanguageStandard_C>stdc17</LanguageStandard_C>
<PreprocessorDefinitions>
</PreprocessorDefinitions>
<AdditionalIncludeDirectories>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 builds
repl: $(TOY_OUTDIR) library repl: $(TOY_OUTDIR) library
$(MAKE) -C repl $(MAKE) -j8 -C repl
repl-static: $(TOY_OUTDIR) static repl-static: $(TOY_OUTDIR) static
$(MAKE) -C repl $(MAKE) -j8 -C repl
repl-release: clean $(TOY_OUTDIR) library-release repl-release: clean $(TOY_OUTDIR) library-release
$(MAKE) -C repl release $(MAKE) -C repl release
-1003
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);
+74 -32
View File
@@ -7,10 +7,11 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
typedef struct Toy_Runner { typedef struct Toy_Runner {
Toy_Interpreter interpreter; Toy_Interpreter interpreter;
unsigned char* bytecode; const unsigned char* bytecode;
size_t size; size_t size;
bool dirty; bool dirty;
@@ -32,6 +33,11 @@ static int nativeLoadScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu
Toy_freeLiteral(drivePathLiteralIdn); Toy_freeLiteral(drivePathLiteralIdn);
} }
if (TOY_IS_IDENTIFIER(drivePathLiteral)) {
Toy_freeLiteral(drivePathLiteral);
return -1;
}
Toy_Literal filePathLiteral = Toy_getFilePathLiteral(interpreter, &drivePathLiteral); Toy_Literal filePathLiteral = Toy_getFilePathLiteral(interpreter, &drivePathLiteral);
if (TOY_IS_NULL(filePathLiteral)) { if (TOY_IS_NULL(filePathLiteral)) {
@@ -43,12 +49,12 @@ static int nativeLoadScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu
Toy_freeLiteral(drivePathLiteral); Toy_freeLiteral(drivePathLiteral);
//use raw types - easier //use raw types - easier
char* filePath = Toy_toCString(TOY_AS_STRING(filePathLiteral)); 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 //load and compile the bytecode
size_t fileSize = 0; size_t fileSize = 0;
char* source = Toy_readFile(filePath, &fileSize); const char* source = (const char*)Toy_readFile(filePath, &fileSize);
if (!source) { if (!source) {
interpreter->errorOutput("Failed to load source file\n"); interpreter->errorOutput("Failed to load source file\n");
@@ -56,7 +62,7 @@ static int nativeLoadScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu
return -1; return -1;
} }
unsigned char* bytecode = Toy_compileString(source, &fileSize); const unsigned char* bytecode = Toy_compileString(source, &fileSize);
free((void*)source); free((void*)source);
if (!bytecode) { if (!bytecode) {
@@ -102,10 +108,15 @@ static int nativeLoadScriptBytecode(Toy_Interpreter* interpreter, Toy_LiteralArr
Toy_freeLiteral(drivePathLiteralIdn); Toy_freeLiteral(drivePathLiteralIdn);
} }
if (TOY_IS_IDENTIFIER(drivePathLiteral)) {
Toy_freeLiteral(drivePathLiteral);
return -1;
}
Toy_RefString* drivePath = Toy_copyRefString(TOY_AS_STRING(drivePathLiteral)); Toy_RefString* drivePath = Toy_copyRefString(TOY_AS_STRING(drivePathLiteral));
//get the drive and path as a string (can't trust that pesky strtok - custom split) TODO: move this to refstring library //get the drive and path as a string (can't trust that pesky strtok - custom split) TODO: move this to refstring library
int driveLength = 0; size_t driveLength = 0;
while (Toy_toCString(drivePath)[driveLength] != ':') { while (Toy_toCString(drivePath)[driveLength] != ':') {
if (driveLength >= Toy_lengthRefString(drivePath)) { if (driveLength >= Toy_lengthRefString(drivePath)) {
interpreter->errorOutput("Incorrect drive path format given to loadScriptBytecode\n"); interpreter->errorOutput("Incorrect drive path format given to loadScriptBytecode\n");
@@ -138,7 +149,7 @@ static int nativeLoadScriptBytecode(Toy_Interpreter* interpreter, Toy_LiteralArr
//get the final real file path (concat) TODO: move this concat to refstring library //get the final real file path (concat) TODO: move this concat to refstring library
Toy_RefString* realDrive = Toy_copyRefString(TOY_AS_STRING(realDriveLiteral)); 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 char* filePath = TOY_ALLOCATE(char, realLength + 1); //+1 for null
snprintf(filePath, realLength, "%s%s", Toy_toCString(realDrive), Toy_toCString(path)); snprintf(filePath, realLength, "%s%s", Toy_toCString(realDrive), Toy_toCString(path));
@@ -159,7 +170,7 @@ static int nativeLoadScriptBytecode(Toy_Interpreter* interpreter, Toy_LiteralArr
} }
//check for break-out attempts //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] == '.') { if (filePath[i] == '.' && filePath[i + 1] == '.') {
interpreter->errorOutput("Parent directory access not allowed\n"); interpreter->errorOutput("Parent directory access not allowed\n");
TOY_FREE_ARRAY(char, filePath, realLength); TOY_FREE_ARRAY(char, filePath, realLength);
@@ -200,7 +211,7 @@ static int nativeLoadScriptBytecode(Toy_Interpreter* interpreter, Toy_LiteralArr
static int nativeRunScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { static int nativeRunScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments //no arguments
if (arguments->count != 1) { if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _runScript\n"); interpreter->errorOutput("Incorrect number of arguments to runScript\n");
return -1; return -1;
} }
@@ -212,8 +223,13 @@ static int nativeRunScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argum
Toy_freeLiteral(runnerIdn); Toy_freeLiteral(runnerIdn);
} }
if (TOY_IS_IDENTIFIER(runnerLiteral)) {
Toy_freeLiteral(runnerLiteral);
return -1;
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) { 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; return -1;
} }
@@ -241,7 +257,7 @@ static int nativeRunScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argum
static int nativeGetScriptVar(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { static int nativeGetScriptVar(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments //no arguments
if (arguments->count != 2) { if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments to _getScriptVar\n"); interpreter->errorOutput("Incorrect number of arguments to getScriptVar\n");
return -1; return -1;
} }
@@ -259,8 +275,14 @@ static int nativeGetScriptVar(Toy_Interpreter* interpreter, Toy_LiteralArray* ar
Toy_freeLiteral(runnerIdn); Toy_freeLiteral(runnerIdn);
} }
if (TOY_IS_IDENTIFIER(varName) || TOY_IS_IDENTIFIER(runnerLiteral)) {
Toy_freeLiteral(varName);
Toy_freeLiteral(runnerLiteral);
return -1;
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) { 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; return -1;
} }
@@ -292,7 +314,7 @@ static int nativeGetScriptVar(Toy_Interpreter* interpreter, Toy_LiteralArray* ar
static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments //no arguments
if (arguments->count < 2) { if (arguments->count < 2) {
interpreter->errorOutput("Incorrect number of arguments to _callScriptFn\n"); interpreter->errorOutput("Incorrect number of arguments to callScriptFn\n");
return -1; return -1;
} }
@@ -309,7 +331,7 @@ static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* ar
Toy_LiteralArray rest; Toy_LiteralArray rest;
Toy_initLiteralArray(&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_Literal lit = Toy_popLiteralArray(&tmp);
Toy_pushLiteralArray(&rest, lit); Toy_pushLiteralArray(&rest, lit);
Toy_freeLiteral(lit); Toy_freeLiteral(lit);
@@ -317,7 +339,6 @@ static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* ar
Toy_freeLiteralArray(&tmp); Toy_freeLiteralArray(&tmp);
//get the runner object //get the runner object
Toy_Literal varName = Toy_popLiteralArray(arguments); Toy_Literal varName = Toy_popLiteralArray(arguments);
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments); Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
@@ -332,8 +353,14 @@ static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* ar
Toy_freeLiteral(runnerIdn); Toy_freeLiteral(runnerIdn);
} }
if (TOY_IS_IDENTIFIER(varName) || TOY_IS_IDENTIFIER(runnerLiteral)) {
Toy_freeLiteral(varName);
Toy_freeLiteral(runnerLiteral);
return -1;
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) { 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; return -1;
} }
@@ -389,7 +416,7 @@ static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* ar
static int nativeResetScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { static int nativeResetScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments //no arguments
if (arguments->count != 1) { if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _resetScript\n"); interpreter->errorOutput("Incorrect number of arguments to resetScript\n");
return -1; return -1;
} }
@@ -401,8 +428,13 @@ static int nativeResetScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arg
Toy_freeLiteral(runnerIdn); Toy_freeLiteral(runnerIdn);
} }
if (TOY_IS_IDENTIFIER(runnerLiteral)) {
Toy_freeLiteral(runnerLiteral);
return -1;
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) { 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; return -1;
} }
@@ -425,7 +457,7 @@ static int nativeResetScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arg
static int nativeFreeScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { static int nativeFreeScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments //no arguments
if (arguments->count != 1) { if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _freeScript\n"); interpreter->errorOutput("Incorrect number of arguments to freeScript\n");
return -1; return -1;
} }
@@ -437,8 +469,13 @@ static int nativeFreeScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu
Toy_freeLiteral(runnerIdn); Toy_freeLiteral(runnerIdn);
} }
if (TOY_IS_IDENTIFIER(runnerLiteral)) {
Toy_freeLiteral(runnerLiteral);
return -1;
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) { 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; return -1;
} }
@@ -459,7 +496,7 @@ static int nativeFreeScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu
static int nativeCheckScriptDirty(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { static int nativeCheckScriptDirty(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments //no arguments
if (arguments->count != 1) { if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _runScript\n"); interpreter->errorOutput("Incorrect number of arguments to checkScriptDirty\n");
return -1; return -1;
} }
@@ -471,8 +508,13 @@ static int nativeCheckScriptDirty(Toy_Interpreter* interpreter, Toy_LiteralArray
Toy_freeLiteral(runnerIdn); Toy_freeLiteral(runnerIdn);
} }
if (TOY_IS_IDENTIFIER(runnerLiteral)) {
Toy_freeLiteral(runnerLiteral);
return -1;
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) { 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; return -1;
} }
@@ -492,7 +534,7 @@ static int nativeCheckScriptDirty(Toy_Interpreter* interpreter, Toy_LiteralArray
//call the hook //call the hook
typedef struct Natives { typedef struct Natives {
char* name; const char* name;
Toy_NativeFn fn; Toy_NativeFn fn;
} Natives; } Natives;
@@ -501,12 +543,12 @@ int Toy_hookRunner(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Lit
Natives natives[] = { Natives natives[] = {
{"loadScript", nativeLoadScript}, {"loadScript", nativeLoadScript},
{"loadScriptBytecode", nativeLoadScriptBytecode}, {"loadScriptBytecode", nativeLoadScriptBytecode},
{"_runScript", nativeRunScript}, {"runScript", nativeRunScript},
{"_getScriptVar", nativeGetScriptVar}, {"getScriptVar", nativeGetScriptVar},
{"_callScriptFn", nativeCallScriptFn}, {"callScriptFn", nativeCallScriptFn},
{"_resetScript", nativeResetScript}, {"resetScript", nativeResetScript},
{"_freeScript", nativeFreeScript}, {"freeScript", nativeFreeScript},
{"_checkScriptDirty", nativeCheckScriptDirty}, {"checkScriptDirty", nativeCheckScriptDirty},
{NULL, NULL} {NULL, NULL}
}; };
@@ -585,7 +627,7 @@ Toy_Literal Toy_getFilePathLiteral(Toy_Interpreter* interpreter, Toy_Literal* dr
Toy_RefString* drivePath = Toy_copyRefString(TOY_AS_STRING(*drivePathLiteral)); Toy_RefString* drivePath = Toy_copyRefString(TOY_AS_STRING(*drivePathLiteral));
//get the drive and path as a string (can't trust that pesky strtok - custom split) TODO: move this to refstring library //get the drive and path as a string (can't trust that pesky strtok - custom split) TODO: move this to refstring library
int driveLength = 0; size_t driveLength = 0;
while (Toy_toCString(drivePath)[driveLength] != ':') { while (Toy_toCString(drivePath)[driveLength] != ':') {
if (driveLength >= Toy_lengthRefString(drivePath)) { if (driveLength >= Toy_lengthRefString(drivePath)) {
interpreter->errorOutput("Incorrect drive path format given to Toy_getFilePathLiteral\n"); interpreter->errorOutput("Incorrect drive path format given to Toy_getFilePathLiteral\n");
@@ -617,7 +659,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 //get the final real file path (concat) TODO: move this concat to refstring library
Toy_RefString* realDrive = Toy_copyRefString(TOY_AS_STRING(realDriveLiteral)); 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 char* filePath = TOY_ALLOCATE(char, realLength + 1); //+1 for null
snprintf(filePath, realLength, "%s%s", Toy_toCString(realDrive), Toy_toCString(path)); snprintf(filePath, realLength, "%s%s", Toy_toCString(realDrive), Toy_toCString(path));
@@ -630,7 +672,7 @@ Toy_Literal Toy_getFilePathLiteral(Toy_Interpreter* interpreter, Toy_Literal* dr
Toy_deleteRefString(drivePath); Toy_deleteRefString(drivePath);
//check for break-out attempts //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] == '.') { if (filePath[i] == '.' && filePath[i + 1] == '.') {
interpreter->errorOutput("Parent directory access not allowed\n"); interpreter->errorOutput("Parent directory access not allowed\n");
TOY_FREE_ARRAY(char, filePath, realLength + 1); TOY_FREE_ARRAY(char, filePath, realLength + 1);
+4 -3
View File
@@ -1,13 +1,14 @@
#pragma once #pragma once
#include "toy_common.h"
#include "toy_interpreter.h" #include "toy_interpreter.h"
int Toy_hookRunner(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias); int Toy_hookRunner(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
//file system API - these need to be set by the host //file system API - these need to be set by the host
void Toy_initDriveDictionary(); TOY_API void Toy_initDriveDictionary();
void Toy_freeDriveDictionary(); TOY_API void Toy_freeDriveDictionary();
Toy_LiteralDictionary* Toy_getDriveDictionary(); TOY_API Toy_LiteralDictionary* Toy_getDriveDictionary();
#define TOY_OPAQUE_TAG_RUNNER 100 #define TOY_OPAQUE_TAG_RUNNER 100
+1649 -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);
+66 -16
View File
@@ -1,8 +1,6 @@
#include "repl_tools.h" #include "repl_tools.h"
#include "lib_about.h" #include "lib_about.h"
#include "lib_compound.h"
#include "lib_standard.h" #include "lib_standard.h"
#include "lib_timer.h"
#include "lib_runner.h" #include "lib_runner.h"
#include "toy_console_colors.h" #include "toy_console_colors.h"
@@ -16,31 +14,31 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
void repl() { #define INPUT_BUFFER_SIZE 2048
void repl(const char* initialInput) {
//repl does it's own thing for now //repl does it's own thing for now
bool error = false; bool error = false;
const int size = 2048; char input[INPUT_BUFFER_SIZE];
char input[size]; memset(input, 0, INPUT_BUFFER_SIZE);
memset(input, 0, size);
Toy_Interpreter interpreter; //persist the interpreter for the scopes Toy_Interpreter interpreter; //persist the interpreter for the scopes
Toy_initInterpreter(&interpreter); Toy_initInterpreter(&interpreter);
//inject the libs //inject the libs
Toy_injectNativeHook(&interpreter, "about", Toy_hookAbout); Toy_injectNativeHook(&interpreter, "about", Toy_hookAbout);
Toy_injectNativeHook(&interpreter, "compound", Toy_hookCompound);
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard); Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
Toy_injectNativeHook(&interpreter, "timer", Toy_hookTimer);
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner); Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
for(;;) { for(;;) {
printf("> "); if (!initialInput) {
//handle EOF for exits //handle EOF for exits
if (!fgets(input, size, stdin)) { printf("> ");
if (!fgets(input, INPUT_BUFFER_SIZE, stdin)) {
break; break;
} }
}
//escape the repl (length of 5 to accomodate the newline) //escape the repl (length of 5 to accomodate the newline)
if (strlen(input) == 5 && (!strncmp(input, "exit", 4) || !strncmp(input, "quit", 4))) { if (strlen(input) == 5 && (!strncmp(input, "exit", 4) || !strncmp(input, "quit", 4))) {
@@ -52,7 +50,8 @@ void repl() {
Toy_Parser parser; Toy_Parser parser;
Toy_Compiler compiler; Toy_Compiler compiler;
Toy_initLexer(&lexer, input); Toy_initLexer(&lexer, initialInput ? initialInput : input);
Toy_private_setComments(&lexer, initialInput != NULL); //BUGFIX: disable comments here
Toy_initParser(&parser, &lexer); Toy_initParser(&parser, &lexer);
Toy_initCompiler(&compiler); Toy_initCompiler(&compiler);
@@ -76,7 +75,7 @@ void repl() {
if (!error) { if (!error) {
//get the bytecode dump //get the bytecode dump
int size = 0; size_t size = 0;
unsigned char* tb = Toy_collateCompiler(&compiler, &size); unsigned char* tb = Toy_collateCompiler(&compiler, &size);
//run the bytecode //run the bytecode
@@ -87,6 +86,15 @@ void repl() {
Toy_freeCompiler(&compiler); Toy_freeCompiler(&compiler);
Toy_freeParser(&parser); Toy_freeParser(&parser);
error = false; error = false;
if (initialInput) {
free((void*)initialInput);
initialInput = NULL;
if (interpreter.panic) {
break;
}
}
} }
Toy_freeInterpreter(&interpreter); Toy_freeInterpreter(&interpreter);
@@ -130,6 +138,14 @@ int main(int argc, const char* argv[]) {
//run source file //run source file
if (Toy_commandLine.sourcefile) { if (Toy_commandLine.sourcefile) {
//only works on toy files
const char* s = strrchr(Toy_commandLine.sourcefile, '.');
if (!s || strcmp(s, ".toy")) {
fprintf(stderr, TOY_CC_ERROR "Bad file extension passed to %s (expected '.toy', found '%s')" TOY_CC_RESET, argv[0], s);
return -1;
}
//run the source file
Toy_runSourceFile(Toy_commandLine.sourcefile); Toy_runSourceFile(Toy_commandLine.sourcefile);
//lib cleanup //lib cleanup
@@ -150,12 +166,25 @@ int main(int argc, const char* argv[]) {
//compile source file //compile source file
if (Toy_commandLine.compilefile && Toy_commandLine.outfile) { if (Toy_commandLine.compilefile && Toy_commandLine.outfile) {
//only works on toy and tb files
const char* c = strrchr(Toy_commandLine.compilefile, '.');
if (!c || strcmp(c, ".toy")) {
fprintf(stderr, TOY_CC_ERROR "Bad file extension passed to %s (expected '.toy', found '%s')" TOY_CC_RESET, argv[0], c);
return -1;
}
const char* o = strrchr(Toy_commandLine.outfile, '.');
if (!o || strcmp(o, ".tb")) {
fprintf(stderr, TOY_CC_ERROR "Bad file extension passed to %s (expected '.tb', found '%s')" TOY_CC_RESET, argv[0], o);
return -1;
}
//compile and save
size_t size = 0; size_t size = 0;
char* source = Toy_readFile(Toy_commandLine.compilefile, &size); const char* source = (const char*)Toy_readFile(Toy_commandLine.compilefile, &size);
if (!source) { if (!source) {
return 1; return 1;
} }
unsigned char* tb = Toy_compileString(source, &size); const unsigned char* tb = Toy_compileString(source, &size);
if (!tb) { if (!tb) {
return 1; return 1;
} }
@@ -165,6 +194,14 @@ int main(int argc, const char* argv[]) {
//run binary //run binary
if (Toy_commandLine.binaryfile) { if (Toy_commandLine.binaryfile) {
//only works on tb files
const char* c = strrchr(Toy_commandLine.binaryfile, '.');
if (!c || strcmp(c, ".tb")) {
fprintf(stderr, TOY_CC_ERROR "Bad file extension passed to %s (expected '.tb', found '%s')" TOY_CC_RESET, argv[0], c); //this one is never seen
return -1;
}
//run the binary file
Toy_runBinaryFile(Toy_commandLine.binaryfile); Toy_runBinaryFile(Toy_commandLine.binaryfile);
//lib cleanup //lib cleanup
@@ -173,7 +210,20 @@ int main(int argc, const char* argv[]) {
return 0; 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 //lib cleanup
Toy_freeDriveDictionary(); Toy_freeDriveDictionary();
+15 -19
View File
@@ -1,8 +1,6 @@
#include "repl_tools.h" #include "repl_tools.h"
#include "lib_about.h" #include "lib_about.h"
#include "lib_compound.h"
#include "lib_standard.h" #include "lib_standard.h"
#include "lib_timer.h"
#include "lib_runner.h" #include "lib_runner.h"
#include "toy_console_colors.h" #include "toy_console_colors.h"
@@ -16,7 +14,7 @@
#include <stdlib.h> #include <stdlib.h>
//IO functions //IO functions
char* Toy_readFile(char* path, size_t* fileSize) { const unsigned char* Toy_readFile(const char* path, size_t* fileSize) {
FILE* file = fopen(path, "rb"); FILE* file = fopen(path, "rb");
if (file == NULL) { if (file == NULL) {
@@ -28,14 +26,14 @@ char* Toy_readFile(char* path, size_t* fileSize) {
*fileSize = ftell(file); *fileSize = ftell(file);
rewind(file); rewind(file);
char* buffer = (char*)malloc(*fileSize + 1); unsigned char* buffer = (unsigned char*)malloc(*fileSize + 1);
if (buffer == NULL) { if (buffer == NULL) {
fprintf(stderr, TOY_CC_ERROR "Not enough memory to read \"%s\"\n" TOY_CC_RESET, path); fprintf(stderr, TOY_CC_ERROR "Not enough memory to read \"%s\"\n" TOY_CC_RESET, path);
return NULL; 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 buffer[*fileSize] = '\0'; //NOTE: fread doesn't append this
@@ -49,7 +47,7 @@ char* Toy_readFile(char* path, size_t* fileSize) {
return buffer; return buffer;
} }
int Toy_writeFile(char* path, unsigned char* bytes, size_t size) { int Toy_writeFile(const char* path, const unsigned char* bytes, size_t size) {
FILE* file = fopen(path, "wb"); FILE* file = fopen(path, "wb");
if (file == NULL) { if (file == NULL) {
@@ -57,7 +55,7 @@ int Toy_writeFile(char* path, unsigned char* bytes, size_t size) {
return -1; return -1;
} }
int written = fwrite(bytes, size, 1, file); size_t written = fwrite(bytes, size, 1, file);
if (written != 1) { if (written != 1) {
fprintf(stderr, TOY_CC_ERROR "Could not write file \"%s\"\n" TOY_CC_RESET, path); fprintf(stderr, TOY_CC_ERROR "Could not write file \"%s\"\n" TOY_CC_RESET, path);
@@ -70,7 +68,7 @@ int Toy_writeFile(char* path, unsigned char* bytes, size_t size) {
} }
//repl functions //repl functions
unsigned char* Toy_compileString(char* source, size_t* size) { const unsigned char* Toy_compileString(const char* source, size_t* size) {
Toy_Lexer lexer; Toy_Lexer lexer;
Toy_Parser parser; Toy_Parser parser;
Toy_Compiler compiler; Toy_Compiler compiler;
@@ -96,7 +94,7 @@ unsigned char* Toy_compileString(char* source, size_t* size) {
} }
//get the bytecode dump //get the bytecode dump
unsigned char* tb = Toy_collateCompiler(&compiler, (int*)(size)); const unsigned char* tb = Toy_collateCompiler(&compiler, size);
//cleanup //cleanup
Toy_freeCompiler(&compiler); Toy_freeCompiler(&compiler);
@@ -107,24 +105,22 @@ unsigned char* Toy_compileString(char* source, size_t* size) {
return tb; return tb;
} }
void Toy_runBinary(unsigned char* tb, size_t size) { void Toy_runBinary(const unsigned char* tb, size_t size) {
Toy_Interpreter interpreter; Toy_Interpreter interpreter;
Toy_initInterpreter(&interpreter); Toy_initInterpreter(&interpreter);
//inject the libs //inject the libs
Toy_injectNativeHook(&interpreter, "about", Toy_hookAbout); Toy_injectNativeHook(&interpreter, "about", Toy_hookAbout);
Toy_injectNativeHook(&interpreter, "compound", Toy_hookCompound);
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard); Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
Toy_injectNativeHook(&interpreter, "timer", Toy_hookTimer);
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner); Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
Toy_runInterpreter(&interpreter, tb, size); Toy_runInterpreter(&interpreter, tb, (int)size);
Toy_freeInterpreter(&interpreter); Toy_freeInterpreter(&interpreter);
} }
void Toy_runBinaryFile(char* fname) { void Toy_runBinaryFile(const char* fname) {
size_t size = 0; //not used size_t size = 0; //not used
unsigned char* tb = (unsigned char*)Toy_readFile(fname, &size); const unsigned char* tb = Toy_readFile(fname, &size);
if (!tb) { if (!tb) {
return; return;
} }
@@ -132,9 +128,9 @@ void Toy_runBinaryFile(char* fname) {
//interpreter takes ownership of the binary data //interpreter takes ownership of the binary data
} }
void Toy_runSource(char* source) { void Toy_runSource(const char* source) {
size_t size = 0; size_t size = 0;
unsigned char* tb = Toy_compileString(source, &size); const unsigned char* tb = Toy_compileString(source, &size);
if (!tb) { if (!tb) {
return; return;
} }
@@ -142,9 +138,9 @@ void Toy_runSource(char* source) {
Toy_runBinary(tb, size); Toy_runBinary(tb, size);
} }
void Toy_runSourceFile(char* fname) { void Toy_runSourceFile(const char* fname) {
size_t size = 0; //not used size_t size = 0; //not used
char* source = Toy_readFile(fname, &size); const char* source = (const char*)Toy_readFile(fname, &size);
if (!source) { if (!source) {
return; return;
} }
+7 -7
View File
@@ -2,13 +2,13 @@
#include "toy_common.h" #include "toy_common.h"
char* Toy_readFile(char* path, size_t* fileSize); const unsigned char* Toy_readFile(const char* path, size_t* fileSize);
int Toy_writeFile(char* path, unsigned char* bytes, size_t size); int Toy_writeFile(const char* path, const unsigned char* bytes, size_t size);
unsigned char* Toy_compileString(char* source, size_t* size); const unsigned char* Toy_compileString(const char* source, size_t* size);
void Toy_runBinary(unsigned char* tb, size_t size); void Toy_runBinary(const unsigned char* tb, size_t size);
void Toy_runBinaryFile(char* fname); void Toy_runBinaryFile(const char* fname);
void Toy_runSource(char* source); void Toy_runSource(const char* source);
void Toy_runSourceFile(char* fname); void Toy_runSourceFile(const char* fname);
+7 -7
View File
@@ -24,7 +24,7 @@ fn getY(node: opaque) {
//lifecycle functions //lifecycle functions
fn onInit(node: opaque) { fn onInit(node: opaque) {
print "render.toy:onInit() called"; print "render.toy:onInit() called\n";
node.loadTexture("sprites:/character.png"); node.loadTexture("sprites:/character.png");
parent = node.getNodeParent(); parent = node.getNodeParent();
@@ -36,13 +36,13 @@ fn onStep(node: opaque) {
} }
fn onFree(node: opaque) { fn onFree(node: opaque) {
print "render.toy:onFree() called"; print "render.toy:onFree() called\n";
node.freeTexture(); node.freeTexture();
} }
fn onDraw(node: opaque) { fn onDraw(node: opaque) {
// print "render.toy:onDraw() called"; // print "render.toy:onDraw() called\n";
var px = parent.callNode("getX"); var px = parent.callNode("getX");
var py = parent.callNode("getY"); var py = parent.callNode("getY");
@@ -104,11 +104,11 @@ fn onKeyUp(node: opaque, event: string) {
} }
fn onMouseMotion(node: opaque, x: int, y: int, xrel: int, yrel: int) { fn onMouseMotion(node: opaque, x: int, y: int, xrel: int, yrel: int) {
print "entity.toy:onMouseMotion(" + string x + ", " + string y + ", " + string xrel + ", " + string yrel + ")"; // print "entity.toy:onMouseMotion(" + string x + ", " + string y + ", " + string xrel + ", " + string yrel + ")\n";
} }
fn onMouseButtonDown(node: opaque, x: int, y: int, button: string) { fn onMouseButtonDown(node: opaque, x: int, y: int, button: string) {
print "entity.toy:onMouseButtonDown(" + string x + ", " + string y + ", " + button + ")"; // print "entity.toy:onMouseButtonDown(" + string x + ", " + string y + ", " + button + ")\n";
//jump to pos //jump to pos
posX = x - WIDTH / 2; posX = x - WIDTH / 2;
@@ -116,10 +116,10 @@ fn onMouseButtonDown(node: opaque, x: int, y: int, button: string) {
} }
fn onMouseButtonUp(node: opaque, x: int, y: int, button: string) { fn onMouseButtonUp(node: opaque, x: int, y: int, button: string) {
print "entity.toy:onMouseButtonUp(" + string x + ", " + string y + ", " + button + ")"; // print "entity.toy:onMouseButtonUp(" + string x + ", " + string y + ", " + button + ")\n";
} }
fn onMouseWheel(node: opaque, xrel: int, yrel: int) { fn onMouseWheel(node: opaque, xrel: int, yrel: int) {
print "entity.toy:onMouseWheel(" + string xrel + ", " + string yrel + ")"; // print "entity.toy:onMouseWheel(" + string xrel + ", " + string yrel + ")\n";
} }
+1
View File
@@ -1,3 +1,4 @@
//WARNING: please think twice before using this in a test
fn fib(n : int) { fn fib(n : int) {
if (n < 2) return n; if (n < 2) return n;
return fib(n-1) + fib(n-2); return fib(n-1) + fib(n-2);
+90
View File
@@ -0,0 +1,90 @@
/*
How to run this program:
toyrepl -n -t scripts/level.toy
How to move around:
move(up);
move(down);
move(left);
move(right);
*/
//constants
var WIDTH: int const = 12;
var HEIGHT: int const = 12;
//WIDTH * HEIGHT in size
var tiles: [[int]] const = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1],
[1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1],
[1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1],
[1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] //BUG: map is twisted along this diagonal
];
var tileset: [int: string] const = [
0: " ",
1: " X "
];
//variables
var posX: int = 4;
var posY: int = 4;
//functions
fn draw() {
for (var j: int = 0; j < HEIGHT; j++) {
for (var i: int = 0; i < WIDTH; i++) {
//draw the player pos
if (i == posX && j == posY) {
print " O ";
continue;
}
print tileset[ tiles[i][j] ];
}
print "\n";
}
print "\n";
}
fn moveRelative(xrel: int, yrel: int) {
if (xrel > 1 || xrel < -1 || yrel > 1 || yrel < -1 || (xrel != 0 && yrel != 0)) {
print "too fast!\n";
return;
}
if (tiles[posX + xrel][posY + yrel] > 0) {
print "Can't move that way\n";
return;
}
posX += xrel;
posY += yrel;
draw();
}
//wrap for easy use
var up: [int] const = [0, -1];
var down: [int] const = [0, 1];
var left: [int] const = [-1, 0];
var right: [int] const = [1, 0];
fn move(dir: [int] const) {
return moveRelative(dir[0], dir[1]);
}
//initial display
move([0, 0]);
+1 -1
View File
@@ -1,5 +1,5 @@
//number of iterations //number of iterations
var SIZE: int const = 260; var SIZE: int const = 100;
//lookup table //lookup table
var lookup = [ var lookup = [
-6
View File
@@ -1,6 +0,0 @@
import compound;
var arr: [int] = [1, 2, 3];
fn f(_, v: int): int { return v + 1; }
print arr.map(f);
+12
View File
@@ -135,6 +135,10 @@ static void freeASTNodeCustom(Toy_ASTNode* node, bool freeSelf) {
Toy_freeLiteral(node->import.identifier); Toy_freeLiteral(node->import.identifier);
Toy_freeLiteral(node->import.alias); Toy_freeLiteral(node->import.alias);
break; break;
case TOY_AST_NODE_PASS:
//EMPTY
break;
} }
if (freeSelf) { if (freeSelf) {
@@ -383,3 +387,11 @@ void Toy_emitASTNodeImport(Toy_ASTNode** nodeHandle, Toy_Literal identifier, Toy
*nodeHandle = tmp; *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_PREFIX_DECREMENT, //decrement a variable
TOY_AST_NODE_POSTFIX_DECREMENT, //decrement a variable TOY_AST_NODE_POSTFIX_DECREMENT, //decrement a variable
TOY_AST_NODE_IMPORT, //import a library TOY_AST_NODE_IMPORT, //import a library
TOY_AST_NODE_PASS, //for doing nothing
} Toy_ASTNodeType; } Toy_ASTNodeType;
//literals //literals
@@ -238,6 +239,9 @@ typedef struct Toy_NodeImport {
Toy_Literal alias; Toy_Literal alias;
} Toy_NodeImport; } Toy_NodeImport;
//for doing nothing
void Toy_emitASTNodePass(Toy_ASTNode** nodeHandle);
union Toy_private_node { union Toy_private_node {
Toy_ASTNodeType type; Toy_ASTNodeType type;
Toy_NodeLiteral atomic; Toy_NodeLiteral atomic;
+161 -42
View File
@@ -4,6 +4,7 @@
#include "toy_literal.h" #include "toy_literal.h"
#include <stdio.h> #include <stdio.h>
#include <string.h>
//static math utils, copied from the interpreter //static math utils, copied from the interpreter
static Toy_Literal addition(Toy_Interpreter* interpreter, Toy_Literal lhs, Toy_Literal rhs) { static Toy_Literal addition(Toy_Interpreter* interpreter, Toy_Literal lhs, Toy_Literal rhs) {
@@ -278,6 +279,17 @@ int Toy_private_index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
Toy_freeLiteral(idn); Toy_freeLiteral(idn);
} }
if (TOY_IS_IDENTIFIER(first) || TOY_IS_IDENTIFIER(second) || TOY_IS_IDENTIFIER(third)) {
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
//second and third are bad args to dictionaries //second and third are bad args to dictionaries
if (!TOY_IS_NULL(second) || !TOY_IS_NULL(third)) { if (!TOY_IS_NULL(second) || !TOY_IS_NULL(third)) {
interpreter->errorOutput("Index slicing not allowed for dictionaries\n"); interpreter->errorOutput("Index slicing not allowed for dictionaries\n");
@@ -400,6 +412,17 @@ int Toy_private_index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
Toy_freeLiteral(idn); Toy_freeLiteral(idn);
} }
if (TOY_IS_IDENTIFIER(first) || TOY_IS_IDENTIFIER(second) || TOY_IS_IDENTIFIER(third)) {
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
//handle each error case //handle each error case
if (!TOY_IS_INTEGER(first) || TOY_AS_INTEGER(first) < 0 || TOY_AS_INTEGER(first) >= TOY_AS_ARRAY(compound)->count) { if (!TOY_IS_INTEGER(first) || TOY_AS_INTEGER(first) < 0 || TOY_AS_INTEGER(first) >= TOY_AS_ARRAY(compound)->count) {
interpreter->errorOutput("Bad first indexing\n"); interpreter->errorOutput("Bad first indexing\n");
@@ -542,6 +565,17 @@ int Toy_private_index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
Toy_freeLiteral(idn); Toy_freeLiteral(idn);
} }
if (TOY_IS_IDENTIFIER(first) || TOY_IS_IDENTIFIER(second) || TOY_IS_IDENTIFIER(third)) {
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
//handle each error case //handle each error case
if (!TOY_IS_INTEGER(first) || TOY_AS_INTEGER(first) < 0 || TOY_AS_INTEGER(first) >= TOY_AS_ARRAY(compound)->count) { if (!TOY_IS_INTEGER(first) || TOY_AS_INTEGER(first) < 0 || TOY_AS_INTEGER(first) >= TOY_AS_ARRAY(compound)->count) {
interpreter->errorOutput("Bad first indexing assignment\n"); interpreter->errorOutput("Bad first indexing assignment\n");
@@ -704,6 +738,17 @@ int Toy_private_index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
Toy_freeLiteral(idn); Toy_freeLiteral(idn);
} }
if (TOY_IS_IDENTIFIER(first)) {
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
Toy_Literal value = Toy_getLiteralArray(TOY_AS_ARRAY(compound), first); Toy_Literal value = Toy_getLiteralArray(TOY_AS_ARRAY(compound), first);
if (TOY_IS_STRING(op) && Toy_equalsRefStringCString(TOY_AS_STRING(op), "+=")) { if (TOY_IS_STRING(op) && Toy_equalsRefStringCString(TOY_AS_STRING(op), "+=")) {
@@ -792,8 +837,19 @@ int Toy_private_index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
Toy_freeLiteral(idn); Toy_freeLiteral(idn);
} }
if (TOY_IS_IDENTIFIER(first) || TOY_IS_IDENTIFIER(second) || TOY_IS_IDENTIFIER(third)) {
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
//handle each error case //handle each error case
if (!TOY_IS_INTEGER(first) || TOY_AS_INTEGER(first) < 0 || TOY_AS_INTEGER(first) >= TOY_AS_STRING(compound)->length) { if (!TOY_IS_INTEGER(first) || TOY_AS_INTEGER(first) < 0 || TOY_AS_INTEGER(first) >= (int)Toy_lengthRefString(TOY_AS_STRING(compound))) {
interpreter->errorOutput("Bad first indexing in string\n"); interpreter->errorOutput("Bad first indexing in string\n");
//something is weird - skip out //something is weird - skip out
@@ -807,7 +863,7 @@ int Toy_private_index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
return -1; return -1;
} }
if ((!TOY_IS_NULL(second) && !TOY_IS_INTEGER(second)) || TOY_AS_INTEGER(second) < 0 || TOY_AS_INTEGER(second) >= TOY_AS_STRING(compound)->length) { if ((!TOY_IS_NULL(second) && !TOY_IS_INTEGER(second)) || TOY_AS_INTEGER(second) < 0 || TOY_AS_INTEGER(second) >= (int)Toy_lengthRefString(TOY_AS_STRING(compound))) {
interpreter->errorOutput("Bad second indexing in string\n"); interpreter->errorOutput("Bad second indexing in string\n");
//something is weird - skip out //something is weird - skip out
@@ -838,7 +894,7 @@ int Toy_private_index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
//simple indexing if second is null //simple indexing if second is null
if (TOY_IS_NULL(second)) { if (TOY_IS_NULL(second)) {
char* cstr = Toy_toCString(TOY_AS_STRING(compound)); const char* cstr = Toy_toCString(TOY_AS_STRING(compound));
char buf[16]; char buf[16];
snprintf(buf, 16, "%s", &(cstr[ TOY_AS_INTEGER(first) ]) ); snprintf(buf, 16, "%s", &(cstr[ TOY_AS_INTEGER(first) ]) );
@@ -936,8 +992,19 @@ int Toy_private_index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
Toy_freeLiteral(idn); Toy_freeLiteral(idn);
} }
if (TOY_IS_IDENTIFIER(first) || TOY_IS_IDENTIFIER(second) || TOY_IS_IDENTIFIER(third)) {
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
//handle each error case //handle each error case
if (!TOY_IS_INTEGER(first) || TOY_AS_INTEGER(first) < 0 || TOY_AS_INTEGER(first) >= TOY_AS_STRING(compound)->length) { if (!TOY_IS_INTEGER(first) || TOY_AS_INTEGER(first) < 0 || TOY_AS_INTEGER(first) >= (int)Toy_lengthRefString(TOY_AS_STRING(compound))) {
interpreter->errorOutput("Bad first indexing in string assignment\n"); interpreter->errorOutput("Bad first indexing in string assignment\n");
//something is weird - skip out //something is weird - skip out
@@ -951,7 +1018,7 @@ int Toy_private_index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
return -1; return -1;
} }
if ((!TOY_IS_NULL(second) && !TOY_IS_INTEGER(second)) || TOY_AS_INTEGER(second) < 0 || TOY_AS_INTEGER(second) >= TOY_AS_STRING(compound)->length) { if ((!TOY_IS_NULL(second) && !TOY_IS_INTEGER(second)) || TOY_AS_INTEGER(second) < 0 || TOY_AS_INTEGER(second) >= (int)Toy_lengthRefString(TOY_AS_STRING(compound))) {
interpreter->errorOutput("Bad second indexing in string assignment\n"); interpreter->errorOutput("Bad second indexing in string assignment\n");
//something is weird - skip out //something is weird - skip out
@@ -1063,7 +1130,7 @@ int Toy_private_index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
int Toy_private_set(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { int Toy_private_set(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//if wrong number of arguments, fail //if wrong number of arguments, fail
if (arguments->count != 3) { if (arguments->count != 3) {
interpreter->errorOutput("Incorrect number of arguments to _set\n"); interpreter->errorOutput("Incorrect number of arguments to set\n");
return -1; return -1;
} }
@@ -1073,12 +1140,16 @@ int Toy_private_set(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
Toy_Literal val = arguments->literals[2]; Toy_Literal val = arguments->literals[2];
if (!TOY_IS_IDENTIFIER(idn)) { if (!TOY_IS_IDENTIFIER(idn)) {
interpreter->errorOutput("Expected identifier in _set\n"); interpreter->errorOutput("Expected identifier in set\n");
return -1; return -1;
} }
Toy_parseIdentifierToValue(interpreter, &obj); Toy_parseIdentifierToValue(interpreter, &obj);
if (TOY_IS_IDENTIFIER(obj)) {
return -1;
}
bool freeKey = false; bool freeKey = false;
if (TOY_IS_IDENTIFIER(key)) { if (TOY_IS_IDENTIFIER(key)) {
Toy_parseIdentifierToValue(interpreter, &key); Toy_parseIdentifierToValue(interpreter, &key);
@@ -1091,26 +1162,40 @@ int Toy_private_set(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
freeVal = true; freeVal = true;
} }
if (TOY_IS_IDENTIFIER(key) || TOY_IS_IDENTIFIER(val)) {
if (freeKey) {
Toy_freeLiteral(key);
}
if (freeVal) {
Toy_freeLiteral(val);
}
return -1;
}
switch(obj.type) { switch(obj.type) {
case TOY_LITERAL_ARRAY: { case TOY_LITERAL_ARRAY: {
Toy_Literal typeLiteral = Toy_getScopeType(interpreter->scope, key); //check the subtype of the array, if there is one, against the given argument
Toy_Literal typeLiteral = Toy_getScopeType(interpreter->scope, idn);
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_ARRAY) { if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_ARRAY) {
Toy_Literal subtypeLiteral = ((Toy_Literal*)(TOY_AS_TYPE(typeLiteral).subtypes))[0]; Toy_Literal subtypeLiteral = ((Toy_Literal*)(TOY_AS_TYPE(typeLiteral).subtypes))[0];
if (TOY_AS_TYPE(subtypeLiteral).typeOf != TOY_LITERAL_ANY && TOY_AS_TYPE(subtypeLiteral).typeOf != val.type) { if (TOY_AS_TYPE(subtypeLiteral).typeOf != TOY_LITERAL_ANY && TOY_AS_TYPE(subtypeLiteral).typeOf != val.type) {
interpreter->errorOutput("Bad argument type in _set\n"); interpreter->errorOutput("Bad argument type in set\n");
Toy_freeLiteral(typeLiteral);
return -1; return -1;
} }
} }
Toy_freeLiteral(typeLiteral);
if (!TOY_IS_INTEGER(key)) { if (!TOY_IS_INTEGER(key)) {
interpreter->errorOutput("Expected integer index in _set\n"); interpreter->errorOutput("Expected integer index in set\n");
return -1; return -1;
} }
if (TOY_AS_ARRAY(obj)->count <= TOY_AS_INTEGER(key) || TOY_AS_INTEGER(key) < 0) { if (TOY_AS_INTEGER(key) >= TOY_AS_ARRAY(obj)->count || TOY_AS_INTEGER(key) < 0) {
interpreter->errorOutput("Index out of bounds in _set\n"); interpreter->errorOutput("Index out of bounds in set\n");
return -1; return -1;
} }
@@ -1119,7 +1204,7 @@ int Toy_private_set(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
TOY_AS_ARRAY(obj)->literals[TOY_AS_INTEGER(key)] = Toy_copyLiteral(val); TOY_AS_ARRAY(obj)->literals[TOY_AS_INTEGER(key)] = Toy_copyLiteral(val);
if (!Toy_setScopeVariable(interpreter->scope, idn, obj, true)) { if (!Toy_setScopeVariable(interpreter->scope, idn, obj, true)) {
interpreter->errorOutput("Incorrect type assigned to array in _set: \""); interpreter->errorOutput("Incorrect type assigned to array in set: \"");
Toy_printLiteralCustom(val, interpreter->errorOutput); Toy_printLiteralCustom(val, interpreter->errorOutput);
interpreter->errorOutput("\"\n"); interpreter->errorOutput("\"\n");
return -1; return -1;
@@ -1136,12 +1221,12 @@ int Toy_private_set(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
Toy_Literal valSubtypeLiteral = ((Toy_Literal*)(TOY_AS_TYPE(typeLiteral).subtypes))[1]; Toy_Literal valSubtypeLiteral = ((Toy_Literal*)(TOY_AS_TYPE(typeLiteral).subtypes))[1];
if (TOY_AS_TYPE(keySubtypeLiteral).typeOf != TOY_LITERAL_ANY && TOY_AS_TYPE(keySubtypeLiteral).typeOf != key.type) { if (TOY_AS_TYPE(keySubtypeLiteral).typeOf != TOY_LITERAL_ANY && TOY_AS_TYPE(keySubtypeLiteral).typeOf != key.type) {
interpreter->printOutput("bad argument type in _set\n"); interpreter->printOutput("bad argument type in set\n");
return -1; return -1;
} }
if (TOY_AS_TYPE(valSubtypeLiteral).typeOf != TOY_LITERAL_ANY && TOY_AS_TYPE(valSubtypeLiteral).typeOf != val.type) { if (TOY_AS_TYPE(valSubtypeLiteral).typeOf != TOY_LITERAL_ANY && TOY_AS_TYPE(valSubtypeLiteral).typeOf != val.type) {
interpreter->printOutput("bad argument type in _set\n"); interpreter->printOutput("bad argument type in set\n");
return -1; return -1;
} }
} }
@@ -1149,7 +1234,7 @@ int Toy_private_set(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
Toy_setLiteralDictionary(TOY_AS_DICTIONARY(obj), key, val); Toy_setLiteralDictionary(TOY_AS_DICTIONARY(obj), key, val);
if (!Toy_setScopeVariable(interpreter->scope, idn, obj, true)) { if (!Toy_setScopeVariable(interpreter->scope, idn, obj, true)) {
interpreter->errorOutput("Incorrect type assigned to dictionary in _set: \""); interpreter->errorOutput("Incorrect type assigned to dictionary in set: \"");
Toy_printLiteralCustom(val, interpreter->errorOutput); Toy_printLiteralCustom(val, interpreter->errorOutput);
interpreter->errorOutput("\"\n"); interpreter->errorOutput("\"\n");
return -1; return -1;
@@ -1159,7 +1244,7 @@ int Toy_private_set(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
} }
default: default:
interpreter->errorOutput("Incorrect compound type in _set: "); interpreter->errorOutput("Incorrect compound type in set: ");
Toy_printLiteralCustom(obj, interpreter->errorOutput); Toy_printLiteralCustom(obj, interpreter->errorOutput);
interpreter->errorOutput("\"\n"); interpreter->errorOutput("\"\n");
return -1; return -1;
@@ -1181,7 +1266,7 @@ int Toy_private_set(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
int Toy_private_get(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { int Toy_private_get(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//if wrong number of arguments, fail //if wrong number of arguments, fail
if (arguments->count != 2) { if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments to _get"); interpreter->errorOutput("Incorrect number of arguments to get");
return -1; return -1;
} }
@@ -1200,15 +1285,25 @@ int Toy_private_get(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
freeKey = true; freeKey = true;
} }
switch(obj.type) { if (TOY_IS_IDENTIFIER(obj) || TOY_IS_IDENTIFIER(key)) {
case TOY_LITERAL_ARRAY: { if (freeObj) {
if (!TOY_IS_INTEGER(key)) { Toy_freeLiteral(obj);
interpreter->errorOutput("Expected integer index in _get\n"); }
if (freeKey) {
Toy_freeLiteral(key);
}
return -1; return -1;
} }
if (TOY_AS_ARRAY(obj)->count <= TOY_AS_INTEGER(key) || TOY_AS_INTEGER(key) < 0) { switch(obj.type) {
interpreter->errorOutput("Index out of bounds in _get\n"); case TOY_LITERAL_ARRAY: {
if (!TOY_IS_INTEGER(key)) {
interpreter->errorOutput("Expected integer index in get\n");
return -1;
}
if (TOY_AS_INTEGER(key) >= TOY_AS_ARRAY(obj)->count || TOY_AS_INTEGER(key) < 0) {
interpreter->errorOutput("Index out of bounds in get\n");
return -1; return -1;
} }
@@ -1242,7 +1337,7 @@ int Toy_private_get(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
} }
default: default:
interpreter->errorOutput("Incorrect compound type in _get \""); interpreter->errorOutput("Incorrect compound type in get \"");
Toy_printLiteralCustom(obj, interpreter->errorOutput); Toy_printLiteralCustom(obj, interpreter->errorOutput);
interpreter->errorOutput("\"\n"); interpreter->errorOutput("\"\n");
return -1; return -1;
@@ -1252,7 +1347,7 @@ int Toy_private_get(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
int Toy_private_push(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { int Toy_private_push(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//if wrong number of arguments, fail //if wrong number of arguments, fail
if (arguments->count != 2) { if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments to _push\n"); interpreter->errorOutput("Incorrect number of arguments to push\n");
return -1; return -1;
} }
@@ -1261,35 +1356,47 @@ int Toy_private_push(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
Toy_Literal val = arguments->literals[1]; Toy_Literal val = arguments->literals[1];
if (!TOY_IS_IDENTIFIER(idn)) { if (!TOY_IS_IDENTIFIER(idn)) {
interpreter->errorOutput("Expected identifier in _push\n"); interpreter->errorOutput("Expected identifier in push\n");
return -1; return -1;
} }
Toy_parseIdentifierToValue(interpreter, &obj); Toy_parseIdentifierToValue(interpreter, &obj);
if (TOY_IS_IDENTIFIER(obj)) {
return -1;
}
bool freeVal = false; bool freeVal = false;
if (TOY_IS_IDENTIFIER(val)) { if (TOY_IS_IDENTIFIER(val)) {
Toy_parseIdentifierToValue(interpreter, &val); Toy_parseIdentifierToValue(interpreter, &val);
freeVal = true; freeVal = true;
} }
if (TOY_IS_IDENTIFIER(val)) {
return -1;
}
switch(obj.type) { switch(obj.type) {
case TOY_LITERAL_ARRAY: { case TOY_LITERAL_ARRAY: {
Toy_Literal typeLiteral = Toy_getScopeType(interpreter->scope, val); //check the subtype of the array, if there is one, against the given argument
Toy_Literal typeLiteral = Toy_getScopeType(interpreter->scope, idn);
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_ARRAY) { if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_ARRAY) {
Toy_Literal subtypeLiteral = ((Toy_Literal*)(TOY_AS_TYPE(typeLiteral).subtypes))[0]; Toy_Literal subtypeLiteral = ((Toy_Literal*)(TOY_AS_TYPE(typeLiteral).subtypes))[0];
if (TOY_AS_TYPE(subtypeLiteral).typeOf != TOY_LITERAL_ANY && TOY_AS_TYPE(subtypeLiteral).typeOf != val.type) { if (TOY_AS_TYPE(subtypeLiteral).typeOf != TOY_LITERAL_ANY && TOY_AS_TYPE(subtypeLiteral).typeOf != val.type) {
interpreter->errorOutput("Bad argument type in _push"); interpreter->errorOutput("Bad argument type in push");
Toy_freeLiteral(typeLiteral);
return -1; return -1;
} }
} }
Toy_freeLiteral(typeLiteral);
Toy_pushLiteralArray(TOY_AS_ARRAY(obj), val); Toy_pushLiteralArray(TOY_AS_ARRAY(obj), val);
if (!Toy_setScopeVariable(interpreter->scope, idn, obj, true)) { //TODO: could definitely be more efficient than overwriting the whole original object if (!Toy_setScopeVariable(interpreter->scope, idn, obj, true)) { //TODO: could definitely be more efficient than overwriting the whole original object
interpreter->errorOutput("Incorrect type assigned to array in _push: \""); interpreter->errorOutput("Incorrect type assigned to array in push: \"");
Toy_printLiteralCustom(val, interpreter->errorOutput); Toy_printLiteralCustom(val, interpreter->errorOutput);
interpreter->errorOutput("\"\n"); interpreter->errorOutput("\"\n");
return -1; return -1;
@@ -1305,7 +1412,7 @@ int Toy_private_push(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
} }
default: default:
interpreter->errorOutput("Incorrect compound type in _push: "); interpreter->errorOutput("Incorrect compound type in push: ");
Toy_printLiteralCustom(obj, interpreter->errorOutput); Toy_printLiteralCustom(obj, interpreter->errorOutput);
interpreter->errorOutput("\n"); interpreter->errorOutput("\n");
return -1; return -1;
@@ -1315,7 +1422,7 @@ int Toy_private_push(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
int Toy_private_pop(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { int Toy_private_pop(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//if wrong number of arguments, fail //if wrong number of arguments, fail
if (arguments->count != 1) { if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _pop\n"); interpreter->errorOutput("Incorrect number of arguments to pop\n");
return -1; return -1;
} }
@@ -1323,12 +1430,16 @@ int Toy_private_pop(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
Toy_Literal obj = arguments->literals[0]; Toy_Literal obj = arguments->literals[0];
if (!TOY_IS_IDENTIFIER(idn)) { if (!TOY_IS_IDENTIFIER(idn)) {
interpreter->errorOutput("Expected identifier in _pop\n"); interpreter->errorOutput("Expected identifier in pop\n");
return -1; return -1;
} }
Toy_parseIdentifierToValue(interpreter, &obj); Toy_parseIdentifierToValue(interpreter, &obj);
if (TOY_IS_IDENTIFIER(obj)) {
return -1;
}
switch(obj.type) { switch(obj.type) {
case TOY_LITERAL_ARRAY: { case TOY_LITERAL_ARRAY: {
Toy_Literal lit = Toy_popLiteralArray(TOY_AS_ARRAY(obj)); Toy_Literal lit = Toy_popLiteralArray(TOY_AS_ARRAY(obj));
@@ -1336,7 +1447,7 @@ int Toy_private_pop(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
Toy_freeLiteral(lit); Toy_freeLiteral(lit);
if (!Toy_setScopeVariable(interpreter->scope, idn, obj, true)) { //TODO: could definitely be more efficient than overwriting the whole original object if (!Toy_setScopeVariable(interpreter->scope, idn, obj, true)) { //TODO: could definitely be more efficient than overwriting the whole original object
interpreter->errorOutput("Incorrect type assigned to array in _pop: "); interpreter->errorOutput("Incorrect type assigned to array in pop: ");
Toy_printLiteralCustom(obj, interpreter->errorOutput); Toy_printLiteralCustom(obj, interpreter->errorOutput);
interpreter->errorOutput("\n"); interpreter->errorOutput("\n");
return -1; return -1;
@@ -1348,7 +1459,7 @@ int Toy_private_pop(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
} }
default: default:
interpreter->errorOutput("Incorrect compound type in _pop: "); interpreter->errorOutput("Incorrect compound type in pop: ");
Toy_printLiteralCustom(obj, interpreter->errorOutput); Toy_printLiteralCustom(obj, interpreter->errorOutput);
interpreter->errorOutput("\n"); interpreter->errorOutput("\n");
return -1; return -1;
@@ -1358,7 +1469,7 @@ int Toy_private_pop(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
int Toy_private_length(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { int Toy_private_length(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//if wrong number of arguments, fail //if wrong number of arguments, fail
if (arguments->count != 1) { if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _length\n"); interpreter->errorOutput("Incorrect number of arguments to length\n");
return -1; return -1;
} }
@@ -1370,6 +1481,10 @@ int Toy_private_length(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments
freeObj = true; freeObj = true;
} }
if (TOY_IS_IDENTIFIER(obj)) {
return -1;
}
switch(obj.type) { switch(obj.type) {
case TOY_LITERAL_ARRAY: { case TOY_LITERAL_ARRAY: {
Toy_Literal lit = TOY_TO_INTEGER_LITERAL( TOY_AS_ARRAY(obj)->count ); Toy_Literal lit = TOY_TO_INTEGER_LITERAL( TOY_AS_ARRAY(obj)->count );
@@ -1393,7 +1508,7 @@ int Toy_private_length(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments
} }
default: default:
interpreter->errorOutput("Incorrect compound type in _length: "); interpreter->errorOutput("Incorrect compound type in length: ");
Toy_printLiteralCustom(obj, interpreter->errorOutput); Toy_printLiteralCustom(obj, interpreter->errorOutput);
interpreter->errorOutput("\n"); interpreter->errorOutput("\n");
return -1; return -1;
@@ -1409,7 +1524,7 @@ int Toy_private_length(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments
int Toy_private_clear(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { int Toy_private_clear(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//if wrong number of arguments, fail //if wrong number of arguments, fail
if (arguments->count != 1) { if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _clear\n"); interpreter->errorOutput("Incorrect number of arguments to clear\n");
return -1; return -1;
} }
@@ -1417,12 +1532,16 @@ int Toy_private_clear(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
Toy_Literal obj = arguments->literals[0]; Toy_Literal obj = arguments->literals[0];
if (!TOY_IS_IDENTIFIER(idn)) { if (!TOY_IS_IDENTIFIER(idn)) {
interpreter->errorOutput("expected identifier in _clear\n"); interpreter->errorOutput("expected identifier in clear\n");
return -1; return -1;
} }
Toy_parseIdentifierToValue(interpreter, &obj); Toy_parseIdentifierToValue(interpreter, &obj);
if (TOY_IS_IDENTIFIER(obj)) {
return -1;
}
//NOTE: just pass in new compounds //NOTE: just pass in new compounds
switch(obj.type) { switch(obj.type) {
@@ -1433,7 +1552,7 @@ int Toy_private_clear(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
Toy_Literal obj = TOY_TO_ARRAY_LITERAL(array); Toy_Literal obj = TOY_TO_ARRAY_LITERAL(array);
if (!Toy_setScopeVariable(interpreter->scope, idn, obj, true)) { if (!Toy_setScopeVariable(interpreter->scope, idn, obj, true)) {
interpreter->errorOutput("Incorrect type assigned to array in _clear: "); interpreter->errorOutput("Incorrect type assigned to array in clear: ");
Toy_printLiteralCustom(obj, interpreter->errorOutput); Toy_printLiteralCustom(obj, interpreter->errorOutput);
interpreter->errorOutput("\n"); interpreter->errorOutput("\n");
return -1; return -1;
@@ -1451,7 +1570,7 @@ int Toy_private_clear(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
Toy_Literal obj = TOY_TO_DICTIONARY_LITERAL(dictionary); Toy_Literal obj = TOY_TO_DICTIONARY_LITERAL(dictionary);
if (!Toy_setScopeVariable(interpreter->scope, idn, obj, true)) { if (!Toy_setScopeVariable(interpreter->scope, idn, obj, true)) {
interpreter->errorOutput("Incorrect type assigned to dictionary in _clear: "); interpreter->errorOutput("Incorrect type assigned to dictionary in clear: ");
Toy_printLiteralCustom(obj, interpreter->errorOutput); Toy_printLiteralCustom(obj, interpreter->errorOutput);
interpreter->errorOutput("\n"); interpreter->errorOutput("\n");
return -1; return -1;
@@ -1463,7 +1582,7 @@ int Toy_private_clear(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
} }
default: default:
interpreter->errorOutput("Incorrect compound type in _clear: "); interpreter->errorOutput("Incorrect compound type in clear: ");
Toy_printLiteralCustom(obj, interpreter->errorOutput); Toy_printLiteralCustom(obj, interpreter->errorOutput);
interpreter->errorOutput("\n"); interpreter->errorOutput("\n");
return -1; return -1;
+37 -26
View File
@@ -15,23 +15,22 @@ STATIC_ASSERT(sizeof(unsigned char) == 1);
STATIC_ASSERT(sizeof(unsigned short) == 2); STATIC_ASSERT(sizeof(unsigned short) == 2);
STATIC_ASSERT(sizeof(unsigned int) == 4); STATIC_ASSERT(sizeof(unsigned int) == 4);
#ifndef TOY_EXPORT //declare the singleton with default values
Toy_CommandLine Toy_commandLine = {
//declare the singleton .error = false,
Toy_CommandLine Toy_commandLine; .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[]) { 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 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 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; 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 //option without a flag + ending in .tb = binary input
if (i < argc) { if (i < argc) {
if (strncmp(&(argv[i][strlen(argv[i]) - 3]), ".tb", 3) == 0) { if (strncmp(&(argv[i][strlen(argv[i]) - 3]), ".tb", 3) == 0) {
@@ -96,20 +108,21 @@ void Toy_initCommandLine(int argc, const char* argv[]) {
} }
void Toy_usageCommandLine(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[]) { void Toy_helpCommandLine(int argc, const char* argv[]) {
Toy_usageCommandLine(argc, argv); Toy_usageCommandLine(argc, argv);
printf("<file.tb>\t\t\tBinary input file in tb format, must be version %d.%d.%d.\n\n", TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH); printf(" -h, --help\t\t\tShow this help then exit.\n");
printf("-h\t| --help\t\tShow this help then exit.\n\n"); printf(" -v, --version\t\t\tShow version and copyright information then exit.\n");
printf("-v\t| --version\t\tShow version and copyright information then exit.\n\n"); printf(" -d, --debug\t\t\tBe verbose when operating.\n");
printf("-d\t| --debug\t\tBe verbose when operating.\n\n"); printf(" -f, --file filename\t\tParse, compile and execute the source file.\n");
printf("-f\t| --file filename\tParse, compile and execute the source file.\n\n"); printf(" -i, --input source\t\tParse, compile and execute this given string of source code.\n");
printf("-i\t| --input source\tParse, compile and execute this given string of source code.\n\n"); printf(" -c, --compile filename\tParse and compile the specified source file into an output file.\n");
printf("-c\t| --compile filename\tParse and compile the specified source file into an output file.\n\n"); printf(" -o, --output outfile\t\tName of the output file built with --compile (default: out.tb).\n");
printf("-o\t| --output outfile\tName of the output file built with --compile (default: out.tb).\n\n"); printf(" -t, --initial filename\tStart the repl as normal, after first running the given file.\n");
printf(" -n\t\t\t\tDisable the newline character at the end of the print statement.\n");
} }
void Toy_copyrightCommandLine(int argc, const char* argv[]) { void Toy_copyrightCommandLine(int argc, const char* argv[]) {
@@ -121,5 +134,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("2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\n\n");
printf("3. This notice may not be removed or altered from any source distribution.\n\n"); printf("3. This notice may not be removed or altered from any source distribution.\n\n");
} }
#endif
+22 -14
View File
@@ -4,24 +4,30 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#define TOY_VERSION_MAJOR 0 #define TOY_VERSION_MAJOR 1
#define TOY_VERSION_MINOR 8 #define TOY_VERSION_MINOR 0
#define TOY_VERSION_PATCH 1 #define TOY_VERSION_PATCH 1
#define TOY_VERSION_BUILD __DATE__ " " __TIME__ #define TOY_VERSION_BUILD __DATE__ " " __TIME__
//platform-specific specifications //platform/compiler-specific instructions
#if defined(__linux__) #if defined(__linux__) || defined(__MINGW32__) || defined(__GNUC__)
#define TOY_API extern #define TOY_API extern
#elif defined(_WIN32) || defined(WIN32) #elif defined(_MSC_VER)
#define TOY_API
#ifndef TOY_EXPORT
#define TOY_API __declspec(dllimport)
#else
#define TOY_API __declspec(dllexport)
#endif
#else #else
#define TOY_API
#define TOY_API extern
#endif #endif
#ifndef TOY_EXPORT
//for processing the command line arguments //for processing the command line arguments
typedef struct { typedef struct {
bool error; bool error;
@@ -32,14 +38,16 @@ typedef struct {
char* compilefile; char* compilefile;
char* outfile; //defaults to out.tb char* outfile; //defaults to out.tb
char* source; char* source;
char* initialfile;
bool enablePrintNewline;
bool verbose; bool verbose;
} Toy_CommandLine; } 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[]); TOY_API void Toy_usageCommandLine(int argc, const char* argv[]);
void Toy_helpCommandLine(int argc, const char* argv[]); TOY_API void Toy_helpCommandLine(int argc, const char* argv[]);
void Toy_copyrightCommandLine(int argc, const char* argv[]); TOY_API void Toy_copyrightCommandLine(int argc, const char* argv[]);
#endif
+24 -8
View File
@@ -9,6 +9,7 @@
#include "toy_console_colors.h" #include "toy_console_colors.h"
#include <stdio.h> #include <stdio.h>
#include <string.h>
void Toy_initCompiler(Toy_Compiler* compiler) { void Toy_initCompiler(Toy_Compiler* compiler) {
Toy_initLiteralArray(&compiler->literalCache); 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 //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) { 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); 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)TOY_OP_INDEX_ASSIGN; //1 byte WARNING: enum trickery
compiler->bytecode[compiler->count++] = (unsigned char)node->binary.opcode; //1 byte compiler->bytecode[compiler->count++] = (unsigned char)node->binary.opcode; //1 byte
return TOY_OP_EOF; return TOY_OP_EOF;
@@ -315,7 +322,7 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
//return this if... //return this if...
Toy_Opcode ret = Toy_writeCompilerWithJumps(compiler, node->binary.right, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); 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; 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 return TOY_OP_INDEX_ASSIGN; //override binary's instruction IF it is assign
} }
break; break;
case TOY_AST_NODE_PASS: {
return TOY_OP_PASS;
}
break;
} }
return TOY_OP_EOF; 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 if (op != TOY_OP_EOF) {//compensate for indexing & dot notation being screwy
compiler->bytecode[compiler->count++] = (unsigned char)op; //1 byte compiler->bytecode[compiler->count++] = (unsigned char)op; //1 byte
} }
//TODO: could free up AST Nodes
} }
void Toy_freeCompiler(Toy_Compiler* compiler) { void Toy_freeCompiler(Toy_Compiler* compiler) {
@@ -978,6 +992,7 @@ void Toy_freeCompiler(Toy_Compiler* compiler) {
compiler->bytecode = NULL; compiler->bytecode = NULL;
compiler->capacity = 0; compiler->capacity = 0;
compiler->count = 0; compiler->count = 0;
compiler->panic = false;
} }
static void emitByte(unsigned char** collationPtr, int* capacityPtr, int* countPtr, unsigned char byte) { 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 //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) { if (compiler->panic) {
fprintf(stderr, TOY_CC_ERROR "[internal] Can't collate a panicked compiler\n" TOY_CC_RESET); fprintf(stderr, TOY_CC_ERROR "[internal] Can't collate a panicked compiler\n" TOY_CC_RESET);
return NULL; return NULL;
@@ -1096,7 +1111,7 @@ static unsigned char* collateCompilerHeaderOpt(Toy_Compiler* compiler, int* size
Toy_Literal str = compiler->literalCache.literals[i]; Toy_Literal str = compiler->literalCache.literals[i];
for (int c = 0; c < TOY_AS_STRING(str)->length; c++) { for (int c = 0; c < (int)Toy_lengthRefString(TOY_AS_STRING(str)); c++) {
emitByte(&collation, &capacity, &count, Toy_toCString(TOY_AS_STRING(str))[c]); emitByte(&collation, &capacity, &count, Toy_toCString(TOY_AS_STRING(str))[c]);
} }
@@ -1167,17 +1182,17 @@ static unsigned char* collateCompilerHeaderOpt(Toy_Compiler* compiler, int* size
case TOY_LITERAL_FUNCTION_INTERMEDIATE: { case TOY_LITERAL_FUNCTION_INTERMEDIATE: {
//extract the compiler //extract the compiler
Toy_Literal fn = compiler->literalCache.literals[i]; Toy_Literal fn = compiler->literalCache.literals[i];
void* fnCompiler = TOY_AS_FUNCTION(fn).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) //collate the function into bytecode (without header)
int size = 0; size_t size = 0;
unsigned char* bytes = collateCompilerHeaderOpt((Toy_Compiler*)fnCompiler, &size, false); unsigned char* bytes = collateCompilerHeaderOpt((Toy_Compiler*)fnCompiler, &size, false);
//emit how long this section is, +1 for ending mark //emit how long this section is, +1 for ending mark
Toy_emitShort(&fnCollation, &fnCapacity, &fnCount, (unsigned short)size + 1); Toy_emitShort(&fnCollation, &fnCapacity, &fnCount, (unsigned short)size + 1);
//write the fn to the fn collation //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]); emitByte(&fnCollation, &fnCapacity, &fnCount, bytes[i]);
} }
@@ -1198,7 +1213,7 @@ static unsigned char* collateCompilerHeaderOpt(Toy_Compiler* compiler, int* size
Toy_Literal identifier = compiler->literalCache.literals[i]; Toy_Literal identifier = compiler->literalCache.literals[i];
for (int c = 0; c < TOY_AS_IDENTIFIER(identifier)->length; c++) { for (int c = 0; c < (int)Toy_lengthRefString(TOY_AS_IDENTIFIER(identifier)); c++) {
emitByte(&collation, &capacity, &count, Toy_toCString(TOY_AS_IDENTIFIER(identifier))[c]); emitByte(&collation, &capacity, &count, Toy_toCString(TOY_AS_IDENTIFIER(identifier))[c]);
} }
@@ -1284,6 +1299,7 @@ static unsigned char* collateCompilerHeaderOpt(Toy_Compiler* compiler, int* size
return collation; return collation;
} }
unsigned char* Toy_collateCompiler(Toy_Compiler* compiler, int* size) { //the whole point of the compiler is to alter bytecode, so leave it as non-const
unsigned char* Toy_collateCompiler(Toy_Compiler* compiler, size_t* size) {
return collateCompilerHeaderOpt(compiler, size, true); 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); TOY_API void Toy_freeCompiler(Toy_Compiler* compiler);
//embed the header, data section, code section, function section, etc. //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);
+34
View File
@@ -2,6 +2,9 @@
//NOTE: you need both font AND background for these to work //NOTE: you need both font AND background for these to work
//platform/compiler-specific instructions
#if defined(__linux__) || defined(__MINGW32__) || defined(__GNUC__)
//fonts color //fonts color
#define TOY_CC_FONT_BLACK "\033[30;" #define TOY_CC_FONT_BLACK "\033[30;"
#define TOY_CC_FONT_RED "\033[31;" #define TOY_CC_FONT_RED "\033[31;"
@@ -28,3 +31,34 @@
#define TOY_CC_WARN TOY_CC_FONT_YELLOW 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_ERROR TOY_CC_FONT_RED TOY_CC_BACK_BLACK
#define TOY_CC_RESET "\033[0m" #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
+216 -91
View File
@@ -12,29 +12,30 @@
#include <string.h> #include <string.h>
static void printWrapper(const char* output) { static void printWrapper(const char* output) {
if (Toy_commandLine.enablePrintNewline) {
printf("%s\n", output);
}
else {
printf("%s", output); printf("%s", output);
printf("\n"); //default new line }
} }
static void assertWrapper(const char* output) { static void assertWrapper(const char* output) {
fprintf(stderr, TOY_CC_ERROR "Assertion failure: "); fprintf(stderr, TOY_CC_ERROR "Assertion failure: %s\n" TOY_CC_RESET, output);
fprintf(stderr, "%s", output);
fprintf(stderr, "\n" TOY_CC_RESET); //default new line
} }
static void errorWrapper(const char* output) { static void errorWrapper(const char* output) {
fprintf(stderr, TOY_CC_ERROR "%s" TOY_CC_RESET, output); //no newline fprintf(stderr, TOY_CC_ERROR "%s" TOY_CC_RESET, output); //no newline
} }
bool Toy_injectNativeFn(Toy_Interpreter* interpreter, char* name, Toy_NativeFn func) { bool Toy_injectNativeFn(Toy_Interpreter* interpreter, const char* name, Toy_NativeFn func) {
//reject reserved words //reject reserved words
if (Toy_findTypeByKeyword(name) != TOY_TOKEN_EOF) { if (Toy_findTypeByKeyword(name) != TOY_TOKEN_EOF) {
interpreter->errorOutput("Can't override an existing keyword\n"); interpreter->errorOutput("Can't override an existing keyword\n");
return false; return false;
} }
int identifierLength = strlen(name); Toy_Literal identifier = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString(name));
Toy_Literal identifier = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefStringLength(name, identifierLength));
//make sure the name isn't taken //make sure the name isn't taken
if (Toy_existsLiteralDictionary(&interpreter->scope->variables, identifier)) { if (Toy_existsLiteralDictionary(&interpreter->scope->variables, identifier)) {
@@ -54,7 +55,7 @@ bool Toy_injectNativeFn(Toy_Interpreter* interpreter, char* name, Toy_NativeFn f
return true; return true;
} }
bool Toy_injectNativeHook(Toy_Interpreter* interpreter, char* name, Toy_HookFn hook) { bool Toy_injectNativeHook(Toy_Interpreter* interpreter, const char* name, Toy_HookFn hook) {
//reject reserved words //reject reserved words
if (Toy_findTypeByKeyword(name) != TOY_TOKEN_EOF) { if (Toy_findTypeByKeyword(name) != TOY_TOKEN_EOF) {
interpreter->errorOutput("Can't inject a hook on an existing keyword\n"); interpreter->errorOutput("Can't inject a hook on an existing keyword\n");
@@ -169,40 +170,40 @@ void Toy_setInterpreterError(Toy_Interpreter* interpreter, Toy_PrintFn errorOutp
} }
//utils //utils
static unsigned char readByte(unsigned char* tb, int* count) { static unsigned char readByte(const unsigned char* tb, int* count) {
unsigned char ret = *(unsigned char*)(tb + *count); unsigned char ret = *(unsigned char*)(tb + *count);
*count += 1; *count += 1;
return ret; return ret;
} }
static unsigned short readShort(unsigned char* tb, int* count) { static unsigned short readShort(const unsigned char* tb, int* count) {
unsigned short ret = 0; unsigned short ret = 0;
memcpy(&ret, tb + *count, 2); memcpy(&ret, tb + *count, 2);
*count += 2; *count += 2;
return ret; return ret;
} }
static int readInt(unsigned char* tb, int* count) { static int readInt(const unsigned char* tb, int* count) {
int ret = 0; int ret = 0;
memcpy(&ret, tb + *count, 4); memcpy(&ret, tb + *count, 4);
*count += 4; *count += 4;
return ret; return ret;
} }
static float readFloat(unsigned char* tb, int* count) { static float readFloat(const unsigned char* tb, int* count) {
float ret = 0; float ret = 0;
memcpy(&ret, tb + *count, 4); memcpy(&ret, tb + *count, 4);
*count += 4; *count += 4;
return ret; return ret;
} }
static char* readString(unsigned char* tb, int* count) { static const char* readString(const unsigned char* tb, int* count) {
unsigned char* ret = tb + *count; const unsigned char* ret = tb + *count;
*count += strlen((char*)ret) + 1; //+1 for null character *count += strlen((char*)ret) + 1; //+1 for null character
return (char*)ret; return (const char*)ret;
} }
static void consumeByte(Toy_Interpreter* interpreter, unsigned char byte, unsigned char* tb, int* count) { static void consumeByte(Toy_Interpreter* interpreter, unsigned char byte, const unsigned char* tb, int* count) {
if (byte != tb[*count]) { if (byte != tb[*count]) {
char buffer[512]; char buffer[512];
snprintf(buffer, 512, "[internal] Failed to consume the correct byte (expected %u, found %u)\n", byte, tb[*count]); snprintf(buffer, 512, "[internal] Failed to consume the correct byte (expected %u, found %u)\n", byte, tb[*count]);
@@ -211,7 +212,7 @@ static void consumeByte(Toy_Interpreter* interpreter, unsigned char byte, unsign
*count += 1; *count += 1;
} }
static void consumeShort(Toy_Interpreter* interpreter, unsigned short bytes, unsigned char* tb, int* count) { static void consumeShort(Toy_Interpreter* interpreter, unsigned short bytes, const unsigned char* tb, int* count) {
if (bytes != *(unsigned short*)(tb + *count)) { if (bytes != *(unsigned short*)(tb + *count)) {
char buffer[512]; char buffer[512];
snprintf(buffer, 512, "[internal] Failed to consume the correct bytes (expected %u, found %u)\n", bytes, *(unsigned short*)(tb + *count)); snprintf(buffer, 512, "[internal] Failed to consume the correct bytes (expected %u, found %u)\n", bytes, *(unsigned short*)(tb + *count));
@@ -230,6 +231,12 @@ static bool execAssert(Toy_Interpreter* interpreter) {
Toy_freeLiteral(lhsIdn); Toy_freeLiteral(lhsIdn);
} }
if (TOY_IS_IDENTIFIER(lhs)) {
Toy_freeLiteral(lhs);
Toy_freeLiteral(rhs);
return false;
}
if (!TOY_IS_STRING(rhs)) { if (!TOY_IS_STRING(rhs)) {
interpreter->errorOutput("The assert keyword needs a string as the second argument, received: "); interpreter->errorOutput("The assert keyword needs a string as the second argument, received: ");
Toy_printLiteralCustom(rhs, interpreter->errorOutput); Toy_printLiteralCustom(rhs, interpreter->errorOutput);
@@ -264,6 +271,11 @@ static bool execPrint(Toy_Interpreter* interpreter) {
Toy_freeLiteral(idn); Toy_freeLiteral(idn);
} }
if (TOY_IS_IDENTIFIER(lit)) {
Toy_freeLiteral(lit);
return false;
}
Toy_printLiteralCustom(lit, interpreter->printOutput); Toy_printLiteralCustom(lit, interpreter->printOutput);
Toy_freeLiteral(lit); Toy_freeLiteral(lit);
@@ -296,6 +308,11 @@ static bool rawLiteral(Toy_Interpreter* interpreter) {
Toy_freeLiteral(idn); Toy_freeLiteral(idn);
} }
if (TOY_IS_IDENTIFIER(lit)) {
Toy_freeLiteral(lit);
return false;
}
Toy_pushLiteralArray(&interpreter->stack, lit); Toy_pushLiteralArray(&interpreter->stack, lit);
Toy_freeLiteral(lit); Toy_freeLiteral(lit);
@@ -311,6 +328,11 @@ static bool execNegate(Toy_Interpreter* interpreter) {
Toy_freeLiteral(idn); Toy_freeLiteral(idn);
} }
if (TOY_IS_IDENTIFIER(lit)) {
Toy_freeLiteral(lit);
return false;
}
if (TOY_IS_INTEGER(lit)) { if (TOY_IS_INTEGER(lit)) {
lit = TOY_TO_INTEGER_LITERAL(-TOY_AS_INTEGER(lit)); lit = TOY_TO_INTEGER_LITERAL(-TOY_AS_INTEGER(lit));
} }
@@ -342,6 +364,11 @@ static bool execInvert(Toy_Interpreter* interpreter) {
Toy_freeLiteral(idn); Toy_freeLiteral(idn);
} }
if (TOY_IS_IDENTIFIER(lit)) {
Toy_freeLiteral(lit);
return false;
}
if (TOY_IS_BOOLEAN(lit)) { if (TOY_IS_BOOLEAN(lit)) {
lit = TOY_TO_BOOLEAN_LITERAL(!TOY_AS_BOOLEAN(lit)); lit = TOY_TO_BOOLEAN_LITERAL(!TOY_AS_BOOLEAN(lit));
} }
@@ -375,6 +402,12 @@ static bool execArithmetic(Toy_Interpreter* interpreter, Toy_Opcode opcode) {
Toy_freeLiteral(lhsIdn); Toy_freeLiteral(lhsIdn);
} }
if (TOY_IS_IDENTIFIER(lhs) || TOY_IS_IDENTIFIER(rhs)) {
Toy_freeLiteral(lhs);
Toy_freeLiteral(rhs);
return false;
}
//special case for string concatenation ONLY //special case for string concatenation ONLY
if (TOY_IS_STRING(lhs) && TOY_IS_STRING(rhs) && (opcode == TOY_OP_ADDITION || opcode == TOY_OP_VAR_ADDITION_ASSIGN)) { if (TOY_IS_STRING(lhs) && TOY_IS_STRING(rhs) && (opcode == TOY_OP_ADDITION || opcode == TOY_OP_VAR_ADDITION_ASSIGN)) {
//check for overflow //check for overflow
@@ -507,6 +540,10 @@ static Toy_Literal parseTypeToValue(Toy_Interpreter* interpreter, Toy_Literal ty
Toy_freeLiteral(typeIdn); Toy_freeLiteral(typeIdn);
} }
if (TOY_IS_IDENTIFIER(type)) {
return TOY_TO_NULL_LITERAL;
}
//if this is an array or dictionary, continue to the subtypes //if this is an array or dictionary, continue to the subtypes
if (TOY_IS_TYPE(type) && (TOY_AS_TYPE(type).typeOf == TOY_LITERAL_ARRAY || TOY_AS_TYPE(type).typeOf == TOY_LITERAL_DICTIONARY)) { if (TOY_IS_TYPE(type) && (TOY_AS_TYPE(type).typeOf == TOY_LITERAL_ARRAY || TOY_AS_TYPE(type).typeOf == TOY_LITERAL_DICTIONARY)) {
for (int i = 0; i < TOY_AS_TYPE(type).count; i++) { for (int i = 0; i < TOY_AS_TYPE(type).count; i++) {
@@ -547,6 +584,12 @@ static bool execVarDecl(Toy_Interpreter* interpreter, bool lng) {
Toy_freeLiteral(typeIdn); Toy_freeLiteral(typeIdn);
} }
if (TOY_IS_IDENTIFIER(type)) {
Toy_freeLiteral(identifier);
Toy_freeLiteral(type);
return false;
}
//BUGFIX: because identifiers are getting embedded in type definitions //BUGFIX: because identifiers are getting embedded in type definitions
type = parseTypeToValue(interpreter, type); type = parseTypeToValue(interpreter, type);
@@ -564,6 +607,13 @@ static bool execVarDecl(Toy_Interpreter* interpreter, bool lng) {
Toy_freeLiteral(valIdn); Toy_freeLiteral(valIdn);
} }
if (TOY_IS_IDENTIFIER(val)) {
Toy_freeLiteral(identifier);
Toy_freeLiteral(type);
Toy_freeLiteral(val);
return false;
}
if (TOY_IS_ARRAY(val) || TOY_IS_DICTIONARY(val)) { if (TOY_IS_ARRAY(val) || TOY_IS_DICTIONARY(val)) {
Toy_parseCompoundToPureValues(interpreter, &val); Toy_parseCompoundToPureValues(interpreter, &val);
} }
@@ -644,6 +694,12 @@ static bool execVarAssign(Toy_Interpreter* interpreter) {
Toy_freeLiteral(rhsIdn); Toy_freeLiteral(rhsIdn);
} }
if (TOY_IS_IDENTIFIER(rhs)) {
Toy_freeLiteral(lhs);
Toy_freeLiteral(rhs);
return false;
}
if (TOY_IS_ARRAY(rhs) || TOY_IS_DICTIONARY(rhs)) { if (TOY_IS_ARRAY(rhs) || TOY_IS_DICTIONARY(rhs)) {
Toy_parseCompoundToPureValues(interpreter, &rhs); Toy_parseCompoundToPureValues(interpreter, &rhs);
} }
@@ -713,6 +769,12 @@ static bool execValCast(Toy_Interpreter* interpreter) {
Toy_freeLiteral(valueIdn); Toy_freeLiteral(valueIdn);
} }
if (TOY_IS_IDENTIFIER(value)) {
Toy_freeLiteral(type);
Toy_freeLiteral(value);
return false;
}
Toy_Literal result = TOY_TO_NULL_LITERAL; Toy_Literal result = TOY_TO_NULL_LITERAL;
if (TOY_IS_NULL(value)) { if (TOY_IS_NULL(value)) {
@@ -847,6 +909,12 @@ static bool execCompareEqual(Toy_Interpreter* interpreter, bool invert) {
Toy_freeLiteral(lhsIdn); Toy_freeLiteral(lhsIdn);
} }
if (TOY_IS_IDENTIFIER(lhs) || TOY_IS_IDENTIFIER(rhs)) {
Toy_freeLiteral(lhs);
Toy_freeLiteral(rhs);
return false;
}
bool result = Toy_literalsAreEqual(lhs, rhs); bool result = Toy_literalsAreEqual(lhs, rhs);
if (invert) { if (invert) {
@@ -875,6 +943,12 @@ static bool execCompareLess(Toy_Interpreter* interpreter, bool invert) {
Toy_freeLiteral(lhsIdn); Toy_freeLiteral(lhsIdn);
} }
if (TOY_IS_IDENTIFIER(lhs) || TOY_IS_IDENTIFIER(rhs)) {
Toy_freeLiteral(lhs);
Toy_freeLiteral(rhs);
return false;
}
//not a number, return falure //not a number, return falure
if (!(TOY_IS_INTEGER(lhs) || TOY_IS_FLOAT(lhs))) { if (!(TOY_IS_INTEGER(lhs) || TOY_IS_FLOAT(lhs))) {
interpreter->errorOutput("Incorrect type in comparison, value \""); interpreter->errorOutput("Incorrect type in comparison, value \"");
@@ -935,6 +1009,12 @@ static bool execCompareLessEqual(Toy_Interpreter* interpreter, bool invert) {
Toy_freeLiteral(lhsIdn); Toy_freeLiteral(lhsIdn);
} }
if (TOY_IS_IDENTIFIER(lhs) || TOY_IS_IDENTIFIER(rhs)) {
Toy_freeLiteral(lhs);
Toy_freeLiteral(rhs);
return false;
}
//not a number, return falure //not a number, return falure
if (!(TOY_IS_INTEGER(lhs) || TOY_IS_FLOAT(lhs))) { if (!(TOY_IS_INTEGER(lhs) || TOY_IS_FLOAT(lhs))) {
interpreter->errorOutput("Incorrect type in comparison, value \""); interpreter->errorOutput("Incorrect type in comparison, value \"");
@@ -996,6 +1076,12 @@ static bool execAnd(Toy_Interpreter* interpreter) {
Toy_freeLiteral(lhsIdn); Toy_freeLiteral(lhsIdn);
} }
if (TOY_IS_IDENTIFIER(lhs) || TOY_IS_IDENTIFIER(rhs)) {
Toy_freeLiteral(lhs);
Toy_freeLiteral(rhs);
return false;
}
if (TOY_IS_TRUTHY(lhs) && TOY_IS_TRUTHY(rhs)) { if (TOY_IS_TRUTHY(lhs) && TOY_IS_TRUTHY(rhs)) {
Toy_pushLiteralArray(&interpreter->stack, TOY_TO_BOOLEAN_LITERAL(true)); Toy_pushLiteralArray(&interpreter->stack, TOY_TO_BOOLEAN_LITERAL(true));
} }
@@ -1023,6 +1109,12 @@ static bool execOr(Toy_Interpreter* interpreter) {
Toy_freeLiteral(lhsIdn); Toy_freeLiteral(lhsIdn);
} }
if (TOY_IS_IDENTIFIER(lhs) || TOY_IS_IDENTIFIER(rhs)) {
Toy_freeLiteral(lhs);
Toy_freeLiteral(rhs);
return false;
}
if (TOY_IS_TRUTHY(lhs) || TOY_IS_TRUTHY(rhs)) { if (TOY_IS_TRUTHY(lhs) || TOY_IS_TRUTHY(rhs)) {
Toy_pushLiteralArray(&interpreter->stack, TOY_TO_BOOLEAN_LITERAL(true)); Toy_pushLiteralArray(&interpreter->stack, TOY_TO_BOOLEAN_LITERAL(true));
} }
@@ -1066,6 +1158,11 @@ static bool execFalseJump(Toy_Interpreter* interpreter) {
Toy_freeLiteral(litIdn); Toy_freeLiteral(litIdn);
} }
if (TOY_IS_IDENTIFIER(lit)) {
Toy_freeLiteral(lit);
return false;
}
if (TOY_IS_NULL(lit)) { if (TOY_IS_NULL(lit)) {
interpreter->errorOutput("Null detected in comparison\n"); interpreter->errorOutput("Null detected in comparison\n");
Toy_freeLiteral(lit); Toy_freeLiteral(lit);
@@ -1085,6 +1182,8 @@ static bool execFalseJump(Toy_Interpreter* interpreter) {
static void execInterpreter(Toy_Interpreter*); static void execInterpreter(Toy_Interpreter*);
static void readInterpreterSections(Toy_Interpreter* 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) { static bool execFnCall(Toy_Interpreter* interpreter, bool looseFirstArgument) {
//BUGFIX: depth check - don't drown! //BUGFIX: depth check - don't drown!
if (interpreter->depth >= 200) { if (interpreter->depth >= 200) {
@@ -1121,24 +1220,7 @@ static bool execFnCall(Toy_Interpreter* interpreter, bool looseFirstArgument) {
Toy_freeLiteral(lit); Toy_freeLiteral(lit);
} }
//let's screw with the fn name, too //get the function literal
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));
}
Toy_Literal func = identifier; Toy_Literal func = identifier;
if (!Toy_parseIdentifierToValue(interpreter, &func)) { if (!Toy_parseIdentifierToValue(interpreter, &func)) {
@@ -1148,30 +1230,7 @@ static bool execFnCall(Toy_Interpreter* interpreter, bool looseFirstArgument) {
return false; return false;
} }
//check for side-loaded native functions if (!TOY_IS_FUNCTION(func) && !TOY_IS_FUNCTION_NATIVE(func)) {
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)) {
interpreter->errorOutput("Function not found: "); interpreter->errorOutput("Function not found: ");
Toy_printLiteralCustom(identifier, interpreter->errorOutput); Toy_printLiteralCustom(identifier, interpreter->errorOutput);
interpreter->errorOutput("\n"); interpreter->errorOutput("\n");
@@ -1182,7 +1241,18 @@ static bool execFnCall(Toy_Interpreter* interpreter, bool looseFirstArgument) {
return false; 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) { if (!ret) {
interpreter->errorOutput("Error encountered in function \""); interpreter->errorOutput("Error encountered in function \"");
@@ -1190,6 +1260,7 @@ static bool execFnCall(Toy_Interpreter* interpreter, bool looseFirstArgument) {
interpreter->errorOutput("\"\n"); interpreter->errorOutput("\"\n");
} }
Toy_freeLiteralArray(&correct);
Toy_freeLiteralArray(&arguments); Toy_freeLiteralArray(&arguments);
Toy_freeLiteral(func); Toy_freeLiteral(func);
Toy_freeLiteral(stackSize); Toy_freeLiteral(stackSize);
@@ -1198,25 +1269,17 @@ static bool execFnCall(Toy_Interpreter* interpreter, bool looseFirstArgument) {
return ret; return ret;
} }
//expects arguments in correct order
bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_LiteralArray* arguments, Toy_LiteralArray* returns) { bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_LiteralArray* arguments, Toy_LiteralArray* returns) {
//check for side-loaded native functions //check for side-loaded native functions
if (TOY_IS_FUNCTION_NATIVE(func)) { if (TOY_IS_FUNCTION_NATIVE(func)) {
//reverse the order to the correct order //TODO: parse out identifier values, see issue #64
Toy_LiteralArray correct;
Toy_initLiteralArray(&correct);
while(arguments->count) {
Toy_Literal lit = Toy_popLiteralArray(arguments);
Toy_pushLiteralArray(&correct, lit);
Toy_freeLiteral(lit);
}
//call the native function //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) { if (returnsCount < 0) {
interpreter->errorOutput("Unknown error from native function\n"); // interpreter->errorOutput("Unknown error from native function\n");
Toy_freeLiteralArray(&correct);
return false; return false;
} }
@@ -1238,13 +1301,12 @@ bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_Liter
} }
Toy_freeLiteralArray(&returnsFromInner); Toy_freeLiteralArray(&returnsFromInner);
Toy_freeLiteralArray(&correct);
return true; return true;
} }
//normal Toy function //normal Toy function
if (!TOY_IS_FUNCTION(func)) { if (!TOY_IS_FUNCTION(func)) {
interpreter->errorOutput("Function required in Toy_callLiteralFn()\n"); interpreter->errorOutput("Function literal required in Toy_callLiteralFn()\n");
return false; return false;
} }
@@ -1254,8 +1316,8 @@ bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_Liter
//init the inner interpreter manually //init the inner interpreter manually
Toy_initLiteralArray(&inner.literalCache); Toy_initLiteralArray(&inner.literalCache);
inner.scope = Toy_pushScope(func.as.function.scope); inner.scope = Toy_pushScope(func.as.function.scope);
inner.bytecode = TOY_AS_FUNCTION(func).bytecode; inner.bytecode = TOY_AS_FUNCTION(func).inner.bytecode;
inner.length = TOY_AS_FUNCTION(func).length; inner.length = TOY_AS_FUNCTION_BYTECODE_LENGTH(func);
inner.count = 0; inner.count = 0;
inner.codeStart = -1; inner.codeStart = -1;
inner.depth = interpreter->depth + 1; inner.depth = interpreter->depth + 1;
@@ -1292,6 +1354,9 @@ bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_Liter
return false; return false;
} }
//BUGFIX: access the arguments from the beginning
int argumentIndex = 0;
//contents is the indexes of identifier & type //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 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 //declare and define each entry in the scope
@@ -1307,13 +1372,28 @@ bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_Liter
return false; 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; Toy_Literal argIdn = arg;
if (TOY_IS_IDENTIFIER(arg) && Toy_parseIdentifierToValue(interpreter, &arg)) { if (TOY_IS_IDENTIFIER(arg) && Toy_parseIdentifierToValue(interpreter, &arg)) {
Toy_freeLiteral(argIdn); Toy_freeLiteral(argIdn);
} }
if (TOY_IS_IDENTIFIER(arg)) {
//free, and skip out
Toy_freeLiteral(arg);
Toy_popScope(inner.scope);
Toy_freeLiteralArray(&inner.stack);
Toy_freeLiteralArray(&inner.literalCache);
return false;
}
if (!Toy_setScopeVariable(inner.scope, paramArray->literals[i], arg, false)) { if (!Toy_setScopeVariable(inner.scope, paramArray->literals[i], arg, false)) {
interpreter->errorOutput("[internal] Could not define parameter (bad type?)\n"); interpreter->errorOutput("[internal] Could not define parameter (bad type?)\n");
@@ -1334,8 +1414,9 @@ bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_Liter
Toy_LiteralArray rest; Toy_LiteralArray rest;
Toy_initLiteralArray(&rest); Toy_initLiteralArray(&rest);
while (arguments->count > 0) { //access the arguments in order
Toy_Literal lit = Toy_popLiteralArray(arguments); while (argumentIndex < arguments->count) {
Toy_Literal lit = Toy_copyLiteral(arguments->literals[argumentIndex++]);
Toy_pushLiteralArray(&rest, lit); Toy_pushLiteralArray(&rest, lit);
Toy_freeLiteral(lit); Toy_freeLiteral(lit);
} }
@@ -1442,11 +1523,14 @@ bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_Liter
Toy_freeLiteralArray(&inner.stack); Toy_freeLiteralArray(&inner.stack);
Toy_freeLiteralArray(&inner.literalCache); Toy_freeLiteralArray(&inner.literalCache);
//BUGFIX: this function needs to eat the arguments
Toy_freeLiteralArray(arguments);
//actual bytecode persists until next call //actual bytecode persists until next call
return true; return true;
} }
bool Toy_callFn(Toy_Interpreter* interpreter, char* name, Toy_LiteralArray* arguments, Toy_LiteralArray* returns) { bool Toy_callFn(Toy_Interpreter* interpreter, const char* name, Toy_LiteralArray* arguments, Toy_LiteralArray* returns) {
Toy_Literal key = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefStringLength(name, strlen(name))); Toy_Literal key = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefStringLength(name, strlen(name)));
Toy_Literal val = TOY_TO_NULL_LITERAL; Toy_Literal val = TOY_TO_NULL_LITERAL;
@@ -1478,6 +1562,12 @@ static bool execFnReturn(Toy_Interpreter* interpreter) {
Toy_freeLiteral(litIdn); Toy_freeLiteral(litIdn);
} }
if (TOY_IS_IDENTIFIER(lit)) {
Toy_freeLiteralArray(&returns);
Toy_freeLiteral(lit);
return false;
}
if (TOY_IS_ARRAY(lit) || TOY_IS_DICTIONARY(lit)) { if (TOY_IS_ARRAY(lit) || TOY_IS_DICTIONARY(lit)) {
Toy_parseCompoundToPureValues(interpreter, &lit); Toy_parseCompoundToPureValues(interpreter, &lit);
} }
@@ -1507,7 +1597,7 @@ static bool execImport(Toy_Interpreter* interpreter) {
if (!Toy_existsLiteralDictionary(interpreter->hooks, identifier)) { if (!Toy_existsLiteralDictionary(interpreter->hooks, identifier)) {
interpreter->errorOutput("Unknown library name in import statement: "); interpreter->errorOutput("Unknown library name in import statement: ");
Toy_printLiteralCustom(identifier, interpreter->errorOutput); Toy_printLiteralCustom(identifier, interpreter->errorOutput);
interpreter->errorOutput("\"\n"); interpreter->errorOutput("\n");
Toy_freeLiteral(alias); Toy_freeLiteral(alias);
Toy_freeLiteral(identifier); Toy_freeLiteral(identifier);
@@ -1549,6 +1639,17 @@ static bool execIndex(Toy_Interpreter* interpreter, bool assignIntermediate) {
freeIdn = true; freeIdn = true;
} }
if (TOY_IS_IDENTIFIER(compound)) {
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
if (freeIdn) {
Toy_freeLiteral(compoundIdn);
}
return true;
}
if (!TOY_IS_ARRAY(compound) && !TOY_IS_DICTIONARY(compound) && !TOY_IS_STRING(compound)) { if (!TOY_IS_ARRAY(compound) && !TOY_IS_DICTIONARY(compound) && !TOY_IS_STRING(compound)) {
interpreter->errorOutput("Unknown compound found in indexing notation: "); interpreter->errorOutput("Unknown compound found in indexing notation: ");
Toy_printLiteralCustom(compound, interpreter->errorOutput); Toy_printLiteralCustom(compound, interpreter->errorOutput);
@@ -1633,12 +1734,33 @@ static bool execIndexAssign(Toy_Interpreter* interpreter) {
Toy_freeLiteral(assignIdn); Toy_freeLiteral(assignIdn);
} }
if (TOY_IS_IDENTIFIER(assign)) {
Toy_freeLiteral(compound);
Toy_freeLiteral(first);
Toy_freeLiteral(second);
Toy_freeLiteral(third);
Toy_freeLiteral(assign);
return false;
}
Toy_Literal compoundIdn = compound; Toy_Literal compoundIdn = compound;
bool freeIdn = false; bool freeIdn = false;
if (TOY_IS_IDENTIFIER(compound) && Toy_parseIdentifierToValue(interpreter, &compound)) { if (TOY_IS_IDENTIFIER(compound) && Toy_parseIdentifierToValue(interpreter, &compound)) {
freeIdn = true; freeIdn = true;
} }
if (TOY_IS_IDENTIFIER(compound)) {
Toy_freeLiteral(compound);
Toy_freeLiteral(first);
Toy_freeLiteral(second);
Toy_freeLiteral(third);
Toy_freeLiteral(assign);
if (freeIdn) {
Toy_freeLiteral(compoundIdn);
}
return false;
}
if (!TOY_IS_ARRAY(compound) && !TOY_IS_DICTIONARY(compound) && !TOY_IS_STRING(compound)) { if (!TOY_IS_ARRAY(compound) && !TOY_IS_DICTIONARY(compound) && !TOY_IS_STRING(compound)) {
interpreter->errorOutput("Unknown compound found in index assigning notation\n"); interpreter->errorOutput("Unknown compound found in index assigning notation\n");
Toy_freeLiteral(assign); Toy_freeLiteral(assign);
@@ -1827,6 +1949,10 @@ static void execInterpreter(Toy_Interpreter* interpreter) {
while(opcode != TOY_OP_EOF && opcode != TOY_OP_SECTION_END && !interpreter->panic) { while(opcode != TOY_OP_EOF && opcode != TOY_OP_SECTION_END && !interpreter->panic) {
switch(opcode) { switch(opcode) {
case TOY_OP_PASS:
//DO NOTHING
break;
case TOY_OP_ASSERT: case TOY_OP_ASSERT:
if (!execAssert(interpreter)) { if (!execAssert(interpreter)) {
return; return;
@@ -2125,7 +2251,7 @@ static void readInterpreterSections(Toy_Interpreter* interpreter) {
break; break;
case TOY_LITERAL_STRING: { case TOY_LITERAL_STRING: {
char* s = readString(interpreter->bytecode, &interpreter->count); const char* s = readString(interpreter->bytecode, &interpreter->count);
int length = strlen(s); int length = strlen(s);
Toy_Literal literal = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(s, length)); Toy_Literal literal = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(s, length));
Toy_pushLiteralArray(&interpreter->literalCache, literal); Toy_pushLiteralArray(&interpreter->literalCache, literal);
@@ -2222,7 +2348,7 @@ static void readInterpreterSections(Toy_Interpreter* interpreter) {
break; break;
case TOY_LITERAL_IDENTIFIER: { case TOY_LITERAL_IDENTIFIER: {
char* str = readString(interpreter->bytecode, &interpreter->count); const char* str = readString(interpreter->bytecode, &interpreter->count);
int length = strlen(str); int length = strlen(str);
Toy_Literal identifier = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefStringLength(str, length)); Toy_Literal identifier = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefStringLength(str, length));
@@ -2335,7 +2461,6 @@ static void readInterpreterSections(Toy_Interpreter* interpreter) {
//change the type to normal //change the type to normal
interpreter->literalCache.literals[i] = TOY_TO_FUNCTION_LITERAL(bytes, size); interpreter->literalCache.literals[i] = TOY_TO_FUNCTION_LITERAL(bytes, size);
TOY_AS_FUNCTION(interpreter->literalCache.literals[i]).scope = NULL;
} }
} }
@@ -2356,7 +2481,7 @@ void Toy_initInterpreter(Toy_Interpreter* interpreter) {
Toy_resetInterpreter(interpreter); Toy_resetInterpreter(interpreter);
} }
void Toy_runInterpreter(Toy_Interpreter* interpreter, unsigned char* bytecode, int length) { void Toy_runInterpreter(Toy_Interpreter* interpreter, const unsigned char* bytecode, size_t length) {
//initialize here instead of initInterpreter() //initialize here instead of initInterpreter()
Toy_initLiteralArray(&interpreter->literalCache); Toy_initLiteralArray(&interpreter->literalCache);
interpreter->bytecode = NULL; interpreter->bytecode = NULL;
@@ -2445,12 +2570,12 @@ void Toy_resetInterpreter(Toy_Interpreter* interpreter) {
interpreter->scope = Toy_pushScope(NULL); interpreter->scope = Toy_pushScope(NULL);
//globally available functions //globally available functions
Toy_injectNativeFn(interpreter, "_set", Toy_private_set); Toy_injectNativeFn(interpreter, "set", Toy_private_set);
Toy_injectNativeFn(interpreter, "_get", Toy_private_get); Toy_injectNativeFn(interpreter, "get", Toy_private_get);
Toy_injectNativeFn(interpreter, "_push", Toy_private_push); Toy_injectNativeFn(interpreter, "push", Toy_private_push);
Toy_injectNativeFn(interpreter, "_pop", Toy_private_pop); Toy_injectNativeFn(interpreter, "pop", Toy_private_pop);
Toy_injectNativeFn(interpreter, "_length", Toy_private_length); Toy_injectNativeFn(interpreter, "length", Toy_private_length);
Toy_injectNativeFn(interpreter, "_clear", Toy_private_clear); Toy_injectNativeFn(interpreter, "clear", Toy_private_clear);
} }
void Toy_freeInterpreter(Toy_Interpreter* interpreter) { void Toy_freeInterpreter(Toy_Interpreter* interpreter) {
+5 -7
View File
@@ -6,12 +6,10 @@
#include "toy_literal_dictionary.h" #include "toy_literal_dictionary.h"
#include "toy_scope.h" #include "toy_scope.h"
typedef void (*Toy_PrintFn)(const char*);
//the interpreter acts depending on the bytecode instructions //the interpreter acts depending on the bytecode instructions
typedef struct Toy_Interpreter { typedef struct Toy_Interpreter {
//input //input
unsigned char* bytecode; const unsigned char* bytecode;
int length; int length;
int count; int count;
int codeStart; //BUGFIX: for jumps, must be initialized to -1 int codeStart; //BUGFIX: for jumps, must be initialized to -1
@@ -34,11 +32,11 @@ typedef struct Toy_Interpreter {
} Toy_Interpreter; } Toy_Interpreter;
//native API //native API
TOY_API bool Toy_injectNativeFn(Toy_Interpreter* interpreter, char* name, Toy_NativeFn func); TOY_API bool Toy_injectNativeFn(Toy_Interpreter* interpreter, const char* name, Toy_NativeFn func);
TOY_API bool Toy_injectNativeHook(Toy_Interpreter* interpreter, char* name, Toy_HookFn hook); TOY_API bool Toy_injectNativeHook(Toy_Interpreter* interpreter, const char* name, Toy_HookFn hook);
TOY_API bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_LiteralArray* arguments, Toy_LiteralArray* returns); TOY_API bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_LiteralArray* arguments, Toy_LiteralArray* returns);
TOY_API bool Toy_callFn(Toy_Interpreter* interpreter, char* name, Toy_LiteralArray* arguments, Toy_LiteralArray* returns); TOY_API bool Toy_callFn(Toy_Interpreter* interpreter, const char* name, Toy_LiteralArray* arguments, Toy_LiteralArray* returns);
//utilities for the host program //utilities for the host program
TOY_API bool Toy_parseIdentifierToValue(Toy_Interpreter* interpreter, Toy_Literal* literalPtr); TOY_API bool Toy_parseIdentifierToValue(Toy_Interpreter* interpreter, Toy_Literal* literalPtr);
@@ -48,6 +46,6 @@ TOY_API void Toy_setInterpreterError(Toy_Interpreter* interpreter, Toy_PrintFn e
//main access //main access
TOY_API void Toy_initInterpreter(Toy_Interpreter* interpreter); //start of program TOY_API void Toy_initInterpreter(Toy_Interpreter* interpreter); //start of program
TOY_API void Toy_runInterpreter(Toy_Interpreter* interpreter, unsigned char* bytecode, int length); //run the code TOY_API void Toy_runInterpreter(Toy_Interpreter* interpreter, const unsigned char* bytecode, size_t length); //run the code
TOY_API void Toy_resetInterpreter(Toy_Interpreter* interpreter); //use this to reset the interpreter's environment between runs TOY_API void Toy_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 TOY_API void Toy_freeInterpreter(Toy_Interpreter* interpreter); //end of program
+21 -12
View File
@@ -12,6 +12,7 @@ static void cleanLexer(Toy_Lexer* lexer) {
lexer->start = 0; lexer->start = 0;
lexer->current = 0; lexer->current = 0;
lexer->line = 1; lexer->line = 1;
lexer->commentsEnabled = true;
} }
static bool isAtEnd(Toy_Lexer* lexer) { static bool isAtEnd(Toy_Lexer* lexer) {
@@ -54,9 +55,13 @@ static void eatWhitespace(Toy_Lexer* lexer) {
//comments //comments
case '/': case '/':
if (!lexer->commentsEnabled) {
return;
}
//eat the line //eat the line
if (peekNext(lexer) == '/') { if (peekNext(lexer) == '/') {
while (advance(lexer) != '\n' && !isAtEnd(lexer)); while (!isAtEnd(lexer) && advance(lexer) != '\n');
break; break;
} }
@@ -64,7 +69,7 @@ static void eatWhitespace(Toy_Lexer* lexer) {
if (peekNext(lexer) == '*') { if (peekNext(lexer) == '*') {
advance(lexer); advance(lexer);
advance(lexer); advance(lexer);
while(!(peek(lexer) == '*' && peekNext(lexer) == '/')) advance(lexer); while(!isAtEnd(lexer) && !(peek(lexer) == '*' && peekNext(lexer) == '/')) advance(lexer);
advance(lexer); advance(lexer);
advance(lexer); advance(lexer);
break; break;
@@ -112,7 +117,7 @@ static Toy_Token makeErrorToken(Toy_Lexer* lexer, char* msg) {
#ifndef TOY_EXPORT #ifndef TOY_EXPORT
if (Toy_commandLine.verbose) { if (Toy_commandLine.verbose) {
printf("err:"); printf("err:");
Toy_printToken(&token); Toy_private_printToken(&token);
} }
#endif #endif
@@ -131,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 //BUG #10: this shows TOKEN_EOF twice due to the overarching structure of the program - can't be fixed
if (Toy_commandLine.verbose) { if (Toy_commandLine.verbose) {
printf("tok:"); printf("tok:");
Toy_printToken(&token); Toy_private_printToken(&token);
} }
#endif #endif
@@ -163,7 +168,7 @@ static Toy_Token makeIntegerOrFloat(Toy_Lexer* lexer) {
} else { } else {
printf("flt:"); printf("flt:");
} }
Toy_printToken(&token); Toy_private_printToken(&token);
} }
#endif #endif
@@ -216,7 +221,7 @@ static Toy_Token makeString(Toy_Lexer* lexer, char terminator) {
#ifndef TOY_EXPORT #ifndef TOY_EXPORT
if (Toy_commandLine.verbose) { if (Toy_commandLine.verbose) {
printf("str:"); printf("str:");
Toy_printToken(&token); Toy_private_printToken(&token);
} }
#endif #endif
@@ -243,7 +248,7 @@ static Toy_Token makeKeywordOrIdentifier(Toy_Lexer* lexer) {
#ifndef TOY_EXPORT #ifndef TOY_EXPORT
if (Toy_commandLine.verbose) { if (Toy_commandLine.verbose) {
printf("kwd:"); printf("kwd:");
Toy_printToken(&token); Toy_private_printToken(&token);
} }
#endif #endif
@@ -262,7 +267,7 @@ static Toy_Token makeKeywordOrIdentifier(Toy_Lexer* lexer) {
#ifndef TOY_EXPORT #ifndef TOY_EXPORT
if (Toy_commandLine.verbose) { if (Toy_commandLine.verbose) {
printf("idf:"); printf("idf:");
Toy_printToken(&token); Toy_private_printToken(&token);
} }
#endif #endif
@@ -270,13 +275,13 @@ static Toy_Token makeKeywordOrIdentifier(Toy_Lexer* lexer) {
} }
//exposed functions //exposed functions
void Toy_initLexer(Toy_Lexer* lexer, char* source) { void Toy_initLexer(Toy_Lexer* lexer, const char* source) {
cleanLexer(lexer); cleanLexer(lexer);
lexer->source = source; lexer->source = source;
} }
Toy_Token Toy_scanLexer(Toy_Lexer* lexer) { Toy_Token Toy_private_scanLexer(Toy_Lexer* lexer) {
eatWhitespace(lexer); eatWhitespace(lexer);
lexer->start = lexer->current; lexer->start = lexer->current;
@@ -347,7 +352,7 @@ static void trim(char** s, int* l) { //all this to remove a newline?
} }
//for debugging //for debugging
void Toy_printToken(Toy_Token* token) { void Toy_private_printToken(Toy_Token* token) {
if (token->type == TOY_TOKEN_ERROR) { 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); printf(TOY_CC_ERROR "Error\t%d\t%.*s\n" TOY_CC_RESET, token->line, token->length, token->lexeme);
return; return;
@@ -363,7 +368,7 @@ void Toy_printToken(Toy_Token* token) {
if (keyword != NULL) { if (keyword != NULL) {
printf("%s", keyword); printf("%s", keyword);
} else { } else {
char* str = token->lexeme; char* str = (char*)token->lexeme; //strip const-ness for trimming
int length = token->length; int length = token->length;
trim(&str, &length); trim(&str, &length);
printf("%.*s", length, str); printf("%.*s", length, str);
@@ -372,3 +377,7 @@ void Toy_printToken(Toy_Token* token) {
printf("\n"); printf("\n");
} }
void Toy_private_setComments(Toy_Lexer* lexer, bool enabled) {
lexer->commentsEnabled = enabled;
}
+8 -5
View File
@@ -5,22 +5,25 @@
//lexers are bound to a string of code, and return a single token every time scan is called //lexers are bound to a string of code, and return a single token every time scan is called
typedef struct { typedef struct {
char* source; const char* source;
int start; //start of the token int start; //start of the token
int current; //current position of the lexer int current; //current position of the lexer
int line; //track this for error handling int line; //track this for error handling
bool commentsEnabled; //BUGFIX: enable comments (disabled in repl)
} Toy_Lexer; } Toy_Lexer;
//tokens are intermediaries between lexers and parsers //tokens are intermediaries between lexers and parsers
typedef struct { typedef struct {
Toy_TokenType type; Toy_TokenType type;
char* lexeme; const char* lexeme;
int length; int length;
int line; int line;
} Toy_Token; } Toy_Token;
TOY_API void Toy_initLexer(Toy_Lexer* lexer, char* source); 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 //for debugging
void Toy_printToken(Toy_Token* token); TOY_API void Toy_private_printToken(Toy_Token* token);
TOY_API void Toy_private_setComments(Toy_Lexer* lexer, bool enabled);
+17 -15
View File
@@ -8,6 +8,7 @@
#include "toy_console_colors.h" #include "toy_console_colors.h"
#include <stdio.h> #include <stdio.h>
#include <string.h>
//hash util functions //hash util functions
static unsigned int hashString(const char* string, int length) { static unsigned int hashString(const char* string, int length) {
@@ -58,7 +59,7 @@ void Toy_freeLiteral(Toy_Literal literal) {
if (TOY_IS_FUNCTION(literal)) { if (TOY_IS_FUNCTION(literal)) {
Toy_popScope(TOY_AS_FUNCTION(literal).scope); Toy_popScope(TOY_AS_FUNCTION(literal).scope);
TOY_AS_FUNCTION(literal).scope = NULL; TOY_AS_FUNCTION(literal).scope = NULL;
TOY_FREE_ARRAY(unsigned char, TOY_AS_FUNCTION(literal).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)) { if (TOY_IS_TYPE(literal)) {
@@ -72,7 +73,7 @@ void Toy_freeLiteral(Toy_Literal literal) {
bool Toy_private_isTruthy(Toy_Literal x) { bool Toy_private_isTruthy(Toy_Literal x) {
if (TOY_IS_NULL(x)) { if (TOY_IS_NULL(x)) {
fprintf(stderr, TOY_CC_ERROR "TOY_CC_ERROR: Null is neither true nor false\n" TOY_CC_RESET); fprintf(stderr, TOY_CC_ERROR "Null is neither true nor false\n" TOY_CC_RESET);
return false; return false;
} }
@@ -84,11 +85,11 @@ bool Toy_private_isTruthy(Toy_Literal x) {
} }
Toy_Literal Toy_private_toStringLiteral(Toy_RefString* ptr) { 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) { 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) { Toy_Literal* Toy_private_typePushSubtype(Toy_Literal* lit, Toy_Literal subtype) {
@@ -145,16 +146,17 @@ Toy_Literal Toy_copyLiteral(Toy_Literal original) {
} }
case TOY_LITERAL_FUNCTION: { case TOY_LITERAL_FUNCTION: {
unsigned char* buffer = TOY_ALLOCATE(unsigned char, TOY_AS_FUNCTION(original).length); unsigned char* buffer = TOY_ALLOCATE(unsigned char, TOY_AS_FUNCTION_BYTECODE_LENGTH(original));
memcpy(buffer, TOY_AS_FUNCTION(original).bytecode, TOY_AS_FUNCTION(original).length); 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); TOY_AS_FUNCTION(literal).scope = Toy_copyScope(TOY_AS_FUNCTION(original).scope);
return literal; return literal;
} }
case TOY_LITERAL_IDENTIFIER: { case TOY_LITERAL_IDENTIFIER: {
//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))); return TOY_TO_IDENTIFIER_LITERAL(Toy_copyRefString(TOY_AS_IDENTIFIER(original)));
} }
@@ -228,7 +230,7 @@ Toy_Literal Toy_copyLiteral(Toy_Literal original) {
return original; return original;
default: default:
fprintf(stderr, TOY_CC_ERROR "TOY_CC_ERROR: Can't copy that literal type: %d\n" TOY_CC_RESET, original.type); fprintf(stderr, TOY_CC_ERROR "Can't copy that literal type: %d\n" TOY_CC_RESET, original.type);
return TOY_TO_NULL_LITERAL; return TOY_TO_NULL_LITERAL;
} }
} }
@@ -404,20 +406,20 @@ int Toy_hashLiteral(Toy_Literal lit) {
case TOY_LITERAL_FUNCTION: case TOY_LITERAL_FUNCTION:
case TOY_LITERAL_FUNCTION_NATIVE: case TOY_LITERAL_FUNCTION_NATIVE:
case TOY_LITERAL_FUNCTION_HOOK: case TOY_LITERAL_FUNCTION_HOOK:
return 0; //can't hash these return -1; //can't hash these
case TOY_LITERAL_IDENTIFIER: case TOY_LITERAL_IDENTIFIER:
return TOY_HASH_I(lit); //pre-computed return TOY_HASH_I(lit); //pre-computed
case TOY_LITERAL_TYPE: 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_OPAQUE:
case TOY_LITERAL_ANY: case TOY_LITERAL_ANY:
return -1; return -1;
default: 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); fprintf(stderr, TOY_CC_ERROR "[internal] Unrecognized literal type in hash: %d\n" TOY_CC_RESET, lit.type);
return 0; return 0;
} }
@@ -453,7 +455,7 @@ void Toy_printLiteral(Toy_Literal literal) {
Toy_printLiteralCustom(literal, stdoutWrapper); 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) { switch(literal.type) {
case TOY_LITERAL_NULL: case TOY_LITERAL_NULL:
printFn("null"); printFn("null");
@@ -487,10 +489,10 @@ void Toy_printLiteralCustom(Toy_Literal literal, void (printFn)(const char*)) {
case TOY_LITERAL_STRING: { case TOY_LITERAL_STRING: {
char buffer[TOY_MAX_STRING_LENGTH]; char buffer[TOY_MAX_STRING_LENGTH];
if (!quotes) { if (!quotes) {
snprintf(buffer, TOY_MAX_STRING_LENGTH, "%.*s", Toy_lengthRefString(TOY_AS_STRING(literal)), Toy_toCString(TOY_AS_STRING(literal))); snprintf(buffer, TOY_MAX_STRING_LENGTH, "%.*s", (int)Toy_lengthRefString(TOY_AS_STRING(literal)), Toy_toCString(TOY_AS_STRING(literal)));
} }
else { else {
snprintf(buffer, TOY_MAX_STRING_LENGTH, "%c%.*s%c", quotes, Toy_lengthRefString(TOY_AS_STRING(literal)), Toy_toCString(TOY_AS_STRING(literal)), quotes); snprintf(buffer, TOY_MAX_STRING_LENGTH, "%c%.*s%c", quotes, (int)Toy_lengthRefString(TOY_AS_STRING(literal)), Toy_toCString(TOY_AS_STRING(literal)), quotes);
} }
printFn(buffer); printFn(buffer);
} }
@@ -596,7 +598,7 @@ void Toy_printLiteralCustom(Toy_Literal literal, void (printFn)(const char*)) {
case TOY_LITERAL_IDENTIFIER: { case TOY_LITERAL_IDENTIFIER: {
char buffer[256]; char buffer[256];
snprintf(buffer, 256, "%.*s", Toy_lengthRefString(TOY_AS_IDENTIFIER(literal)), Toy_toCString(TOY_AS_IDENTIFIER(literal))); snprintf(buffer, 256, "%.*s", (int)Toy_lengthRefString(TOY_AS_IDENTIFIER(literal)), Toy_toCString(TOY_AS_IDENTIFIER(literal)));
printFn(buffer); printFn(buffer);
} }
break; break;
+50 -44
View File
@@ -10,8 +10,7 @@ struct Toy_Interpreter;
struct Toy_LiteralArray; struct Toy_LiteralArray;
typedef int (*Toy_NativeFn)(struct Toy_Interpreter* interpreter, struct Toy_LiteralArray* arguments); typedef int (*Toy_NativeFn)(struct Toy_Interpreter* interpreter, struct Toy_LiteralArray* arguments);
typedef int (*Toy_HookFn)(struct Toy_Interpreter* interpreter, struct Toy_Literal identifier, struct Toy_Literal alias); typedef int (*Toy_HookFn)(struct Toy_Interpreter* interpreter, struct Toy_Literal identifier, struct Toy_Literal alias);
typedef void (*Toy_PrintFn)(const char*);
#include <string.h>
typedef enum { typedef enum {
TOY_LITERAL_NULL, TOY_LITERAL_NULL,
@@ -39,45 +38,49 @@ typedef enum {
} Toy_LiteralType; } Toy_LiteralType;
typedef struct Toy_Literal { typedef struct Toy_Literal {
Toy_LiteralType type;
union { union {
bool boolean; bool boolean; //1
int integer; int integer; //4
float number; float number;//4
struct { struct {
Toy_RefString* ptr; Toy_RefString* ptr; //8
//string hash? //string hash?
} string; } string; //8
void* array; void* array; //8
void* dictionary; void* dictionary; //8
struct { struct {
void* bytecode; union {
Toy_NativeFn native; //already a pointer void* bytecode; //8
Toy_HookFn hook; //already a pointer Toy_NativeFn native; //8
void* scope; Toy_HookFn hook; //8
int length; } inner; //8
} function; void* scope; //8
} function; //16
struct { //for variable names struct { //for variable names
Toy_RefString* ptr; Toy_RefString* ptr; //8
int hash; int hash; //4
} identifier; } identifier; //16
struct { struct {
Toy_LiteralType typeOf; void* subtypes; //8
bool constant; Toy_LiteralType typeOf; //4
void* subtypes; //for nested types caused by compounds unsigned char capacity; //1
int capacity; unsigned char count; //1
int count; bool constant; //1
} type; } type; //16
struct { struct {
void* ptr; void* ptr; //8
int tag; int tag; //4
} opaque; } opaque; //16
} as; } as; //16
Toy_LiteralType type; //4
int bytecodeLength; //4 - shenanigans with byte alignment reduces the size of Toy_Literal
} Toy_Literal; } Toy_Literal;
#define TOY_IS_NULL(value) ((value).type == TOY_LITERAL_NULL) #define TOY_IS_NULL(value) ((value).type == TOY_LITERAL_NULL)
@@ -101,34 +104,36 @@ typedef struct Toy_Literal {
#define TOY_AS_ARRAY(value) ((Toy_LiteralArray*)((value).as.array)) #define TOY_AS_ARRAY(value) ((Toy_LiteralArray*)((value).as.array))
#define TOY_AS_DICTIONARY(value) ((Toy_LiteralDictionary*)((value).as.dictionary)) #define TOY_AS_DICTIONARY(value) ((Toy_LiteralDictionary*)((value).as.dictionary))
#define TOY_AS_FUNCTION(value) ((value).as.function) #define TOY_AS_FUNCTION(value) ((value).as.function)
#define TOY_AS_FUNCTION_NATIVE(value) ((value).as.function.native) #define TOY_AS_FUNCTION_NATIVE(value) ((value).as.function.inner.native)
#define TOY_AS_FUNCTION_HOOK(value) ((value).as.function.hook) #define TOY_AS_FUNCTION_HOOK(value) ((value).as.function.inner.hook)
#define TOY_AS_IDENTIFIER(value) ((value).as.identifier.ptr) #define TOY_AS_IDENTIFIER(value) ((value).as.identifier.ptr)
#define TOY_AS_TYPE(value) ((value).as.type) #define TOY_AS_TYPE(value) ((value).as.type)
#define TOY_AS_OPAQUE(value) ((value).as.opaque.ptr) #define TOY_AS_OPAQUE(value) ((value).as.opaque.ptr)
#define TOY_TO_NULL_LITERAL ((Toy_Literal){TOY_LITERAL_NULL, { .integer = 0 }}) #define TOY_TO_NULL_LITERAL ((Toy_Literal){{ .integer = 0 }, TOY_LITERAL_NULL, 0})
#define TOY_TO_BOOLEAN_LITERAL(value) ((Toy_Literal){TOY_LITERAL_BOOLEAN, { .boolean = value }}) #define TOY_TO_BOOLEAN_LITERAL(value) ((Toy_Literal){{ .boolean = value }, TOY_LITERAL_BOOLEAN, 0})
#define TOY_TO_INTEGER_LITERAL(value) ((Toy_Literal){TOY_LITERAL_INTEGER, { .integer = value }}) #define TOY_TO_INTEGER_LITERAL(value) ((Toy_Literal){{ .integer = value }, TOY_LITERAL_INTEGER, 0})
#define TOY_TO_FLOAT_LITERAL(value) ((Toy_Literal){TOY_LITERAL_FLOAT, { .number = value }}) #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_STRING_LITERAL(value) Toy_private_toStringLiteral(value)
#define TOY_TO_ARRAY_LITERAL(value) ((Toy_Literal){TOY_LITERAL_ARRAY, { .array = value }}) #define TOY_TO_ARRAY_LITERAL(value) ((Toy_Literal){{ .array = value }, TOY_LITERAL_ARRAY, 0})
#define TOY_TO_DICTIONARY_LITERAL(value) ((Toy_Literal){TOY_LITERAL_DICTIONARY, { .dictionary = value }}) #define TOY_TO_DICTIONARY_LITERAL(value) ((Toy_Literal){{ .dictionary = value }, TOY_LITERAL_DICTIONARY, 0})
#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_LITERAL(value, l) ((Toy_Literal){{ .function = { .inner = { .bytecode = value }, .scope = NULL }}, TOY_LITERAL_FUNCTION, 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_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){TOY_LITERAL_FUNCTION_HOOK, { .function.hook = value, .function.scope = NULL, .function.length = 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_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_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){ TOY_LITERAL_OPAQUE, { .opaque.ptr = value, .opaque.tag = t }}) #define TOY_TO_OPAQUE_LITERAL(value, t) ((Toy_Literal){{ .opaque = { .ptr = value, .tag = t }}, TOY_LITERAL_OPAQUE, 0})
//BUGFIX: For blank indexing //BUGFIX: For blank indexing
#define TOY_IS_INDEX_BLANK(value) ((value).type == TOY_LITERAL_INDEX_BLANK) #define TOY_IS_INDEX_BLANK(value) ((value).type == TOY_LITERAL_INDEX_BLANK)
#define TOY_TO_INDEX_BLANK_LITERAL ((Toy_Literal){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); TOY_API void Toy_freeLiteral(Toy_Literal literal);
#define TOY_IS_TRUTHY(x) Toy_private_isTruthy(x) #define TOY_IS_TRUTHY(x) Toy_private_isTruthy(x)
#define TOY_AS_FUNCTION_BYTECODE_LENGTH(lit) ((lit).bytecodeLength)
#define TOY_MAX_STRING_LENGTH 4096 #define TOY_MAX_STRING_LENGTH 4096
#define TOY_HASH_I(lit) ((lit).as.identifier.hash) #define TOY_HASH_I(lit) ((lit).as.identifier.hash)
#define TOY_TYPE_PUSH_SUBTYPE(lit, subtype) Toy_private_typePushSubtype(lit, subtype) #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 bool Toy_literalsAreEqual(Toy_Literal lhs, Toy_Literal rhs);
TOY_API int Toy_hashLiteral(Toy_Literal lit); TOY_API int Toy_hashLiteral(Toy_Literal lit);
//not thread-safe
TOY_API void Toy_printLiteral(Toy_Literal literal); 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); TOY_API Toy_Literal Toy_getLiteralArray(Toy_LiteralArray* array, Toy_Literal index);
int Toy_findLiteralIndex(Toy_LiteralArray* array, Toy_Literal literal); 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> #include <stdio.h>
//util functions //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 //much simpler now
Toy_freeLiteral(entry->key); Toy_freeLiteral(entry->key);
entry->key = Toy_copyLiteral(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); 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 //find "key", starting at index
unsigned int index = hash % capacity; unsigned int index = hash % capacity;
unsigned int start = index; unsigned int start = index;
@@ -26,7 +26,7 @@ static Toy_private_entry* getEntryArray(Toy_private_entry* array, int capacity,
//literal probing and collision checking //literal probing and collision checking
while (index != start) { //WARNING: this is the only function allowed to retrieve an entry from the array 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->key)) { //if key is empty, it's either empty or tombstone
if (TOY_IS_NULL(entry->value) && !mustExist) { if (TOY_IS_NULL(entry->value) && !mustExist) {
@@ -46,9 +46,9 @@ static Toy_private_entry* getEntryArray(Toy_private_entry* array, int capacity,
return NULL; 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 //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++) { for (int i = 0; i < capacity; i++) {
newEntries[i].key = TOY_TO_NULL_LITERAL; 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) //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->key = (*dictionaryHandle)[i].key;
entry->value = (*dictionaryHandle)[i].value; entry->value = (*dictionaryHandle)[i].value;
} }
//clear the old array //clear the old array
TOY_FREE_ARRAY(Toy_private_entry, *dictionaryHandle, oldCapacity); TOY_FREE_ARRAY(Toy_private_dictionary_entry, *dictionaryHandle, oldCapacity);
*dictionaryHandle = newEntries; *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 //expand array if needed
if (contains + 1 > *capacityPtr * TOY_DICTIONARY_MAX_LOAD) { if (contains + 1 > *capacityPtr * TOY_DICTIONARY_MAX_LOAD) {
int oldCapacity = *capacityPtr; 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 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 //true = contains increase
if (TOY_IS_NULL(entry->key)) { if (TOY_IS_NULL(entry->key)) {
@@ -97,14 +97,14 @@ static bool setEntryArray(Toy_private_entry** dictionaryHandle, int* capacityPtr
return false; return false;
} }
static void freeEntry(Toy_private_entry* entry) { static void freeEntry(Toy_private_dictionary_entry* entry) {
Toy_freeLiteral(entry->key); Toy_freeLiteral(entry->key);
Toy_freeLiteral(entry->value); Toy_freeLiteral(entry->value);
entry->key = TOY_TO_NULL_LITERAL; entry->key = TOY_TO_NULL_LITERAL;
entry->value = 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) { if (array == NULL) {
return; 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 //exposed functions
@@ -141,7 +141,7 @@ void Toy_setLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key
} }
//BUGFIX: Can't hash a function //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); fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have function keys (set)\n" TOY_CC_RESET);
return; return;
} }
@@ -166,7 +166,7 @@ Toy_Literal Toy_getLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Lite
} }
//BUGFIX: Can't hash a function //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); fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have function keys (get)\n" TOY_CC_RESET);
return TOY_TO_NULL_LITERAL; return TOY_TO_NULL_LITERAL;
} }
@@ -176,7 +176,7 @@ Toy_Literal Toy_getLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Lite
return TOY_TO_NULL_LITERAL; 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) { if (entry != NULL) {
return Toy_copyLiteral(entry->value); return Toy_copyLiteral(entry->value);
@@ -193,7 +193,7 @@ void Toy_removeLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal
} }
//BUGFIX: Can't hash a function //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); fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have function keys (remove)\n" TOY_CC_RESET);
return; return;
} }
@@ -203,7 +203,7 @@ void Toy_removeLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal
return; 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) { if (entry != NULL) {
freeEntry(entry); freeEntry(entry);
@@ -214,6 +214,6 @@ void Toy_removeLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal
bool Toy_existsLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key) { bool Toy_existsLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key) {
//null & not tombstoned //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)); return !(TOY_IS_NULL(entry->key) && TOY_IS_NULL(entry->value));
} }
+3 -3
View File
@@ -7,13 +7,13 @@
//TODO: benchmark this //TODO: benchmark this
#define TOY_DICTIONARY_MAX_LOAD 0.75 #define TOY_DICTIONARY_MAX_LOAD 0.75
typedef struct Toy_private_entry { typedef struct Toy_private_dictionary_entry {
Toy_Literal key; Toy_Literal key;
Toy_Literal value; Toy_Literal value;
} Toy_private_entry; } Toy_private_dictionary_entry;
typedef struct Toy_LiteralDictionary { typedef struct Toy_LiteralDictionary {
Toy_private_entry* entries; Toy_private_dictionary_entry* entries;
int capacity; int capacity;
int count; int count;
int contains; //count + tombstones, for internal use 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) { if (newSize == 0) {
free(pointer); free(pointer);
return NULL; return NULL;
} }
void* mem = realloc(pointer, newSize); void* mem = realloc(pointer, newSize);
if (mem == NULL) { if (mem == NULL) {
fprintf(stderr, TOY_CC_ERROR "[internal] Memory allocation error (requested %d, replacing %d)\n" TOY_CC_RESET, (int)newSize, (int)oldSize); fprintf(stderr, TOY_CC_ERROR "[internal] Memory allocation error (requested %zu, replacing %zu)\n" TOY_CC_RESET, newSize, oldSize);
exit(-1); return NULL;
} }
return mem; return mem;
+8 -5
View File
@@ -2,16 +2,19 @@
#include "toy_common.h" #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(capacity) ((capacity) < 8 ? 8 : (capacity) * 2)
#define TOY_GROW_CAPACITY_FAST(capacity) ((capacity) < 32 ? 32 : (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_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_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 //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 //assign the memory allocator
typedef void* (*Toy_MemoryAllocatorFn)(void* pointer, size_t oldSize, size_t newSize); typedef void* (*Toy_MemoryAllocatorFn)(void* pointer, size_t oldSize, size_t newSize);
+3
View File
@@ -3,6 +3,9 @@
typedef enum Toy_Opcode { typedef enum Toy_Opcode {
TOY_OP_EOF, TOY_OP_EOF,
//do nothing
TOY_OP_PASS,
//basic statements //basic statements
TOY_OP_ASSERT, TOY_OP_ASSERT,
TOY_OP_PRINT, TOY_OP_PRINT,
+72 -9
View File
@@ -32,7 +32,7 @@ static void error(Toy_Parser* parser, Toy_Token token, const char* message) {
static void advance(Toy_Parser* parser) { static void advance(Toy_Parser* parser) {
parser->previous = parser->current; parser->previous = parser->current;
parser->current = Toy_scanLexer(parser->lexer); parser->current = Toy_private_scanLexer(parser->lexer);
if (parser->current.type == TOY_TOKEN_ERROR) { if (parser->current.type == TOY_TOKEN_ERROR) {
error(parser, parser->current, "Toy_Lexer error"); error(parser, parser->current, "Toy_Lexer error");
@@ -428,12 +428,12 @@ static Toy_Opcode binary(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
} }
case TOY_TOKEN_AND: { case TOY_TOKEN_AND: {
parsePrecedence(parser, nodeHandle, PREC_COMPARISON); parsePrecedence(parser, nodeHandle, PREC_AND);
return TOY_OP_AND; return TOY_OP_AND;
} }
case TOY_TOKEN_OR: { case TOY_TOKEN_OR: {
parsePrecedence(parser, nodeHandle, PREC_COMPARISON); parsePrecedence(parser, nodeHandle, PREC_OR);
return TOY_OP_OR; return TOY_OP_OR;
} }
@@ -448,7 +448,7 @@ static Toy_Opcode unary(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
if (parser->previous.type == TOY_TOKEN_MINUS) { if (parser->previous.type == TOY_TOKEN_MINUS) {
//temp handle to potentially negate values //temp handle to potentially negate values
parsePrecedence(parser, &tmpNode, PREC_TERNARY); //can be a literal parsePrecedence(parser, &tmpNode, PREC_TERM); //can be a literal
//optimisation: check for negative literals //optimisation: check for negative literals
if (tmpNode != NULL && tmpNode->type == TOY_AST_NODE_LITERAL && (TOY_IS_INTEGER(tmpNode->atomic.literal) || TOY_IS_FLOAT(tmpNode->atomic.literal))) { if (tmpNode != NULL && tmpNode->type == TOY_AST_NODE_LITERAL && (TOY_IS_INTEGER(tmpNode->atomic.literal) || TOY_IS_FLOAT(tmpNode->atomic.literal))) {
@@ -508,7 +508,7 @@ static Toy_Opcode unary(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
return TOY_OP_EOF; return TOY_OP_EOF;
} }
static char* removeChar(char* lexeme, int length, char c) { static char* removeChar(const char* lexeme, int length, char c) {
int resPos = 0; int resPos = 0;
char* result = TOY_ALLOCATE(char, length + 1); char* result = TOY_ALLOCATE(char, length + 1);
@@ -540,7 +540,7 @@ static Toy_Opcode atomic(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
case TOY_TOKEN_LITERAL_INTEGER: { case TOY_TOKEN_LITERAL_INTEGER: {
int value = 0; int value = 0;
char* lexeme = removeChar(parser->previous.lexeme, parser->previous.length, '_'); const char* lexeme = removeChar(parser->previous.lexeme, parser->previous.length, '_');
sscanf(lexeme, "%d", &value); sscanf(lexeme, "%d", &value);
TOY_FREE_ARRAY(char, lexeme, parser->previous.length + 1); TOY_FREE_ARRAY(char, lexeme, parser->previous.length + 1);
Toy_emitASTNodeLiteral(nodeHandle, TOY_TO_INTEGER_LITERAL(value)); Toy_emitASTNodeLiteral(nodeHandle, TOY_TO_INTEGER_LITERAL(value));
@@ -549,7 +549,7 @@ static Toy_Opcode atomic(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
case TOY_TOKEN_LITERAL_FLOAT: { case TOY_TOKEN_LITERAL_FLOAT: {
float value = 0; float value = 0;
char* lexeme = removeChar(parser->previous.lexeme, parser->previous.length, '_'); const char* lexeme = removeChar(parser->previous.lexeme, parser->previous.length, '_');
sscanf(lexeme, "%f", &value); sscanf(lexeme, "%f", &value);
TOY_FREE_ARRAY(char, lexeme, parser->previous.length + 1); TOY_FREE_ARRAY(char, lexeme, parser->previous.length + 1);
Toy_emitASTNodeLiteral(nodeHandle, TOY_TO_FLOAT_LITERAL(value)); Toy_emitASTNodeLiteral(nodeHandle, TOY_TO_FLOAT_LITERAL(value));
@@ -676,6 +676,10 @@ static Toy_Opcode incrementPrefix(Toy_Parser* parser, Toy_ASTNode** nodeHandle)
Toy_ASTNode* tmpNode = NULL; Toy_ASTNode* tmpNode = NULL;
identifier(parser, &tmpNode); identifier(parser, &tmpNode);
if (!tmpNode) {
return TOY_OP_EOF;
}
Toy_emitASTNodePrefixIncrement(nodeHandle, tmpNode->atomic.literal); Toy_emitASTNodePrefixIncrement(nodeHandle, tmpNode->atomic.literal);
Toy_freeASTNode(tmpNode); Toy_freeASTNode(tmpNode);
@@ -689,6 +693,10 @@ static Toy_Opcode incrementInfix(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
advance(parser); advance(parser);
if (!tmpNode) {
return TOY_OP_EOF;
}
Toy_emitASTNodePostfixIncrement(nodeHandle, tmpNode->atomic.literal); Toy_emitASTNodePostfixIncrement(nodeHandle, tmpNode->atomic.literal);
Toy_freeASTNode(tmpNode); Toy_freeASTNode(tmpNode);
@@ -700,7 +708,11 @@ static Toy_Opcode decrementPrefix(Toy_Parser* parser, Toy_ASTNode** nodeHandle)
advance(parser); advance(parser);
Toy_ASTNode* tmpNode = NULL; Toy_ASTNode* tmpNode = NULL;
identifier(parser, &tmpNode); //weird identifier(parser, &tmpNode);
if (!tmpNode) {
return TOY_OP_EOF;
}
Toy_emitASTNodePrefixDecrement(nodeHandle, tmpNode->atomic.literal); Toy_emitASTNodePrefixDecrement(nodeHandle, tmpNode->atomic.literal);
@@ -715,6 +727,10 @@ static Toy_Opcode decrementInfix(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
advance(parser); advance(parser);
if (!tmpNode) {
return TOY_OP_EOF;
}
Toy_emitASTNodePostfixDecrement(nodeHandle, tmpNode->atomic.literal); Toy_emitASTNodePostfixDecrement(nodeHandle, tmpNode->atomic.literal);
Toy_freeASTNode(tmpNode); Toy_freeASTNode(tmpNode);
@@ -794,13 +810,20 @@ static Toy_Opcode indexAccess(Toy_Parser* parser, Toy_ASTNode** nodeHandle) { //
//eat the first //eat the first
if (!match(parser, TOY_TOKEN_COLON)) { if (!match(parser, TOY_TOKEN_COLON)) {
Toy_freeASTNode(first); Toy_freeASTNode(first);
first = NULL;
parsePrecedence(parser, &first, PREC_TERNARY); parsePrecedence(parser, &first, PREC_TERNARY);
match(parser, TOY_TOKEN_COLON); match(parser, TOY_TOKEN_COLON);
readFirst = true; readFirst = true;
} }
if (match(parser, TOY_TOKEN_BRACKET_RIGHT)) { if (!first) {
Toy_freeASTNode(first);
Toy_freeASTNode(second);
Toy_freeASTNode(third);
return TOY_OP_EOF;
}
if (match(parser, TOY_TOKEN_BRACKET_RIGHT)) {
if (readFirst) { if (readFirst) {
Toy_freeASTNode(second); Toy_freeASTNode(second);
second = NULL; second = NULL;
@@ -816,10 +839,18 @@ static Toy_Opcode indexAccess(Toy_Parser* parser, Toy_ASTNode** nodeHandle) { //
//eat the second //eat the second
if (!match(parser, TOY_TOKEN_COLON)) { if (!match(parser, TOY_TOKEN_COLON)) {
Toy_freeASTNode(second); Toy_freeASTNode(second);
second = NULL;
parsePrecedence(parser, &second, PREC_TERNARY); parsePrecedence(parser, &second, PREC_TERNARY);
match(parser, TOY_TOKEN_COLON); match(parser, TOY_TOKEN_COLON);
} }
if (!second) {
Toy_freeASTNode(first);
Toy_freeASTNode(second);
Toy_freeASTNode(third);
return TOY_OP_EOF;
}
if (match(parser, TOY_TOKEN_BRACKET_RIGHT)) { if (match(parser, TOY_TOKEN_BRACKET_RIGHT)) {
Toy_freeASTNode(third); Toy_freeASTNode(third);
third = NULL; third = NULL;
@@ -829,7 +860,16 @@ static Toy_Opcode indexAccess(Toy_Parser* parser, Toy_ASTNode** nodeHandle) { //
//eat the third //eat the third
Toy_freeASTNode(third); Toy_freeASTNode(third);
third = NULL;
parsePrecedence(parser, &third, PREC_TERNARY); parsePrecedence(parser, &third, PREC_TERNARY);
if (!third) {
Toy_freeASTNode(first);
Toy_freeASTNode(second);
Toy_freeASTNode(third);
return TOY_OP_EOF;
}
Toy_emitASTNodeIndex(nodeHandle, first, second, third); Toy_emitASTNodeIndex(nodeHandle, first, second, third);
consume(parser, TOY_TOKEN_BRACKET_RIGHT, "Expected ']' in index notation"); consume(parser, TOY_TOKEN_BRACKET_RIGHT, "Expected ']' in index notation");
@@ -1334,13 +1374,36 @@ static void forStmt(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
//read the clauses //read the clauses
consume(parser, TOY_TOKEN_PAREN_LEFT, "Expected '(' at beginning of for clause"); consume(parser, TOY_TOKEN_PAREN_LEFT, "Expected '(' at beginning of for clause");
//check the pre-clause
if (parser->current.type != TOY_TOKEN_SEMICOLON) {
declaration(parser, &preClause); //allow defining variables in the pre-clause 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);
}
//check the condition clause
if (parser->current.type != TOY_TOKEN_SEMICOLON) {
parsePrecedence(parser, &condition, PREC_TERNARY); parsePrecedence(parser, &condition, PREC_TERNARY);
consume(parser, TOY_TOKEN_SEMICOLON, "Expected ';' after condition of for clause"); 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);
}
//check the postfix clause
if (parser->current.type != TOY_TOKEN_PAREN_RIGHT) {
parsePrecedence(parser, &postClause, PREC_ASSIGNMENT); parsePrecedence(parser, &postClause, PREC_ASSIGNMENT);
consume(parser, TOY_TOKEN_PAREN_RIGHT, "Expected ')' at end of for clause"); 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 //read the path
declaration(parser, &thenPath); declaration(parser, &thenPath);
+18 -24
View File
@@ -1,15 +1,5 @@
#include "toy_refstring.h" #include "toy_refstring.h"
#include <string.h>
#include <assert.h>
//test variable sizes based on platform (safety)
#define STATIC_ASSERT(test_for_true) static_assert((test_for_true), "(" #test_for_true ") failed")
STATIC_ASSERT(sizeof(Toy_RefString) == 12);
STATIC_ASSERT(sizeof(int) == 4);
STATIC_ASSERT(sizeof(char) == 1);
//memory allocation //memory allocation
extern void* Toy_private_defaultMemoryAllocator(void* pointer, size_t oldSize, size_t newSize); extern void* Toy_private_defaultMemoryAllocator(void* pointer, size_t oldSize, size_t newSize);
static Toy_RefStringAllocatorFn allocate = Toy_private_defaultMemoryAllocator; static Toy_RefStringAllocatorFn allocate = Toy_private_defaultMemoryAllocator;
@@ -19,18 +9,22 @@ void Toy_setRefStringAllocatorFn(Toy_RefStringAllocatorFn allocator) {
} }
//API //API
Toy_RefString* Toy_createRefString(char* cstring) { Toy_RefString* Toy_createRefString(const char* cstring) {
int length = strlen(cstring); size_t length = strlen(cstring);
return Toy_createRefStringLength(cstring, length); return Toy_createRefStringLength(cstring, length);
} }
Toy_RefString* Toy_createRefStringLength(char* cstring, int length) { Toy_RefString* Toy_createRefStringLength(const char* cstring, size_t length) {
//allocate the memory area (including metadata space) //allocate the memory area (including metadata space)
Toy_RefString* refString = (Toy_RefString*)allocate(NULL, 0, sizeof(int) * 2 + sizeof(char) * length + 1); Toy_RefString* refString = allocate(NULL, 0, sizeof(size_t) + sizeof(int) + sizeof(char) * (length + 1));
if (refString == NULL) {
return NULL;
}
//set the data //set the data
refString->refcount = 1; refString->refCount = 1;
refString->length = length; refString->length = length;
strncpy(refString->data, cstring, refString->length); strncpy(refString->data, cstring, refString->length);
@@ -41,32 +35,32 @@ Toy_RefString* Toy_createRefStringLength(char* cstring, int length) {
void Toy_deleteRefString(Toy_RefString* refString) { void Toy_deleteRefString(Toy_RefString* refString) {
//decrement, then check //decrement, then check
refString->refcount--; refString->refCount--;
if (refString->refcount <= 0) { if (refString->refCount <= 0) {
allocate(refString, sizeof(int) * 2 + sizeof(char) * refString->length + 1, 0); allocate(refString, sizeof(size_t) + sizeof(int) + sizeof(char) * (refString->length + 1), 0);
} }
} }
int Toy_countRefString(Toy_RefString* refString) { int Toy_countRefString(Toy_RefString* refString) {
return refString->refcount; return refString->refCount;
} }
int Toy_lengthRefString(Toy_RefString* refString) { size_t Toy_lengthRefString(Toy_RefString* refString) {
return refString->length; return refString->length;
} }
Toy_RefString* Toy_copyRefString(Toy_RefString* refString) { Toy_RefString* Toy_copyRefString(Toy_RefString* refString) {
//Cheaty McCheater Face //Cheaty McCheater Face
refString->refcount++; refString->refCount++;
return refString; return refString;
} }
Toy_RefString* Toy_deepCopyRefString(Toy_RefString* refString) { Toy_RefString* Toy_deepCopyRefString(Toy_RefString* refString) {
//create a new string, with a new refcount //create a new string, with a new refCount
return Toy_createRefStringLength(refString->data, refString->length); return Toy_createRefStringLength(refString->data, refString->length);
} }
char* Toy_toCString(Toy_RefString* refString) { const char* Toy_toCString(Toy_RefString* refString) {
return refString->data; return refString->data;
} }
@@ -87,7 +81,7 @@ bool Toy_equalsRefString(Toy_RefString* lhs, Toy_RefString* rhs) {
bool Toy_equalsRefStringCString(Toy_RefString* lhs, char* cstring) { bool Toy_equalsRefStringCString(Toy_RefString* lhs, char* cstring) {
//get the rhs length //get the rhs length
int length = strlen(cstring); size_t length = strlen(cstring);
//different length //different length
if (lhs->length != length) { if (lhs->length != length) {
+20 -16
View File
@@ -1,27 +1,31 @@
#pragma once #pragma once
#include <stdbool.h> #include "toy_common.h"
#include <stddef.h>
#include <string.h>
//memory allocation hook //memory allocation hook
typedef void* (*Toy_RefStringAllocatorFn)(void* pointer, size_t oldSize, size_t newSize); 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 //the RefString structure
typedef struct Toy_RefString { typedef struct Toy_RefString {
int refcount; size_t length;
int length; int refCount;
char data[1]; char data[];
} Toy_RefString; } Toy_RefString;
//API //API
Toy_RefString* Toy_createRefString(char* cstring); TOY_API Toy_RefString* Toy_createRefString(const char* cstring);
Toy_RefString* Toy_createRefStringLength(char* cstring, int length); TOY_API Toy_RefString* Toy_createRefStringLength(const char* cstring, size_t length);
void Toy_deleteRefString(Toy_RefString* refString); TOY_API void Toy_deleteRefString(Toy_RefString* refString);
int Toy_countRefString(Toy_RefString* refString); TOY_API int Toy_countRefString(Toy_RefString* refString);
int Toy_lengthRefString(Toy_RefString* refString); TOY_API size_t Toy_lengthRefString(Toy_RefString* refString);
Toy_RefString* Toy_copyRefString(Toy_RefString* refString); TOY_API Toy_RefString* Toy_copyRefString(Toy_RefString* refString);
Toy_RefString* Toy_deepCopyRefString(Toy_RefString* refString); TOY_API Toy_RefString* Toy_deepCopyRefString(Toy_RefString* refString);
char* Toy_toCString(Toy_RefString* refString); TOY_API const char* Toy_toCString(Toy_RefString* refString);
bool Toy_equalsRefString(Toy_RefString* lhs, Toy_RefString* rhs); TOY_API bool Toy_equalsRefString(Toy_RefString* lhs, Toy_RefString* rhs);
bool Toy_equalsRefStringCString(Toy_RefString* lhs, char* cstring); 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 //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++) { 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)) { 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; return false;
} }
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_OPAQUE && !TOY_IS_OPAQUE(value)) {
return false;
}
return true; return true;
} }
@@ -185,7 +189,7 @@ Toy_Scope* Toy_popScope(Toy_Scope* scope) {
Toy_Scope* ret = scope->ancestor; 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++) { for (int i = 0; i < scope->variables.capacity; i++) {
//handle keys, just in case //handle keys, just in case
if (TOY_IS_FUNCTION(scope->variables.entries[i].key)) { 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 //actually assign
Toy_setLiteralDictionary(&scope->variables, key, value); Toy_setLiteralDictionary(&scope->variables, key, value); //key & value are copied here
Toy_freeLiteral(typeLiteral); Toy_freeLiteral(typeLiteral);
Toy_freeLiteral(original); Toy_freeLiteral(original);
+9 -8
View File
@@ -1,5 +1,6 @@
#pragma once #pragma once
#include "toy_literal.h"
#include "toy_literal_array.h" #include "toy_literal_array.h"
#include "toy_literal_dictionary.h" #include "toy_literal_dictionary.h"
@@ -10,16 +11,16 @@ typedef struct Toy_Scope {
int references; //how many scopes point here int references; //how many scopes point here
} Toy_Scope; } Toy_Scope;
Toy_Scope* Toy_pushScope(Toy_Scope* scope); TOY_API Toy_Scope* Toy_pushScope(Toy_Scope* scope);
Toy_Scope* Toy_popScope(Toy_Scope* scope); TOY_API Toy_Scope* Toy_popScope(Toy_Scope* scope);
Toy_Scope* Toy_copyScope(Toy_Scope* original); TOY_API Toy_Scope* Toy_copyScope(Toy_Scope* original);
//returns false if error //returns false if error
bool Toy_declareScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal type); TOY_API 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_isDelcaredScopeVariable(Toy_Scope* scope, Toy_Literal key);
//return false if undefined //return false if undefined
bool Toy_setScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal value, bool constCheck); TOY_API 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_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 a = [1, 2, 3];
var b = [4, 5, 6]; 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; var acc = 0;
for (var i = 0; i < _length(a); i++) { for (var i = 0; i < length(a); i++) {
acc += _get(a, i) * _get(b, i); acc += get(a, i) * get(b, i);
} }
assert acc == 32, "dot product failed"; assert acc == 32, "dot product failed";
@@ -15,38 +15,38 @@ assert acc == 32, "dot product failed";
//assume the args are matrices //assume the args are matrices
fn matrix(first, second) { fn matrix(first, second) {
//get the matrix size //get the matrix size
var l1 = _length(first); //rows var l1 = length(first); //rows
var l2 = _length(_get(first, 0)); //cols var l2 = length(get(first, 0)); //cols
var l3 = _length(second); //rows var l3 = length(second); //rows
var l4 = _length(_get(second, 0)); //cols var l4 = length(get(second, 0)); //cols
//pre-allocate the matrix //pre-allocate the matrix
var row = []; var row = [];
for (var j = 0; j < l4; j++) { for (var j = 0; j < l4; j++) {
_push(row, 0); push(row, 0);
} }
var result = []; var result = [];
for (var i = 0; i < l1; i++) { for (var i = 0; i < l1; i++) {
_push(result, row); push(result, row);
} }
//assign the values //assign the values
for (var i = 0; i < _length(first); i++) { for (var i = 0; i < length(first); i++) {
//select each element of "first" //select each element of "first"
var firstElement = _get(first, i); var firstElement = get(first, i);
//for each element of second //for each element of second
for (var i2 = 0; i2 < _length(second); i2++) { for (var i2 = 0; i2 < length(second); i2++) {
for (var j2 = 0; j2 < _length(_get(second, 0)); j2++) { 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 //TODO: needs better notation than this tmpRow variable
var tmpRow = _get(result, i); var tmpRow = get(result, i);
_set(tmpRow, j2, val); set(tmpRow, j2, val);
_set(result, i, tmpRow); set(result, i, tmpRow);
//result[ i ][ j2 ] += first[i][i2] * second[i2][j2] //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; return self;
} }
+3 -3
View File
@@ -1,10 +1,10 @@
//test function chaining with the dot operator //test function chaining with the dot operator
fn _identity(self) { fn identity(self) {
return self; return self;
} }
fn _check(self) { fn check(self) {
assert self == 42, "dot chaining failed"; assert self == 42, "dot chaining failed";
return self; return self;
} }
@@ -20,7 +20,7 @@ val
//test the value is actually altered //test the value is actually altered
fn _increment(self) { fn increment(self) {
return self + 1; return self + 1;
} }
+1 -1
View File
@@ -1,5 +1,5 @@
fn _add(self, inc) { fn add(self, inc) {
return self + inc; return self + inc;
} }
+1 -1
View File
@@ -63,7 +63,7 @@ extra("one", "two", "three", "four", "five", "six", "seven");
//test underscore functions //test underscore functions
fn _example(self, a, b, c) { fn example(self, a, b, c) {
assert a == "a", "underscore failed (a)"; assert a == "a", "underscore failed (a)";
assert b == "b", "underscore failed (b)"; assert b == "b", "underscore failed (b)";
assert c == "c", "underscore failed (c)"; 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";
-189
View File
@@ -1,189 +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 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 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 //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";
} }
@@ -0,0 +1 @@
"a"[--];
+39 -39
View File
@@ -3,41 +3,41 @@
//test arrays without types //test arrays without types
var array = []; var array = [];
assert _length(array) == 0, "_length failed with array"; assert length(array) == 0, "length failed with array";
_push(array, 1); push(array, 1);
_push(array, 2); push(array, 2);
_push(array, 3); push(array, 3);
_push(array, 4); push(array, 4);
_push(array, "foo"); push(array, "foo");
assert _length(array) == 5, "_push failed with array"; assert length(array) == 5, "push failed with array";
assert _pop(array) == "foo", "_pop failed with array"; assert pop(array) == "foo", "pop failed with array";
_set(array, 2, "bar"); set(array, 2, "bar");
assert array == [1, 2, "bar", 4], "_set failed with array"; assert array == [1, 2, "bar", 4], "set failed with array";
assert _get(array, 3) == 4, "_get failed with array"; assert get(array, 3) == 4, "get failed with array";
//test dictionaries without types //test dictionaries without types
var dict = [:]; var dict = [:];
_set(dict, "key", "value"); set(dict, "key", "value");
_set(dict, 1, 2); set(dict, 1, 2);
assert dict == ["key":"value", 1:2], "_set failed with dictionaries"; assert dict == ["key":"value", 1:2], "set failed with dictionaries";
assert _get(dict, "key") == "value", "_get failed with dictionaries"; assert get(dict, "key") == "value", "get failed with dictionaries";
//test _length //test length
assert _length(array) == 4 && _length(dict) == 2, "_length failed with array or dictionaries"; assert length(array) == 4 && length(dict) == 2, "length failed with array or dictionaries";
//test clear //test clear
_clear(array); clear(array);
_clear(dict); 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 //test arrays with types
var array: [int] = []; 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, 1);
_push(array, 2); push(array, 2);
_push(array, 3); push(array, 3);
_push(array, 4); push(array, 4);
_push(array, 10); push(array, 10);
assert _length(array) == 5, "_push or failed with array (+ types)"; assert length(array) == 5, "push or failed with array (+ types)";
assert _pop(array) == 10, "_pop failed with array (+ types)"; assert pop(array) == 10, "pop failed with array (+ types)";
_set(array, 2, 70); set(array, 2, 70);
assert array == [1, 2, 70, 4], "_set failed with array (+ types)"; assert array == [1, 2, 70, 4], "set failed with array (+ types)";
assert _get(array, 3) == 4, "_get failed with array (+ types)"; assert get(array, 3) == 4, "get failed with array (+ types)";
//test dictionaries with types //test dictionaries with types
var dict: [string : string] = [:]; var dict: [string : string] = [:];
_set(dict, "key", "value"); set(dict, "key", "value");
assert dict == ["key":"value"], "_set failed with dictionaries (+ types)"; assert dict == ["key":"value"], "set failed with dictionaries (+ types)";
assert _get(dict, "key") == "value", "_get failed with dictionaries (+ types)"; assert get(dict, "key") == "value", "get failed with dictionaries (+ types)";
//test length with 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 //test clear with types
_clear(array); clear(array);
_clear(dict); 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"; var str = "hello world";
assert _length(str) == 11, "_length failed with string"; assert length(str) == 11, "length failed with string";
} }
+7
View File
@@ -0,0 +1,7 @@
//This is just a check to ensure that unary minus doesn't screw up the AST
var xrel: int = 0;
var yrel: int = 0;
assert (xrel > 1 || xrel < -1 || yrel > 1 || yrel < -1) == false, "or-chaining bugfix failed";
+22
View File
@@ -0,0 +1,22 @@
//polyfill the insert function
fn insert(self, k, v) {
var tmp1 = v;
var tmp2;
for (var i = k; i < self.length(); i++) {
tmp2 = self[i];
self[i] = tmp1;
tmp1 = tmp2;
}
self.push(tmp1);
return self;
}
var a = [1, 2, 3];
a = a.insert(1, 42);
assert a == [1, 42, 2, 3], "polyfill insert failed";
print "All good";
+23
View File
@@ -0,0 +1,23 @@
//polyfill the remove function
fn remove(self, k) {
var result = [];
for (var i = 0; i <= k - 1; i++) {
result.push( self[i] );
}
for (var i = k + 1; i < self.length(); i++) {
result.push( self[i] );
}
return result;
}
var a = [1, 2, 3];
assert a.remove(0) == [2, 3], "polyfill remove(start) failed";
assert a.remove(1) == [1, 3], "polyfill remove(middle) failed";
assert a.remove(2) == [1, 2], "polyfill remove(end) failed";
print "All good";
+11 -2
View File
@@ -1,12 +1,21 @@
//memoize the fib function
var memo: [int : int] = [:];
fn fib(n : int) { fn fib(n : int) {
if (n < 2) { if (n < 2) {
return n; return n;
} }
return fib(n-1) + fib(n-2); 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); var res = fib(i);
print string i + ": " + string res; print string i + ": " + string res;
} }
+23 -23
View File
@@ -20,15 +20,15 @@ static void noPrintFn(const char* output) {
} }
void error(char* msg) { void error(char* msg) {
printf("%s", msg); printf("%s\n", msg);
exit(-1); exit(-1);
} }
int main() { int main() {
{ {
size_t size = 0; size_t size = 0;
char* source = Toy_readFile("scripts/call-from-host.toy", &size); const char* source = (const char*)Toy_readFile("scripts/call-from-host.toy", &size);
unsigned char* tb = Toy_compileString(source, &size); const unsigned char* tb = Toy_compileString(source, &size);
free((void*)source); free((void*)source);
if (!tb) { if (!tb) {
@@ -52,15 +52,15 @@ int main() {
//check the results //check the results
if (arguments.count != 0) { 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) { 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) { 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); Toy_freeLiteralArray(&arguments);
@@ -85,17 +85,17 @@ int main() {
//check the results //check the results
if (arguments.count != 0) { 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) { 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 float epsilon = 0.1; //because floats are evil
if (!TOY_IS_FLOAT(returns.literals[0]) || fabs(TOY_AS_FLOAT(returns.literals[0]) - pi) > epsilon) { 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); Toy_freeLiteralArray(&arguments);
@@ -115,11 +115,11 @@ int main() {
//check the results //check the results
if (arguments.count != 0) { 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) { 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 //grab the resulting literal
@@ -139,15 +139,15 @@ int main() {
//check the results //check the results
if (arguments.count != 0) { 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) { 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) { 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); Toy_freeLiteralArray(&arguments);
@@ -164,15 +164,15 @@ int main() {
//check the results //check the results
if (arguments.count != 0) { 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) { 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) { 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); Toy_freeLiteralArray(&arguments);
@@ -189,15 +189,15 @@ int main() {
//check the results //check the results
if (arguments.count != 0) { 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) { 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) { 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); Toy_freeLiteralArray(&arguments);
@@ -222,15 +222,15 @@ int main() {
//check the results //check the results
if (arguments.count != 0) { 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])) { 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) { if (!ret) {
error("Assertion gives the wrong return value\n"); error("Assertion gives the wrong return value");
} }
Toy_freeLiteralArray(&arguments); Toy_freeLiteralArray(&arguments);
+3 -3
View File
@@ -39,7 +39,7 @@ int main() {
Toy_writeCompiler(&compiler, node); Toy_writeCompiler(&compiler, node);
//collate //collate
int size = 0; size_t size = 0;
unsigned char* bytecode = Toy_collateCompiler(&compiler, &size); unsigned char* bytecode = Toy_collateCompiler(&compiler, &size);
//cleanup //cleanup
@@ -52,7 +52,7 @@ int main() {
{ {
//source //source
size_t sourceLength = 0; size_t sourceLength = 0;
char* source = Toy_readFile("scripts/compiler_sample_code.toy", &sourceLength); const char* source = (const char*)Toy_readFile("scripts/compiler_sample_code.toy", &sourceLength);
//test basic compilation & collation //test basic compilation & collation
Toy_Lexer lexer; Toy_Lexer lexer;
@@ -78,7 +78,7 @@ int main() {
} }
//collate //collate
int size = 0; size_t size = 0;
unsigned char* bytecode = Toy_collateCompiler(&compiler, &size); unsigned char* bytecode = Toy_collateCompiler(&compiler, &size);
//cleanup //cleanup
+14 -9
View File
@@ -30,7 +30,7 @@ static void noAssertFn(const char* output) {
} }
} }
void runBinaryCustom(unsigned char* tb, size_t size) { void runBinaryCustom(const unsigned char* tb, size_t size) {
Toy_Interpreter interpreter; Toy_Interpreter interpreter;
Toy_initInterpreter(&interpreter); Toy_initInterpreter(&interpreter);
@@ -42,18 +42,18 @@ void runBinaryCustom(unsigned char* tb, size_t size) {
Toy_freeInterpreter(&interpreter); Toy_freeInterpreter(&interpreter);
} }
void runSourceCustom(char* source) { void runSourceCustom(const char* source) {
size_t size = 0; size_t size = 0;
unsigned char* tb = Toy_compileString(source, &size); const unsigned char* tb = Toy_compileString(source, &size);
if (!tb) { if (!tb) {
return; return;
} }
runBinaryCustom(tb, size); runBinaryCustom(tb, size);
} }
void runSourceFileCustom(char* fname) { void runSourceFileCustom(const char* fname) {
size_t size = 0; //not used size_t size = 0; //not used
char* source = Toy_readFile(fname, &size); const char* source = (const char*)Toy_readFile(fname, &size);
runSourceCustom(source); runSourceCustom(source);
free((void*)source); free((void*)source);
} }
@@ -68,7 +68,7 @@ int main() {
{ {
//source //source
char* source = "print null;"; const char* source = "print null;";
//test basic compilation & collation //test basic compilation & collation
Toy_Lexer lexer; Toy_Lexer lexer;
@@ -87,8 +87,8 @@ int main() {
Toy_writeCompiler(&compiler, node); Toy_writeCompiler(&compiler, node);
//collate //collate
int size = 0; size_t size = 0;
unsigned char* bytecode = Toy_collateCompiler(&compiler, &size); const unsigned char* bytecode = Toy_collateCompiler(&compiler, &size);
//NOTE: suppress print output for testing //NOTE: suppress print output for testing
Toy_setInterpreterPrint(&interpreter, noPrintFn); Toy_setInterpreterPrint(&interpreter, noPrintFn);
@@ -106,7 +106,7 @@ int main() {
{ {
//run each file in tests/scripts/ //run each file in tests/scripts/
char* filenames[] = { const char* filenames[] = {
"arithmetic.toy", "arithmetic.toy",
"casting.toy", "casting.toy",
"coercions.toy", "coercions.toy",
@@ -117,6 +117,8 @@ int main() {
"dottify-bugfix.toy", "dottify-bugfix.toy",
"functions.toy", "functions.toy",
"index-arrays.toy", "index-arrays.toy",
"index-assignment-both-bugfix.toy",
"index-assignment-left-bugfix.toy",
"index-dictionaries.toy", "index-dictionaries.toy",
"index-strings.toy", "index-strings.toy",
"jumps.toy", "jumps.toy",
@@ -126,7 +128,10 @@ int main() {
"long-dictionary.toy", "long-dictionary.toy",
"long-literals.toy", "long-literals.toy",
"native-functions.toy", "native-functions.toy",
"or-chaining-bugfix.toy",
"panic-within-functions.toy", "panic-within-functions.toy",
"polyfill-insert.toy",
"polyfill-remove.toy",
"ternary-expressions.toy", "ternary-expressions.toy",
"types.toy", "types.toy",
NULL NULL
+4 -4
View File
@@ -15,10 +15,10 @@ int main() {
Toy_initLexer(&lexer, source); Toy_initLexer(&lexer, source);
//get each token //get each token
Toy_Token print = Toy_scanLexer(&lexer); Toy_Token print = Toy_private_scanLexer(&lexer);
Toy_Token null = Toy_scanLexer(&lexer); Toy_Token null = Toy_private_scanLexer(&lexer);
Toy_Token semi = Toy_scanLexer(&lexer); Toy_Token semi = Toy_private_scanLexer(&lexer);
Toy_Token eof = Toy_scanLexer(&lexer); Toy_Token eof = Toy_private_scanLexer(&lexer);
//test each token is correct //test each token is correct
if (strncmp(print.lexeme, "print", print.length)) { if (strncmp(print.lexeme, "print", print.length)) {
+7 -13
View File
@@ -14,10 +14,8 @@
#include "../repl/repl_tools.h" #include "../repl/repl_tools.h"
#include "../repl/lib_about.h" #include "../repl/lib_about.h"
#include "../repl/lib_compound.h"
#include "../repl/lib_runner.h" #include "../repl/lib_runner.h"
#include "../repl/lib_standard.h" #include "../repl/lib_standard.h"
#include "../repl/lib_timer.h"
//supress the print output //supress the print output
static void noPrintFn(const char* output) { static void noPrintFn(const char* output) {
@@ -37,7 +35,7 @@ static void errorWrapper(const char* output) {
fprintf(stderr, TOY_CC_ERROR "%s" TOY_CC_RESET, output); fprintf(stderr, TOY_CC_ERROR "%s" TOY_CC_RESET, output);
} }
void runBinaryWithLibrary(unsigned char* tb, size_t size, char* library, Toy_HookFn hook) { void runBinaryWithLibrary(const unsigned char* tb, size_t size, const char* library, Toy_HookFn hook) {
Toy_Interpreter interpreter; Toy_Interpreter interpreter;
Toy_initInterpreter(&interpreter); Toy_initInterpreter(&interpreter);
@@ -53,7 +51,7 @@ void runBinaryWithLibrary(unsigned char* tb, size_t size, char* library, Toy_Hoo
Toy_freeInterpreter(&interpreter); Toy_freeInterpreter(&interpreter);
} }
void runBinaryQuietly(unsigned char* tb, size_t size) { void runBinaryQuietly(const unsigned char* tb, size_t size) {
Toy_Interpreter interpreter; Toy_Interpreter interpreter;
Toy_initInterpreter(&interpreter); Toy_initInterpreter(&interpreter);
@@ -64,9 +62,7 @@ void runBinaryQuietly(unsigned char* tb, size_t size) {
//inject the libs //inject the libs
Toy_injectNativeHook(&interpreter, "about", Toy_hookAbout); Toy_injectNativeHook(&interpreter, "about", Toy_hookAbout);
Toy_injectNativeHook(&interpreter, "compound", Toy_hookCompound);
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard); Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
Toy_injectNativeHook(&interpreter, "timer", Toy_hookTimer);
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner); Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
Toy_runInterpreter(&interpreter, tb, size); Toy_runInterpreter(&interpreter, tb, size);
@@ -96,10 +92,8 @@ int main() {
Payload payloads[] = { Payload payloads[] = {
{"interactions.toy", "standard", Toy_hookStandard}, //interactions needs standard {"interactions.toy", "standard", Toy_hookStandard}, //interactions needs standard
{"about.toy", "about", Toy_hookAbout}, {"about.toy", "about", Toy_hookAbout},
{"compound.toy", "compound", Toy_hookCompound},
{"runner.toy", "runner", Toy_hookRunner},
{"standard.toy", "standard", Toy_hookStandard}, {"standard.toy", "standard", Toy_hookStandard},
{"timer.toy", "timer", Toy_hookTimer}, {"runner.toy", "runner", Toy_hookRunner},
{NULL, NULL, NULL} {NULL, NULL, NULL}
}; };
@@ -111,14 +105,14 @@ int main() {
//compile the source //compile the source
size_t size = 0; size_t size = 0;
char* source = Toy_readFile(fname, &size); const char* source = (const char*)Toy_readFile(fname, &size);
if (!source) { if (!source) {
printf(TOY_CC_ERROR "Failed to load file: %s\n" TOY_CC_RESET, fname); printf(TOY_CC_ERROR "Failed to load file: %s\n" TOY_CC_RESET, fname);
failedAsserts++; failedAsserts++;
continue; continue;
} }
unsigned char* tb = Toy_compileString(source, &size); const unsigned char* tb = Toy_compileString(source, &size);
free((void*)source); free((void*)source);
if (!tb) { if (!tb) {
@@ -146,14 +140,14 @@ int main() {
//compile the source //compile the source
size_t size = 0; size_t size = 0;
char* source = Toy_readFile(fname, &size); const char* source = (const char*)Toy_readFile(fname, &size);
if (!source) { if (!source) {
printf(TOY_CC_ERROR "Failed to load file: %s\n" TOY_CC_RESET, fname); printf(TOY_CC_ERROR "Failed to load file: %s\n" TOY_CC_RESET, fname);
failedAsserts++; failedAsserts++;
continue; continue;
} }
unsigned char* tb = Toy_compileString(source, &size); const unsigned char* tb = Toy_compileString(source, &size);
free((void*)source); free((void*)source);
if (!tb) { if (!tb) {
+8 -7
View File
@@ -23,7 +23,7 @@ static void noErrorFn(const char* output) {
errorsTriggered++; errorsTriggered++;
} }
unsigned char* compileStringCustom(char* source, size_t* size) { const unsigned char* compileStringCustom(const char* source, size_t* size) {
Toy_Lexer lexer; Toy_Lexer lexer;
Toy_Parser parser; Toy_Parser parser;
Toy_Compiler compiler; Toy_Compiler compiler;
@@ -50,7 +50,7 @@ unsigned char* compileStringCustom(char* source, size_t* size) {
} }
//get the bytecode dump //get the bytecode dump
unsigned char* tb = Toy_collateCompiler(&compiler, (int*)(size)); const unsigned char* tb = Toy_collateCompiler(&compiler, size);
//cleanup //cleanup
Toy_freeCompiler(&compiler); Toy_freeCompiler(&compiler);
@@ -61,7 +61,7 @@ unsigned char* compileStringCustom(char* source, size_t* size) {
return tb; return tb;
} }
void runBinaryCustom(unsigned char* tb, size_t size) { void runBinaryCustom(const unsigned char* tb, size_t size) {
Toy_Interpreter interpreter; Toy_Interpreter interpreter;
Toy_initInterpreter(&interpreter); Toy_initInterpreter(&interpreter);
@@ -73,18 +73,18 @@ void runBinaryCustom(unsigned char* tb, size_t size) {
Toy_freeInterpreter(&interpreter); Toy_freeInterpreter(&interpreter);
} }
void runSourceCustom(char* source) { void runSourceCustom(const char* source) {
size_t size = 0; size_t size = 0;
unsigned char* tb = compileStringCustom(source, &size); const unsigned char* tb = compileStringCustom(source, &size);
if (!tb) { if (!tb) {
return; return;
} }
runBinaryCustom(tb, size); runBinaryCustom(tb, size);
} }
void runSourceFileCustom(char* fname) { void runSourceFileCustom(const char* fname) {
size_t size = 0; //not used size_t size = 0; //not used
char* source = Toy_readFile(fname, &size); const char* source = (const char*)Toy_readFile(fname, &size);
runSourceCustom(source); runSourceCustom(source);
free((void*)source); free((void*)source);
} }
@@ -101,6 +101,7 @@ int main() {
"declare-types-array.toy", "declare-types-array.toy",
"declare-types-dictionary-key.toy", "declare-types-dictionary-key.toy",
"declare-types-dictionary-value.toy", "declare-types-dictionary-value.toy",
"index-access-bugfix.toy",
"index-arrays-non-integer.toy", "index-arrays-non-integer.toy",
"string-concat.toy", "string-concat.toy",
"unary-inverted-nothing.toy", "unary-inverted-nothing.toy",
+2 -2
View File
@@ -68,8 +68,8 @@ static int consume(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
int main() { int main() {
{ {
size_t size = 0; size_t size = 0;
char* source = Toy_readFile("scripts/opaque-data-type.toy", &size); const char* source = (const char*)Toy_readFile("scripts/opaque-data-type.toy", &size);
unsigned char* tb = Toy_compileString(source, &size); const unsigned char* tb = Toy_compileString(source, &size);
free((void*)source); free((void*)source);
if (!tb) { if (!tb) {
+5 -5
View File
@@ -11,7 +11,7 @@
int main() { int main() {
{ {
//source //source
char* source = "print null;"; const char* source = "print null;";
//test init & quit //test init & quit
Toy_Lexer lexer; Toy_Lexer lexer;
@@ -24,7 +24,7 @@ int main() {
{ {
//source //source
char* source = "print null;"; const char* source = "print null;";
//test parsing //test parsing
Toy_Lexer lexer; Toy_Lexer lexer;
@@ -58,7 +58,7 @@ int main() {
{ {
//get the source file //get the source file
size_t size = 0; size_t size = 0;
char* source = Toy_readFile("scripts/parser_sample_code.toy", &size); const char* source = (const char*)Toy_readFile("scripts/parser_sample_code.toy", &size);
//test parsing a chunk of junk (valgrind will find leaks) //test parsing a chunk of junk (valgrind will find leaks)
Toy_Lexer lexer; Toy_Lexer lexer;
@@ -85,7 +85,7 @@ int main() {
{ {
//test parsing of escaped characters //test parsing of escaped characters
char* source = "print \"\\\"\";"; //NOTE: this string goes through two layers of escaping const char* source = "print \"\\\"\";"; //NOTE: this string goes through two layers of escaping
//test parsing //test parsing
Toy_Lexer lexer; Toy_Lexer lexer;
@@ -123,7 +123,7 @@ int main() {
{ {
//test parsing of underscored numbers //test parsing of underscored numbers
char* source = "print 1_000_000;"; const char* source = "print 1_000_000;";
//test parsing //test parsing
Toy_Lexer lexer; Toy_Lexer lexer;
+4 -1
View File
@@ -39,11 +39,14 @@ static void* trackerAllocator(void* pointer, size_t oldSize, size_t newSize) {
return mem; return mem;
} }
int main(int argc, char* argv[]) { int main(int argc, const char* argv[]) {
if (argc <= 1) { if (argc <= 1) {
return -1; return -1;
} }
//not used, except for print
Toy_initCommandLine(argc, argv);
//setup for runner //setup for runner
Toy_initDriveDictionary(); Toy_initDriveDictionary();