Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f84cdff883 | |||
| f869c9425a | |||
| 76ddd5703e | |||
| 669808730e | |||
| e6d9809da5 | |||
| 502032e514 | |||
| 6e9d42f892 | |||
| 70ca27486e | |||
| 12fa434e0f | |||
| efc1e764d2 | |||
| c5c0122243 | |||
| 348b7b8c24 | |||
| e243ad949a | |||
| 9b673f23ad | |||
| 624a0c80ba | |||
| 1064b69d04 | |||
| e9b347acb6 | |||
| 071c8da2aa | |||
| d6538812bf | |||
| 3aeddff736 | |||
| c88c1b125d | |||
| 1513ba9878 | |||
| bc0289c3f4 | |||
| 92c71a374d | |||
| e0547474b8 | |||
| 3e6d21afbb | |||
| d3df01c1c4 | |||
| cdca6fa45c | |||
| 1dde9d8f29 | |||
| 7f0f17b6e0 | |||
| 3507104121 | |||
| 87de634e30 | |||
| 6fa224fa7b | |||
| 8a68d864e6 | |||
| 49f240ea07 | |||
| 3acbd7447a | |||
| 6f126e6daa | |||
| 2adb9d9158 | |||
| 1668dca255 | |||
| 501ff6fff4 | |||
| 3845627fe5 | |||
| cdae03bd54 | |||
| 7b501b71b5 | |||
| 913738a4d1 | |||
| 3312a38c7c | |||
| 71b57fd42c | |||
| 453afbab41 | |||
| 57af5a6d59 | |||
| 0737b2a483 | |||
| eae96d6403 | |||
| b55b8e879e | |||
| 1ed114b80d | |||
| eb8e522bf2 | |||
| 16b71ba6f4 | |||
| 9725f3c6a3 | |||
| 8653a2663f | |||
| ab2cd5dc93 | |||
| 724804a78a | |||
| 77a128e0f7 | |||
| 5343e1054d | |||
| 3930ec0477 | |||
| 996744d7ec | |||
| c00b32017b | |||
| 457014d577 | |||
| be4cbf1ad6 | |||
| aeb008c684 | |||
| 53012dbce1 | |||
| 4fe57f9562 | |||
| 3ba2e420ea | |||
| c81a139c97 | |||
| 66ea684a90 | |||
| a26a6a56d0 | |||
| ee226ea426 | |||
| 76a0290290 |
+6
-3
@@ -1,6 +1,4 @@
|
||||
#Editor generated files
|
||||
*.sln
|
||||
*.vcproj
|
||||
*.suo
|
||||
*.ncb
|
||||
*.user
|
||||
@@ -13,18 +11,23 @@ Out/
|
||||
release/
|
||||
debug/
|
||||
out/
|
||||
bin/
|
||||
.cache/
|
||||
.vs/
|
||||
|
||||
#Project generated files
|
||||
*.db
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
*.dll
|
||||
*.exe
|
||||
*.meta
|
||||
*.log
|
||||
out
|
||||
*.out
|
||||
*.stackdump
|
||||
*.tb
|
||||
*.filters
|
||||
|
||||
#Shell files
|
||||
*.bat
|
||||
|
||||
@@ -23,7 +23,9 @@ Special thanks to http://craftinginterpreters.com/ for their fantastic book that
|
||||
|
||||
For Windows(mingw32 & cygwin), Linux and MacOS, simply run `make` in the root directory.
|
||||
|
||||
Note: MacOS is not officially supported (no machines for testing), but we'll do our best!
|
||||
For Windows(MSVC), Visual Studio project files are included.
|
||||
|
||||
Note: MacOS and Windows(MSVC) are not officially supported, but we'll do our best!
|
||||
|
||||
## Tools
|
||||
|
||||
@@ -36,7 +38,6 @@ Run `make install-tools` to install a number of tools, including:
|
||||
```
|
||||
import standard; //for a bunch of utility functions
|
||||
|
||||
|
||||
print "Hello world"; //"print" is a keyword
|
||||
|
||||
var msg = "foobar"; //declare a variable like this
|
||||
@@ -60,8 +61,6 @@ var tally = makeCounter();
|
||||
print tally(); //1
|
||||
print tally(); //2
|
||||
print tally(); //3
|
||||
|
||||
export tally; //export this variable to the host program
|
||||
```
|
||||
|
||||
# License
|
||||
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
<?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>LIB_RUNNER_EXPORT</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<LanguageStandard_C>stdc17</LanguageStandard_C>
|
||||
<PreprocessorDefinitions>LIB_RUNNER_EXPORT</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)/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_random.c" />
|
||||
<ClCompile Include="repl\lib_runner.c" />
|
||||
<ClCompile Include="repl\lib_standard.c" />
|
||||
<ClCompile Include="repl\repl_main.c" />
|
||||
<ClCompile Include="repl\repl_tools.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="repl\lib_about.h" />
|
||||
<ClInclude Include="repl\lib_random.h" />
|
||||
<ClInclude Include="repl\lib_runner.h" />
|
||||
<ClInclude Include="repl\lib_standard.h" />
|
||||
<ClInclude Include="repl\repl_tools.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="Toy.vcxproj">
|
||||
<Project>{26360002-cc2a-469a-9b28-ba0c1af41657}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
+159
@@ -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
@@ -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
|
||||
@@ -10,10 +10,10 @@ all: $(TOY_OUTDIR) repl
|
||||
|
||||
#repl builds
|
||||
repl: $(TOY_OUTDIR) library
|
||||
$(MAKE) -C repl
|
||||
$(MAKE) -j8 -C repl
|
||||
|
||||
repl-static: $(TOY_OUTDIR) static
|
||||
$(MAKE) -C repl
|
||||
$(MAKE) -j8 -C repl
|
||||
|
||||
repl-release: clean $(TOY_OUTDIR) library-release
|
||||
$(MAKE) -C repl release
|
||||
|
||||
-1003
File diff suppressed because it is too large
Load Diff
@@ -1,6 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "toy_interpreter.h"
|
||||
|
||||
int Toy_hookCompound(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
#include "lib_random.h"
|
||||
|
||||
#include "toy_memory.h"
|
||||
|
||||
static int hashInt(int x) {
|
||||
x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||
x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||
x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||
x = (x >> 16) ^ x;
|
||||
return x;
|
||||
}
|
||||
|
||||
typedef struct Toy_RandomGenerator {
|
||||
int seed; //mutated with each call
|
||||
} Toy_RandomGenerator;
|
||||
|
||||
//Toy native functions
|
||||
static int nativeCreateRandomGenerator(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
//arguments
|
||||
if (arguments->count != 1) {
|
||||
interpreter->errorOutput("Incorrect number of arguments to createRandomGenerator\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
//get the seed argument
|
||||
Toy_Literal seedLiteral = Toy_popLiteralArray(arguments);
|
||||
|
||||
Toy_Literal seedLiteralIdn = seedLiteral;
|
||||
if (TOY_IS_IDENTIFIER(seedLiteral) && Toy_parseIdentifierToValue(interpreter, &seedLiteral)) {
|
||||
Toy_freeLiteral(seedLiteralIdn);
|
||||
}
|
||||
|
||||
if (TOY_IS_IDENTIFIER(seedLiteral)) {
|
||||
Toy_freeLiteral(seedLiteral);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!TOY_IS_INTEGER(seedLiteral)) {
|
||||
interpreter->errorOutput("Incorrect literal type passed to createRandomGenerator");
|
||||
Toy_freeLiteral(seedLiteral);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//generate the generator object
|
||||
Toy_RandomGenerator* generator = TOY_ALLOCATE(Toy_RandomGenerator, 1);
|
||||
generator->seed = TOY_AS_INTEGER(seedLiteral);
|
||||
Toy_Literal generatorLiteral = TOY_TO_OPAQUE_LITERAL(generator, TOY_OPAQUE_TAG_RANDOM);
|
||||
|
||||
//return and cleanup
|
||||
Toy_pushLiteralArray(&interpreter->stack, generatorLiteral);
|
||||
|
||||
Toy_freeLiteral(seedLiteral);
|
||||
Toy_freeLiteral(generatorLiteral);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int nativeGenerateRandomNumber(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
//no arguments
|
||||
if (arguments->count != 1) {
|
||||
interpreter->errorOutput("Incorrect number of arguments to generateRandomNumber\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
//get the runner object
|
||||
Toy_Literal generatorLiteral = Toy_popLiteralArray(arguments);
|
||||
|
||||
Toy_Literal generatorLiteralIdn = generatorLiteral;
|
||||
if (TOY_IS_IDENTIFIER(generatorLiteral) && Toy_parseIdentifierToValue(interpreter, &generatorLiteral)) {
|
||||
Toy_freeLiteral(generatorLiteralIdn);
|
||||
}
|
||||
|
||||
if (TOY_IS_IDENTIFIER(generatorLiteral)) {
|
||||
Toy_freeLiteral(generatorLiteral);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (TOY_GET_OPAQUE_TAG(generatorLiteral) != TOY_OPAQUE_TAG_RANDOM) {
|
||||
interpreter->errorOutput("Unrecognized opaque literal in generateRandomNumber\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Toy_RandomGenerator* generator = TOY_AS_OPAQUE(generatorLiteral);
|
||||
|
||||
//generate the new value and package up the return
|
||||
generator->seed = hashInt(generator->seed);
|
||||
|
||||
Toy_Literal resultLiteral = TOY_TO_INTEGER_LITERAL(generator->seed);
|
||||
|
||||
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
|
||||
|
||||
//cleanup
|
||||
Toy_freeLiteral(generatorLiteral);
|
||||
Toy_freeLiteral(resultLiteral);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nativeFreeRandomGenerator(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
//no arguments
|
||||
if (arguments->count != 1) {
|
||||
interpreter->errorOutput("Incorrect number of arguments to freeRandomGenerator\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
//get the runner object
|
||||
Toy_Literal generatorLiteral = Toy_popLiteralArray(arguments);
|
||||
|
||||
Toy_Literal generatorLiteralIdn = generatorLiteral;
|
||||
if (TOY_IS_IDENTIFIER(generatorLiteral) && Toy_parseIdentifierToValue(interpreter, &generatorLiteral)) {
|
||||
Toy_freeLiteral(generatorLiteralIdn);
|
||||
}
|
||||
|
||||
if (TOY_IS_IDENTIFIER(generatorLiteral)) {
|
||||
Toy_freeLiteral(generatorLiteral);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (TOY_GET_OPAQUE_TAG(generatorLiteral) != TOY_OPAQUE_TAG_RANDOM) {
|
||||
interpreter->errorOutput("Unrecognized opaque literal in freeRandomGenerator\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Toy_RandomGenerator* generator = TOY_AS_OPAQUE(generatorLiteral);
|
||||
|
||||
//clear out the runner object
|
||||
TOY_FREE(Toy_RandomGenerator, generator);
|
||||
Toy_freeLiteral(generatorLiteral);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//call the hook
|
||||
typedef struct Natives {
|
||||
const char* name;
|
||||
Toy_NativeFn fn;
|
||||
} Natives;
|
||||
|
||||
int Toy_hookRandom(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
|
||||
//build the natives list
|
||||
Natives natives[] = {
|
||||
{"createRandomGenerator", nativeCreateRandomGenerator},
|
||||
{"generateRandomNumber", nativeGenerateRandomNumber},
|
||||
{"freeRandomGenerator", nativeFreeRandomGenerator},
|
||||
{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;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "toy_interpreter.h"
|
||||
|
||||
int Toy_hookRandom(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
|
||||
|
||||
#define TOY_OPAQUE_TAG_RANDOM 200
|
||||
+74
-32
@@ -7,10 +7,11 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct Toy_Runner {
|
||||
Toy_Interpreter interpreter;
|
||||
unsigned char* bytecode;
|
||||
const unsigned char* bytecode;
|
||||
size_t size;
|
||||
|
||||
bool dirty;
|
||||
@@ -32,6 +33,11 @@ static int nativeLoadScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu
|
||||
Toy_freeLiteral(drivePathLiteralIdn);
|
||||
}
|
||||
|
||||
if (TOY_IS_IDENTIFIER(drivePathLiteral)) {
|
||||
Toy_freeLiteral(drivePathLiteral);
|
||||
return -1;
|
||||
}
|
||||
|
||||
Toy_Literal filePathLiteral = Toy_getFilePathLiteral(interpreter, &drivePathLiteral);
|
||||
|
||||
if (TOY_IS_NULL(filePathLiteral)) {
|
||||
@@ -43,12 +49,12 @@ static int nativeLoadScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu
|
||||
Toy_freeLiteral(drivePathLiteral);
|
||||
|
||||
//use raw types - easier
|
||||
char* filePath = Toy_toCString(TOY_AS_STRING(filePathLiteral));
|
||||
int filePathLength = Toy_lengthRefString(TOY_AS_STRING(filePathLiteral));
|
||||
const char* filePath = Toy_toCString(TOY_AS_STRING(filePathLiteral));
|
||||
size_t filePathLength = Toy_lengthRefString(TOY_AS_STRING(filePathLiteral));
|
||||
|
||||
//load and compile the bytecode
|
||||
size_t fileSize = 0;
|
||||
char* source = Toy_readFile(filePath, &fileSize);
|
||||
const char* source = (const char*)Toy_readFile(filePath, &fileSize);
|
||||
|
||||
if (!source) {
|
||||
interpreter->errorOutput("Failed to load source file\n");
|
||||
@@ -56,7 +62,7 @@ static int nativeLoadScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned char* bytecode = Toy_compileString(source, &fileSize);
|
||||
const unsigned char* bytecode = Toy_compileString(source, &fileSize);
|
||||
free((void*)source);
|
||||
|
||||
if (!bytecode) {
|
||||
@@ -102,10 +108,15 @@ static int nativeLoadScriptBytecode(Toy_Interpreter* interpreter, Toy_LiteralArr
|
||||
Toy_freeLiteral(drivePathLiteralIdn);
|
||||
}
|
||||
|
||||
if (TOY_IS_IDENTIFIER(drivePathLiteral)) {
|
||||
Toy_freeLiteral(drivePathLiteral);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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
|
||||
int driveLength = 0;
|
||||
size_t driveLength = 0;
|
||||
while (Toy_toCString(drivePath)[driveLength] != ':') {
|
||||
if (driveLength >= Toy_lengthRefString(drivePath)) {
|
||||
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
|
||||
Toy_RefString* realDrive = Toy_copyRefString(TOY_AS_STRING(realDriveLiteral));
|
||||
int realLength = Toy_lengthRefString(realDrive) + Toy_lengthRefString(path);
|
||||
size_t realLength = Toy_lengthRefString(realDrive) + Toy_lengthRefString(path);
|
||||
|
||||
char* filePath = TOY_ALLOCATE(char, realLength + 1); //+1 for null
|
||||
snprintf(filePath, realLength, "%s%s", Toy_toCString(realDrive), Toy_toCString(path));
|
||||
@@ -159,7 +170,7 @@ static int nativeLoadScriptBytecode(Toy_Interpreter* interpreter, Toy_LiteralArr
|
||||
}
|
||||
|
||||
//check for break-out attempts
|
||||
for (int i = 0; i < realLength - 1; i++) {
|
||||
for (size_t i = 0; i < realLength - 1; i++) {
|
||||
if (filePath[i] == '.' && filePath[i + 1] == '.') {
|
||||
interpreter->errorOutput("Parent directory access not allowed\n");
|
||||
TOY_FREE_ARRAY(char, filePath, realLength);
|
||||
@@ -200,7 +211,7 @@ static int nativeLoadScriptBytecode(Toy_Interpreter* interpreter, Toy_LiteralArr
|
||||
static int nativeRunScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
//no arguments
|
||||
if (arguments->count != 1) {
|
||||
interpreter->errorOutput("Incorrect number of arguments to _runScript\n");
|
||||
interpreter->errorOutput("Incorrect number of arguments to runScript\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -212,8 +223,13 @@ static int nativeRunScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argum
|
||||
Toy_freeLiteral(runnerIdn);
|
||||
}
|
||||
|
||||
if (TOY_IS_IDENTIFIER(runnerLiteral)) {
|
||||
Toy_freeLiteral(runnerLiteral);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
|
||||
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
|
||||
interpreter->errorOutput("Unrecognized opaque literal in runScript\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -241,7 +257,7 @@ static int nativeRunScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argum
|
||||
static int nativeGetScriptVar(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
//no arguments
|
||||
if (arguments->count != 2) {
|
||||
interpreter->errorOutput("Incorrect number of arguments to _getScriptVar\n");
|
||||
interpreter->errorOutput("Incorrect number of arguments to getScriptVar\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -259,8 +275,14 @@ static int nativeGetScriptVar(Toy_Interpreter* interpreter, Toy_LiteralArray* ar
|
||||
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) {
|
||||
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
|
||||
interpreter->errorOutput("Unrecognized opaque literal in getScriptVar\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -292,7 +314,7 @@ static int nativeGetScriptVar(Toy_Interpreter* interpreter, Toy_LiteralArray* ar
|
||||
static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
//no arguments
|
||||
if (arguments->count < 2) {
|
||||
interpreter->errorOutput("Incorrect number of arguments to _callScriptFn\n");
|
||||
interpreter->errorOutput("Incorrect number of arguments to callScriptFn\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -309,7 +331,7 @@ static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* ar
|
||||
Toy_LiteralArray rest;
|
||||
Toy_initLiteralArray(&rest);
|
||||
|
||||
while (tmp.count) { //correct the order of the rest args
|
||||
while (tmp.count > 0) { //correct the order of the rest args
|
||||
Toy_Literal lit = Toy_popLiteralArray(&tmp);
|
||||
Toy_pushLiteralArray(&rest, lit);
|
||||
Toy_freeLiteral(lit);
|
||||
@@ -317,7 +339,6 @@ static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* ar
|
||||
|
||||
Toy_freeLiteralArray(&tmp);
|
||||
|
||||
|
||||
//get the runner object
|
||||
Toy_Literal varName = Toy_popLiteralArray(arguments);
|
||||
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
|
||||
@@ -332,8 +353,14 @@ static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* ar
|
||||
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) {
|
||||
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
|
||||
interpreter->errorOutput("Unrecognized opaque literal in callScriptFn\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -389,7 +416,7 @@ static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* ar
|
||||
static int nativeResetScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
//no arguments
|
||||
if (arguments->count != 1) {
|
||||
interpreter->errorOutput("Incorrect number of arguments to _resetScript\n");
|
||||
interpreter->errorOutput("Incorrect number of arguments to resetScript\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -401,8 +428,13 @@ static int nativeResetScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arg
|
||||
Toy_freeLiteral(runnerIdn);
|
||||
}
|
||||
|
||||
if (TOY_IS_IDENTIFIER(runnerLiteral)) {
|
||||
Toy_freeLiteral(runnerLiteral);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
|
||||
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
|
||||
interpreter->errorOutput("Unrecognized opaque literal in resetScript\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -425,7 +457,7 @@ static int nativeResetScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arg
|
||||
static int nativeFreeScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
//no arguments
|
||||
if (arguments->count != 1) {
|
||||
interpreter->errorOutput("Incorrect number of arguments to _freeScript\n");
|
||||
interpreter->errorOutput("Incorrect number of arguments to freeScript\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -437,8 +469,13 @@ static int nativeFreeScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu
|
||||
Toy_freeLiteral(runnerIdn);
|
||||
}
|
||||
|
||||
if (TOY_IS_IDENTIFIER(runnerLiteral)) {
|
||||
Toy_freeLiteral(runnerLiteral);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
|
||||
interpreter->errorOutput("Unrecognized opaque literal in _freeScript\n");
|
||||
interpreter->errorOutput("Unrecognized opaque literal in freeScript\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -459,7 +496,7 @@ static int nativeFreeScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu
|
||||
static int nativeCheckScriptDirty(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
//no arguments
|
||||
if (arguments->count != 1) {
|
||||
interpreter->errorOutput("Incorrect number of arguments to _runScript\n");
|
||||
interpreter->errorOutput("Incorrect number of arguments to checkScriptDirty\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -471,8 +508,13 @@ static int nativeCheckScriptDirty(Toy_Interpreter* interpreter, Toy_LiteralArray
|
||||
Toy_freeLiteral(runnerIdn);
|
||||
}
|
||||
|
||||
if (TOY_IS_IDENTIFIER(runnerLiteral)) {
|
||||
Toy_freeLiteral(runnerLiteral);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -492,7 +534,7 @@ static int nativeCheckScriptDirty(Toy_Interpreter* interpreter, Toy_LiteralArray
|
||||
|
||||
//call the hook
|
||||
typedef struct Natives {
|
||||
char* name;
|
||||
const char* name;
|
||||
Toy_NativeFn fn;
|
||||
} Natives;
|
||||
|
||||
@@ -501,12 +543,12 @@ int Toy_hookRunner(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Lit
|
||||
Natives natives[] = {
|
||||
{"loadScript", nativeLoadScript},
|
||||
{"loadScriptBytecode", nativeLoadScriptBytecode},
|
||||
{"_runScript", nativeRunScript},
|
||||
{"_getScriptVar", nativeGetScriptVar},
|
||||
{"_callScriptFn", nativeCallScriptFn},
|
||||
{"_resetScript", nativeResetScript},
|
||||
{"_freeScript", nativeFreeScript},
|
||||
{"_checkScriptDirty", nativeCheckScriptDirty},
|
||||
{"runScript", nativeRunScript},
|
||||
{"getScriptVar", nativeGetScriptVar},
|
||||
{"callScriptFn", nativeCallScriptFn},
|
||||
{"resetScript", nativeResetScript},
|
||||
{"freeScript", nativeFreeScript},
|
||||
{"checkScriptDirty", nativeCheckScriptDirty},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
@@ -585,7 +627,7 @@ Toy_Literal Toy_getFilePathLiteral(Toy_Interpreter* interpreter, Toy_Literal* dr
|
||||
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
|
||||
int driveLength = 0;
|
||||
size_t driveLength = 0;
|
||||
while (Toy_toCString(drivePath)[driveLength] != ':') {
|
||||
if (driveLength >= Toy_lengthRefString(drivePath)) {
|
||||
interpreter->errorOutput("Incorrect drive path format given to Toy_getFilePathLiteral\n");
|
||||
@@ -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
|
||||
Toy_RefString* realDrive = Toy_copyRefString(TOY_AS_STRING(realDriveLiteral));
|
||||
int realLength = Toy_lengthRefString(realDrive) + Toy_lengthRefString(path);
|
||||
size_t realLength = Toy_lengthRefString(realDrive) + Toy_lengthRefString(path);
|
||||
|
||||
char* filePath = TOY_ALLOCATE(char, realLength + 1); //+1 for null
|
||||
snprintf(filePath, realLength, "%s%s", Toy_toCString(realDrive), Toy_toCString(path));
|
||||
@@ -630,7 +672,7 @@ Toy_Literal Toy_getFilePathLiteral(Toy_Interpreter* interpreter, Toy_Literal* dr
|
||||
Toy_deleteRefString(drivePath);
|
||||
|
||||
//check for break-out attempts
|
||||
for (int i = 0; i < realLength - 1; i++) {
|
||||
for (size_t i = 0; i < realLength - 1; i++) {
|
||||
if (filePath[i] == '.' && filePath[i + 1] == '.') {
|
||||
interpreter->errorOutput("Parent directory access not allowed\n");
|
||||
TOY_FREE_ARRAY(char, filePath, realLength + 1);
|
||||
|
||||
+26
-6
@@ -1,15 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include "toy_common.h"
|
||||
#include "toy_interpreter.h"
|
||||
|
||||
int Toy_hookRunner(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
|
||||
|
||||
//file system API - these need to be set by the host
|
||||
void Toy_initDriveDictionary();
|
||||
void Toy_freeDriveDictionary();
|
||||
Toy_LiteralDictionary* Toy_getDriveDictionary();
|
||||
|
||||
#define TOY_OPAQUE_TAG_RUNNER 100
|
||||
|
||||
//platform/compiler-specific instructions - because MSVC + Box Engine are dumber than a bag of rocks
|
||||
#if defined(__linux__) || defined(__MINGW32__) || defined(__GNUC__)
|
||||
|
||||
#define LIB_RUNNER_API extern
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
#ifndef LIB_RUNNER_EXPORT
|
||||
#define LIB_RUNNER_API __declspec(dllimport)
|
||||
#else
|
||||
#define LIB_RUNNER_API __declspec(dllexport)
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define LIB_RUNNER_API extern
|
||||
|
||||
#endif
|
||||
|
||||
//file system API - these need to be set by the host
|
||||
LIB_RUNNER_API void Toy_initDriveDictionary();
|
||||
LIB_RUNNER_API void Toy_freeDriveDictionary();
|
||||
LIB_RUNNER_API Toy_LiteralDictionary* Toy_getDriveDictionary();
|
||||
|
||||
//file system API - for use with other libs
|
||||
Toy_Literal Toy_getFilePathLiteral(Toy_Interpreter* interpreter, Toy_Literal* drivePathLiteral);
|
||||
LIB_RUNNER_API Toy_Literal Toy_getFilePathLiteral(Toy_Interpreter* interpreter, Toy_Literal* drivePathLiteral);
|
||||
|
||||
+1994
-2
File diff suppressed because it is too large
Load Diff
@@ -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, µsecondLiteral)) {
|
||||
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;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "toy_interpreter.h"
|
||||
|
||||
int Toy_hookTimer(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
|
||||
|
||||
+70
-18
@@ -1,8 +1,7 @@
|
||||
#include "repl_tools.h"
|
||||
#include "lib_about.h"
|
||||
#include "lib_compound.h"
|
||||
#include "lib_standard.h"
|
||||
#include "lib_timer.h"
|
||||
#include "lib_random.h"
|
||||
#include "lib_runner.h"
|
||||
|
||||
#include "toy_console_colors.h"
|
||||
@@ -16,30 +15,31 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void repl() {
|
||||
#define INPUT_BUFFER_SIZE 2048
|
||||
|
||||
void repl(const char* initialInput) {
|
||||
//repl does it's own thing for now
|
||||
bool error = false;
|
||||
|
||||
const int size = 2048;
|
||||
char input[size];
|
||||
memset(input, 0, size);
|
||||
char input[INPUT_BUFFER_SIZE];
|
||||
memset(input, 0, INPUT_BUFFER_SIZE);
|
||||
|
||||
Toy_Interpreter interpreter; //persist the interpreter for the scopes
|
||||
Toy_initInterpreter(&interpreter);
|
||||
|
||||
//inject the libs
|
||||
Toy_injectNativeHook(&interpreter, "about", Toy_hookAbout);
|
||||
Toy_injectNativeHook(&interpreter, "compound", Toy_hookCompound);
|
||||
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
|
||||
Toy_injectNativeHook(&interpreter, "timer", Toy_hookTimer);
|
||||
Toy_injectNativeHook(&interpreter, "random", Toy_hookRandom);
|
||||
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
|
||||
|
||||
for(;;) {
|
||||
printf("> ");
|
||||
|
||||
//handle EOF for exits
|
||||
if (!fgets(input, size, stdin)) {
|
||||
break;
|
||||
if (!initialInput) {
|
||||
//handle EOF for exits
|
||||
printf("> ");
|
||||
if (!fgets(input, INPUT_BUFFER_SIZE, stdin)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//escape the repl (length of 5 to accomodate the newline)
|
||||
@@ -52,7 +52,8 @@ void repl() {
|
||||
Toy_Parser parser;
|
||||
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_initCompiler(&compiler);
|
||||
|
||||
@@ -76,7 +77,7 @@ void repl() {
|
||||
|
||||
if (!error) {
|
||||
//get the bytecode dump
|
||||
int size = 0;
|
||||
size_t size = 0;
|
||||
unsigned char* tb = Toy_collateCompiler(&compiler, &size);
|
||||
|
||||
//run the bytecode
|
||||
@@ -87,6 +88,15 @@ void repl() {
|
||||
Toy_freeCompiler(&compiler);
|
||||
Toy_freeParser(&parser);
|
||||
error = false;
|
||||
|
||||
if (initialInput) {
|
||||
free((void*)initialInput);
|
||||
initialInput = NULL;
|
||||
|
||||
if (interpreter.panic) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Toy_freeInterpreter(&interpreter);
|
||||
@@ -130,6 +140,14 @@ int main(int argc, const char* argv[]) {
|
||||
|
||||
//run source file
|
||||
if (Toy_commandLine.sourcefile) {
|
||||
//only works on toy files
|
||||
const char* s = strrchr(Toy_commandLine.sourcefile, '.');
|
||||
if (!s || strcmp(s, ".toy")) {
|
||||
fprintf(stderr, TOY_CC_ERROR "Bad file extension passed to %s (expected '.toy', found '%s')" TOY_CC_RESET, argv[0], s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//run the source file
|
||||
Toy_runSourceFile(Toy_commandLine.sourcefile);
|
||||
|
||||
//lib cleanup
|
||||
@@ -150,12 +168,25 @@ int main(int argc, const char* argv[]) {
|
||||
|
||||
//compile source file
|
||||
if (Toy_commandLine.compilefile && Toy_commandLine.outfile) {
|
||||
//only works on toy and tb files
|
||||
const char* c = strrchr(Toy_commandLine.compilefile, '.');
|
||||
if (!c || strcmp(c, ".toy")) {
|
||||
fprintf(stderr, TOY_CC_ERROR "Bad file extension passed to %s (expected '.toy', found '%s')" TOY_CC_RESET, argv[0], c);
|
||||
return -1;
|
||||
}
|
||||
const char* o = strrchr(Toy_commandLine.outfile, '.');
|
||||
if (!o || strcmp(o, ".tb")) {
|
||||
fprintf(stderr, TOY_CC_ERROR "Bad file extension passed to %s (expected '.tb', found '%s')" TOY_CC_RESET, argv[0], o);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//compile and save
|
||||
size_t size = 0;
|
||||
char* source = Toy_readFile(Toy_commandLine.compilefile, &size);
|
||||
const char* source = (const char*)Toy_readFile(Toy_commandLine.compilefile, &size);
|
||||
if (!source) {
|
||||
return 1;
|
||||
}
|
||||
unsigned char* tb = Toy_compileString(source, &size);
|
||||
const unsigned char* tb = Toy_compileString(source, &size);
|
||||
if (!tb) {
|
||||
return 1;
|
||||
}
|
||||
@@ -165,6 +196,14 @@ int main(int argc, const char* argv[]) {
|
||||
|
||||
//run binary
|
||||
if (Toy_commandLine.binaryfile) {
|
||||
//only works on tb files
|
||||
const char* c = strrchr(Toy_commandLine.binaryfile, '.');
|
||||
if (!c || strcmp(c, ".tb")) {
|
||||
fprintf(stderr, TOY_CC_ERROR "Bad file extension passed to %s (expected '.tb', found '%s')" TOY_CC_RESET, argv[0], c); //this one is never seen
|
||||
return -1;
|
||||
}
|
||||
|
||||
//run the binary file
|
||||
Toy_runBinaryFile(Toy_commandLine.binaryfile);
|
||||
|
||||
//lib cleanup
|
||||
@@ -173,7 +212,20 @@ int main(int argc, const char* argv[]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
repl();
|
||||
const char* initialSource = NULL;
|
||||
if (Toy_commandLine.initialfile) {
|
||||
//only works on toy files
|
||||
const char* s = strrchr(Toy_commandLine.initialfile, '.');
|
||||
if (!s || strcmp(s, ".toy")) {
|
||||
fprintf(stderr, TOY_CC_ERROR "Bad file extension passed to %s (expected '.toy', found '%s')" TOY_CC_RESET, argv[0], s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t size;
|
||||
initialSource = (const char*)Toy_readFile(Toy_commandLine.initialfile, &size);
|
||||
}
|
||||
|
||||
repl(initialSource);
|
||||
|
||||
//lib cleanup
|
||||
Toy_freeDriveDictionary();
|
||||
|
||||
+17
-19
@@ -1,8 +1,7 @@
|
||||
#include "repl_tools.h"
|
||||
#include "lib_about.h"
|
||||
#include "lib_compound.h"
|
||||
#include "lib_standard.h"
|
||||
#include "lib_timer.h"
|
||||
#include "lib_random.h"
|
||||
#include "lib_runner.h"
|
||||
|
||||
#include "toy_console_colors.h"
|
||||
@@ -16,7 +15,7 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
//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");
|
||||
|
||||
if (file == NULL) {
|
||||
@@ -28,14 +27,14 @@ char* Toy_readFile(char* path, size_t* fileSize) {
|
||||
*fileSize = ftell(file);
|
||||
rewind(file);
|
||||
|
||||
char* buffer = (char*)malloc(*fileSize + 1);
|
||||
unsigned char* buffer = (unsigned char*)malloc(*fileSize + 1);
|
||||
|
||||
if (buffer == NULL) {
|
||||
fprintf(stderr, TOY_CC_ERROR "Not enough memory to read \"%s\"\n" TOY_CC_RESET, path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t bytesRead = fread(buffer, sizeof(char), *fileSize, file);
|
||||
size_t bytesRead = fread(buffer, sizeof(unsigned char), *fileSize, file);
|
||||
|
||||
buffer[*fileSize] = '\0'; //NOTE: fread doesn't append this
|
||||
|
||||
@@ -49,7 +48,7 @@ char* Toy_readFile(char* path, size_t* fileSize) {
|
||||
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");
|
||||
|
||||
if (file == NULL) {
|
||||
@@ -57,7 +56,7 @@ int Toy_writeFile(char* path, unsigned char* bytes, size_t size) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int written = fwrite(bytes, size, 1, file);
|
||||
size_t written = fwrite(bytes, size, 1, file);
|
||||
|
||||
if (written != 1) {
|
||||
fprintf(stderr, TOY_CC_ERROR "Could not write file \"%s\"\n" TOY_CC_RESET, path);
|
||||
@@ -70,7 +69,7 @@ int Toy_writeFile(char* path, unsigned char* bytes, size_t size) {
|
||||
}
|
||||
|
||||
//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_Parser parser;
|
||||
Toy_Compiler compiler;
|
||||
@@ -96,7 +95,7 @@ unsigned char* Toy_compileString(char* source, size_t* size) {
|
||||
}
|
||||
|
||||
//get the bytecode dump
|
||||
unsigned char* tb = Toy_collateCompiler(&compiler, (int*)(size));
|
||||
const unsigned char* tb = Toy_collateCompiler(&compiler, size);
|
||||
|
||||
//cleanup
|
||||
Toy_freeCompiler(&compiler);
|
||||
@@ -107,24 +106,23 @@ unsigned char* Toy_compileString(char* source, size_t* size) {
|
||||
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_initInterpreter(&interpreter);
|
||||
|
||||
//inject the libs
|
||||
Toy_injectNativeHook(&interpreter, "about", Toy_hookAbout);
|
||||
Toy_injectNativeHook(&interpreter, "compound", Toy_hookCompound);
|
||||
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
|
||||
Toy_injectNativeHook(&interpreter, "timer", Toy_hookTimer);
|
||||
Toy_injectNativeHook(&interpreter, "random", Toy_hookRandom);
|
||||
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
|
||||
|
||||
Toy_runInterpreter(&interpreter, tb, size);
|
||||
Toy_runInterpreter(&interpreter, tb, (int)size);
|
||||
Toy_freeInterpreter(&interpreter);
|
||||
}
|
||||
|
||||
void Toy_runBinaryFile(char* fname) {
|
||||
void Toy_runBinaryFile(const char* fname) {
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
@@ -132,9 +130,9 @@ void Toy_runBinaryFile(char* fname) {
|
||||
//interpreter takes ownership of the binary data
|
||||
}
|
||||
|
||||
void Toy_runSource(char* source) {
|
||||
void Toy_runSource(const char* source) {
|
||||
size_t size = 0;
|
||||
unsigned char* tb = Toy_compileString(source, &size);
|
||||
const unsigned char* tb = Toy_compileString(source, &size);
|
||||
if (!tb) {
|
||||
return;
|
||||
}
|
||||
@@ -142,9 +140,9 @@ void Toy_runSource(char* source) {
|
||||
Toy_runBinary(tb, size);
|
||||
}
|
||||
|
||||
void Toy_runSourceFile(char* fname) {
|
||||
void Toy_runSourceFile(const char* fname) {
|
||||
size_t size = 0; //not used
|
||||
char* source = Toy_readFile(fname, &size);
|
||||
const char* source = (const char*)Toy_readFile(fname, &size);
|
||||
if (!source) {
|
||||
return;
|
||||
}
|
||||
|
||||
+7
-7
@@ -2,13 +2,13 @@
|
||||
|
||||
#include "toy_common.h"
|
||||
|
||||
char* Toy_readFile(char* path, size_t* fileSize);
|
||||
int Toy_writeFile(char* path, unsigned char* bytes, size_t size);
|
||||
const unsigned char* Toy_readFile(const char* path, size_t* fileSize);
|
||||
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_runBinaryFile(char* fname);
|
||||
void Toy_runSource(char* source);
|
||||
void Toy_runSourceFile(char* fname);
|
||||
void Toy_runBinary(const unsigned char* tb, size_t size);
|
||||
void Toy_runBinaryFile(const char* fname);
|
||||
void Toy_runSource(const char* source);
|
||||
void Toy_runSourceFile(const char* fname);
|
||||
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
import node;
|
||||
|
||||
//constants
|
||||
var SPEED: int const = 10;
|
||||
|
||||
//variables
|
||||
var parent: opaque = null;
|
||||
var posX: int = 50;
|
||||
var posY: int = 50;
|
||||
var WIDTH: int const = 100;
|
||||
var HEIGHT: int const = 100;
|
||||
|
||||
var xspeed: int = 0;
|
||||
var yspeed: int = 0;
|
||||
|
||||
//accessors - variables are private, functions are public
|
||||
fn getX(node: opaque) {
|
||||
return posX;
|
||||
}
|
||||
|
||||
fn getY(node: opaque) {
|
||||
return posY;
|
||||
}
|
||||
|
||||
//lifecycle functions
|
||||
fn onInit(node: opaque) {
|
||||
print "render.toy:onInit() called";
|
||||
|
||||
node.loadTexture("sprites:/character.png");
|
||||
parent = node.getNodeParent();
|
||||
}
|
||||
|
||||
fn onStep(node: opaque) {
|
||||
posX += xspeed;
|
||||
posY += yspeed;
|
||||
}
|
||||
|
||||
fn onFree(node: opaque) {
|
||||
print "render.toy:onFree() called";
|
||||
|
||||
node.freeTexture();
|
||||
}
|
||||
|
||||
fn onDraw(node: opaque) {
|
||||
// print "render.toy:onDraw() called";
|
||||
|
||||
var px = parent.callNode("getX");
|
||||
var py = parent.callNode("getY");
|
||||
|
||||
if (px == null) {
|
||||
px = 0;
|
||||
}
|
||||
|
||||
if (py == null) {
|
||||
py = 0;
|
||||
}
|
||||
|
||||
node.drawNode(posX + px, posY + py, WIDTH, HEIGHT);
|
||||
}
|
||||
|
||||
//event functions
|
||||
fn onKeyDown(node: opaque, event: string) {
|
||||
if (event == "character_up") {
|
||||
yspeed -= SPEED;
|
||||
return;
|
||||
}
|
||||
|
||||
if (event == "character_down") {
|
||||
yspeed += SPEED;
|
||||
return;
|
||||
}
|
||||
|
||||
if (event == "character_left") {
|
||||
xspeed -= SPEED;
|
||||
return;
|
||||
}
|
||||
|
||||
if (event == "character_right") {
|
||||
xspeed += SPEED;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fn onKeyUp(node: opaque, event: string) {
|
||||
if (event == "character_up" && yspeed < 0) {
|
||||
yspeed = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (event == "character_down" && yspeed > 0) {
|
||||
yspeed = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (event == "character_left" && xspeed < 0) {
|
||||
xspeed = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (event == "character_right" && xspeed > 0) {
|
||||
xspeed = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fn onMouseMotion(node: opaque, x: int, y: int, xrel: int, yrel: int) {
|
||||
print "entity.toy:onMouseMotion(" + string x + ", " + string y + ", " + string xrel + ", " + string yrel + ")";
|
||||
}
|
||||
|
||||
fn onMouseButtonDown(node: opaque, x: int, y: int, button: string) {
|
||||
print "entity.toy:onMouseButtonDown(" + string x + ", " + string y + ", " + button + ")";
|
||||
|
||||
//jump to pos
|
||||
posX = x - WIDTH / 2;
|
||||
posY = y - HEIGHT / 2;
|
||||
}
|
||||
|
||||
fn onMouseButtonUp(node: opaque, x: int, y: int, button: string) {
|
||||
print "entity.toy:onMouseButtonUp(" + string x + ", " + string y + ", " + button + ")";
|
||||
}
|
||||
|
||||
fn onMouseWheel(node: opaque, xrel: int, yrel: int) {
|
||||
print "entity.toy:onMouseWheel(" + string xrel + ", " + string yrel + ")";
|
||||
}
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
//single line comment
|
||||
|
||||
/*
|
||||
multi line comment
|
||||
*/
|
||||
|
||||
//test primitive literals
|
||||
print "hello world";
|
||||
print null;
|
||||
print true;
|
||||
print false;
|
||||
print 42;
|
||||
print 3.14;
|
||||
print -69;
|
||||
print -4.20;
|
||||
print 2 + (3 * 3);
|
||||
|
||||
//test operators (integers)
|
||||
print 1 + 1;
|
||||
print 1 - 1;
|
||||
print 2 * 2;
|
||||
print 1 / 2;
|
||||
print 4 % 2;
|
||||
|
||||
//test operators (floats)
|
||||
print 1.0 + 1.0;
|
||||
print 1.0 - 1.0;
|
||||
print 2.0 * 2.0;
|
||||
print 1.0 / 2.0;
|
||||
|
||||
//test scopes
|
||||
{
|
||||
print "This statement is within a scope.";
|
||||
{
|
||||
print "This is a deeper scope.";
|
||||
}
|
||||
}
|
||||
print "Back to the outer scope.";
|
||||
|
||||
//test scope will delegate to higher scope
|
||||
var a = 1;
|
||||
{
|
||||
a = 2;
|
||||
print a;
|
||||
}
|
||||
print a;
|
||||
|
||||
//test scope will shadow higher scope on redefine
|
||||
var b: int = 3;
|
||||
{
|
||||
var b = 4;
|
||||
print b;
|
||||
}
|
||||
print b;
|
||||
|
||||
//test compounds, repeatedly
|
||||
print [1, 2, 3];
|
||||
print [4, 5];
|
||||
print ["key":"value"];
|
||||
print [1, 2, 3];
|
||||
print [4, 5];
|
||||
print ["key":"value"];
|
||||
|
||||
//test empties
|
||||
print [];
|
||||
print [:];
|
||||
|
||||
//test nested compounds
|
||||
print [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
|
||||
|
||||
//var declarations
|
||||
var x = 31;
|
||||
var y : int = 42;
|
||||
var arr : [int] = [1, 2, 3, 42];
|
||||
var dict : [string:int] = ["hello": 1, "world":2];
|
||||
|
||||
//printing expressions
|
||||
print x;
|
||||
print x + y;
|
||||
print arr;
|
||||
print dict;
|
||||
|
||||
//test asserts at the end of the file
|
||||
assert x, "This won't be seen";
|
||||
assert true, "This won't be seen";
|
||||
assert false, "This is a failed assert, and will end execution";
|
||||
|
||||
print "This will not be printed because of the above assert";
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//WARNING: please think twice before using this in a test
|
||||
fn fib(n : int) {
|
||||
if (n < 2) return n;
|
||||
return fib(n-1) + fib(n-2);
|
||||
|
||||
@@ -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]);
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
|
||||
Since this is a pseudo-random generator, and there's no internal state to the algorithm other
|
||||
than the generator opaque, there needs to be a "call counter" (current depth) to shuffle the
|
||||
initial seeds, otherwise generators created from other generators will resemble their parents,
|
||||
but one call greater.
|
||||
|
||||
*/
|
||||
|
||||
import standard;
|
||||
import random;
|
||||
|
||||
var DEPTH: int const = 20;
|
||||
var levels = [];
|
||||
|
||||
//generate the level seeds
|
||||
var generator: opaque = createRandomGenerator(clock().hash());
|
||||
|
||||
for (var i: int = 0; i < DEPTH; i++) {
|
||||
levels.push(generator.generateRandomNumber());
|
||||
}
|
||||
|
||||
generator.freeRandomGenerator();
|
||||
|
||||
//generate "levels" of a roguelike
|
||||
for (var i = 0; i < DEPTH; i++) {
|
||||
var rng: opaque = createRandomGenerator(levels[i] + i);
|
||||
|
||||
print "---";
|
||||
print levels[i];
|
||||
print rng.generateRandomNumber();
|
||||
print rng.generateRandomNumber();
|
||||
print rng.generateRandomNumber();
|
||||
|
||||
rng.freeRandomGenerator();
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
//number of iterations
|
||||
var SIZE: int const = 260;
|
||||
var SIZE: int const = 100;
|
||||
|
||||
//lookup table
|
||||
var lookup = [
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
import compound;
|
||||
var arr: [int] = [1, 2, 3];
|
||||
fn f(_, v: int): int { return v + 1; }
|
||||
print arr.map(f);
|
||||
|
||||
|
||||
+27
-9
@@ -40,17 +40,21 @@ static void freeASTNodeCustom(Toy_ASTNode* node, bool freeSelf) {
|
||||
break;
|
||||
|
||||
case TOY_AST_NODE_BLOCK:
|
||||
for (int i = 0; i < node->block.count; i++) {
|
||||
freeASTNodeCustom(node->block.nodes + i, false);
|
||||
if (node->block.capacity > 0) {
|
||||
for (int i = 0; i < node->block.count; i++) {
|
||||
freeASTNodeCustom(node->block.nodes + i, false);
|
||||
}
|
||||
TOY_FREE_ARRAY(Toy_ASTNode, node->block.nodes, node->block.capacity);
|
||||
}
|
||||
TOY_FREE_ARRAY(Toy_ASTNode, node->block.nodes, node->block.capacity);
|
||||
break;
|
||||
|
||||
case TOY_AST_NODE_COMPOUND:
|
||||
for (int i = 0; i < node->compound.count; i++) {
|
||||
freeASTNodeCustom(node->compound.nodes + i, false);
|
||||
if (node->compound.capacity > 0) {
|
||||
for (int i = 0; i < node->compound.count; i++) {
|
||||
freeASTNodeCustom(node->compound.nodes + i, false);
|
||||
}
|
||||
TOY_FREE_ARRAY(Toy_ASTNode, node->compound.nodes, node->compound.capacity);
|
||||
}
|
||||
TOY_FREE_ARRAY(Toy_ASTNode, node->compound.nodes, node->compound.capacity);
|
||||
break;
|
||||
|
||||
case TOY_AST_NODE_PAIR:
|
||||
@@ -71,10 +75,12 @@ static void freeASTNodeCustom(Toy_ASTNode* node, bool freeSelf) {
|
||||
break;
|
||||
|
||||
case TOY_AST_NODE_FN_COLLECTION:
|
||||
for (int i = 0; i < node->fnCollection.count; i++) {
|
||||
freeASTNodeCustom(node->fnCollection.nodes + i, false);
|
||||
if (node->fnCollection.capacity > 0) {
|
||||
for (int i = 0; i < node->fnCollection.count; i++) {
|
||||
freeASTNodeCustom(node->fnCollection.nodes + i, false);
|
||||
}
|
||||
TOY_FREE_ARRAY(Toy_ASTNode, node->fnCollection.nodes, node->fnCollection.capacity);
|
||||
}
|
||||
TOY_FREE_ARRAY(Toy_ASTNode, node->fnCollection.nodes, node->fnCollection.capacity);
|
||||
break;
|
||||
|
||||
case TOY_AST_NODE_FN_DECL:
|
||||
@@ -135,6 +141,10 @@ static void freeASTNodeCustom(Toy_ASTNode* node, bool freeSelf) {
|
||||
Toy_freeLiteral(node->import.identifier);
|
||||
Toy_freeLiteral(node->import.alias);
|
||||
break;
|
||||
|
||||
case TOY_AST_NODE_PASS:
|
||||
//EMPTY
|
||||
break;
|
||||
}
|
||||
|
||||
if (freeSelf) {
|
||||
@@ -383,3 +393,11 @@ void Toy_emitASTNodeImport(Toy_ASTNode** nodeHandle, Toy_Literal identifier, Toy
|
||||
|
||||
*nodeHandle = tmp;
|
||||
}
|
||||
|
||||
void Toy_emitASTNodePass(Toy_ASTNode** nodeHandle) {
|
||||
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||
|
||||
tmp->type = TOY_AST_NODE_PASS;
|
||||
|
||||
*nodeHandle = tmp;
|
||||
}
|
||||
@@ -34,6 +34,7 @@ typedef enum Toy_ASTNodeType {
|
||||
TOY_AST_NODE_PREFIX_DECREMENT, //decrement a variable
|
||||
TOY_AST_NODE_POSTFIX_DECREMENT, //decrement a variable
|
||||
TOY_AST_NODE_IMPORT, //import a library
|
||||
TOY_AST_NODE_PASS, //for doing nothing
|
||||
} Toy_ASTNodeType;
|
||||
|
||||
//literals
|
||||
@@ -238,6 +239,9 @@ typedef struct Toy_NodeImport {
|
||||
Toy_Literal alias;
|
||||
} Toy_NodeImport;
|
||||
|
||||
//for doing nothing
|
||||
void Toy_emitASTNodePass(Toy_ASTNode** nodeHandle);
|
||||
|
||||
union Toy_private_node {
|
||||
Toy_ASTNodeType type;
|
||||
Toy_NodeLiteral atomic;
|
||||
|
||||
+160
-40
@@ -4,6 +4,7 @@
|
||||
#include "toy_literal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
//static math utils, copied from the interpreter
|
||||
static Toy_Literal addition(Toy_Interpreter* interpreter, Toy_Literal lhs, Toy_Literal rhs) {
|
||||
@@ -278,6 +279,17 @@ int Toy_private_index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
||||
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
|
||||
if (!TOY_IS_NULL(second) || !TOY_IS_NULL(third)) {
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
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");
|
||||
@@ -542,6 +565,17 @@ int Toy_private_index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
||||
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
|
||||
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");
|
||||
@@ -587,7 +621,7 @@ int Toy_private_index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
||||
|
||||
//simple indexing assignment if second is null
|
||||
if (TOY_IS_NULL(second)) {
|
||||
bool ret = -1;
|
||||
int ret = -1;
|
||||
|
||||
if (!Toy_setLiteralArray(TOY_AS_ARRAY(compound), first, assign)) {
|
||||
interpreter->errorOutput("Array index out of bounds in assignment");
|
||||
@@ -595,6 +629,7 @@ int Toy_private_index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
||||
}
|
||||
else {
|
||||
Toy_pushLiteralArray(&interpreter->stack, compound); //leave the array on the stack
|
||||
//...
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
@@ -704,6 +739,17 @@ int Toy_private_index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
||||
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);
|
||||
|
||||
if (TOY_IS_STRING(op) && Toy_equalsRefStringCString(TOY_AS_STRING(op), "+=")) {
|
||||
@@ -792,8 +838,19 @@ int Toy_private_index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
||||
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
|
||||
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");
|
||||
|
||||
//something is weird - skip out
|
||||
@@ -807,7 +864,7 @@ int Toy_private_index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
||||
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");
|
||||
|
||||
//something is weird - skip out
|
||||
@@ -838,7 +895,7 @@ int Toy_private_index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
||||
//simple indexing if second is null
|
||||
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];
|
||||
|
||||
snprintf(buf, 16, "%s", &(cstr[ TOY_AS_INTEGER(first) ]) );
|
||||
@@ -936,8 +993,19 @@ int Toy_private_index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
||||
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
|
||||
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");
|
||||
|
||||
//something is weird - skip out
|
||||
@@ -951,7 +1019,7 @@ int Toy_private_index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
||||
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");
|
||||
|
||||
//something is weird - skip out
|
||||
@@ -1063,7 +1131,7 @@ int Toy_private_index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
||||
int Toy_private_set(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
//if wrong number of arguments, fail
|
||||
if (arguments->count != 3) {
|
||||
interpreter->errorOutput("Incorrect number of arguments to _set\n");
|
||||
interpreter->errorOutput("Incorrect number of arguments to set\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1073,12 +1141,16 @@ int Toy_private_set(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
Toy_Literal val = arguments->literals[2];
|
||||
|
||||
if (!TOY_IS_IDENTIFIER(idn)) {
|
||||
interpreter->errorOutput("Expected identifier in _set\n");
|
||||
interpreter->errorOutput("Expected identifier in set\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Toy_parseIdentifierToValue(interpreter, &obj);
|
||||
|
||||
if (TOY_IS_IDENTIFIER(obj)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool freeKey = false;
|
||||
if (TOY_IS_IDENTIFIER(key)) {
|
||||
Toy_parseIdentifierToValue(interpreter, &key);
|
||||
@@ -1091,26 +1163,40 @@ int Toy_private_set(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
interpreter->errorOutput("Bad argument type in _set\n");
|
||||
interpreter->errorOutput("Bad argument type in set\n");
|
||||
Toy_freeLiteral(typeLiteral);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
Toy_freeLiteral(typeLiteral);
|
||||
|
||||
if (!TOY_IS_INTEGER(key)) {
|
||||
interpreter->errorOutput("Expected integer index in _set\n");
|
||||
interpreter->errorOutput("Expected integer index in set\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (TOY_AS_ARRAY(obj)->count <= TOY_AS_INTEGER(key) || TOY_AS_INTEGER(key) < 0) {
|
||||
interpreter->errorOutput("Index out of bounds in _set\n");
|
||||
if (TOY_AS_INTEGER(key) >= TOY_AS_ARRAY(obj)->count || TOY_AS_INTEGER(key) < 0) {
|
||||
interpreter->errorOutput("Index out of bounds in set\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1119,7 +1205,7 @@ int Toy_private_set(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
TOY_AS_ARRAY(obj)->literals[TOY_AS_INTEGER(key)] = Toy_copyLiteral(val);
|
||||
|
||||
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);
|
||||
interpreter->errorOutput("\"\n");
|
||||
return -1;
|
||||
@@ -1136,12 +1222,12 @@ int Toy_private_set(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
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) {
|
||||
interpreter->printOutput("bad argument type in _set\n");
|
||||
interpreter->printOutput("bad argument type in set\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1149,7 +1235,7 @@ int Toy_private_set(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
Toy_setLiteralDictionary(TOY_AS_DICTIONARY(obj), key, val);
|
||||
|
||||
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);
|
||||
interpreter->errorOutput("\"\n");
|
||||
return -1;
|
||||
@@ -1159,7 +1245,7 @@ int Toy_private_set(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
}
|
||||
|
||||
default:
|
||||
interpreter->errorOutput("Incorrect compound type in _set: ");
|
||||
interpreter->errorOutput("Incorrect compound type in set: ");
|
||||
Toy_printLiteralCustom(obj, interpreter->errorOutput);
|
||||
interpreter->errorOutput("\"\n");
|
||||
return -1;
|
||||
@@ -1181,7 +1267,7 @@ int Toy_private_set(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
int Toy_private_get(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
//if wrong number of arguments, fail
|
||||
if (arguments->count != 2) {
|
||||
interpreter->errorOutput("Incorrect number of arguments to _get");
|
||||
interpreter->errorOutput("Incorrect number of arguments to get");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1200,15 +1286,25 @@ int Toy_private_get(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
freeKey = true;
|
||||
}
|
||||
|
||||
if (TOY_IS_IDENTIFIER(obj) || TOY_IS_IDENTIFIER(key)) {
|
||||
if (freeObj) {
|
||||
Toy_freeLiteral(obj);
|
||||
}
|
||||
if (freeKey) {
|
||||
Toy_freeLiteral(key);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(obj.type) {
|
||||
case TOY_LITERAL_ARRAY: {
|
||||
if (!TOY_IS_INTEGER(key)) {
|
||||
interpreter->errorOutput("Expected integer index in _get\n");
|
||||
interpreter->errorOutput("Expected integer index in get\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (TOY_AS_ARRAY(obj)->count <= TOY_AS_INTEGER(key) || TOY_AS_INTEGER(key) < 0) {
|
||||
interpreter->errorOutput("Index out of bounds in _get\n");
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1242,7 +1338,7 @@ int Toy_private_get(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
}
|
||||
|
||||
default:
|
||||
interpreter->errorOutput("Incorrect compound type in _get \"");
|
||||
interpreter->errorOutput("Incorrect compound type in get \"");
|
||||
Toy_printLiteralCustom(obj, interpreter->errorOutput);
|
||||
interpreter->errorOutput("\"\n");
|
||||
return -1;
|
||||
@@ -1252,7 +1348,7 @@ int Toy_private_get(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
int Toy_private_push(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
//if wrong number of arguments, fail
|
||||
if (arguments->count != 2) {
|
||||
interpreter->errorOutput("Incorrect number of arguments to _push\n");
|
||||
interpreter->errorOutput("Incorrect number of arguments to push\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1261,35 +1357,47 @@ int Toy_private_push(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
||||
Toy_Literal val = arguments->literals[1];
|
||||
|
||||
if (!TOY_IS_IDENTIFIER(idn)) {
|
||||
interpreter->errorOutput("Expected identifier in _push\n");
|
||||
interpreter->errorOutput("Expected identifier in push\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Toy_parseIdentifierToValue(interpreter, &obj);
|
||||
|
||||
if (TOY_IS_IDENTIFIER(obj)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool freeVal = false;
|
||||
if (TOY_IS_IDENTIFIER(val)) {
|
||||
Toy_parseIdentifierToValue(interpreter, &val);
|
||||
freeVal = true;
|
||||
}
|
||||
|
||||
if (TOY_IS_IDENTIFIER(val)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(obj.type) {
|
||||
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) {
|
||||
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) {
|
||||
interpreter->errorOutput("Bad argument type in _push");
|
||||
interpreter->errorOutput("Bad argument type in push\n");
|
||||
Toy_freeLiteral(typeLiteral);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
Toy_freeLiteral(typeLiteral);
|
||||
|
||||
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
|
||||
interpreter->errorOutput("Incorrect type assigned to array in _push: \"");
|
||||
interpreter->errorOutput("Incorrect type assigned to array in push: \"");
|
||||
Toy_printLiteralCustom(val, interpreter->errorOutput);
|
||||
interpreter->errorOutput("\"\n");
|
||||
return -1;
|
||||
@@ -1305,7 +1413,7 @@ int Toy_private_push(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
||||
}
|
||||
|
||||
default:
|
||||
interpreter->errorOutput("Incorrect compound type in _push: ");
|
||||
interpreter->errorOutput("Incorrect compound type in push: ");
|
||||
Toy_printLiteralCustom(obj, interpreter->errorOutput);
|
||||
interpreter->errorOutput("\n");
|
||||
return -1;
|
||||
@@ -1315,7 +1423,7 @@ int Toy_private_push(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
||||
int Toy_private_pop(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
//if wrong number of arguments, fail
|
||||
if (arguments->count != 1) {
|
||||
interpreter->errorOutput("Incorrect number of arguments to _pop\n");
|
||||
interpreter->errorOutput("Incorrect number of arguments to pop\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1323,12 +1431,16 @@ int Toy_private_pop(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
Toy_Literal obj = arguments->literals[0];
|
||||
|
||||
if (!TOY_IS_IDENTIFIER(idn)) {
|
||||
interpreter->errorOutput("Expected identifier in _pop\n");
|
||||
interpreter->errorOutput("Expected identifier in pop\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Toy_parseIdentifierToValue(interpreter, &obj);
|
||||
|
||||
if (TOY_IS_IDENTIFIER(obj)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(obj.type) {
|
||||
case TOY_LITERAL_ARRAY: {
|
||||
Toy_Literal lit = Toy_popLiteralArray(TOY_AS_ARRAY(obj));
|
||||
@@ -1336,7 +1448,7 @@ int Toy_private_pop(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
Toy_freeLiteral(lit);
|
||||
|
||||
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);
|
||||
interpreter->errorOutput("\n");
|
||||
return -1;
|
||||
@@ -1348,7 +1460,7 @@ int Toy_private_pop(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
}
|
||||
|
||||
default:
|
||||
interpreter->errorOutput("Incorrect compound type in _pop: ");
|
||||
interpreter->errorOutput("Incorrect compound type in pop: ");
|
||||
Toy_printLiteralCustom(obj, interpreter->errorOutput);
|
||||
interpreter->errorOutput("\n");
|
||||
return -1;
|
||||
@@ -1358,7 +1470,7 @@ int Toy_private_pop(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
int Toy_private_length(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
//if wrong number of arguments, fail
|
||||
if (arguments->count != 1) {
|
||||
interpreter->errorOutput("Incorrect number of arguments to _length\n");
|
||||
interpreter->errorOutput("Incorrect number of arguments to length\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1370,6 +1482,10 @@ int Toy_private_length(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments
|
||||
freeObj = true;
|
||||
}
|
||||
|
||||
if (TOY_IS_IDENTIFIER(obj)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(obj.type) {
|
||||
case TOY_LITERAL_ARRAY: {
|
||||
Toy_Literal lit = TOY_TO_INTEGER_LITERAL( TOY_AS_ARRAY(obj)->count );
|
||||
@@ -1393,7 +1509,7 @@ int Toy_private_length(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments
|
||||
}
|
||||
|
||||
default:
|
||||
interpreter->errorOutput("Incorrect compound type in _length: ");
|
||||
interpreter->errorOutput("Incorrect compound type in length: ");
|
||||
Toy_printLiteralCustom(obj, interpreter->errorOutput);
|
||||
interpreter->errorOutput("\n");
|
||||
return -1;
|
||||
@@ -1409,7 +1525,7 @@ int Toy_private_length(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments
|
||||
int Toy_private_clear(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
//if wrong number of arguments, fail
|
||||
if (arguments->count != 1) {
|
||||
interpreter->errorOutput("Incorrect number of arguments to _clear\n");
|
||||
interpreter->errorOutput("Incorrect number of arguments to clear\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1417,12 +1533,16 @@ int Toy_private_clear(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
||||
Toy_Literal obj = arguments->literals[0];
|
||||
|
||||
if (!TOY_IS_IDENTIFIER(idn)) {
|
||||
interpreter->errorOutput("expected identifier in _clear\n");
|
||||
interpreter->errorOutput("expected identifier in clear\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Toy_parseIdentifierToValue(interpreter, &obj);
|
||||
|
||||
if (TOY_IS_IDENTIFIER(obj)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
//NOTE: just pass in new compounds
|
||||
|
||||
switch(obj.type) {
|
||||
@@ -1433,7 +1553,7 @@ int Toy_private_clear(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
||||
Toy_Literal obj = TOY_TO_ARRAY_LITERAL(array);
|
||||
|
||||
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);
|
||||
interpreter->errorOutput("\n");
|
||||
return -1;
|
||||
@@ -1451,7 +1571,7 @@ int Toy_private_clear(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
||||
Toy_Literal obj = TOY_TO_DICTIONARY_LITERAL(dictionary);
|
||||
|
||||
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);
|
||||
interpreter->errorOutput("\n");
|
||||
return -1;
|
||||
@@ -1463,7 +1583,7 @@ int Toy_private_clear(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
||||
}
|
||||
|
||||
default:
|
||||
interpreter->errorOutput("Incorrect compound type in _clear: ");
|
||||
interpreter->errorOutput("Incorrect compound type in clear: ");
|
||||
Toy_printLiteralCustom(obj, interpreter->errorOutput);
|
||||
interpreter->errorOutput("\n");
|
||||
return -1;
|
||||
|
||||
+37
-26
@@ -15,23 +15,22 @@ STATIC_ASSERT(sizeof(unsigned char) == 1);
|
||||
STATIC_ASSERT(sizeof(unsigned short) == 2);
|
||||
STATIC_ASSERT(sizeof(unsigned int) == 4);
|
||||
|
||||
#ifndef TOY_EXPORT
|
||||
|
||||
//declare the singleton
|
||||
Toy_CommandLine Toy_commandLine;
|
||||
//declare the singleton with default values
|
||||
Toy_CommandLine Toy_commandLine = {
|
||||
.error = false,
|
||||
.help = false,
|
||||
.version = false,
|
||||
.binaryfile = NULL,
|
||||
.sourcefile = NULL,
|
||||
.compilefile = NULL,
|
||||
.outfile = "out.tb",
|
||||
.source = NULL,
|
||||
.initialfile = NULL,
|
||||
.enablePrintNewline = true,
|
||||
.verbose = false
|
||||
};
|
||||
|
||||
void Toy_initCommandLine(int argc, const char* argv[]) {
|
||||
//default values
|
||||
Toy_commandLine.error = false;
|
||||
Toy_commandLine.help = false;
|
||||
Toy_commandLine.version = false;
|
||||
Toy_commandLine.binaryfile = NULL;
|
||||
Toy_commandLine.sourcefile = NULL;
|
||||
Toy_commandLine.compilefile = NULL;
|
||||
Toy_commandLine.outfile = "out.tb";
|
||||
Toy_commandLine.source = NULL;
|
||||
Toy_commandLine.verbose = false;
|
||||
|
||||
for (int i = 1; i < argc; i++) { //start at 1 to skip the program name
|
||||
Toy_commandLine.error = true; //error state by default, set to false by successful flags
|
||||
|
||||
@@ -81,6 +80,19 @@ void Toy_initCommandLine(int argc, const char* argv[]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((!strcmp(argv[i], "-t") || !strcmp(argv[i], "--initial")) && i + 1 < argc) {
|
||||
Toy_commandLine.initialfile = (char*)argv[i + 1];
|
||||
i++;
|
||||
Toy_commandLine.error = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-n")) {
|
||||
Toy_commandLine.enablePrintNewline = false;
|
||||
Toy_commandLine.error = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
//option without a flag + ending in .tb = binary input
|
||||
if (i < argc) {
|
||||
if (strncmp(&(argv[i][strlen(argv[i]) - 3]), ".tb", 3) == 0) {
|
||||
@@ -96,20 +108,21 @@ void Toy_initCommandLine(int argc, const char* argv[]) {
|
||||
}
|
||||
|
||||
void Toy_usageCommandLine(int argc, const char* argv[]) {
|
||||
printf("Usage: %s [<file.tb> | -h | -v | [-d][-f file | -i source | -c file [-o outfile]]]\n\n", argv[0]);
|
||||
printf("Usage: %s [ file.tb | -h | -v | -d | -f file.toy | -i source | -c file.toy -o out.tb | -t file.toy ]\n\n", argv[0]);
|
||||
}
|
||||
|
||||
void Toy_helpCommandLine(int argc, const char* argv[]) {
|
||||
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\t| --help\t\tShow this help then exit.\n\n");
|
||||
printf("-v\t| --version\t\tShow version and copyright information then exit.\n\n");
|
||||
printf("-d\t| --debug\t\tBe verbose when operating.\n\n");
|
||||
printf("-f\t| --file filename\tParse, compile and execute the source file.\n\n");
|
||||
printf("-i\t| --input source\tParse, compile and execute this given string of source code.\n\n");
|
||||
printf("-c\t| --compile filename\tParse and compile the specified source file into an output file.\n\n");
|
||||
printf("-o\t| --output outfile\tName of the output file built with --compile (default: out.tb).\n\n");
|
||||
printf(" -h, --help\t\t\tShow this help then exit.\n");
|
||||
printf(" -v, --version\t\t\tShow version and copyright information then exit.\n");
|
||||
printf(" -d, --debug\t\t\tBe verbose when operating.\n");
|
||||
printf(" -f, --file filename\t\tParse, compile and execute the source file.\n");
|
||||
printf(" -i, --input source\t\tParse, compile and execute this given string of source code.\n");
|
||||
printf(" -c, --compile filename\tParse and compile the specified source file into an output file.\n");
|
||||
printf(" -o, --output outfile\t\tName of the output file built with --compile (default: out.tb).\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[]) {
|
||||
@@ -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("3. This notice may not be removed or altered from any source distribution.\n\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+22
-14
@@ -4,24 +4,30 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define TOY_VERSION_MAJOR 0
|
||||
#define TOY_VERSION_MINOR 8
|
||||
#define TOY_VERSION_MAJOR 1
|
||||
#define TOY_VERSION_MINOR 1
|
||||
#define TOY_VERSION_PATCH 1
|
||||
#define TOY_VERSION_BUILD __DATE__ " " __TIME__
|
||||
|
||||
//platform-specific specifications
|
||||
#if defined(__linux__)
|
||||
//platform/compiler-specific instructions
|
||||
#if defined(__linux__) || defined(__MINGW32__) || defined(__GNUC__)
|
||||
|
||||
#define TOY_API extern
|
||||
|
||||
#elif defined(_WIN32) || defined(WIN32)
|
||||
#define TOY_API
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
#ifndef TOY_EXPORT
|
||||
#define TOY_API __declspec(dllimport)
|
||||
#else
|
||||
#define TOY_API __declspec(dllexport)
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define TOY_API
|
||||
|
||||
#define TOY_API extern
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef TOY_EXPORT
|
||||
//for processing the command line arguments
|
||||
typedef struct {
|
||||
bool error;
|
||||
@@ -32,14 +38,16 @@ typedef struct {
|
||||
char* compilefile;
|
||||
char* outfile; //defaults to out.tb
|
||||
char* source;
|
||||
char* initialfile;
|
||||
bool enablePrintNewline;
|
||||
bool verbose;
|
||||
} Toy_CommandLine;
|
||||
|
||||
extern Toy_CommandLine Toy_commandLine;
|
||||
//these are intended for the repl only, despite using the api prefix
|
||||
TOY_API Toy_CommandLine Toy_commandLine;
|
||||
|
||||
void Toy_initCommandLine(int argc, const char* argv[]);
|
||||
TOY_API void Toy_initCommandLine(int argc, const char* argv[]);
|
||||
|
||||
void Toy_usageCommandLine(int argc, const char* argv[]);
|
||||
void Toy_helpCommandLine(int argc, const char* argv[]);
|
||||
void Toy_copyrightCommandLine(int argc, const char* argv[]);
|
||||
#endif
|
||||
TOY_API void Toy_usageCommandLine(int argc, const char* argv[]);
|
||||
TOY_API void Toy_helpCommandLine(int argc, const char* argv[]);
|
||||
TOY_API void Toy_copyrightCommandLine(int argc, const char* argv[]);
|
||||
|
||||
+25
-9
@@ -9,6 +9,7 @@
|
||||
#include "toy_console_colors.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
void Toy_initCompiler(Toy_Compiler* compiler) {
|
||||
Toy_initLiteralArray(&compiler->literalCache);
|
||||
@@ -129,7 +130,7 @@ static int writeNodeCompoundToCache(Toy_Compiler* compiler, Toy_ASTNode* node) {
|
||||
}
|
||||
|
||||
//push the store to the cache, with instructions about how pack it
|
||||
Toy_Literal literal = TOY_TO_DICTIONARY_LITERAL(store);
|
||||
Toy_Literal literal = TOY_TO_DICTIONARY_LITERAL((Toy_LiteralDictionary*)store); //cast from array to dict, because it's intermediate
|
||||
literal.type = TOY_LITERAL_DICTIONARY_INTERMEDIATE; //god damn it - nested in a dictionary
|
||||
index = Toy_pushLiteralArray(&compiler->literalCache, literal);
|
||||
Toy_freeLiteral(literal);
|
||||
@@ -302,6 +303,12 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
|
||||
//special case for when indexing and assigning
|
||||
if (override != TOY_OP_EOF && node->binary.opcode >= TOY_OP_VAR_ASSIGN && node->binary.opcode <= TOY_OP_VAR_MODULO_ASSIGN) {
|
||||
Toy_writeCompilerWithJumps(compiler, node->binary.right, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
|
||||
|
||||
//Special case if there's an index on both sides of the sign, just set it as indexing
|
||||
if (node->binary.left->type == TOY_AST_NODE_BINARY && node->binary.right->type == TOY_AST_NODE_BINARY && node->binary.left->binary.opcode == TOY_OP_INDEX && node->binary.right->binary.opcode == TOY_OP_INDEX) {
|
||||
compiler->bytecode[compiler->count++] = (unsigned char)TOY_OP_INDEX;
|
||||
}
|
||||
|
||||
compiler->bytecode[compiler->count++] = (unsigned char)TOY_OP_INDEX_ASSIGN; //1 byte WARNING: enum trickery
|
||||
compiler->bytecode[compiler->count++] = (unsigned char)node->binary.opcode; //1 byte
|
||||
return TOY_OP_EOF;
|
||||
@@ -315,7 +322,7 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
|
||||
//return this if...
|
||||
Toy_Opcode ret = Toy_writeCompilerWithJumps(compiler, node->binary.right, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
|
||||
|
||||
if (node->binary.opcode == TOY_OP_INDEX && rootNode->type == TOY_AST_NODE_BINARY && (rootNode->binary.opcode >= TOY_OP_VAR_ASSIGN && rootNode->binary.opcode <= TOY_OP_VAR_MODULO_ASSIGN)) { //range-based check for assignment type
|
||||
if (node->binary.opcode == TOY_OP_INDEX && rootNode->type == TOY_AST_NODE_BINARY && (rootNode->binary.opcode >= TOY_OP_VAR_ASSIGN && rootNode->binary.opcode <= TOY_OP_VAR_MODULO_ASSIGN) && rootNode->binary.right != node) { //range-based check for assignment type; make sure the index is on the left of the assignment symbol
|
||||
return TOY_OP_INDEX_ASSIGN_INTERMEDIATE;
|
||||
}
|
||||
|
||||
@@ -959,6 +966,11 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
|
||||
return TOY_OP_INDEX_ASSIGN; //override binary's instruction IF it is assign
|
||||
}
|
||||
break;
|
||||
|
||||
case TOY_AST_NODE_PASS: {
|
||||
return TOY_OP_PASS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return TOY_OP_EOF;
|
||||
@@ -970,6 +982,8 @@ void Toy_writeCompiler(Toy_Compiler* compiler, Toy_ASTNode* node) {
|
||||
if (op != TOY_OP_EOF) {//compensate for indexing & dot notation being screwy
|
||||
compiler->bytecode[compiler->count++] = (unsigned char)op; //1 byte
|
||||
}
|
||||
|
||||
//TODO: could free up AST Nodes
|
||||
}
|
||||
|
||||
void Toy_freeCompiler(Toy_Compiler* compiler) {
|
||||
@@ -978,6 +992,7 @@ void Toy_freeCompiler(Toy_Compiler* compiler) {
|
||||
compiler->bytecode = NULL;
|
||||
compiler->capacity = 0;
|
||||
compiler->count = 0;
|
||||
compiler->panic = false;
|
||||
}
|
||||
|
||||
static void emitByte(unsigned char** collationPtr, int* capacityPtr, int* countPtr, unsigned char byte) {
|
||||
@@ -1025,7 +1040,7 @@ static void emitFloat(unsigned char** collationPtr, int* capacityPtr, int* count
|
||||
}
|
||||
|
||||
//return the result
|
||||
static unsigned char* collateCompilerHeaderOpt(Toy_Compiler* compiler, int* size, bool embedHeader) {
|
||||
static unsigned char* collateCompilerHeaderOpt(Toy_Compiler* compiler, size_t* size, bool embedHeader) {
|
||||
if (compiler->panic) {
|
||||
fprintf(stderr, TOY_CC_ERROR "[internal] Can't collate a panicked compiler\n" TOY_CC_RESET);
|
||||
return NULL;
|
||||
@@ -1096,7 +1111,7 @@ static unsigned char* collateCompilerHeaderOpt(Toy_Compiler* compiler, int* size
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
@@ -1167,17 +1182,17 @@ static unsigned char* collateCompilerHeaderOpt(Toy_Compiler* compiler, int* size
|
||||
case TOY_LITERAL_FUNCTION_INTERMEDIATE: {
|
||||
//extract the compiler
|
||||
Toy_Literal fn = compiler->literalCache.literals[i];
|
||||
void* fnCompiler = TOY_AS_FUNCTION(fn).bytecode; //store the compiler here for now
|
||||
void* fnCompiler = TOY_AS_FUNCTION(fn).inner.bytecode; //store the compiler here for now
|
||||
|
||||
//collate the function into bytecode (without header)
|
||||
int size = 0;
|
||||
size_t size = 0;
|
||||
unsigned char* bytes = collateCompilerHeaderOpt((Toy_Compiler*)fnCompiler, &size, false);
|
||||
|
||||
//emit how long this section is, +1 for ending mark
|
||||
Toy_emitShort(&fnCollation, &fnCapacity, &fnCount, (unsigned short)size + 1);
|
||||
|
||||
//write the fn to the fn collation
|
||||
for (int i = 0; i < size; i++) {
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
emitByte(&fnCollation, &fnCapacity, &fnCount, bytes[i]);
|
||||
}
|
||||
|
||||
@@ -1198,7 +1213,7 @@ static unsigned char* collateCompilerHeaderOpt(Toy_Compiler* compiler, int* size
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
@@ -1284,6 +1299,7 @@ static unsigned char* collateCompilerHeaderOpt(Toy_Compiler* compiler, int* size
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -19,4 +19,4 @@ TOY_API void Toy_writeCompiler(Toy_Compiler* compiler, Toy_ASTNode* node);
|
||||
TOY_API void Toy_freeCompiler(Toy_Compiler* compiler);
|
||||
|
||||
//embed the header, data section, code section, function section, etc.
|
||||
TOY_API unsigned char* Toy_collateCompiler(Toy_Compiler* compiler, int* size);
|
||||
TOY_API unsigned char* Toy_collateCompiler(Toy_Compiler* compiler, size_t* size);
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
//NOTE: you need both font AND background for these to work
|
||||
|
||||
//platform/compiler-specific instructions
|
||||
#if defined(__linux__) || defined(__MINGW32__) || defined(__GNUC__)
|
||||
|
||||
//fonts color
|
||||
#define TOY_CC_FONT_BLACK "\033[30;"
|
||||
#define TOY_CC_FONT_RED "\033[31;"
|
||||
@@ -25,6 +28,37 @@
|
||||
|
||||
//useful
|
||||
#define TOY_CC_NOTICE TOY_CC_FONT_GREEN TOY_CC_BACK_BLACK
|
||||
#define TOY_CC_WARN TOY_CC_FONT_YELLOW TOY_CC_BACK_BLACK
|
||||
#define TOY_CC_ERROR TOY_CC_FONT_RED TOY_CC_BACK_BLACK
|
||||
#define TOY_CC_WARN TOY_CC_FONT_YELLOW TOY_CC_BACK_BLACK
|
||||
#define TOY_CC_ERROR TOY_CC_FONT_RED TOY_CC_BACK_BLACK
|
||||
#define TOY_CC_RESET "\033[0m"
|
||||
|
||||
#else
|
||||
|
||||
//fonts color
|
||||
#define TOY_CC_FONT_BLACK
|
||||
#define TOY_CC_FONT_RED
|
||||
#define TOY_CC_FONT_GREEN
|
||||
#define TOY_CC_FONT_YELLOW
|
||||
#define TOY_CC_FONT_BLUE
|
||||
#define TOY_CC_FONT_PURPLE
|
||||
#define TOY_CC_FONT_DGREEN
|
||||
#define TOY_CC_FONT_WHITE
|
||||
#define TOY_CC_FONT_CYAN
|
||||
|
||||
//background color
|
||||
#define TOY_CC_BACK_BLACK
|
||||
#define TOY_CC_BACK_RED
|
||||
#define TOY_CC_BACK_GREEN
|
||||
#define TOY_CC_BACK_YELLOW
|
||||
#define TOY_CC_BACK_BLUE
|
||||
#define TOY_CC_BACK_PURPLE
|
||||
#define TOY_CC_BACK_DGREEN
|
||||
#define TOY_CC_BACK_WHITE
|
||||
|
||||
//useful
|
||||
#define TOY_CC_NOTICE TOY_CC_FONT_GREEN TOY_CC_BACK_BLACK
|
||||
#define TOY_CC_WARN TOY_CC_FONT_YELLOW TOY_CC_BACK_BLACK
|
||||
#define TOY_CC_ERROR TOY_CC_FONT_RED TOY_CC_BACK_BLACK
|
||||
#define TOY_CC_RESET
|
||||
|
||||
#endif
|
||||
|
||||
+324
-225
@@ -12,29 +12,30 @@
|
||||
#include <string.h>
|
||||
|
||||
static void printWrapper(const char* output) {
|
||||
printf("%s", output);
|
||||
printf("\n"); //default new line
|
||||
if (Toy_commandLine.enablePrintNewline) {
|
||||
printf("%s\n", output);
|
||||
}
|
||||
else {
|
||||
printf("%s", output);
|
||||
}
|
||||
}
|
||||
|
||||
static void assertWrapper(const char* output) {
|
||||
fprintf(stderr, TOY_CC_ERROR "Assertion failure: ");
|
||||
fprintf(stderr, "%s", output);
|
||||
fprintf(stderr, "\n" TOY_CC_RESET); //default new line
|
||||
fprintf(stderr, TOY_CC_ERROR "Assertion failure: %s\n" TOY_CC_RESET, output);
|
||||
}
|
||||
|
||||
static void errorWrapper(const char* output) {
|
||||
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
|
||||
if (Toy_findTypeByKeyword(name) != TOY_TOKEN_EOF) {
|
||||
interpreter->errorOutput("Can't override an existing keyword\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
int identifierLength = strlen(name);
|
||||
Toy_Literal identifier = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefStringLength(name, identifierLength));
|
||||
Toy_Literal identifier = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString(name));
|
||||
|
||||
//make sure the name isn't taken
|
||||
if (Toy_existsLiteralDictionary(&interpreter->scope->variables, identifier)) {
|
||||
@@ -54,7 +55,7 @@ bool Toy_injectNativeFn(Toy_Interpreter* interpreter, char* name, Toy_NativeFn f
|
||||
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
|
||||
if (Toy_findTypeByKeyword(name) != TOY_TOKEN_EOF) {
|
||||
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
|
||||
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);
|
||||
*count += 1;
|
||||
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;
|
||||
memcpy(&ret, tb + *count, 2);
|
||||
*count += 2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int readInt(unsigned char* tb, int* count) {
|
||||
static int readInt(const unsigned char* tb, int* count) {
|
||||
int ret = 0;
|
||||
memcpy(&ret, tb + *count, 4);
|
||||
*count += 4;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static float readFloat(unsigned char* tb, int* count) {
|
||||
static float readFloat(const unsigned char* tb, int* count) {
|
||||
float ret = 0;
|
||||
memcpy(&ret, tb + *count, 4);
|
||||
*count += 4;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char* readString(unsigned char* tb, int* count) {
|
||||
unsigned char* ret = tb + *count;
|
||||
static const char* readString(const unsigned char* tb, int* count) {
|
||||
const unsigned char* ret = tb + *count;
|
||||
*count += strlen((char*)ret) + 1; //+1 for null character
|
||||
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]) {
|
||||
char buffer[512];
|
||||
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;
|
||||
}
|
||||
|
||||
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)) {
|
||||
char buffer[512];
|
||||
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);
|
||||
}
|
||||
|
||||
if (TOY_IS_IDENTIFIER(lhs)) {
|
||||
Toy_freeLiteral(lhs);
|
||||
Toy_freeLiteral(rhs);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TOY_IS_STRING(rhs)) {
|
||||
interpreter->errorOutput("The assert keyword needs a string as the second argument, received: ");
|
||||
Toy_printLiteralCustom(rhs, interpreter->errorOutput);
|
||||
@@ -264,6 +271,11 @@ static bool execPrint(Toy_Interpreter* interpreter) {
|
||||
Toy_freeLiteral(idn);
|
||||
}
|
||||
|
||||
if (TOY_IS_IDENTIFIER(lit)) {
|
||||
Toy_freeLiteral(lit);
|
||||
return false;
|
||||
}
|
||||
|
||||
Toy_printLiteralCustom(lit, interpreter->printOutput);
|
||||
|
||||
Toy_freeLiteral(lit);
|
||||
@@ -296,6 +308,11 @@ static bool rawLiteral(Toy_Interpreter* interpreter) {
|
||||
Toy_freeLiteral(idn);
|
||||
}
|
||||
|
||||
if (TOY_IS_IDENTIFIER(lit)) {
|
||||
Toy_freeLiteral(lit);
|
||||
return false;
|
||||
}
|
||||
|
||||
Toy_pushLiteralArray(&interpreter->stack, lit);
|
||||
Toy_freeLiteral(lit);
|
||||
|
||||
@@ -311,6 +328,11 @@ static bool execNegate(Toy_Interpreter* interpreter) {
|
||||
Toy_freeLiteral(idn);
|
||||
}
|
||||
|
||||
if (TOY_IS_IDENTIFIER(lit)) {
|
||||
Toy_freeLiteral(lit);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TOY_IS_INTEGER(lit)) {
|
||||
lit = TOY_TO_INTEGER_LITERAL(-TOY_AS_INTEGER(lit));
|
||||
}
|
||||
@@ -342,6 +364,11 @@ static bool execInvert(Toy_Interpreter* interpreter) {
|
||||
Toy_freeLiteral(idn);
|
||||
}
|
||||
|
||||
if (TOY_IS_IDENTIFIER(lit)) {
|
||||
Toy_freeLiteral(lit);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TOY_IS_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);
|
||||
}
|
||||
|
||||
if (TOY_IS_IDENTIFIER(lhs) || TOY_IS_IDENTIFIER(rhs)) {
|
||||
Toy_freeLiteral(lhs);
|
||||
Toy_freeLiteral(rhs);
|
||||
return false;
|
||||
}
|
||||
|
||||
//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)) {
|
||||
//check for overflow
|
||||
@@ -507,6 +540,10 @@ static Toy_Literal parseTypeToValue(Toy_Interpreter* interpreter, Toy_Literal ty
|
||||
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 (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++) {
|
||||
@@ -547,6 +584,12 @@ static bool execVarDecl(Toy_Interpreter* interpreter, bool lng) {
|
||||
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
|
||||
type = parseTypeToValue(interpreter, type);
|
||||
|
||||
@@ -564,6 +607,13 @@ static bool execVarDecl(Toy_Interpreter* interpreter, bool lng) {
|
||||
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)) {
|
||||
Toy_parseCompoundToPureValues(interpreter, &val);
|
||||
}
|
||||
@@ -644,6 +694,12 @@ static bool execVarAssign(Toy_Interpreter* interpreter) {
|
||||
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)) {
|
||||
Toy_parseCompoundToPureValues(interpreter, &rhs);
|
||||
}
|
||||
@@ -713,6 +769,12 @@ static bool execValCast(Toy_Interpreter* interpreter) {
|
||||
Toy_freeLiteral(valueIdn);
|
||||
}
|
||||
|
||||
if (TOY_IS_IDENTIFIER(value)) {
|
||||
Toy_freeLiteral(type);
|
||||
Toy_freeLiteral(value);
|
||||
return false;
|
||||
}
|
||||
|
||||
Toy_Literal result = TOY_TO_NULL_LITERAL;
|
||||
|
||||
if (TOY_IS_NULL(value)) {
|
||||
@@ -847,6 +909,12 @@ static bool execCompareEqual(Toy_Interpreter* interpreter, bool invert) {
|
||||
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);
|
||||
|
||||
if (invert) {
|
||||
@@ -875,6 +943,12 @@ static bool execCompareLess(Toy_Interpreter* interpreter, bool invert) {
|
||||
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
|
||||
if (!(TOY_IS_INTEGER(lhs) || TOY_IS_FLOAT(lhs))) {
|
||||
interpreter->errorOutput("Incorrect type in comparison, value \"");
|
||||
@@ -935,6 +1009,12 @@ static bool execCompareLessEqual(Toy_Interpreter* interpreter, bool invert) {
|
||||
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
|
||||
if (!(TOY_IS_INTEGER(lhs) || TOY_IS_FLOAT(lhs))) {
|
||||
interpreter->errorOutput("Incorrect type in comparison, value \"");
|
||||
@@ -996,6 +1076,12 @@ static bool execAnd(Toy_Interpreter* interpreter) {
|
||||
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)) {
|
||||
Toy_pushLiteralArray(&interpreter->stack, TOY_TO_BOOLEAN_LITERAL(true));
|
||||
}
|
||||
@@ -1023,6 +1109,12 @@ static bool execOr(Toy_Interpreter* interpreter) {
|
||||
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)) {
|
||||
Toy_pushLiteralArray(&interpreter->stack, TOY_TO_BOOLEAN_LITERAL(true));
|
||||
}
|
||||
@@ -1066,6 +1158,11 @@ static bool execFalseJump(Toy_Interpreter* interpreter) {
|
||||
Toy_freeLiteral(litIdn);
|
||||
}
|
||||
|
||||
if (TOY_IS_IDENTIFIER(lit)) {
|
||||
Toy_freeLiteral(lit);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TOY_IS_NULL(lit)) {
|
||||
interpreter->errorOutput("Null detected in comparison\n");
|
||||
Toy_freeLiteral(lit);
|
||||
@@ -1085,6 +1182,8 @@ static bool execFalseJump(Toy_Interpreter* interpreter) {
|
||||
static void execInterpreter(Toy_Interpreter*);
|
||||
static void readInterpreterSections(Toy_Interpreter* interpreter);
|
||||
|
||||
//expect stack: identifier, arg1, arg2, arg3..., stackSize
|
||||
//also supports identifier & arg1 to be other way around (looseFirstArgument)
|
||||
static bool execFnCall(Toy_Interpreter* interpreter, bool looseFirstArgument) {
|
||||
//BUGFIX: depth check - don't drown!
|
||||
if (interpreter->depth >= 200) {
|
||||
@@ -1121,24 +1220,7 @@ static bool execFnCall(Toy_Interpreter* interpreter, bool looseFirstArgument) {
|
||||
Toy_freeLiteral(lit);
|
||||
}
|
||||
|
||||
//let's screw with the fn name, too
|
||||
if (looseFirstArgument) {
|
||||
if (!TOY_IS_IDENTIFIER(identifier)) {
|
||||
interpreter->errorOutput("Bad literal passed as a function identifier\n");
|
||||
Toy_freeLiteral(identifier);
|
||||
Toy_freeLiteral(stackSize);
|
||||
Toy_freeLiteralArray(&arguments);
|
||||
return false;
|
||||
}
|
||||
|
||||
int length = TOY_AS_IDENTIFIER(identifier)->length + 1;
|
||||
char buffer[TOY_MAX_STRING_LENGTH];
|
||||
snprintf(buffer, TOY_MAX_STRING_LENGTH, "_%s", Toy_toCString(TOY_AS_IDENTIFIER(identifier))); //prepend an underscore
|
||||
|
||||
Toy_freeLiteral(identifier);
|
||||
identifier = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefStringLength(buffer, length));
|
||||
}
|
||||
|
||||
//get the function literal
|
||||
Toy_Literal func = identifier;
|
||||
|
||||
if (!Toy_parseIdentifierToValue(interpreter, &func)) {
|
||||
@@ -1148,30 +1230,7 @@ static bool execFnCall(Toy_Interpreter* interpreter, bool looseFirstArgument) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//check for side-loaded native functions
|
||||
if (TOY_IS_FUNCTION_NATIVE(func)) {
|
||||
//reverse the order to the correct order
|
||||
Toy_LiteralArray correct;
|
||||
Toy_initLiteralArray(&correct);
|
||||
|
||||
while(arguments.count) {
|
||||
Toy_Literal lit = Toy_popLiteralArray(&arguments);
|
||||
Toy_pushLiteralArray(&correct, lit);
|
||||
Toy_freeLiteral(lit);
|
||||
}
|
||||
|
||||
Toy_freeLiteralArray(&arguments);
|
||||
|
||||
//call the native function
|
||||
TOY_AS_FUNCTION_NATIVE(func)(interpreter, &correct);
|
||||
|
||||
Toy_freeLiteralArray(&correct);
|
||||
Toy_freeLiteral(stackSize);
|
||||
Toy_freeLiteral(identifier);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!TOY_IS_FUNCTION(func)) {
|
||||
if (!TOY_IS_FUNCTION(func) && !TOY_IS_FUNCTION_NATIVE(func)) {
|
||||
interpreter->errorOutput("Function not found: ");
|
||||
Toy_printLiteralCustom(identifier, interpreter->errorOutput);
|
||||
interpreter->errorOutput("\n");
|
||||
@@ -1182,7 +1241,18 @@ static bool execFnCall(Toy_Interpreter* interpreter, bool looseFirstArgument) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret = Toy_callLiteralFn(interpreter, func, &arguments, &interpreter->stack);
|
||||
//BUGFIX: correct the argument order
|
||||
Toy_LiteralArray correct;
|
||||
Toy_initLiteralArray(&correct);
|
||||
|
||||
while (arguments.count > 0) {
|
||||
Toy_Literal lit = Toy_popLiteralArray(&arguments);
|
||||
Toy_pushLiteralArray(&correct, lit);
|
||||
Toy_freeLiteral(lit);
|
||||
}
|
||||
|
||||
//call the function literal
|
||||
bool ret = Toy_callLiteralFn(interpreter, func, &correct, &interpreter->stack);
|
||||
|
||||
if (!ret) {
|
||||
interpreter->errorOutput("Error encountered in function \"");
|
||||
@@ -1190,6 +1260,7 @@ static bool execFnCall(Toy_Interpreter* interpreter, bool looseFirstArgument) {
|
||||
interpreter->errorOutput("\"\n");
|
||||
}
|
||||
|
||||
Toy_freeLiteralArray(&correct);
|
||||
Toy_freeLiteralArray(&arguments);
|
||||
Toy_freeLiteral(func);
|
||||
Toy_freeLiteral(stackSize);
|
||||
@@ -1198,25 +1269,17 @@ static bool execFnCall(Toy_Interpreter* interpreter, bool looseFirstArgument) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
//expects arguments in correct order
|
||||
bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_LiteralArray* arguments, Toy_LiteralArray* returns) {
|
||||
//check for side-loaded native functions
|
||||
if (TOY_IS_FUNCTION_NATIVE(func)) {
|
||||
//reverse the order to the correct order
|
||||
Toy_LiteralArray correct;
|
||||
Toy_initLiteralArray(&correct);
|
||||
|
||||
while(arguments->count) {
|
||||
Toy_Literal lit = Toy_popLiteralArray(arguments);
|
||||
Toy_pushLiteralArray(&correct, lit);
|
||||
Toy_freeLiteral(lit);
|
||||
}
|
||||
//TODO: parse out identifier values, see issue #64
|
||||
|
||||
//call the native function
|
||||
int returnsCount = TOY_AS_FUNCTION_NATIVE(func)(interpreter, &correct);
|
||||
int returnsCount = TOY_AS_FUNCTION_NATIVE(func)(interpreter, arguments);
|
||||
|
||||
if (returnsCount < 0) {
|
||||
interpreter->errorOutput("Unknown error from native function\n");
|
||||
Toy_freeLiteralArray(&correct);
|
||||
// interpreter->errorOutput("Unknown error from native function\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1238,13 +1301,12 @@ bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_Liter
|
||||
}
|
||||
|
||||
Toy_freeLiteralArray(&returnsFromInner);
|
||||
Toy_freeLiteralArray(&correct);
|
||||
return true;
|
||||
}
|
||||
|
||||
//normal Toy function
|
||||
if (!TOY_IS_FUNCTION(func)) {
|
||||
interpreter->errorOutput("Function required in Toy_callLiteralFn()\n");
|
||||
interpreter->errorOutput("Function literal required in Toy_callLiteralFn()\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1254,8 +1316,8 @@ bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_Liter
|
||||
//init the inner interpreter manually
|
||||
Toy_initLiteralArray(&inner.literalCache);
|
||||
inner.scope = Toy_pushScope(func.as.function.scope);
|
||||
inner.bytecode = TOY_AS_FUNCTION(func).bytecode;
|
||||
inner.length = TOY_AS_FUNCTION(func).length;
|
||||
inner.bytecode = TOY_AS_FUNCTION(func).inner.bytecode;
|
||||
inner.length = TOY_AS_FUNCTION_BYTECODE_LENGTH(func);
|
||||
inner.count = 0;
|
||||
inner.codeStart = -1;
|
||||
inner.depth = interpreter->depth + 1;
|
||||
@@ -1292,6 +1354,9 @@ bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_Liter
|
||||
return false;
|
||||
}
|
||||
|
||||
//BUGFIX: access the arguments from the beginning
|
||||
int argumentIndex = 0;
|
||||
|
||||
//contents is the indexes of identifier & type
|
||||
for (int i = 0; i < paramArray->count - (TOY_IS_NULL(restParam) ? 0 : 2); i += 2) { //don't count the rest parameter, if present
|
||||
//declare and define each entry in the scope
|
||||
@@ -1307,13 +1372,28 @@ bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_Liter
|
||||
return false;
|
||||
}
|
||||
|
||||
Toy_Literal arg = Toy_popLiteralArray(arguments);
|
||||
//access the arguments in order
|
||||
Toy_Literal arg = TOY_TO_NULL_LITERAL;
|
||||
if (argumentIndex < arguments->count) {
|
||||
arg = Toy_copyLiteral(arguments->literals[argumentIndex++]);
|
||||
}
|
||||
|
||||
Toy_Literal argIdn = arg;
|
||||
if (TOY_IS_IDENTIFIER(arg) && Toy_parseIdentifierToValue(interpreter, &arg)) {
|
||||
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)) {
|
||||
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_initLiteralArray(&rest);
|
||||
|
||||
while (arguments->count > 0) {
|
||||
Toy_Literal lit = Toy_popLiteralArray(arguments);
|
||||
//access the arguments in order
|
||||
while (argumentIndex < arguments->count) {
|
||||
Toy_Literal lit = Toy_copyLiteral(arguments->literals[argumentIndex++]);
|
||||
Toy_pushLiteralArray(&rest, lit);
|
||||
Toy_freeLiteral(lit);
|
||||
}
|
||||
@@ -1442,11 +1523,14 @@ bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_Liter
|
||||
Toy_freeLiteralArray(&inner.stack);
|
||||
Toy_freeLiteralArray(&inner.literalCache);
|
||||
|
||||
//BUGFIX: this function needs to eat the arguments
|
||||
Toy_freeLiteralArray(arguments);
|
||||
|
||||
//actual bytecode persists until next call
|
||||
return true;
|
||||
}
|
||||
|
||||
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 val = TOY_TO_NULL_LITERAL;
|
||||
|
||||
@@ -1478,6 +1562,12 @@ static bool execFnReturn(Toy_Interpreter* interpreter) {
|
||||
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)) {
|
||||
Toy_parseCompoundToPureValues(interpreter, &lit);
|
||||
}
|
||||
@@ -1507,7 +1597,7 @@ static bool execImport(Toy_Interpreter* interpreter) {
|
||||
if (!Toy_existsLiteralDictionary(interpreter->hooks, identifier)) {
|
||||
interpreter->errorOutput("Unknown library name in import statement: ");
|
||||
Toy_printLiteralCustom(identifier, interpreter->errorOutput);
|
||||
interpreter->errorOutput("\"\n");
|
||||
interpreter->errorOutput("\n");
|
||||
|
||||
Toy_freeLiteral(alias);
|
||||
Toy_freeLiteral(identifier);
|
||||
@@ -1549,8 +1639,19 @@ static bool execIndex(Toy_Interpreter* interpreter, bool assignIntermediate) {
|
||||
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)) {
|
||||
interpreter->errorOutput("Unknown compound found in indexing notation: ");
|
||||
interpreter->errorOutput("Unknown compound found in index notation: ");
|
||||
Toy_printLiteralCustom(compound, interpreter->errorOutput);
|
||||
interpreter->errorOutput("\n");
|
||||
|
||||
@@ -1588,7 +1689,7 @@ static bool execIndex(Toy_Interpreter* interpreter, bool assignIntermediate) {
|
||||
Toy_pushLiteralArray(&interpreter->stack, third);
|
||||
}
|
||||
|
||||
//call the _index function
|
||||
//call the index function
|
||||
if (Toy_private_index(interpreter, &arguments) < 0) {
|
||||
interpreter->errorOutput("Something went wrong while indexing (simple index): ");
|
||||
Toy_printLiteralCustom(compoundIdn, interpreter->errorOutput);
|
||||
@@ -1619,64 +1720,101 @@ static bool execIndex(Toy_Interpreter* interpreter, bool assignIntermediate) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool execIndexAssign(Toy_Interpreter* interpreter) {
|
||||
static bool execIndexAssign(Toy_Interpreter* interpreter, int assignDepth) {
|
||||
//assume -> compound, first, second, third, assign are all on the stack
|
||||
|
||||
Toy_Literal assign = Toy_popLiteralArray(&interpreter->stack);
|
||||
Toy_Literal third = Toy_popLiteralArray(&interpreter->stack);
|
||||
Toy_Literal second = Toy_popLiteralArray(&interpreter->stack);
|
||||
Toy_Literal first = Toy_popLiteralArray(&interpreter->stack);
|
||||
Toy_Literal compound = Toy_popLiteralArray(&interpreter->stack);
|
||||
|
||||
Toy_Literal assignIdn = assign;
|
||||
if (TOY_IS_IDENTIFIER(assign) && Toy_parseIdentifierToValue(interpreter, &assign)) {
|
||||
Toy_freeLiteral(assignIdn);
|
||||
}
|
||||
|
||||
Toy_Literal compoundIdn = compound;
|
||||
Toy_Literal assign = TOY_TO_NULL_LITERAL, third = TOY_TO_NULL_LITERAL, second = TOY_TO_NULL_LITERAL, first = TOY_TO_NULL_LITERAL, compound = TOY_TO_NULL_LITERAL, result = TOY_TO_NULL_LITERAL;
|
||||
Toy_Literal compoundIdn = TOY_TO_NULL_LITERAL;
|
||||
bool freeIdn = false;
|
||||
if (TOY_IS_IDENTIFIER(compound) && Toy_parseIdentifierToValue(interpreter, &compound)) {
|
||||
freeIdn = true;
|
||||
|
||||
//build the opcode
|
||||
unsigned char opcode = readByte(interpreter->bytecode, &interpreter->count);
|
||||
char* opStr = "";
|
||||
switch (opcode) {
|
||||
case TOY_OP_VAR_ASSIGN:
|
||||
opStr = "=";
|
||||
break;
|
||||
case TOY_OP_VAR_ADDITION_ASSIGN:
|
||||
opStr = "+=";
|
||||
break;
|
||||
case TOY_OP_VAR_SUBTRACTION_ASSIGN:
|
||||
opStr = "-=";
|
||||
break;
|
||||
case TOY_OP_VAR_MULTIPLICATION_ASSIGN:
|
||||
opStr = "*=";
|
||||
break;
|
||||
case TOY_OP_VAR_DIVISION_ASSIGN:
|
||||
opStr = "/=";
|
||||
break;
|
||||
case TOY_OP_VAR_MODULO_ASSIGN:
|
||||
opStr = "%=";
|
||||
break;
|
||||
|
||||
default:
|
||||
interpreter->errorOutput("bad opcode in index assigning notation\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TOY_IS_ARRAY(compound) && !TOY_IS_DICTIONARY(compound) && !TOY_IS_STRING(compound)) {
|
||||
interpreter->errorOutput("Unknown compound found in index assigning notation\n");
|
||||
//iterate...
|
||||
while(assignDepth-- >= 0) {
|
||||
Toy_freeLiteral(assign);
|
||||
Toy_freeLiteral(third);
|
||||
Toy_freeLiteral(second);
|
||||
Toy_freeLiteral(first);
|
||||
Toy_freeLiteral(compound);
|
||||
if (freeIdn) {
|
||||
Toy_freeLiteral(compoundIdn);
|
||||
|
||||
if (TOY_IS_NULL(result)) {
|
||||
assign = Toy_popLiteralArray(&interpreter->stack);
|
||||
}
|
||||
else {
|
||||
assign = result;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//build the opcode
|
||||
unsigned char opcode = readByte(interpreter->bytecode, &interpreter->count);
|
||||
char* opStr = "";
|
||||
switch(opcode) {
|
||||
case TOY_OP_VAR_ASSIGN:
|
||||
opStr = "=";
|
||||
break;
|
||||
case TOY_OP_VAR_ADDITION_ASSIGN:
|
||||
opStr = "+=";
|
||||
break;
|
||||
case TOY_OP_VAR_SUBTRACTION_ASSIGN:
|
||||
opStr = "-=";
|
||||
break;
|
||||
case TOY_OP_VAR_MULTIPLICATION_ASSIGN:
|
||||
opStr = "*=";
|
||||
break;
|
||||
case TOY_OP_VAR_DIVISION_ASSIGN:
|
||||
opStr = "/=";
|
||||
break;
|
||||
case TOY_OP_VAR_MODULO_ASSIGN:
|
||||
opStr = "%=";
|
||||
break;
|
||||
third = Toy_popLiteralArray(&interpreter->stack);
|
||||
second = Toy_popLiteralArray(&interpreter->stack);
|
||||
first = Toy_popLiteralArray(&interpreter->stack);
|
||||
compound = Toy_popLiteralArray(&interpreter->stack);
|
||||
|
||||
default:
|
||||
interpreter->errorOutput("bad opcode in index assigning notation\n");
|
||||
if (TOY_IS_IDENTIFIER(compound)) {
|
||||
if (freeIdn) {
|
||||
Toy_freeLiteral(compoundIdn);
|
||||
}
|
||||
|
||||
compoundIdn = compound;
|
||||
Toy_parseIdentifierToValue(interpreter, &compound);
|
||||
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;
|
||||
}
|
||||
|
||||
Toy_Literal assignIdn = assign;
|
||||
if (TOY_IS_IDENTIFIER(assign) && Toy_parseIdentifierToValue(interpreter, &assign)) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (!TOY_IS_ARRAY(compound) && !TOY_IS_DICTIONARY(compound) && !TOY_IS_STRING(compound)) {
|
||||
interpreter->errorOutput("Unknown compound found in index assigning notation: ");
|
||||
Toy_printLiteralCustom(compound, interpreter->errorOutput);
|
||||
interpreter->errorOutput("\n");
|
||||
Toy_freeLiteral(assign);
|
||||
Toy_freeLiteral(third);
|
||||
Toy_freeLiteral(second);
|
||||
@@ -1686,103 +1824,60 @@ static bool execIndexAssign(Toy_Interpreter* interpreter) {
|
||||
Toy_freeLiteral(compoundIdn);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int opLength = strlen(opStr);
|
||||
Toy_Literal op = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(opStr, opLength)); //TODO: static reference optimisation?
|
||||
|
||||
//build the argument list
|
||||
Toy_LiteralArray arguments;
|
||||
Toy_initLiteralArray(&arguments);
|
||||
|
||||
Toy_pushLiteralArray(&arguments, compound);
|
||||
Toy_pushLiteralArray(&arguments, first);
|
||||
Toy_pushLiteralArray(&arguments, second);
|
||||
Toy_pushLiteralArray(&arguments, third);
|
||||
Toy_pushLiteralArray(&arguments, assign); //it expects an assignment command
|
||||
Toy_pushLiteralArray(&arguments, op); //it expects an assignment "opcode"
|
||||
|
||||
//call the _index function
|
||||
if (Toy_private_index(interpreter, &arguments) < 0) {
|
||||
//clean up
|
||||
Toy_freeLiteral(assign);
|
||||
Toy_freeLiteral(third);
|
||||
Toy_freeLiteral(second);
|
||||
Toy_freeLiteral(first);
|
||||
Toy_freeLiteral(compound);
|
||||
if (freeIdn) {
|
||||
Toy_freeLiteral(compoundIdn);
|
||||
}
|
||||
Toy_freeLiteral(op);
|
||||
Toy_freeLiteralArray(&arguments);
|
||||
|
||||
return false;
|
||||
}
|
||||
int opLength = strlen(opStr);
|
||||
Toy_Literal op = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(opStr, opLength)); //TODO: static reference optimisation?
|
||||
|
||||
//save the result (assume top of the interpreter stack is the new compound value)
|
||||
Toy_Literal result = Toy_popLiteralArray(&interpreter->stack);
|
||||
//build the argument list
|
||||
Toy_LiteralArray arguments;
|
||||
Toy_initLiteralArray(&arguments);
|
||||
|
||||
//deep
|
||||
if (!freeIdn) {
|
||||
while (interpreter->stack.count > 1) {
|
||||
//read the new values
|
||||
Toy_freeLiteral(compound);
|
||||
Toy_pushLiteralArray(&arguments, compound);
|
||||
Toy_pushLiteralArray(&arguments, first);
|
||||
Toy_pushLiteralArray(&arguments, second);
|
||||
Toy_pushLiteralArray(&arguments, third);
|
||||
Toy_pushLiteralArray(&arguments, assign); //it expects an assignment command
|
||||
Toy_pushLiteralArray(&arguments, op); //it expects an assignment "opcode"
|
||||
|
||||
//call the index function
|
||||
if (Toy_private_index(interpreter, &arguments) < 0) {
|
||||
//clean up
|
||||
Toy_freeLiteral(assign);
|
||||
Toy_freeLiteral(third);
|
||||
Toy_freeLiteral(second);
|
||||
Toy_freeLiteral(first);
|
||||
Toy_freeLiteralArray(&arguments);
|
||||
Toy_initLiteralArray(&arguments);
|
||||
Toy_freeLiteral(op);
|
||||
|
||||
//reuse these like an idiot
|
||||
third = Toy_popLiteralArray(&interpreter->stack);
|
||||
second = Toy_popLiteralArray(&interpreter->stack);
|
||||
first = Toy_popLiteralArray(&interpreter->stack);
|
||||
compound = Toy_popLiteralArray(&interpreter->stack);
|
||||
|
||||
char* opStr = "="; //shadow, but force assignment
|
||||
int opLength = strlen(opStr);
|
||||
op = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(opStr, opLength)); //TODO: static reference optimisation?
|
||||
|
||||
//assign to the idn / compound - with _index
|
||||
Toy_pushLiteralArray(&arguments, compound); //
|
||||
Toy_pushLiteralArray(&arguments, first);
|
||||
Toy_pushLiteralArray(&arguments, second);
|
||||
Toy_pushLiteralArray(&arguments, third);
|
||||
Toy_pushLiteralArray(&arguments, result);
|
||||
Toy_pushLiteralArray(&arguments, op);
|
||||
|
||||
if (Toy_private_index(interpreter, &arguments) < 0) {
|
||||
interpreter->errorOutput("Something went wrong while indexing (index assign): ");
|
||||
Toy_printLiteralCustom(compound, interpreter->errorOutput);
|
||||
interpreter->errorOutput("\n");
|
||||
|
||||
//clean up
|
||||
Toy_freeLiteral(assign);
|
||||
Toy_freeLiteral(third);
|
||||
Toy_freeLiteral(second);
|
||||
Toy_freeLiteral(first);
|
||||
if (freeIdn) {
|
||||
Toy_freeLiteral(compoundIdn);
|
||||
}
|
||||
Toy_freeLiteral(op);
|
||||
Toy_freeLiteralArray(&arguments);
|
||||
return false;
|
||||
Toy_freeLiteral(compound);
|
||||
if (freeIdn) {
|
||||
Toy_freeLiteral(compoundIdn);
|
||||
}
|
||||
Toy_freeLiteral(op);
|
||||
Toy_freeLiteralArray(&arguments);
|
||||
|
||||
Toy_freeLiteral(result);
|
||||
result = Toy_popLiteralArray(&interpreter->stack);
|
||||
return false;
|
||||
}
|
||||
|
||||
Toy_freeLiteral(compound);
|
||||
compound = Toy_popLiteralArray(&interpreter->stack);
|
||||
compoundIdn = compound;
|
||||
freeIdn = false;
|
||||
//save the result (assume top of the interpreter stack is the new compound value)
|
||||
result = Toy_popLiteralArray(&interpreter->stack);
|
||||
|
||||
Toy_freeLiteral(op);
|
||||
Toy_freeLiteralArray(&arguments);
|
||||
|
||||
//if we loop, then we need to be assigning
|
||||
opStr = "=";
|
||||
}
|
||||
|
||||
//BUGFIX: make sure the compound name can be assigned
|
||||
if (TOY_IS_NULL(compoundIdn)) {
|
||||
compoundIdn = Toy_popLiteralArray(&interpreter->stack);
|
||||
freeIdn = true;
|
||||
}
|
||||
|
||||
if (TOY_IS_IDENTIFIER(compoundIdn) && !Toy_setScopeVariable(interpreter->scope, compoundIdn, result, true)) {
|
||||
interpreter->errorOutput("Incorrect type assigned to compound member ");
|
||||
Toy_printLiteralCustom(compoundIdn, interpreter->errorOutput);
|
||||
interpreter->errorOutput(", value: ");
|
||||
Toy_printLiteralCustom(result, interpreter->errorOutput);
|
||||
interpreter->errorOutput("\n");
|
||||
|
||||
//clean up
|
||||
@@ -1794,8 +1889,6 @@ static bool execIndexAssign(Toy_Interpreter* interpreter) {
|
||||
if (freeIdn) {
|
||||
Toy_freeLiteral(compoundIdn);
|
||||
}
|
||||
Toy_freeLiteral(op);
|
||||
Toy_freeLiteralArray(&arguments);
|
||||
Toy_freeLiteral(result);
|
||||
return false;
|
||||
}
|
||||
@@ -1809,8 +1902,6 @@ static bool execIndexAssign(Toy_Interpreter* interpreter) {
|
||||
if (freeIdn) {
|
||||
Toy_freeLiteral(compoundIdn);
|
||||
}
|
||||
Toy_freeLiteral(op);
|
||||
Toy_freeLiteralArray(&arguments);
|
||||
Toy_freeLiteral(result);
|
||||
|
||||
return true;
|
||||
@@ -1823,10 +1914,17 @@ static void execInterpreter(Toy_Interpreter* interpreter) {
|
||||
interpreter->codeStart = interpreter->count;
|
||||
}
|
||||
|
||||
//BUGFIX
|
||||
int intermediateAssignDepth = 0;
|
||||
|
||||
unsigned char opcode = readByte(interpreter->bytecode, &interpreter->count);
|
||||
|
||||
while(opcode != TOY_OP_EOF && opcode != TOY_OP_SECTION_END && !interpreter->panic) {
|
||||
switch(opcode) {
|
||||
case TOY_OP_PASS:
|
||||
//DO NOTHING
|
||||
break;
|
||||
|
||||
case TOY_OP_ASSERT:
|
||||
if (!execAssert(interpreter)) {
|
||||
return;
|
||||
@@ -2033,12 +2131,14 @@ static void execInterpreter(Toy_Interpreter* interpreter) {
|
||||
if (!execIndex(interpreter, true)) {
|
||||
return;
|
||||
}
|
||||
intermediateAssignDepth++;
|
||||
break;
|
||||
|
||||
case TOY_OP_INDEX_ASSIGN:
|
||||
if (!execIndexAssign(interpreter)) {
|
||||
if (!execIndexAssign(interpreter, intermediateAssignDepth)) {
|
||||
return;
|
||||
}
|
||||
intermediateAssignDepth = 0;
|
||||
break;
|
||||
|
||||
case TOY_OP_POP_STACK:
|
||||
@@ -2125,7 +2225,7 @@ static void readInterpreterSections(Toy_Interpreter* interpreter) {
|
||||
break;
|
||||
|
||||
case TOY_LITERAL_STRING: {
|
||||
char* s = readString(interpreter->bytecode, &interpreter->count);
|
||||
const char* s = readString(interpreter->bytecode, &interpreter->count);
|
||||
int length = strlen(s);
|
||||
Toy_Literal literal = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(s, length));
|
||||
Toy_pushLiteralArray(&interpreter->literalCache, literal);
|
||||
@@ -2222,7 +2322,7 @@ static void readInterpreterSections(Toy_Interpreter* interpreter) {
|
||||
break;
|
||||
|
||||
case TOY_LITERAL_IDENTIFIER: {
|
||||
char* str = readString(interpreter->bytecode, &interpreter->count);
|
||||
const char* str = readString(interpreter->bytecode, &interpreter->count);
|
||||
|
||||
int length = strlen(str);
|
||||
Toy_Literal identifier = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefStringLength(str, length));
|
||||
@@ -2335,7 +2435,6 @@ static void readInterpreterSections(Toy_Interpreter* interpreter) {
|
||||
|
||||
//change the type to normal
|
||||
interpreter->literalCache.literals[i] = TOY_TO_FUNCTION_LITERAL(bytes, size);
|
||||
TOY_AS_FUNCTION(interpreter->literalCache.literals[i]).scope = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2356,7 +2455,7 @@ void Toy_initInterpreter(Toy_Interpreter* 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()
|
||||
Toy_initLiteralArray(&interpreter->literalCache);
|
||||
interpreter->bytecode = NULL;
|
||||
@@ -2445,12 +2544,12 @@ void Toy_resetInterpreter(Toy_Interpreter* interpreter) {
|
||||
interpreter->scope = Toy_pushScope(NULL);
|
||||
|
||||
//globally available functions
|
||||
Toy_injectNativeFn(interpreter, "_set", Toy_private_set);
|
||||
Toy_injectNativeFn(interpreter, "_get", Toy_private_get);
|
||||
Toy_injectNativeFn(interpreter, "_push", Toy_private_push);
|
||||
Toy_injectNativeFn(interpreter, "_pop", Toy_private_pop);
|
||||
Toy_injectNativeFn(interpreter, "_length", Toy_private_length);
|
||||
Toy_injectNativeFn(interpreter, "_clear", Toy_private_clear);
|
||||
Toy_injectNativeFn(interpreter, "set", Toy_private_set);
|
||||
Toy_injectNativeFn(interpreter, "get", Toy_private_get);
|
||||
Toy_injectNativeFn(interpreter, "push", Toy_private_push);
|
||||
Toy_injectNativeFn(interpreter, "pop", Toy_private_pop);
|
||||
Toy_injectNativeFn(interpreter, "length", Toy_private_length);
|
||||
Toy_injectNativeFn(interpreter, "clear", Toy_private_clear);
|
||||
}
|
||||
|
||||
void Toy_freeInterpreter(Toy_Interpreter* interpreter) {
|
||||
|
||||
@@ -6,12 +6,10 @@
|
||||
#include "toy_literal_dictionary.h"
|
||||
#include "toy_scope.h"
|
||||
|
||||
typedef void (*Toy_PrintFn)(const char*);
|
||||
|
||||
//the interpreter acts depending on the bytecode instructions
|
||||
typedef struct Toy_Interpreter {
|
||||
//input
|
||||
unsigned char* bytecode;
|
||||
const unsigned char* bytecode;
|
||||
int length;
|
||||
int count;
|
||||
int codeStart; //BUGFIX: for jumps, must be initialized to -1
|
||||
@@ -34,11 +32,11 @@ typedef struct Toy_Interpreter {
|
||||
} Toy_Interpreter;
|
||||
|
||||
//native API
|
||||
TOY_API bool Toy_injectNativeFn(Toy_Interpreter* interpreter, char* name, Toy_NativeFn func);
|
||||
TOY_API bool Toy_injectNativeHook(Toy_Interpreter* interpreter, char* name, Toy_HookFn hook);
|
||||
TOY_API bool Toy_injectNativeFn(Toy_Interpreter* interpreter, const char* name, Toy_NativeFn func);
|
||||
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_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
|
||||
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
|
||||
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_freeInterpreter(Toy_Interpreter* interpreter); //end of program
|
||||
|
||||
+21
-12
@@ -12,6 +12,7 @@ static void cleanLexer(Toy_Lexer* lexer) {
|
||||
lexer->start = 0;
|
||||
lexer->current = 0;
|
||||
lexer->line = 1;
|
||||
lexer->commentsEnabled = true;
|
||||
}
|
||||
|
||||
static bool isAtEnd(Toy_Lexer* lexer) {
|
||||
@@ -54,9 +55,13 @@ static void eatWhitespace(Toy_Lexer* lexer) {
|
||||
|
||||
//comments
|
||||
case '/':
|
||||
if (!lexer->commentsEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
//eat the line
|
||||
if (peekNext(lexer) == '/') {
|
||||
while (advance(lexer) != '\n' && !isAtEnd(lexer));
|
||||
while (!isAtEnd(lexer) && advance(lexer) != '\n');
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -64,7 +69,7 @@ static void eatWhitespace(Toy_Lexer* lexer) {
|
||||
if (peekNext(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);
|
||||
break;
|
||||
@@ -112,7 +117,7 @@ static Toy_Token makeErrorToken(Toy_Lexer* lexer, char* msg) {
|
||||
#ifndef TOY_EXPORT
|
||||
if (Toy_commandLine.verbose) {
|
||||
printf("err:");
|
||||
Toy_printToken(&token);
|
||||
Toy_private_printToken(&token);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -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
|
||||
if (Toy_commandLine.verbose) {
|
||||
printf("tok:");
|
||||
Toy_printToken(&token);
|
||||
Toy_private_printToken(&token);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -163,7 +168,7 @@ static Toy_Token makeIntegerOrFloat(Toy_Lexer* lexer) {
|
||||
} else {
|
||||
printf("flt:");
|
||||
}
|
||||
Toy_printToken(&token);
|
||||
Toy_private_printToken(&token);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -216,7 +221,7 @@ static Toy_Token makeString(Toy_Lexer* lexer, char terminator) {
|
||||
#ifndef TOY_EXPORT
|
||||
if (Toy_commandLine.verbose) {
|
||||
printf("str:");
|
||||
Toy_printToken(&token);
|
||||
Toy_private_printToken(&token);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -243,7 +248,7 @@ static Toy_Token makeKeywordOrIdentifier(Toy_Lexer* lexer) {
|
||||
#ifndef TOY_EXPORT
|
||||
if (Toy_commandLine.verbose) {
|
||||
printf("kwd:");
|
||||
Toy_printToken(&token);
|
||||
Toy_private_printToken(&token);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -262,7 +267,7 @@ static Toy_Token makeKeywordOrIdentifier(Toy_Lexer* lexer) {
|
||||
#ifndef TOY_EXPORT
|
||||
if (Toy_commandLine.verbose) {
|
||||
printf("idf:");
|
||||
Toy_printToken(&token);
|
||||
Toy_private_printToken(&token);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -270,13 +275,13 @@ static Toy_Token makeKeywordOrIdentifier(Toy_Lexer* lexer) {
|
||||
}
|
||||
|
||||
//exposed functions
|
||||
void Toy_initLexer(Toy_Lexer* lexer, char* source) {
|
||||
void Toy_initLexer(Toy_Lexer* lexer, const char* source) {
|
||||
cleanLexer(lexer);
|
||||
|
||||
lexer->source = source;
|
||||
}
|
||||
|
||||
Toy_Token Toy_scanLexer(Toy_Lexer* lexer) {
|
||||
Toy_Token Toy_private_scanLexer(Toy_Lexer* lexer) {
|
||||
eatWhitespace(lexer);
|
||||
|
||||
lexer->start = lexer->current;
|
||||
@@ -347,7 +352,7 @@ static void trim(char** s, int* l) { //all this to remove a newline?
|
||||
}
|
||||
|
||||
//for debugging
|
||||
void Toy_printToken(Toy_Token* token) {
|
||||
void Toy_private_printToken(Toy_Token* token) {
|
||||
if (token->type == TOY_TOKEN_ERROR) {
|
||||
printf(TOY_CC_ERROR "Error\t%d\t%.*s\n" TOY_CC_RESET, token->line, token->length, token->lexeme);
|
||||
return;
|
||||
@@ -363,7 +368,7 @@ void Toy_printToken(Toy_Token* token) {
|
||||
if (keyword != NULL) {
|
||||
printf("%s", keyword);
|
||||
} else {
|
||||
char* str = token->lexeme;
|
||||
char* str = (char*)token->lexeme; //strip const-ness for trimming
|
||||
int length = token->length;
|
||||
trim(&str, &length);
|
||||
printf("%.*s", length, str);
|
||||
@@ -372,3 +377,7 @@ void Toy_printToken(Toy_Token* token) {
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void Toy_private_setComments(Toy_Lexer* lexer, bool enabled) {
|
||||
lexer->commentsEnabled = enabled;
|
||||
}
|
||||
+8
-5
@@ -5,22 +5,25 @@
|
||||
|
||||
//lexers are bound to a string of code, and return a single token every time scan is called
|
||||
typedef struct {
|
||||
char* source;
|
||||
const char* source;
|
||||
int start; //start of the token
|
||||
int current; //current position of the lexer
|
||||
int line; //track this for error handling
|
||||
bool commentsEnabled; //BUGFIX: enable comments (disabled in repl)
|
||||
} Toy_Lexer;
|
||||
|
||||
//tokens are intermediaries between lexers and parsers
|
||||
typedef struct {
|
||||
Toy_TokenType type;
|
||||
char* lexeme;
|
||||
const char* lexeme;
|
||||
int length;
|
||||
int line;
|
||||
} Toy_Token;
|
||||
|
||||
TOY_API void Toy_initLexer(Toy_Lexer* lexer, char* source);
|
||||
Toy_Token Toy_scanLexer(Toy_Lexer* lexer);
|
||||
TOY_API void Toy_initLexer(Toy_Lexer* lexer, const char* source);
|
||||
TOY_API Toy_Token Toy_private_scanLexer(Toy_Lexer* lexer);
|
||||
|
||||
//for debugging
|
||||
void Toy_printToken(Toy_Token* token);
|
||||
TOY_API void Toy_private_printToken(Toy_Token* token);
|
||||
|
||||
TOY_API void Toy_private_setComments(Toy_Lexer* lexer, bool enabled);
|
||||
|
||||
+21
-19
@@ -8,6 +8,7 @@
|
||||
#include "toy_console_colors.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
//hash util functions
|
||||
static unsigned int hashString(const char* string, int length) {
|
||||
@@ -58,10 +59,10 @@ void Toy_freeLiteral(Toy_Literal literal) {
|
||||
if (TOY_IS_FUNCTION(literal)) {
|
||||
Toy_popScope(TOY_AS_FUNCTION(literal).scope);
|
||||
TOY_AS_FUNCTION(literal).scope = NULL;
|
||||
TOY_FREE_ARRAY(unsigned char, TOY_AS_FUNCTION(literal).bytecode, TOY_AS_FUNCTION(literal).length);
|
||||
TOY_FREE_ARRAY(unsigned char, TOY_AS_FUNCTION(literal).inner.bytecode, TOY_AS_FUNCTION_BYTECODE_LENGTH(literal));
|
||||
}
|
||||
|
||||
if (TOY_IS_TYPE(literal)) {
|
||||
if (TOY_IS_TYPE(literal) && TOY_AS_TYPE(literal).capacity > 0) {
|
||||
for (int i = 0; i < TOY_AS_TYPE(literal).count; i++) {
|
||||
Toy_freeLiteral(((Toy_Literal*)(TOY_AS_TYPE(literal).subtypes))[i]);
|
||||
}
|
||||
@@ -72,7 +73,7 @@ void Toy_freeLiteral(Toy_Literal literal) {
|
||||
|
||||
bool Toy_private_isTruthy(Toy_Literal 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;
|
||||
}
|
||||
|
||||
@@ -84,11 +85,11 @@ bool Toy_private_isTruthy(Toy_Literal x) {
|
||||
}
|
||||
|
||||
Toy_Literal Toy_private_toStringLiteral(Toy_RefString* ptr) {
|
||||
return ((Toy_Literal){TOY_LITERAL_STRING, { .string.ptr = ptr }});
|
||||
return ((Toy_Literal){{ .string = { .ptr = ptr }},TOY_LITERAL_STRING, 0});
|
||||
}
|
||||
|
||||
Toy_Literal Toy_private_toIdentifierLiteral(Toy_RefString* ptr) {
|
||||
return ((Toy_Literal){TOY_LITERAL_IDENTIFIER,{ .identifier.ptr = ptr, .identifier.hash = hashString(Toy_toCString(ptr), Toy_lengthRefString(ptr)) }});
|
||||
return ((Toy_Literal){{ .identifier = { .ptr = ptr, .hash = hashString(Toy_toCString(ptr), Toy_lengthRefString(ptr)) }},TOY_LITERAL_IDENTIFIER, 0});
|
||||
}
|
||||
|
||||
Toy_Literal* Toy_private_typePushSubtype(Toy_Literal* lit, Toy_Literal subtype) {
|
||||
@@ -145,17 +146,18 @@ Toy_Literal Toy_copyLiteral(Toy_Literal original) {
|
||||
}
|
||||
|
||||
case TOY_LITERAL_FUNCTION: {
|
||||
unsigned char* buffer = TOY_ALLOCATE(unsigned char, TOY_AS_FUNCTION(original).length);
|
||||
memcpy(buffer, TOY_AS_FUNCTION(original).bytecode, TOY_AS_FUNCTION(original).length);
|
||||
unsigned char* buffer = TOY_ALLOCATE(unsigned char, TOY_AS_FUNCTION_BYTECODE_LENGTH(original));
|
||||
memcpy(buffer, TOY_AS_FUNCTION(original).inner.bytecode, TOY_AS_FUNCTION_BYTECODE_LENGTH(original));
|
||||
|
||||
Toy_Literal literal = TOY_TO_FUNCTION_LITERAL(buffer, TOY_AS_FUNCTION(original).length);
|
||||
Toy_Literal literal = TOY_TO_FUNCTION_LITERAL(buffer, TOY_AS_FUNCTION_BYTECODE_LENGTH(original));
|
||||
TOY_AS_FUNCTION(literal).scope = Toy_copyScope(TOY_AS_FUNCTION(original).scope);
|
||||
|
||||
return literal;
|
||||
}
|
||||
|
||||
case TOY_LITERAL_IDENTIFIER: {
|
||||
return TOY_TO_IDENTIFIER_LITERAL(Toy_copyRefString(TOY_AS_IDENTIFIER(original)));
|
||||
//NOTE: could optimise this by copying the hash manually, but it's a very small increase in performance
|
||||
return TOY_TO_IDENTIFIER_LITERAL(Toy_copyRefString(TOY_AS_IDENTIFIER(original)));
|
||||
}
|
||||
|
||||
case TOY_LITERAL_TYPE: {
|
||||
@@ -228,7 +230,7 @@ Toy_Literal Toy_copyLiteral(Toy_Literal original) {
|
||||
return original;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -239,10 +241,10 @@ bool Toy_literalsAreEqual(Toy_Literal lhs, Toy_Literal rhs) {
|
||||
// ints and floats are compatible
|
||||
if ((TOY_IS_INTEGER(lhs) || TOY_IS_FLOAT(lhs)) && (TOY_IS_INTEGER(rhs) || TOY_IS_FLOAT(rhs))) {
|
||||
if (TOY_IS_INTEGER(lhs)) {
|
||||
return TOY_AS_INTEGER(lhs) + TOY_AS_FLOAT(rhs);
|
||||
return TOY_AS_INTEGER(lhs) == TOY_AS_FLOAT(rhs);
|
||||
}
|
||||
else {
|
||||
return TOY_AS_FLOAT(lhs) + TOY_AS_INTEGER(rhs);
|
||||
return TOY_AS_FLOAT(lhs) == TOY_AS_INTEGER(rhs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,20 +406,20 @@ int Toy_hashLiteral(Toy_Literal lit) {
|
||||
case TOY_LITERAL_FUNCTION:
|
||||
case TOY_LITERAL_FUNCTION_NATIVE:
|
||||
case TOY_LITERAL_FUNCTION_HOOK:
|
||||
return 0; //can't hash these
|
||||
return -1; //can't hash these
|
||||
|
||||
case TOY_LITERAL_IDENTIFIER:
|
||||
return TOY_HASH_I(lit); //pre-computed
|
||||
|
||||
case TOY_LITERAL_TYPE:
|
||||
return TOY_AS_TYPE(lit).typeOf; //nothing else I can do
|
||||
return -1; //not much i can really do
|
||||
|
||||
case TOY_LITERAL_OPAQUE:
|
||||
case TOY_LITERAL_ANY:
|
||||
return -1;
|
||||
|
||||
default:
|
||||
//should never bee seen
|
||||
//should never be seen
|
||||
fprintf(stderr, TOY_CC_ERROR "[internal] Unrecognized literal type in hash: %d\n" TOY_CC_RESET, lit.type);
|
||||
return 0;
|
||||
}
|
||||
@@ -453,7 +455,7 @@ void Toy_printLiteral(Toy_Literal literal) {
|
||||
Toy_printLiteralCustom(literal, stdoutWrapper);
|
||||
}
|
||||
|
||||
void Toy_printLiteralCustom(Toy_Literal literal, void (printFn)(const char*)) {
|
||||
void Toy_printLiteralCustom(Toy_Literal literal, Toy_PrintFn printFn) {
|
||||
switch(literal.type) {
|
||||
case TOY_LITERAL_NULL:
|
||||
printFn("null");
|
||||
@@ -487,10 +489,10 @@ void Toy_printLiteralCustom(Toy_Literal literal, void (printFn)(const char*)) {
|
||||
case TOY_LITERAL_STRING: {
|
||||
char buffer[TOY_MAX_STRING_LENGTH];
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
@@ -596,7 +598,7 @@ void Toy_printLiteralCustom(Toy_Literal literal, void (printFn)(const char*)) {
|
||||
|
||||
case TOY_LITERAL_IDENTIFIER: {
|
||||
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);
|
||||
}
|
||||
break;
|
||||
|
||||
+53
-44
@@ -8,10 +8,11 @@
|
||||
struct Toy_Literal;
|
||||
struct Toy_Interpreter;
|
||||
struct Toy_LiteralArray;
|
||||
struct Toy_LiteralDictionary;
|
||||
struct Toy_Scope;
|
||||
typedef int (*Toy_NativeFn)(struct Toy_Interpreter* interpreter, struct Toy_LiteralArray* arguments);
|
||||
typedef int (*Toy_HookFn)(struct Toy_Interpreter* interpreter, struct Toy_Literal identifier, struct Toy_Literal alias);
|
||||
|
||||
#include <string.h>
|
||||
typedef void (*Toy_PrintFn)(const char*);
|
||||
|
||||
typedef enum {
|
||||
TOY_LITERAL_NULL,
|
||||
@@ -39,45 +40,50 @@ typedef enum {
|
||||
} Toy_LiteralType;
|
||||
|
||||
typedef struct Toy_Literal {
|
||||
Toy_LiteralType type;
|
||||
union {
|
||||
bool boolean;
|
||||
int integer;
|
||||
float number;
|
||||
bool boolean; //1
|
||||
int integer; //4
|
||||
float number;//4
|
||||
|
||||
struct {
|
||||
Toy_RefString* ptr;
|
||||
Toy_RefString* ptr; //8
|
||||
//string hash?
|
||||
} string;
|
||||
} string; //8
|
||||
|
||||
void* array;
|
||||
void* dictionary;
|
||||
struct Toy_LiteralArray* array; //8
|
||||
struct Toy_LiteralDictionary* dictionary; //8
|
||||
|
||||
struct {
|
||||
void* bytecode;
|
||||
Toy_NativeFn native; //already a pointer
|
||||
Toy_HookFn hook; //already a pointer
|
||||
void* scope;
|
||||
int length;
|
||||
} function;
|
||||
union {
|
||||
void* bytecode; //8
|
||||
Toy_NativeFn native; //8
|
||||
Toy_HookFn hook; //8
|
||||
} inner; //8
|
||||
struct Toy_Scope* scope; //8
|
||||
} function; //16
|
||||
|
||||
struct { //for variable names
|
||||
Toy_RefString* ptr;
|
||||
int hash;
|
||||
} identifier;
|
||||
Toy_RefString* ptr; //8
|
||||
int hash; //4
|
||||
} identifier; //16
|
||||
|
||||
struct {
|
||||
Toy_LiteralType typeOf;
|
||||
bool constant;
|
||||
void* subtypes; //for nested types caused by compounds
|
||||
int capacity;
|
||||
int count;
|
||||
} type;
|
||||
|
||||
struct Toy_Literal* subtypes; //8
|
||||
Toy_LiteralType typeOf; //4
|
||||
unsigned char capacity; //1
|
||||
unsigned char count; //1
|
||||
bool constant; //1
|
||||
} type; //16
|
||||
|
||||
struct {
|
||||
void* ptr;
|
||||
int tag;
|
||||
} opaque;
|
||||
} as;
|
||||
void* ptr; //8
|
||||
int tag; //4
|
||||
} opaque; //16
|
||||
} as; //16
|
||||
|
||||
Toy_LiteralType type; //4
|
||||
int bytecodeLength; //4 - shenanigans with byte alignment reduces the size of Toy_Literal
|
||||
} Toy_Literal;
|
||||
|
||||
#define TOY_IS_NULL(value) ((value).type == TOY_LITERAL_NULL)
|
||||
@@ -101,34 +107,36 @@ typedef struct Toy_Literal {
|
||||
#define TOY_AS_ARRAY(value) ((Toy_LiteralArray*)((value).as.array))
|
||||
#define TOY_AS_DICTIONARY(value) ((Toy_LiteralDictionary*)((value).as.dictionary))
|
||||
#define TOY_AS_FUNCTION(value) ((value).as.function)
|
||||
#define TOY_AS_FUNCTION_NATIVE(value) ((value).as.function.native)
|
||||
#define TOY_AS_FUNCTION_HOOK(value) ((value).as.function.hook)
|
||||
#define TOY_AS_FUNCTION_NATIVE(value) ((value).as.function.inner.native)
|
||||
#define TOY_AS_FUNCTION_HOOK(value) ((value).as.function.inner.hook)
|
||||
#define TOY_AS_IDENTIFIER(value) ((value).as.identifier.ptr)
|
||||
#define TOY_AS_TYPE(value) ((value).as.type)
|
||||
#define TOY_AS_OPAQUE(value) ((value).as.opaque.ptr)
|
||||
|
||||
#define TOY_TO_NULL_LITERAL ((Toy_Literal){TOY_LITERAL_NULL, { .integer = 0 }})
|
||||
#define TOY_TO_BOOLEAN_LITERAL(value) ((Toy_Literal){TOY_LITERAL_BOOLEAN, { .boolean = value }})
|
||||
#define TOY_TO_INTEGER_LITERAL(value) ((Toy_Literal){TOY_LITERAL_INTEGER, { .integer = value }})
|
||||
#define TOY_TO_FLOAT_LITERAL(value) ((Toy_Literal){TOY_LITERAL_FLOAT, { .number = value }})
|
||||
#define TOY_TO_NULL_LITERAL ((Toy_Literal){{ .integer = 0 }, TOY_LITERAL_NULL, 0})
|
||||
#define TOY_TO_BOOLEAN_LITERAL(value) ((Toy_Literal){{ .boolean = value }, TOY_LITERAL_BOOLEAN, 0})
|
||||
#define TOY_TO_INTEGER_LITERAL(value) ((Toy_Literal){{ .integer = value }, TOY_LITERAL_INTEGER, 0})
|
||||
#define TOY_TO_FLOAT_LITERAL(value) ((Toy_Literal){{ .number = value }, TOY_LITERAL_FLOAT, 0})
|
||||
#define TOY_TO_STRING_LITERAL(value) Toy_private_toStringLiteral(value)
|
||||
#define TOY_TO_ARRAY_LITERAL(value) ((Toy_Literal){TOY_LITERAL_ARRAY, { .array = value }})
|
||||
#define TOY_TO_DICTIONARY_LITERAL(value) ((Toy_Literal){TOY_LITERAL_DICTIONARY, { .dictionary = value }})
|
||||
#define TOY_TO_FUNCTION_LITERAL(value, l) ((Toy_Literal){TOY_LITERAL_FUNCTION, { .function.bytecode = value, .function.scope = NULL, .function.length = l }})
|
||||
#define TOY_TO_FUNCTION_NATIVE_LITERAL(value) ((Toy_Literal){TOY_LITERAL_FUNCTION_NATIVE, { .function.native = value, .function.scope = NULL, .function.length = 0 }})
|
||||
#define TOY_TO_FUNCTION_HOOK_LITERAL(value) ((Toy_Literal){TOY_LITERAL_FUNCTION_HOOK, { .function.hook = value, .function.scope = NULL, .function.length = 0 }})
|
||||
#define TOY_TO_ARRAY_LITERAL(value) ((Toy_Literal){{ .array = value }, TOY_LITERAL_ARRAY, 0})
|
||||
#define TOY_TO_DICTIONARY_LITERAL(value) ((Toy_Literal){{ .dictionary = value }, TOY_LITERAL_DICTIONARY, 0})
|
||||
#define TOY_TO_FUNCTION_LITERAL(value, l) ((Toy_Literal){{ .function = { .inner = { .bytecode = value }, .scope = NULL }}, TOY_LITERAL_FUNCTION, l})
|
||||
#define TOY_TO_FUNCTION_NATIVE_LITERAL(value) ((Toy_Literal){{ .function = { .inner = { .native = value }, .scope = NULL }}, TOY_LITERAL_FUNCTION_NATIVE, 0})
|
||||
#define TOY_TO_FUNCTION_HOOK_LITERAL(value) ((Toy_Literal){{ .function = { .inner = { .hook = value }, .scope = NULL }}, TOY_LITERAL_FUNCTION_HOOK, 0})
|
||||
#define TOY_TO_IDENTIFIER_LITERAL(value) Toy_private_toIdentifierLiteral(value)
|
||||
#define TOY_TO_TYPE_LITERAL(value, c) ((Toy_Literal){ TOY_LITERAL_TYPE, { .type.typeOf = value, .type.constant = c, .type.subtypes = NULL, .type.capacity = 0, .type.count = 0 }})
|
||||
#define TOY_TO_OPAQUE_LITERAL(value, t) ((Toy_Literal){ TOY_LITERAL_OPAQUE, { .opaque.ptr = value, .opaque.tag = t }})
|
||||
#define TOY_TO_TYPE_LITERAL(value, c) ((Toy_Literal){{ .type = { .typeOf = value, .constant = c, .subtypes = NULL, .capacity = 0, .count = 0 }}, TOY_LITERAL_TYPE, 0})
|
||||
#define TOY_TO_OPAQUE_LITERAL(value, t) ((Toy_Literal){{ .opaque = { .ptr = value, .tag = t }}, TOY_LITERAL_OPAQUE, 0})
|
||||
|
||||
//BUGFIX: For blank indexing
|
||||
#define TOY_IS_INDEX_BLANK(value) ((value).type == TOY_LITERAL_INDEX_BLANK)
|
||||
#define TOY_TO_INDEX_BLANK_LITERAL ((Toy_Literal){TOY_LITERAL_INDEX_BLANK, { .integer = 0 }})
|
||||
#define TOY_TO_INDEX_BLANK_LITERAL ((Toy_Literal){{ .integer = 0 }, TOY_LITERAL_INDEX_BLANK, 0})
|
||||
|
||||
TOY_API void Toy_freeLiteral(Toy_Literal literal);
|
||||
|
||||
#define TOY_IS_TRUTHY(x) Toy_private_isTruthy(x)
|
||||
|
||||
#define TOY_AS_FUNCTION_BYTECODE_LENGTH(lit) ((lit).bytecodeLength)
|
||||
|
||||
#define TOY_MAX_STRING_LENGTH 4096
|
||||
#define TOY_HASH_I(lit) ((lit).as.identifier.hash)
|
||||
#define TOY_TYPE_PUSH_SUBTYPE(lit, subtype) Toy_private_typePushSubtype(lit, subtype)
|
||||
@@ -145,5 +153,6 @@ TOY_API Toy_Literal Toy_copyLiteral(Toy_Literal original);
|
||||
TOY_API bool Toy_literalsAreEqual(Toy_Literal lhs, Toy_Literal rhs);
|
||||
TOY_API int Toy_hashLiteral(Toy_Literal lit);
|
||||
|
||||
//not thread-safe
|
||||
TOY_API void Toy_printLiteral(Toy_Literal literal);
|
||||
TOY_API void Toy_printLiteralCustom(Toy_Literal literal, void (printFn)(const char*));
|
||||
TOY_API void Toy_printLiteralCustom(Toy_Literal literal, Toy_PrintFn);
|
||||
|
||||
@@ -18,8 +18,10 @@ void Toy_freeLiteralArray(Toy_LiteralArray* array) {
|
||||
Toy_freeLiteral(array->literals[i]);
|
||||
}
|
||||
|
||||
TOY_FREE_ARRAY(Toy_Literal, array->literals, array->capacity);
|
||||
Toy_initLiteralArray(array);
|
||||
if (array->capacity > 0) {
|
||||
TOY_FREE_ARRAY(Toy_Literal, array->literals, array->capacity);
|
||||
Toy_initLiteralArray(array);
|
||||
}
|
||||
}
|
||||
|
||||
int Toy_pushLiteralArray(Toy_LiteralArray* array, Toy_Literal literal) {
|
||||
|
||||
@@ -18,3 +18,5 @@ TOY_API bool Toy_setLiteralArray(Toy_LiteralArray* array, Toy_Literal index, Toy
|
||||
TOY_API Toy_Literal Toy_getLiteralArray(Toy_LiteralArray* array, Toy_Literal index);
|
||||
|
||||
int Toy_findLiteralIndex(Toy_LiteralArray* array, Toy_Literal literal);
|
||||
|
||||
//TODO: add a function to get the capacity & count
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
//util functions
|
||||
static void setEntryValues(Toy_private_entry* entry, Toy_Literal key, Toy_Literal value) {
|
||||
static void setEntryValues(Toy_private_dictionary_entry* entry, Toy_Literal key, Toy_Literal value) {
|
||||
//much simpler now
|
||||
Toy_freeLiteral(entry->key);
|
||||
entry->key = Toy_copyLiteral(key);
|
||||
@@ -16,17 +16,23 @@ static void setEntryValues(Toy_private_entry* entry, Toy_Literal key, Toy_Litera
|
||||
entry->value = Toy_copyLiteral(value);
|
||||
}
|
||||
|
||||
static Toy_private_entry* getEntryArray(Toy_private_entry* array, int capacity, Toy_Literal key, unsigned int hash, bool mustExist) {
|
||||
static Toy_private_dictionary_entry* getEntryArray(Toy_private_dictionary_entry* array, int capacity, Toy_Literal key, unsigned int hash, bool mustExist) {
|
||||
if (!capacity) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//find "key", starting at index
|
||||
unsigned int index = hash % capacity;
|
||||
unsigned int start = index;
|
||||
int index = hash % capacity;
|
||||
int start = index;
|
||||
|
||||
//increment once, so it can't equal start
|
||||
index = (index + 1) % capacity;
|
||||
if (++index >= capacity) {
|
||||
index = 0;
|
||||
}
|
||||
|
||||
//literal probing and collision checking
|
||||
while (index != start) { //WARNING: this is the only function allowed to retrieve an entry from the array
|
||||
Toy_private_entry* entry = &array[index];
|
||||
Toy_private_dictionary_entry* entry = &array[index];
|
||||
|
||||
if (TOY_IS_NULL(entry->key)) { //if key is empty, it's either empty or tombstone
|
||||
if (TOY_IS_NULL(entry->value) && !mustExist) {
|
||||
@@ -40,15 +46,18 @@ static Toy_private_entry* getEntryArray(Toy_private_entry* array, int capacity,
|
||||
}
|
||||
}
|
||||
|
||||
index = (index + 1) % capacity;
|
||||
if (++index >= capacity) {
|
||||
index = 0;
|
||||
}
|
||||
//index = (index + 1) % capacity;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void adjustEntryCapacity(Toy_private_entry** dictionaryHandle, int oldCapacity, int capacity) {
|
||||
static void adjustEntryCapacity(Toy_private_dictionary_entry** dictionaryHandle, int oldCapacity, int capacity) {
|
||||
//new entry space
|
||||
Toy_private_entry* newEntries = TOY_ALLOCATE(Toy_private_entry, capacity);
|
||||
Toy_private_dictionary_entry* newEntries = TOY_ALLOCATE(Toy_private_dictionary_entry, capacity);
|
||||
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
newEntries[i].key = TOY_TO_NULL_LITERAL;
|
||||
@@ -62,19 +71,21 @@ static void adjustEntryCapacity(Toy_private_entry** dictionaryHandle, int oldCap
|
||||
}
|
||||
|
||||
//place the key and value in the new array (reusing string memory)
|
||||
Toy_private_entry* entry = getEntryArray(newEntries, capacity, TOY_TO_NULL_LITERAL, Toy_hashLiteral((*dictionaryHandle)[i].key), false);
|
||||
Toy_private_dictionary_entry* entry = getEntryArray(newEntries, capacity, TOY_TO_NULL_LITERAL, Toy_hashLiteral((*dictionaryHandle)[i].key), false);
|
||||
|
||||
entry->key = (*dictionaryHandle)[i].key;
|
||||
entry->value = (*dictionaryHandle)[i].value;
|
||||
}
|
||||
|
||||
//clear the old array
|
||||
TOY_FREE_ARRAY(Toy_private_entry, *dictionaryHandle, oldCapacity);
|
||||
if (oldCapacity > 0) {
|
||||
TOY_FREE_ARRAY(Toy_private_dictionary_entry, *dictionaryHandle, oldCapacity);
|
||||
}
|
||||
|
||||
*dictionaryHandle = newEntries;
|
||||
}
|
||||
|
||||
static bool setEntryArray(Toy_private_entry** dictionaryHandle, int* capacityPtr, int contains, Toy_Literal key, Toy_Literal value, int hash) {
|
||||
static bool setEntryArray(Toy_private_dictionary_entry** dictionaryHandle, int* capacityPtr, int contains, Toy_Literal key, Toy_Literal value, int hash) {
|
||||
//expand array if needed
|
||||
if (contains + 1 > *capacityPtr * TOY_DICTIONARY_MAX_LOAD) {
|
||||
int oldCapacity = *capacityPtr;
|
||||
@@ -82,7 +93,7 @@ static bool setEntryArray(Toy_private_entry** dictionaryHandle, int* capacityPtr
|
||||
adjustEntryCapacity(dictionaryHandle, oldCapacity, *capacityPtr); //custom rather than automatic reallocation
|
||||
}
|
||||
|
||||
Toy_private_entry* entry = getEntryArray(*dictionaryHandle, *capacityPtr, key, hash, false);
|
||||
Toy_private_dictionary_entry* entry = getEntryArray(*dictionaryHandle, *capacityPtr, key, hash, false);
|
||||
|
||||
//true = contains increase
|
||||
if (TOY_IS_NULL(entry->key)) {
|
||||
@@ -97,14 +108,14 @@ static bool setEntryArray(Toy_private_entry** dictionaryHandle, int* capacityPtr
|
||||
return false;
|
||||
}
|
||||
|
||||
static void freeEntry(Toy_private_entry* entry) {
|
||||
static void freeEntry(Toy_private_dictionary_entry* entry) {
|
||||
Toy_freeLiteral(entry->key);
|
||||
Toy_freeLiteral(entry->value);
|
||||
entry->key = TOY_TO_NULL_LITERAL;
|
||||
entry->value = TOY_TO_NULL_LITERAL;
|
||||
}
|
||||
|
||||
static void freeEntryArray(Toy_private_entry* array, int capacity) {
|
||||
static void freeEntryArray(Toy_private_dictionary_entry* array, int capacity) {
|
||||
if (array == NULL) {
|
||||
return;
|
||||
}
|
||||
@@ -115,23 +126,25 @@ 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
|
||||
void Toy_initLiteralDictionary(Toy_LiteralDictionary* dictionary) {
|
||||
//HACK: because modulo by 0 is undefined, set the capacity to a non-zero value (and allocate the arrays)
|
||||
dictionary->entries = NULL;
|
||||
dictionary->capacity = TOY_GROW_CAPACITY(0);
|
||||
dictionary->capacity = 0;
|
||||
dictionary->contains = 0;
|
||||
dictionary->count = 0;
|
||||
adjustEntryCapacity(&dictionary->entries, 0, dictionary->capacity);
|
||||
dictionary->capacity = 0;
|
||||
}
|
||||
|
||||
void Toy_freeLiteralDictionary(Toy_LiteralDictionary* dictionary) {
|
||||
freeEntryArray(dictionary->entries, dictionary->capacity);
|
||||
dictionary->capacity = 0;
|
||||
dictionary->contains = 0;
|
||||
if (dictionary->capacity > 0) {
|
||||
freeEntryArray(dictionary->entries, dictionary->capacity);
|
||||
dictionary->capacity = 0;
|
||||
dictionary->contains = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Toy_setLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key, Toy_Literal value) {
|
||||
@@ -141,7 +154,7 @@ void Toy_setLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key
|
||||
}
|
||||
|
||||
//BUGFIX: Can't hash a function
|
||||
if (TOY_IS_FUNCTION(key) || TOY_IS_FUNCTION_NATIVE(key)) {
|
||||
if (TOY_IS_FUNCTION(key) || TOY_IS_FUNCTION_NATIVE(key) || TOY_IS_FUNCTION_HOOK(key)) {
|
||||
fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have function keys (set)\n" TOY_CC_RESET);
|
||||
return;
|
||||
}
|
||||
@@ -166,7 +179,7 @@ Toy_Literal Toy_getLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Lite
|
||||
}
|
||||
|
||||
//BUGFIX: Can't hash a function
|
||||
if (TOY_IS_FUNCTION(key) || TOY_IS_FUNCTION_NATIVE(key)) {
|
||||
if (TOY_IS_FUNCTION(key) || TOY_IS_FUNCTION_NATIVE(key) || TOY_IS_FUNCTION_HOOK(key)) {
|
||||
fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have function keys (get)\n" TOY_CC_RESET);
|
||||
return TOY_TO_NULL_LITERAL;
|
||||
}
|
||||
@@ -176,7 +189,7 @@ Toy_Literal Toy_getLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Lite
|
||||
return TOY_TO_NULL_LITERAL;
|
||||
}
|
||||
|
||||
Toy_private_entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, Toy_hashLiteral(key), true);
|
||||
Toy_private_dictionary_entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, Toy_hashLiteral(key), true);
|
||||
|
||||
if (entry != NULL) {
|
||||
return Toy_copyLiteral(entry->value);
|
||||
@@ -193,7 +206,7 @@ void Toy_removeLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal
|
||||
}
|
||||
|
||||
//BUGFIX: Can't hash a function
|
||||
if (TOY_IS_FUNCTION(key) || TOY_IS_FUNCTION_NATIVE(key)) {
|
||||
if (TOY_IS_FUNCTION(key) || TOY_IS_FUNCTION_NATIVE(key) || TOY_IS_FUNCTION_HOOK(key)) {
|
||||
fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have function keys (remove)\n" TOY_CC_RESET);
|
||||
return;
|
||||
}
|
||||
@@ -203,7 +216,7 @@ void Toy_removeLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal
|
||||
return;
|
||||
}
|
||||
|
||||
Toy_private_entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, Toy_hashLiteral(key), true);
|
||||
Toy_private_dictionary_entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, Toy_hashLiteral(key), true);
|
||||
|
||||
if (entry != NULL) {
|
||||
freeEntry(entry);
|
||||
@@ -214,6 +227,6 @@ void Toy_removeLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal
|
||||
|
||||
bool Toy_existsLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key) {
|
||||
//null & not tombstoned
|
||||
Toy_private_entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, Toy_hashLiteral(key), false);
|
||||
return !(TOY_IS_NULL(entry->key) && TOY_IS_NULL(entry->value));
|
||||
Toy_private_dictionary_entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, Toy_hashLiteral(key), false);
|
||||
return entry != NULL && !(TOY_IS_NULL(entry->key) && TOY_IS_NULL(entry->value));
|
||||
}
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
//TODO: benchmark this
|
||||
#define TOY_DICTIONARY_MAX_LOAD 0.75
|
||||
|
||||
typedef struct Toy_private_entry {
|
||||
typedef struct Toy_private_dictionary_entry {
|
||||
Toy_Literal key;
|
||||
Toy_Literal value;
|
||||
} Toy_private_entry;
|
||||
} Toy_private_dictionary_entry;
|
||||
|
||||
typedef struct Toy_LiteralDictionary {
|
||||
Toy_private_entry* entries;
|
||||
Toy_private_dictionary_entry* entries;
|
||||
int capacity;
|
||||
int count;
|
||||
int contains; //count + tombstones, for internal use
|
||||
|
||||
+6
-7
@@ -8,22 +8,21 @@
|
||||
|
||||
//default allocator
|
||||
void* Toy_private_defaultMemoryAllocator(void* pointer, size_t oldSize, size_t newSize) {
|
||||
if (newSize == 0 && oldSize == 0) {
|
||||
//causes issues, so just skip out with a NO-OP
|
||||
return NULL;
|
||||
}
|
||||
//causes issues, so just skip out with a NO-OP (DISABLED for performance reasons)
|
||||
// if (newSize == 0 && oldSize == 0) {
|
||||
// return NULL;
|
||||
// }
|
||||
|
||||
if (newSize == 0) {
|
||||
free(pointer);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* mem = realloc(pointer, newSize);
|
||||
|
||||
if (mem == NULL) {
|
||||
fprintf(stderr, TOY_CC_ERROR "[internal] Memory allocation error (requested %d, replacing %d)\n" TOY_CC_RESET, (int)newSize, (int)oldSize);
|
||||
exit(-1);
|
||||
fprintf(stderr, TOY_CC_ERROR "[internal] Memory allocation error (requested %zu, replacing %zu)\n" TOY_CC_RESET, newSize, oldSize);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return mem;
|
||||
|
||||
+11
-8
@@ -2,16 +2,19 @@
|
||||
|
||||
#include "toy_common.h"
|
||||
|
||||
#define TOY_ALLOCATE(type, count) ((type*)Toy_reallocate(NULL, 0, sizeof(type) * (count)))
|
||||
#define TOY_FREE(type, pointer) Toy_reallocate(pointer, sizeof(type), 0)
|
||||
#define TOY_GROW_CAPACITY(capacity) ((capacity) < 8 ? 8 : (capacity) * 2)
|
||||
#define TOY_GROW_CAPACITY_FAST(capacity) ((capacity) < 32 ? 32 : (capacity) * 2)
|
||||
#define TOY_GROW_ARRAY(type, pointer, oldCount, count) (type*)Toy_reallocate((type*)pointer, sizeof(type) * (oldCount), sizeof(type) * (count))
|
||||
#define TOY_SHRINK_ARRAY(type, pointer, oldCount, count) (type*)Toy_reallocate((type*)pointer, sizeof(type) * (oldCount), sizeof(type) * (count))
|
||||
#define TOY_FREE_ARRAY(type, pointer, oldCount) Toy_reallocate((type*)pointer, sizeof(type) * (oldCount), 0)
|
||||
#define TOY_GROW_CAPACITY(capacity) ((capacity) < 8 ? 8 : (capacity) * 2)
|
||||
#define TOY_GROW_CAPACITY_FAST(capacity) ((capacity) < 32 ? 32 : (capacity) * 2)
|
||||
|
||||
#define TOY_ALLOCATE(type, count) ((type*)Toy_reallocate(NULL, 0, sizeof(type) * (count)))
|
||||
|
||||
#define TOY_FREE(type, pointer) Toy_reallocate(pointer, sizeof(type), 0)
|
||||
#define TOY_FREE_ARRAY(type, pointer, oldCount) Toy_reallocate((type*)pointer, sizeof(type) * (oldCount), 0)
|
||||
|
||||
#define TOY_GROW_ARRAY(type, pointer, oldCount, count) (type*)Toy_reallocate((type*)pointer, sizeof(type) * (oldCount), sizeof(type) * (count))
|
||||
#define TOY_SHRINK_ARRAY(type, pointer, oldCount, count) (type*)Toy_reallocate((type*)pointer, sizeof(type) * (oldCount), sizeof(type) * (count))
|
||||
|
||||
//implementation details
|
||||
void* Toy_reallocate(void* pointer, size_t oldSize, size_t newSize);
|
||||
TOY_API void* Toy_reallocate(void* pointer, size_t oldSize, size_t newSize);
|
||||
|
||||
//assign the memory allocator
|
||||
typedef void* (*Toy_MemoryAllocatorFn)(void* pointer, size_t oldSize, size_t newSize);
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
typedef enum Toy_Opcode {
|
||||
TOY_OP_EOF,
|
||||
|
||||
//do nothing
|
||||
TOY_OP_PASS,
|
||||
|
||||
//basic statements
|
||||
TOY_OP_ASSERT,
|
||||
TOY_OP_PRINT,
|
||||
|
||||
+83
-20
@@ -32,7 +32,7 @@ static void error(Toy_Parser* parser, Toy_Token token, const char* message) {
|
||||
|
||||
static void advance(Toy_Parser* parser) {
|
||||
parser->previous = parser->current;
|
||||
parser->current = Toy_scanLexer(parser->lexer);
|
||||
parser->current = Toy_private_scanLexer(parser->lexer);
|
||||
|
||||
if (parser->current.type == TOY_TOKEN_ERROR) {
|
||||
error(parser, parser->current, "Toy_Lexer error");
|
||||
@@ -140,7 +140,7 @@ static Toy_Opcode asType(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
|
||||
|
||||
static Toy_Opcode typeOf(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
|
||||
Toy_ASTNode* rhs = NULL;
|
||||
parsePrecedence(parser, &rhs, PREC_TERNARY);
|
||||
parsePrecedence(parser, &rhs, PREC_CALL);
|
||||
Toy_emitASTNodeUnary(nodeHandle, TOY_OP_TYPE_OF, rhs);
|
||||
return TOY_OP_EOF;
|
||||
}
|
||||
@@ -341,27 +341,27 @@ static Toy_Opcode binary(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
|
||||
switch(parser->previous.type) {
|
||||
//arithmetic
|
||||
case TOY_TOKEN_PLUS: {
|
||||
parsePrecedence(parser, nodeHandle, PREC_TERM);
|
||||
parsePrecedence(parser, nodeHandle, PREC_TERM + 1);
|
||||
return TOY_OP_ADDITION;
|
||||
}
|
||||
|
||||
case TOY_TOKEN_MINUS: {
|
||||
parsePrecedence(parser, nodeHandle, PREC_TERM);
|
||||
parsePrecedence(parser, nodeHandle, PREC_TERM + 1);
|
||||
return TOY_OP_SUBTRACTION;
|
||||
}
|
||||
|
||||
case TOY_TOKEN_MULTIPLY: {
|
||||
parsePrecedence(parser, nodeHandle, PREC_FACTOR);
|
||||
parsePrecedence(parser, nodeHandle, PREC_FACTOR + 1);
|
||||
return TOY_OP_MULTIPLICATION;
|
||||
}
|
||||
|
||||
case TOY_TOKEN_DIVIDE: {
|
||||
parsePrecedence(parser, nodeHandle, PREC_FACTOR);
|
||||
parsePrecedence(parser, nodeHandle, PREC_FACTOR + 1);
|
||||
return TOY_OP_DIVISION;
|
||||
}
|
||||
|
||||
case TOY_TOKEN_MODULO: {
|
||||
parsePrecedence(parser, nodeHandle, PREC_FACTOR);
|
||||
parsePrecedence(parser, nodeHandle, PREC_FACTOR + 1);
|
||||
return TOY_OP_MODULO;
|
||||
}
|
||||
|
||||
@@ -428,12 +428,12 @@ static Toy_Opcode binary(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
|
||||
}
|
||||
|
||||
case TOY_TOKEN_AND: {
|
||||
parsePrecedence(parser, nodeHandle, PREC_COMPARISON);
|
||||
parsePrecedence(parser, nodeHandle, PREC_AND);
|
||||
return TOY_OP_AND;
|
||||
}
|
||||
|
||||
case TOY_TOKEN_OR: {
|
||||
parsePrecedence(parser, nodeHandle, PREC_COMPARISON);
|
||||
parsePrecedence(parser, nodeHandle, PREC_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) {
|
||||
//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
|
||||
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;
|
||||
}
|
||||
|
||||
static char* removeChar(char* lexeme, int length, char c) {
|
||||
static char* removeChar(const char* lexeme, int length, char c) {
|
||||
int resPos = 0;
|
||||
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: {
|
||||
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);
|
||||
TOY_FREE_ARRAY(char, lexeme, parser->previous.length + 1);
|
||||
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: {
|
||||
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);
|
||||
TOY_FREE_ARRAY(char, lexeme, parser->previous.length + 1);
|
||||
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;
|
||||
identifier(parser, &tmpNode);
|
||||
|
||||
if (!tmpNode) {
|
||||
return TOY_OP_EOF;
|
||||
}
|
||||
|
||||
Toy_emitASTNodePrefixIncrement(nodeHandle, tmpNode->atomic.literal);
|
||||
|
||||
Toy_freeASTNode(tmpNode);
|
||||
@@ -689,6 +693,10 @@ static Toy_Opcode incrementInfix(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
|
||||
|
||||
advance(parser);
|
||||
|
||||
if (!tmpNode) {
|
||||
return TOY_OP_EOF;
|
||||
}
|
||||
|
||||
Toy_emitASTNodePostfixIncrement(nodeHandle, tmpNode->atomic.literal);
|
||||
|
||||
Toy_freeASTNode(tmpNode);
|
||||
@@ -700,7 +708,11 @@ static Toy_Opcode decrementPrefix(Toy_Parser* parser, Toy_ASTNode** nodeHandle)
|
||||
advance(parser);
|
||||
|
||||
Toy_ASTNode* tmpNode = NULL;
|
||||
identifier(parser, &tmpNode); //weird
|
||||
identifier(parser, &tmpNode);
|
||||
|
||||
if (!tmpNode) {
|
||||
return TOY_OP_EOF;
|
||||
}
|
||||
|
||||
Toy_emitASTNodePrefixDecrement(nodeHandle, tmpNode->atomic.literal);
|
||||
|
||||
@@ -715,6 +727,10 @@ static Toy_Opcode decrementInfix(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
|
||||
|
||||
advance(parser);
|
||||
|
||||
if (!tmpNode) {
|
||||
return TOY_OP_EOF;
|
||||
}
|
||||
|
||||
Toy_emitASTNodePostfixDecrement(nodeHandle, tmpNode->atomic.literal);
|
||||
|
||||
Toy_freeASTNode(tmpNode);
|
||||
@@ -794,13 +810,20 @@ static Toy_Opcode indexAccess(Toy_Parser* parser, Toy_ASTNode** nodeHandle) { //
|
||||
//eat the first
|
||||
if (!match(parser, TOY_TOKEN_COLON)) {
|
||||
Toy_freeASTNode(first);
|
||||
first = NULL;
|
||||
parsePrecedence(parser, &first, PREC_TERNARY);
|
||||
match(parser, TOY_TOKEN_COLON);
|
||||
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) {
|
||||
Toy_freeASTNode(second);
|
||||
second = NULL;
|
||||
@@ -816,10 +839,18 @@ static Toy_Opcode indexAccess(Toy_Parser* parser, Toy_ASTNode** nodeHandle) { //
|
||||
//eat the second
|
||||
if (!match(parser, TOY_TOKEN_COLON)) {
|
||||
Toy_freeASTNode(second);
|
||||
second = NULL;
|
||||
parsePrecedence(parser, &second, PREC_TERNARY);
|
||||
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)) {
|
||||
Toy_freeASTNode(third);
|
||||
third = NULL;
|
||||
@@ -829,7 +860,16 @@ static Toy_Opcode indexAccess(Toy_Parser* parser, Toy_ASTNode** nodeHandle) { //
|
||||
|
||||
//eat the third
|
||||
Toy_freeASTNode(third);
|
||||
third = NULL;
|
||||
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);
|
||||
|
||||
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
|
||||
consume(parser, TOY_TOKEN_PAREN_LEFT, "Expected '(' at beginning of for clause");
|
||||
|
||||
declaration(parser, &preClause); //allow defining variables in the pre-clause
|
||||
//check the pre-clause
|
||||
if (parser->current.type != TOY_TOKEN_SEMICOLON) {
|
||||
declaration(parser, &preClause); //allow defining variables in the pre-clause
|
||||
}
|
||||
else {
|
||||
consume(parser, TOY_TOKEN_SEMICOLON, "Expected ';' after empty declaration of for clause");
|
||||
Toy_emitASTNodePass(&preClause);
|
||||
}
|
||||
|
||||
parsePrecedence(parser, &condition, PREC_TERNARY);
|
||||
consume(parser, TOY_TOKEN_SEMICOLON, "Expected ';' after condition of for clause");
|
||||
//check the condition clause
|
||||
if (parser->current.type != TOY_TOKEN_SEMICOLON) {
|
||||
parsePrecedence(parser, &condition, PREC_TERNARY);
|
||||
consume(parser, TOY_TOKEN_SEMICOLON, "Expected ';' after condition of for clause");
|
||||
}
|
||||
else {
|
||||
consume(parser, TOY_TOKEN_SEMICOLON, "Expected ';' after empty condition of for clause");
|
||||
//empty clause defaults to forever
|
||||
Toy_Literal f = TOY_TO_BOOLEAN_LITERAL(true);
|
||||
Toy_emitASTNodeLiteral(&condition, f);
|
||||
}
|
||||
|
||||
parsePrecedence(parser, &postClause, PREC_ASSIGNMENT);
|
||||
consume(parser, TOY_TOKEN_PAREN_RIGHT, "Expected ')' at end of for clause");
|
||||
//check the postfix clause
|
||||
if (parser->current.type != TOY_TOKEN_PAREN_RIGHT) {
|
||||
parsePrecedence(parser, &postClause, PREC_ASSIGNMENT);
|
||||
consume(parser, TOY_TOKEN_PAREN_RIGHT, "Expected ')' at end of for clause");
|
||||
}
|
||||
else {
|
||||
consume(parser, TOY_TOKEN_PAREN_RIGHT, "Expected ')' after empty increment of for clause");
|
||||
Toy_emitASTNodePass(&postClause);
|
||||
}
|
||||
|
||||
//read the path
|
||||
declaration(parser, &thenPath);
|
||||
|
||||
+18
-24
@@ -1,15 +1,5 @@
|
||||
#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
|
||||
extern void* Toy_private_defaultMemoryAllocator(void* pointer, size_t oldSize, size_t newSize);
|
||||
static Toy_RefStringAllocatorFn allocate = Toy_private_defaultMemoryAllocator;
|
||||
@@ -19,18 +9,22 @@ void Toy_setRefStringAllocatorFn(Toy_RefStringAllocatorFn allocator) {
|
||||
}
|
||||
|
||||
//API
|
||||
Toy_RefString* Toy_createRefString(char* cstring) {
|
||||
int length = strlen(cstring);
|
||||
Toy_RefString* Toy_createRefString(const char* cstring) {
|
||||
size_t length = strlen(cstring);
|
||||
|
||||
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)
|
||||
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
|
||||
refString->refcount = 1;
|
||||
refString->refCount = 1;
|
||||
refString->length = 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) {
|
||||
//decrement, then check
|
||||
refString->refcount--;
|
||||
if (refString->refcount <= 0) {
|
||||
allocate(refString, sizeof(int) * 2 + sizeof(char) * refString->length + 1, 0);
|
||||
refString->refCount--;
|
||||
if (refString->refCount <= 0) {
|
||||
allocate(refString, sizeof(size_t) + sizeof(int) + sizeof(char) * (refString->length + 1), 0);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Toy_RefString* Toy_copyRefString(Toy_RefString* refString) {
|
||||
//Cheaty McCheater Face
|
||||
refString->refcount++;
|
||||
refString->refCount++;
|
||||
return 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);
|
||||
}
|
||||
|
||||
char* Toy_toCString(Toy_RefString* refString) {
|
||||
const char* Toy_toCString(Toy_RefString* refString) {
|
||||
return refString->data;
|
||||
}
|
||||
|
||||
@@ -87,7 +81,7 @@ bool Toy_equalsRefString(Toy_RefString* lhs, Toy_RefString* rhs) {
|
||||
|
||||
bool Toy_equalsRefStringCString(Toy_RefString* lhs, char* cstring) {
|
||||
//get the rhs length
|
||||
int length = strlen(cstring);
|
||||
size_t length = strlen(cstring);
|
||||
|
||||
//different length
|
||||
if (lhs->length != length) {
|
||||
|
||||
+20
-16
@@ -1,27 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include "toy_common.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
//memory allocation hook
|
||||
typedef void* (*Toy_RefStringAllocatorFn)(void* pointer, size_t oldSize, size_t newSize);
|
||||
void Toy_setRefStringAllocatorFn(Toy_RefStringAllocatorFn);
|
||||
TOY_API void Toy_setRefStringAllocatorFn(Toy_RefStringAllocatorFn);
|
||||
|
||||
//the RefString structure
|
||||
typedef struct Toy_RefString {
|
||||
int refcount;
|
||||
int length;
|
||||
char data[1];
|
||||
size_t length;
|
||||
int refCount;
|
||||
char data[];
|
||||
} Toy_RefString;
|
||||
|
||||
//API
|
||||
Toy_RefString* Toy_createRefString(char* cstring);
|
||||
Toy_RefString* Toy_createRefStringLength(char* cstring, int length);
|
||||
void Toy_deleteRefString(Toy_RefString* refString);
|
||||
int Toy_countRefString(Toy_RefString* refString);
|
||||
int Toy_lengthRefString(Toy_RefString* refString);
|
||||
Toy_RefString* Toy_copyRefString(Toy_RefString* refString);
|
||||
Toy_RefString* Toy_deepCopyRefString(Toy_RefString* refString);
|
||||
char* Toy_toCString(Toy_RefString* refString);
|
||||
bool Toy_equalsRefString(Toy_RefString* lhs, Toy_RefString* rhs);
|
||||
bool Toy_equalsRefStringCString(Toy_RefString* lhs, char* cstring);
|
||||
TOY_API Toy_RefString* Toy_createRefString(const char* cstring);
|
||||
TOY_API Toy_RefString* Toy_createRefStringLength(const char* cstring, size_t length);
|
||||
TOY_API void Toy_deleteRefString(Toy_RefString* refString);
|
||||
TOY_API int Toy_countRefString(Toy_RefString* refString);
|
||||
TOY_API size_t Toy_lengthRefString(Toy_RefString* refString);
|
||||
TOY_API Toy_RefString* Toy_copyRefString(Toy_RefString* refString);
|
||||
TOY_API Toy_RefString* Toy_deepCopyRefString(Toy_RefString* refString);
|
||||
TOY_API const char* Toy_toCString(Toy_RefString* refString);
|
||||
TOY_API bool Toy_equalsRefString(Toy_RefString* lhs, Toy_RefString* rhs);
|
||||
TOY_API bool Toy_equalsRefStringCString(Toy_RefString* lhs, char* cstring);
|
||||
|
||||
//TODO: merge refstring memory
|
||||
|
||||
|
||||
+64
-62
@@ -4,21 +4,19 @@
|
||||
|
||||
//run up the ancestor chain, freeing anything with 0 references left
|
||||
static void freeAncestorChain(Toy_Scope* scope) {
|
||||
scope->references--;
|
||||
while (scope != NULL) {
|
||||
Toy_Scope* next = scope->ancestor;
|
||||
|
||||
//free scope chain
|
||||
if (scope->ancestor != NULL) {
|
||||
freeAncestorChain(scope->ancestor);
|
||||
scope->references--;
|
||||
|
||||
if (scope->references <= 0) {
|
||||
Toy_freeLiteralDictionary(&scope->variables);
|
||||
Toy_freeLiteralDictionary(&scope->types);
|
||||
TOY_FREE(Toy_Scope, scope);
|
||||
}
|
||||
|
||||
scope = next;
|
||||
}
|
||||
|
||||
if (scope->references > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Toy_freeLiteralDictionary(&scope->variables);
|
||||
Toy_freeLiteralDictionary(&scope->types);
|
||||
|
||||
TOY_FREE(Toy_Scope, scope);
|
||||
}
|
||||
|
||||
//return false if invalid type
|
||||
@@ -126,7 +124,7 @@ static bool checkType(Toy_Literal typeLiteral, Toy_Literal original, Toy_Literal
|
||||
}
|
||||
|
||||
//find the internal child of original that matches this child of value
|
||||
Toy_private_entry* ptr = NULL;
|
||||
Toy_private_dictionary_entry* ptr = NULL;
|
||||
|
||||
for (int j = 0; j < TOY_AS_DICTIONARY(original)->capacity; j++) {
|
||||
if (Toy_literalsAreEqual(TOY_AS_DICTIONARY(original)->entries[j].key, TOY_AS_DICTIONARY(value)->entries[i].key)) {
|
||||
@@ -159,6 +157,10 @@ static bool checkType(Toy_Literal typeLiteral, Toy_Literal original, Toy_Literal
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_OPAQUE && !TOY_IS_OPAQUE(value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -185,7 +187,7 @@ Toy_Scope* Toy_popScope(Toy_Scope* scope) {
|
||||
|
||||
Toy_Scope* ret = scope->ancestor;
|
||||
|
||||
//BUGFIX: when freeing a scope, free the function's scopes manually
|
||||
//BUGFIX: when freeing a scope, free the functions' scopes manually - I *think* this is related to the closure hack-in
|
||||
for (int i = 0; i < scope->variables.capacity; i++) {
|
||||
//handle keys, just in case
|
||||
if (TOY_IS_FUNCTION(scope->variables.entries[i].key)) {
|
||||
@@ -205,6 +207,10 @@ Toy_Scope* Toy_popScope(Toy_Scope* scope) {
|
||||
}
|
||||
|
||||
Toy_Scope* Toy_copyScope(Toy_Scope* original) {
|
||||
if (original == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Toy_Scope* scope = TOY_ALLOCATE(Toy_Scope, 1);
|
||||
scope->ancestor = original->ancestor;
|
||||
Toy_initLiteralDictionary(&scope->variables);
|
||||
@@ -251,74 +257,70 @@ bool Toy_declareScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal typ
|
||||
}
|
||||
|
||||
bool Toy_isDelcaredScopeVariable(Toy_Scope* scope, Toy_Literal key) {
|
||||
if (scope == NULL) {
|
||||
return false;
|
||||
while (scope != NULL) {
|
||||
if (Toy_existsLiteralDictionary(&scope->variables, key)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
scope = scope->ancestor;
|
||||
}
|
||||
|
||||
//if it's not in this scope, keep searching up the chain
|
||||
if (!Toy_existsLiteralDictionary(&scope->variables, key)) {
|
||||
return Toy_isDelcaredScopeVariable(scope->ancestor, key);
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//return false if undefined, or can't be assigned
|
||||
bool Toy_setScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal value, bool constCheck) {
|
||||
//dead end
|
||||
if (scope == NULL) {
|
||||
return false;
|
||||
}
|
||||
while (scope != NULL) {
|
||||
//if it's not in this scope, keep searching up the chain
|
||||
if (!Toy_existsLiteralDictionary(&scope->variables, key)) {
|
||||
scope = scope->ancestor;
|
||||
continue;
|
||||
}
|
||||
|
||||
//if it's not in this scope, keep searching up the chain
|
||||
if (!Toy_existsLiteralDictionary(&scope->variables, key)) {
|
||||
return Toy_setScopeVariable(scope->ancestor, key, value, constCheck);
|
||||
}
|
||||
//type checking
|
||||
Toy_Literal typeLiteral = Toy_getLiteralDictionary(&scope->types, key);
|
||||
Toy_Literal original = Toy_getLiteralDictionary(&scope->variables, key);
|
||||
|
||||
//type checking
|
||||
Toy_Literal typeLiteral = Toy_getLiteralDictionary(&scope->types, key);
|
||||
Toy_Literal original = Toy_getLiteralDictionary(&scope->variables, key);
|
||||
if (!checkType(typeLiteral, original, value, constCheck)) {
|
||||
Toy_freeLiteral(typeLiteral);
|
||||
Toy_freeLiteral(original);
|
||||
return false;
|
||||
}
|
||||
|
||||
//actually assign
|
||||
Toy_setLiteralDictionary(&scope->variables, key, value); //key & value are copied here
|
||||
|
||||
if (!checkType(typeLiteral, original, value, constCheck)) {
|
||||
Toy_freeLiteral(typeLiteral);
|
||||
Toy_freeLiteral(original);
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//actually assign
|
||||
Toy_setLiteralDictionary(&scope->variables, key, value);
|
||||
|
||||
Toy_freeLiteral(typeLiteral);
|
||||
Toy_freeLiteral(original);
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Toy_getScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal* valueHandle) {
|
||||
//dead end
|
||||
if (scope == NULL) {
|
||||
return false;
|
||||
//optimized to reduce call stack
|
||||
while (scope != NULL) {
|
||||
if (Toy_existsLiteralDictionary(&scope->variables, key)) {
|
||||
*valueHandle = Toy_getLiteralDictionary(&scope->variables, key);
|
||||
return true;
|
||||
}
|
||||
|
||||
scope = scope->ancestor;
|
||||
}
|
||||
|
||||
//if it's not in this scope, keep searching up the chain
|
||||
if (!Toy_existsLiteralDictionary(&scope->variables, key)) {
|
||||
return Toy_getScopeVariable(scope->ancestor, key, valueHandle);
|
||||
}
|
||||
|
||||
*valueHandle = Toy_getLiteralDictionary(&scope->variables, key);
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
Toy_Literal Toy_getScopeType(Toy_Scope* scope, Toy_Literal key) {
|
||||
//dead end
|
||||
if (scope == NULL) {
|
||||
return TOY_TO_NULL_LITERAL;
|
||||
while (scope != NULL) {
|
||||
if (Toy_existsLiteralDictionary(&scope->types, key)) {
|
||||
return Toy_getLiteralDictionary(&scope->types, key);
|
||||
}
|
||||
|
||||
scope = scope->ancestor;
|
||||
}
|
||||
|
||||
//if it's not in this scope, keep searching up the chain
|
||||
if (!Toy_existsLiteralDictionary(&scope->types, key)) {
|
||||
return Toy_getScopeType(scope->ancestor, key);
|
||||
}
|
||||
|
||||
return Toy_getLiteralDictionary(&scope->types, key);
|
||||
return TOY_TO_NULL_LITERAL;
|
||||
}
|
||||
|
||||
+9
-8
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "toy_literal.h"
|
||||
#include "toy_literal_array.h"
|
||||
#include "toy_literal_dictionary.h"
|
||||
|
||||
@@ -10,16 +11,16 @@ typedef struct Toy_Scope {
|
||||
int references; //how many scopes point here
|
||||
} Toy_Scope;
|
||||
|
||||
Toy_Scope* Toy_pushScope(Toy_Scope* scope);
|
||||
Toy_Scope* Toy_popScope(Toy_Scope* scope);
|
||||
Toy_Scope* Toy_copyScope(Toy_Scope* original);
|
||||
TOY_API Toy_Scope* Toy_pushScope(Toy_Scope* scope);
|
||||
TOY_API Toy_Scope* Toy_popScope(Toy_Scope* scope);
|
||||
TOY_API Toy_Scope* Toy_copyScope(Toy_Scope* original);
|
||||
|
||||
//returns false if error
|
||||
bool Toy_declareScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal type);
|
||||
bool Toy_isDelcaredScopeVariable(Toy_Scope* scope, Toy_Literal key);
|
||||
TOY_API bool Toy_declareScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal type);
|
||||
TOY_API bool Toy_isDelcaredScopeVariable(Toy_Scope* scope, Toy_Literal key);
|
||||
|
||||
//return false if undefined
|
||||
bool Toy_setScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal value, bool constCheck);
|
||||
bool Toy_getScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal* value);
|
||||
TOY_API bool Toy_setScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal value, bool constCheck);
|
||||
TOY_API bool Toy_getScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal* value);
|
||||
|
||||
Toy_Literal Toy_getScopeType(Toy_Scope* scope, Toy_Literal key);
|
||||
TOY_API Toy_Literal Toy_getScopeType(Toy_Scope* scope, Toy_Literal key);
|
||||
|
||||
@@ -38,5 +38,12 @@ s += "bar";
|
||||
|
||||
assert s == "foobar", "string addition failed (wasn't sticky enough)";
|
||||
|
||||
//check order of operations
|
||||
assert 30 / 3 * 2 == 20, "Order of operations failed (raw numbers)";
|
||||
var x = 30;
|
||||
var y = 3;
|
||||
var z = 2;
|
||||
assert x / y * z == 20, "Order of operations failed (variables)";
|
||||
|
||||
|
||||
print "All good";
|
||||
@@ -2,11 +2,11 @@
|
||||
var a = [1, 2, 3];
|
||||
var b = [4, 5, 6];
|
||||
|
||||
assert _length(a) == _length(b), "a and b lengths are wrong";
|
||||
assert length(a) == length(b), "a and b lengths are wrong";
|
||||
|
||||
var acc = 0;
|
||||
for (var i = 0; i < _length(a); i++) {
|
||||
acc += _get(a, i) * _get(b, i);
|
||||
for (var i = 0; i < length(a); i++) {
|
||||
acc += get(a, i) * get(b, i);
|
||||
}
|
||||
|
||||
assert acc == 32, "dot product failed";
|
||||
@@ -15,38 +15,38 @@ assert acc == 32, "dot product failed";
|
||||
//assume the args are matrices
|
||||
fn matrix(first, second) {
|
||||
//get the matrix size
|
||||
var l1 = _length(first); //rows
|
||||
var l2 = _length(_get(first, 0)); //cols
|
||||
var l1 = length(first); //rows
|
||||
var l2 = length(get(first, 0)); //cols
|
||||
|
||||
var l3 = _length(second); //rows
|
||||
var l4 = _length(_get(second, 0)); //cols
|
||||
var l3 = length(second); //rows
|
||||
var l4 = length(get(second, 0)); //cols
|
||||
|
||||
//pre-allocate the matrix
|
||||
var row = [];
|
||||
for (var j = 0; j < l4; j++) {
|
||||
_push(row, 0);
|
||||
push(row, 0);
|
||||
}
|
||||
|
||||
var result = [];
|
||||
for (var i = 0; i < l1; i++) {
|
||||
_push(result, row);
|
||||
push(result, row);
|
||||
}
|
||||
|
||||
//assign the values
|
||||
for (var i = 0; i < _length(first); i++) {
|
||||
for (var i = 0; i < length(first); i++) {
|
||||
//select each element of "first"
|
||||
var firstElement = _get(first, i);
|
||||
var firstElement = get(first, i);
|
||||
|
||||
//for each element of second
|
||||
for (var i2 = 0; i2 < _length(second); i2++) {
|
||||
for (var j2 = 0; j2 < _length(_get(second, 0)); j2++) {
|
||||
for (var i2 = 0; i2 < length(second); i2++) {
|
||||
for (var j2 = 0; j2 < length(get(second, 0)); j2++) {
|
||||
|
||||
var val = _get(_get(first, i), i2) * _get(_get(second, i2), j2);
|
||||
var val = get(get(first, i), i2) * get(get(second, i2), j2);
|
||||
|
||||
//TODO: needs better notation than this tmpRow variable
|
||||
var tmpRow = _get(result, i);
|
||||
_set(tmpRow, j2, val);
|
||||
_set(result, i, tmpRow);
|
||||
var tmpRow = get(result, i);
|
||||
set(tmpRow, j2, val);
|
||||
set(result, i, tmpRow);
|
||||
|
||||
//result[ i ][ j2 ] += first[i][i2] * second[i2][j2]
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
//test function chaining with the dot operator
|
||||
|
||||
fn _identity(self) {
|
||||
fn identity(self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
fn _check(self) {
|
||||
fn check(self) {
|
||||
assert self == 42, "dot chaining failed";
|
||||
return self;
|
||||
}
|
||||
@@ -20,7 +20,7 @@ val
|
||||
|
||||
|
||||
//test the value is actually altered
|
||||
fn _increment(self) {
|
||||
fn increment(self) {
|
||||
return self + 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
fn _add(self, inc) {
|
||||
fn add(self, inc) {
|
||||
return self + inc;
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ extra("one", "two", "three", "four", "five", "six", "seven");
|
||||
|
||||
|
||||
//test underscore functions
|
||||
fn _example(self, a, b, c) {
|
||||
fn example(self, a, b, c) {
|
||||
assert a == "a", "underscore failed (a)";
|
||||
assert b == "b", "underscore failed (b)";
|
||||
assert c == "c", "underscore failed (c)";
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
|
||||
This ensures that when indexing on both sides of an assignment,
|
||||
it works correctly.
|
||||
|
||||
*/
|
||||
|
||||
var a = [1, 2, 3];
|
||||
var b = [4, 5, 6];
|
||||
|
||||
a[1] = b[1];
|
||||
|
||||
assert a == [1, 5, 3], "index assignment both failed";
|
||||
|
||||
print "All good";
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
|
||||
Compiler note:
|
||||
This is also to test a specific element in the compiler.
|
||||
It ensures that when doing indexing and assignment in one statement,
|
||||
the index is NOT on the right. If it is, then it is treated like a normal
|
||||
assignment.
|
||||
|
||||
*/
|
||||
|
||||
//polyfill the _insert function
|
||||
var a = [1, 2, 3];
|
||||
|
||||
var b = a[1];
|
||||
|
||||
assert b == 2, "index assignment left failed";
|
||||
|
||||
|
||||
print "All good";
|
||||
@@ -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";
|
||||
@@ -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";
|
||||
@@ -0,0 +1,17 @@
|
||||
import standard;
|
||||
import random;
|
||||
|
||||
var generator: opaque = createRandomGenerator(clock().hash()); //create a new generator object, from a non-determinant source
|
||||
|
||||
var a: int = generator.generateRandomNumber();
|
||||
var b: int = generator.generateRandomNumber();
|
||||
var c: int = generator.generateRandomNumber();
|
||||
|
||||
generator.freeRandomGenerator();
|
||||
|
||||
assert a != b, "random a != random b failed";
|
||||
assert a != c, "random a != random c failed";
|
||||
assert b != c, "random b != random c failed";
|
||||
|
||||
|
||||
print "All good";
|
||||
Binary file not shown.
@@ -1,9 +1,417 @@
|
||||
//test the standard library
|
||||
{
|
||||
import standard;
|
||||
import standard;
|
||||
|
||||
//test clock
|
||||
{
|
||||
//this depends on external factors, so only check the length
|
||||
assert clock().length() == 24, "clock() import failed";
|
||||
assert clock().length() == 24, "clock().length() failed";
|
||||
}
|
||||
|
||||
|
||||
//test hash
|
||||
{
|
||||
assert typeof "Hello world".hash() == int, "typeof \"Hello world\".hash() failed";
|
||||
assert "Hello world".hash() == 994097935, "\"Hello world\".hash() failed"; //NOTE: specific value based on algorithm
|
||||
}
|
||||
|
||||
|
||||
//test abs
|
||||
{
|
||||
assert abs(-5) == 5, "abs(-integer) failed";
|
||||
assert abs(-5.5) == 5.5, "abs(-float) failed";
|
||||
assert abs(5) == 5, "abs(+integer) failed";
|
||||
assert abs(5.5) == 5.5, "abs(+float) failed";
|
||||
|
||||
var x = -5;
|
||||
|
||||
assert x.abs() == 5, "var.abs() failed";
|
||||
}
|
||||
|
||||
|
||||
//test ceil
|
||||
{
|
||||
assert ceil(4) == 4, "ceil(int) failed";
|
||||
assert ceil(4.0) == 4, "ceil(float) failed";
|
||||
assert ceil(4.1) == 5, "ceil() failed";
|
||||
|
||||
var x = 4.1;
|
||||
|
||||
assert x.ceil() == 5, "var.ceil() failed";
|
||||
}
|
||||
|
||||
|
||||
//test floor
|
||||
{
|
||||
assert floor(4) == 4, "floor(int) failed";
|
||||
assert floor(4.0) == 4, "floor(float) failed";
|
||||
assert floor(4.1) == 4, "floor() failed";
|
||||
|
||||
var x = 4.1;
|
||||
|
||||
assert x.floor() == 4, "var.floor() failed";
|
||||
}
|
||||
|
||||
|
||||
//test max
|
||||
{
|
||||
assert max(1, 2, 3) == 3, "max() failed";
|
||||
|
||||
var a = 1;
|
||||
var b = 2;
|
||||
var c = 3;
|
||||
|
||||
assert max(a, b, c) == 3, "var.max() failed";
|
||||
|
||||
assert max(1, 2, 3, 4, 5, 6, 7, 8, 9, 0) == 9, "max() with many args failed";
|
||||
|
||||
assert typeof max(1, 2, 3) == int, "typeof max() == int failed";
|
||||
assert typeof max(1, 2, 3.4) == float, "typeof max() == float failed";
|
||||
}
|
||||
|
||||
|
||||
//test min
|
||||
{
|
||||
assert min(1, 2, 3) == 1, "min() failed";
|
||||
|
||||
var a = 1;
|
||||
var b = 2;
|
||||
var c = 3;
|
||||
|
||||
assert min(a, b, c) == 1, "var.min() failed";
|
||||
|
||||
assert min(1, 2, 3, 4, 5, 6, 7, 8, 9, 0) == 0, "min() with many args failed";
|
||||
|
||||
assert typeof min(1, 2, 3) == int, "typeof min() == int failed";
|
||||
assert typeof min(1, 2, 3.4) == float, "typeof min() == float failed";
|
||||
}
|
||||
|
||||
|
||||
//test round
|
||||
{
|
||||
assert round(4) == 4, "round(int) failed";
|
||||
assert round(4.0) == 4, "round(float) failed";
|
||||
assert round(4.1) == 4, "round(less than half) failed";
|
||||
assert round(4.9) == 5, "round(greater than half) failed";
|
||||
assert round(4.5) == 5, "round(exactly half) failed";
|
||||
|
||||
var x = 4.1;
|
||||
|
||||
assert x.round() == 4, "var.round() failed";
|
||||
|
||||
assert typeof round(1.0) == int, "typeof round() == int 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"[--];
|
||||
@@ -3,41 +3,41 @@
|
||||
//test arrays without types
|
||||
var array = [];
|
||||
|
||||
assert _length(array) == 0, "_length failed with array";
|
||||
assert length(array) == 0, "length failed with array";
|
||||
|
||||
_push(array, 1);
|
||||
_push(array, 2);
|
||||
_push(array, 3);
|
||||
_push(array, 4);
|
||||
_push(array, "foo");
|
||||
push(array, 1);
|
||||
push(array, 2);
|
||||
push(array, 3);
|
||||
push(array, 4);
|
||||
push(array, "foo");
|
||||
|
||||
assert _length(array) == 5, "_push failed with array";
|
||||
assert _pop(array) == "foo", "_pop failed with array";
|
||||
assert length(array) == 5, "push failed with array";
|
||||
assert pop(array) == "foo", "pop failed with array";
|
||||
|
||||
_set(array, 2, "bar");
|
||||
assert array == [1, 2, "bar", 4], "_set failed with array";
|
||||
assert _get(array, 3) == 4, "_get failed with array";
|
||||
set(array, 2, "bar");
|
||||
assert array == [1, 2, "bar", 4], "set failed with array";
|
||||
assert get(array, 3) == 4, "get failed with array";
|
||||
|
||||
|
||||
//test dictionaries without types
|
||||
var dict = [:];
|
||||
|
||||
_set(dict, "key", "value");
|
||||
_set(dict, 1, 2);
|
||||
set(dict, "key", "value");
|
||||
set(dict, 1, 2);
|
||||
|
||||
assert dict == ["key":"value", 1:2], "_set failed with dictionaries";
|
||||
assert _get(dict, "key") == "value", "_get failed with dictionaries";
|
||||
assert dict == ["key":"value", 1:2], "set failed with dictionaries";
|
||||
assert get(dict, "key") == "value", "get failed with dictionaries";
|
||||
|
||||
|
||||
//test _length
|
||||
assert _length(array) == 4 && _length(dict) == 2, "_length failed with array or dictionaries";
|
||||
//test length
|
||||
assert length(array) == 4 && length(dict) == 2, "length failed with array or dictionaries";
|
||||
|
||||
|
||||
//test clear
|
||||
_clear(array);
|
||||
_clear(dict);
|
||||
clear(array);
|
||||
clear(dict);
|
||||
|
||||
assert _length(array) == 0 && _length(dict) == 0, "_clear failed with array or dictionaries";
|
||||
assert length(array) == 0 && length(dict) == 0, "clear failed with array or dictionaries";
|
||||
}
|
||||
|
||||
|
||||
@@ -45,46 +45,46 @@
|
||||
//test arrays with types
|
||||
var array: [int] = [];
|
||||
|
||||
assert _length(array) == 0, "_length failed with array (+ types)";
|
||||
assert length(array) == 0, "length failed with array (+ types)";
|
||||
|
||||
_push(array, 1);
|
||||
_push(array, 2);
|
||||
_push(array, 3);
|
||||
_push(array, 4);
|
||||
_push(array, 10);
|
||||
push(array, 1);
|
||||
push(array, 2);
|
||||
push(array, 3);
|
||||
push(array, 4);
|
||||
push(array, 10);
|
||||
|
||||
assert _length(array) == 5, "_push or failed with array (+ types)";
|
||||
assert _pop(array) == 10, "_pop failed with array (+ types)";
|
||||
assert length(array) == 5, "push or failed with array (+ types)";
|
||||
assert pop(array) == 10, "pop failed with array (+ types)";
|
||||
|
||||
_set(array, 2, 70);
|
||||
assert array == [1, 2, 70, 4], "_set failed with array (+ types)";
|
||||
assert _get(array, 3) == 4, "_get failed with array (+ types)";
|
||||
set(array, 2, 70);
|
||||
assert array == [1, 2, 70, 4], "set failed with array (+ types)";
|
||||
assert get(array, 3) == 4, "get failed with array (+ types)";
|
||||
|
||||
|
||||
//test dictionaries with types
|
||||
var dict: [string : string] = [:];
|
||||
|
||||
_set(dict, "key", "value");
|
||||
set(dict, "key", "value");
|
||||
|
||||
assert dict == ["key":"value"], "_set failed with dictionaries (+ types)";
|
||||
assert _get(dict, "key") == "value", "_get failed with dictionaries (+ types)";
|
||||
assert dict == ["key":"value"], "set failed with dictionaries (+ types)";
|
||||
assert get(dict, "key") == "value", "get failed with dictionaries (+ types)";
|
||||
|
||||
|
||||
//test length with types
|
||||
assert _length(array) == 4 && _length(dict) == 1, "_length failed with array or dictionaries (+ types)";
|
||||
assert length(array) == 4 && length(dict) == 1, "length failed with array or dictionaries (+ types)";
|
||||
|
||||
|
||||
//test clear with types
|
||||
_clear(array);
|
||||
_clear(dict);
|
||||
clear(array);
|
||||
clear(dict);
|
||||
|
||||
assert _length(array) == 0 && _length(dict) == 0, "_clear failed with array or dictionaries (+ types)";
|
||||
assert length(array) == 0 && length(dict) == 0, "clear failed with array or dictionaries (+ types)";
|
||||
}
|
||||
|
||||
{
|
||||
var str = "hello world";
|
||||
|
||||
assert _length(str) == 11, "_length failed with string";
|
||||
assert length(str) == 11, "length failed with string";
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
@@ -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";
|
||||
@@ -1,12 +1,21 @@
|
||||
fn fib(n : int) {
|
||||
if (n < 2) {
|
||||
return n;
|
||||
}
|
||||
//memoize the fib function
|
||||
var memo: [int : int] = [:];
|
||||
|
||||
return fib(n-1) + fib(n-2);
|
||||
fn fib(n : int) {
|
||||
if (n < 2) {
|
||||
return n;
|
||||
}
|
||||
|
||||
var result = memo[n];
|
||||
if (result == null) {
|
||||
result = fib(n-1) + fib(n-2);
|
||||
memo[n] = result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
for (var i = 0; i < 20; i++) {
|
||||
for (var i = 0; i < 40; i++) {
|
||||
var res = fib(i);
|
||||
print string i + ": " + string res;
|
||||
}
|
||||
+23
-23
@@ -20,15 +20,15 @@ static void noPrintFn(const char* output) {
|
||||
}
|
||||
|
||||
void error(char* msg) {
|
||||
printf("%s", msg);
|
||||
printf("%s\n", msg);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
int main() {
|
||||
{
|
||||
size_t size = 0;
|
||||
char* source = Toy_readFile("scripts/call-from-host.toy", &size);
|
||||
unsigned char* tb = Toy_compileString(source, &size);
|
||||
const char* source = (const char*)Toy_readFile("scripts/call-from-host.toy", &size);
|
||||
const unsigned char* tb = Toy_compileString(source, &size);
|
||||
free((void*)source);
|
||||
|
||||
if (!tb) {
|
||||
@@ -52,15 +52,15 @@ int main() {
|
||||
|
||||
//check the results
|
||||
if (arguments.count != 0) {
|
||||
error("Arguments has the wrong number of members\n");
|
||||
error("Arguments has the wrong number of members");
|
||||
}
|
||||
|
||||
if (returns.count != 1) {
|
||||
error("Returns has the wrong number of members\n");
|
||||
error("Returns has the wrong number of members");
|
||||
}
|
||||
|
||||
if (!TOY_IS_INTEGER(returns.literals[0]) || TOY_AS_INTEGER(returns.literals[0]) != 42) {
|
||||
error("Returned value is incorrect\n");
|
||||
error("Returned value is incorrect");
|
||||
}
|
||||
|
||||
Toy_freeLiteralArray(&arguments);
|
||||
@@ -85,17 +85,17 @@ int main() {
|
||||
|
||||
//check the results
|
||||
if (arguments.count != 0) {
|
||||
error("Arguments has the wrong number of members\n");
|
||||
error("Arguments has the wrong number of members");
|
||||
}
|
||||
|
||||
if (returns.count != 1) {
|
||||
error("Returns has the wrong number of members\n");
|
||||
error("Returns has the wrong number of members");
|
||||
}
|
||||
|
||||
float epsilon = 0.1; //because floats are evil
|
||||
|
||||
if (!TOY_IS_FLOAT(returns.literals[0]) || fabs(TOY_AS_FLOAT(returns.literals[0]) - pi) > epsilon) {
|
||||
error("Returned value is incorrect\n");
|
||||
error("Returned value is incorrect");
|
||||
}
|
||||
|
||||
Toy_freeLiteralArray(&arguments);
|
||||
@@ -115,11 +115,11 @@ int main() {
|
||||
|
||||
//check the results
|
||||
if (arguments.count != 0) {
|
||||
error("Arguments has the wrong number of members\n");
|
||||
error("Arguments has the wrong number of members");
|
||||
}
|
||||
|
||||
if (returns.count != 1) {
|
||||
error("Returns has the wrong number of members\n");
|
||||
error("Returns has the wrong number of members");
|
||||
}
|
||||
|
||||
//grab the resulting literal
|
||||
@@ -139,15 +139,15 @@ int main() {
|
||||
|
||||
//check the results
|
||||
if (arguments.count != 0) {
|
||||
error("Arguments (1) has the wrong number of members\n");
|
||||
error("Arguments (1) has the wrong number of members");
|
||||
}
|
||||
|
||||
if (returns.count != 1) {
|
||||
error("Returns (1) has the wrong number of members\n");
|
||||
error("Returns (1) has the wrong number of members");
|
||||
}
|
||||
|
||||
if (!TOY_IS_INTEGER(returns.literals[0]) || TOY_AS_INTEGER(returns.literals[0]) != 1) {
|
||||
error("Returned value (1) is incorrect\n");
|
||||
error("Returned value (1) is incorrect");
|
||||
}
|
||||
|
||||
Toy_freeLiteralArray(&arguments);
|
||||
@@ -164,15 +164,15 @@ int main() {
|
||||
|
||||
//check the results
|
||||
if (arguments.count != 0) {
|
||||
error("Arguments (2) has the wrong number of members\n");
|
||||
error("Arguments (2) has the wrong number of members");
|
||||
}
|
||||
|
||||
if (returns.count != 1) {
|
||||
error("Returns (2) has the wrong number of members\n");
|
||||
error("Returns (2) has the wrong number of members");
|
||||
}
|
||||
|
||||
if (!TOY_IS_INTEGER(returns.literals[0]) || TOY_AS_INTEGER(returns.literals[0]) != 2) {
|
||||
error("Returned value (2) is incorrect\n");
|
||||
error("Returned value (2) is incorrect");
|
||||
}
|
||||
|
||||
Toy_freeLiteralArray(&arguments);
|
||||
@@ -189,15 +189,15 @@ int main() {
|
||||
|
||||
//check the results
|
||||
if (arguments.count != 0) {
|
||||
error("Arguments (3) has the wrong number of members\n");
|
||||
error("Arguments (3) has the wrong number of members");
|
||||
}
|
||||
|
||||
if (returns.count != 1) {
|
||||
error("Returns (3) has the wrong number of members\n");
|
||||
error("Returns (3) has the wrong number of members");
|
||||
}
|
||||
|
||||
if (!TOY_IS_INTEGER(returns.literals[0]) || TOY_AS_INTEGER(returns.literals[0]) != 3) {
|
||||
error("Returned value (3) is incorrect\n");
|
||||
error("Returned value (3) is incorrect");
|
||||
}
|
||||
|
||||
Toy_freeLiteralArray(&arguments);
|
||||
@@ -222,15 +222,15 @@ int main() {
|
||||
|
||||
//check the results
|
||||
if (arguments.count != 0) {
|
||||
error("Arguments has the wrong number of members\n");
|
||||
error("Arguments has the wrong number of members");
|
||||
}
|
||||
|
||||
if (returns.count != 1 || !TOY_IS_NULL(returns.literals[0])) {
|
||||
error("Returns has the wrong number of members\n");
|
||||
error("Returns has the wrong number of members");
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
error("Assertion gives the wrong return value\n");
|
||||
error("Assertion gives the wrong return value");
|
||||
}
|
||||
|
||||
Toy_freeLiteralArray(&arguments);
|
||||
|
||||
@@ -39,7 +39,7 @@ int main() {
|
||||
Toy_writeCompiler(&compiler, node);
|
||||
|
||||
//collate
|
||||
int size = 0;
|
||||
size_t size = 0;
|
||||
unsigned char* bytecode = Toy_collateCompiler(&compiler, &size);
|
||||
|
||||
//cleanup
|
||||
@@ -52,7 +52,7 @@ int main() {
|
||||
{
|
||||
//source
|
||||
size_t sourceLength = 0;
|
||||
char* source = Toy_readFile("scripts/compiler_sample_code.toy", &sourceLength);
|
||||
const char* source = (const char*)Toy_readFile("scripts/compiler_sample_code.toy", &sourceLength);
|
||||
|
||||
//test basic compilation & collation
|
||||
Toy_Lexer lexer;
|
||||
@@ -78,7 +78,7 @@ int main() {
|
||||
}
|
||||
|
||||
//collate
|
||||
int size = 0;
|
||||
size_t size = 0;
|
||||
unsigned char* bytecode = Toy_collateCompiler(&compiler, &size);
|
||||
|
||||
//cleanup
|
||||
|
||||
+14
-9
@@ -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_initInterpreter(&interpreter);
|
||||
|
||||
@@ -42,18 +42,18 @@ void runBinaryCustom(unsigned char* tb, size_t size) {
|
||||
Toy_freeInterpreter(&interpreter);
|
||||
}
|
||||
|
||||
void runSourceCustom(char* source) {
|
||||
void runSourceCustom(const char* source) {
|
||||
size_t size = 0;
|
||||
unsigned char* tb = Toy_compileString(source, &size);
|
||||
const unsigned char* tb = Toy_compileString(source, &size);
|
||||
if (!tb) {
|
||||
return;
|
||||
}
|
||||
runBinaryCustom(tb, size);
|
||||
}
|
||||
|
||||
void runSourceFileCustom(char* fname) {
|
||||
void runSourceFileCustom(const char* fname) {
|
||||
size_t size = 0; //not used
|
||||
char* source = Toy_readFile(fname, &size);
|
||||
const char* source = (const char*)Toy_readFile(fname, &size);
|
||||
runSourceCustom(source);
|
||||
free((void*)source);
|
||||
}
|
||||
@@ -68,7 +68,7 @@ int main() {
|
||||
|
||||
{
|
||||
//source
|
||||
char* source = "print null;";
|
||||
const char* source = "print null;";
|
||||
|
||||
//test basic compilation & collation
|
||||
Toy_Lexer lexer;
|
||||
@@ -87,8 +87,8 @@ int main() {
|
||||
Toy_writeCompiler(&compiler, node);
|
||||
|
||||
//collate
|
||||
int size = 0;
|
||||
unsigned char* bytecode = Toy_collateCompiler(&compiler, &size);
|
||||
size_t size = 0;
|
||||
const unsigned char* bytecode = Toy_collateCompiler(&compiler, &size);
|
||||
|
||||
//NOTE: suppress print output for testing
|
||||
Toy_setInterpreterPrint(&interpreter, noPrintFn);
|
||||
@@ -106,7 +106,7 @@ int main() {
|
||||
|
||||
{
|
||||
//run each file in tests/scripts/
|
||||
char* filenames[] = {
|
||||
const char* filenames[] = {
|
||||
"arithmetic.toy",
|
||||
"casting.toy",
|
||||
"coercions.toy",
|
||||
@@ -117,6 +117,8 @@ int main() {
|
||||
"dottify-bugfix.toy",
|
||||
"functions.toy",
|
||||
"index-arrays.toy",
|
||||
"index-assignment-both-bugfix.toy",
|
||||
"index-assignment-left-bugfix.toy",
|
||||
"index-dictionaries.toy",
|
||||
"index-strings.toy",
|
||||
"jumps.toy",
|
||||
@@ -126,7 +128,10 @@ int main() {
|
||||
"long-dictionary.toy",
|
||||
"long-literals.toy",
|
||||
"native-functions.toy",
|
||||
"or-chaining-bugfix.toy",
|
||||
"panic-within-functions.toy",
|
||||
"polyfill-insert.toy",
|
||||
"polyfill-remove.toy",
|
||||
"ternary-expressions.toy",
|
||||
"types.toy",
|
||||
NULL
|
||||
|
||||
+4
-4
@@ -15,10 +15,10 @@ int main() {
|
||||
Toy_initLexer(&lexer, source);
|
||||
|
||||
//get each token
|
||||
Toy_Token print = Toy_scanLexer(&lexer);
|
||||
Toy_Token null = Toy_scanLexer(&lexer);
|
||||
Toy_Token semi = Toy_scanLexer(&lexer);
|
||||
Toy_Token eof = Toy_scanLexer(&lexer);
|
||||
Toy_Token print = Toy_private_scanLexer(&lexer);
|
||||
Toy_Token null = Toy_private_scanLexer(&lexer);
|
||||
Toy_Token semi = Toy_private_scanLexer(&lexer);
|
||||
Toy_Token eof = Toy_private_scanLexer(&lexer);
|
||||
|
||||
//test each token is correct
|
||||
if (strncmp(print.lexeme, "print", print.length)) {
|
||||
|
||||
+9
-63
@@ -14,10 +14,9 @@
|
||||
#include "../repl/repl_tools.h"
|
||||
|
||||
#include "../repl/lib_about.h"
|
||||
#include "../repl/lib_compound.h"
|
||||
#include "../repl/lib_random.h"
|
||||
#include "../repl/lib_runner.h"
|
||||
#include "../repl/lib_standard.h"
|
||||
#include "../repl/lib_timer.h"
|
||||
|
||||
//supress the print output
|
||||
static void noPrintFn(const char* output) {
|
||||
@@ -37,7 +36,7 @@ static void errorWrapper(const char* 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_initInterpreter(&interpreter);
|
||||
|
||||
@@ -47,32 +46,15 @@ void runBinaryWithLibrary(unsigned char* tb, size_t size, char* library, Toy_Hoo
|
||||
Toy_setInterpreterError(&interpreter, errorWrapper);
|
||||
|
||||
//inject the standard libraries into this interpreter
|
||||
if (hook != Toy_hookStandard) {
|
||||
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
|
||||
}
|
||||
Toy_injectNativeHook(&interpreter, library, hook);
|
||||
|
||||
Toy_runInterpreter(&interpreter, tb, size);
|
||||
Toy_freeInterpreter(&interpreter);
|
||||
}
|
||||
|
||||
void runBinaryQuietly(unsigned char* tb, size_t size) {
|
||||
Toy_Interpreter interpreter;
|
||||
Toy_initInterpreter(&interpreter);
|
||||
|
||||
//NOTE: supress print output for testing
|
||||
Toy_setInterpreterPrint(&interpreter, noPrintFn);
|
||||
Toy_setInterpreterAssert(&interpreter, assertWrapper);
|
||||
Toy_setInterpreterError(&interpreter, errorWrapper);
|
||||
|
||||
//inject the libs
|
||||
Toy_injectNativeHook(&interpreter, "about", Toy_hookAbout);
|
||||
Toy_injectNativeHook(&interpreter, "compound", Toy_hookCompound);
|
||||
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
|
||||
Toy_injectNativeHook(&interpreter, "timer", Toy_hookTimer);
|
||||
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
|
||||
|
||||
Toy_runInterpreter(&interpreter, tb, size);
|
||||
Toy_freeInterpreter(&interpreter);
|
||||
}
|
||||
|
||||
typedef struct Payload {
|
||||
char* fname;
|
||||
char* libname;
|
||||
@@ -96,10 +78,9 @@ int main() {
|
||||
Payload payloads[] = {
|
||||
{"interactions.toy", "standard", Toy_hookStandard}, //interactions needs standard
|
||||
{"about.toy", "about", Toy_hookAbout},
|
||||
{"compound.toy", "compound", Toy_hookCompound},
|
||||
{"runner.toy", "runner", Toy_hookRunner},
|
||||
{"standard.toy", "standard", Toy_hookStandard},
|
||||
{"timer.toy", "timer", Toy_hookTimer},
|
||||
{"runner.toy", "runner", Toy_hookRunner},
|
||||
{"random.toy", "random", Toy_hookRandom},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
@@ -111,14 +92,14 @@ int main() {
|
||||
|
||||
//compile the source
|
||||
size_t size = 0;
|
||||
char* source = Toy_readFile(fname, &size);
|
||||
const char* source = (const char*)Toy_readFile(fname, &size);
|
||||
if (!source) {
|
||||
printf(TOY_CC_ERROR "Failed to load file: %s\n" TOY_CC_RESET, fname);
|
||||
failedAsserts++;
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned char* tb = Toy_compileString(source, &size);
|
||||
const unsigned char* tb = Toy_compileString(source, &size);
|
||||
free((void*)source);
|
||||
|
||||
if (!tb) {
|
||||
@@ -131,41 +112,6 @@ int main() {
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
//run whatever, testing stuff together to check for memory leaks
|
||||
char* whatever[] = {
|
||||
"random-stuff.toy",
|
||||
NULL
|
||||
};
|
||||
|
||||
for (int i = 0; whatever[i]; i++) {
|
||||
printf("Running %s\n", whatever[i]);
|
||||
|
||||
char fname[128];
|
||||
snprintf(fname, 128, "scripts/lib/%s", whatever[i]);
|
||||
|
||||
//compile the source
|
||||
size_t size = 0;
|
||||
char* source = Toy_readFile(fname, &size);
|
||||
if (!source) {
|
||||
printf(TOY_CC_ERROR "Failed to load file: %s\n" TOY_CC_RESET, fname);
|
||||
failedAsserts++;
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned char* tb = Toy_compileString(source, &size);
|
||||
free((void*)source);
|
||||
|
||||
if (!tb) {
|
||||
printf(TOY_CC_ERROR "Failed to compile file: %s\n" TOY_CC_RESET, fname);
|
||||
failedAsserts++;
|
||||
continue;
|
||||
}
|
||||
|
||||
runBinaryQuietly(tb, size);
|
||||
}
|
||||
}
|
||||
|
||||
//lib cleanup
|
||||
Toy_freeDriveDictionary();
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ static void noErrorFn(const char* output) {
|
||||
errorsTriggered++;
|
||||
}
|
||||
|
||||
unsigned char* compileStringCustom(char* source, size_t* size) {
|
||||
const unsigned char* compileStringCustom(const char* source, size_t* size) {
|
||||
Toy_Lexer lexer;
|
||||
Toy_Parser parser;
|
||||
Toy_Compiler compiler;
|
||||
@@ -50,7 +50,7 @@ unsigned char* compileStringCustom(char* source, size_t* size) {
|
||||
}
|
||||
|
||||
//get the bytecode dump
|
||||
unsigned char* tb = Toy_collateCompiler(&compiler, (int*)(size));
|
||||
const unsigned char* tb = Toy_collateCompiler(&compiler, size);
|
||||
|
||||
//cleanup
|
||||
Toy_freeCompiler(&compiler);
|
||||
@@ -61,7 +61,7 @@ unsigned char* compileStringCustom(char* source, size_t* size) {
|
||||
return tb;
|
||||
}
|
||||
|
||||
void runBinaryCustom(unsigned char* tb, size_t size) {
|
||||
void runBinaryCustom(const unsigned char* tb, size_t size) {
|
||||
Toy_Interpreter interpreter;
|
||||
Toy_initInterpreter(&interpreter);
|
||||
|
||||
@@ -73,18 +73,18 @@ void runBinaryCustom(unsigned char* tb, size_t size) {
|
||||
Toy_freeInterpreter(&interpreter);
|
||||
}
|
||||
|
||||
void runSourceCustom(char* source) {
|
||||
void runSourceCustom(const char* source) {
|
||||
size_t size = 0;
|
||||
unsigned char* tb = compileStringCustom(source, &size);
|
||||
const unsigned char* tb = compileStringCustom(source, &size);
|
||||
if (!tb) {
|
||||
return;
|
||||
}
|
||||
runBinaryCustom(tb, size);
|
||||
}
|
||||
|
||||
void runSourceFileCustom(char* fname) {
|
||||
void runSourceFileCustom(const char* fname) {
|
||||
size_t size = 0; //not used
|
||||
char* source = Toy_readFile(fname, &size);
|
||||
const char* source = (const char*)Toy_readFile(fname, &size);
|
||||
runSourceCustom(source);
|
||||
free((void*)source);
|
||||
}
|
||||
@@ -101,6 +101,7 @@ int main() {
|
||||
"declare-types-array.toy",
|
||||
"declare-types-dictionary-key.toy",
|
||||
"declare-types-dictionary-value.toy",
|
||||
"index-access-bugfix.toy",
|
||||
"index-arrays-non-integer.toy",
|
||||
"string-concat.toy",
|
||||
"unary-inverted-nothing.toy",
|
||||
|
||||
@@ -68,8 +68,8 @@ static int consume(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||
int main() {
|
||||
{
|
||||
size_t size = 0;
|
||||
char* source = Toy_readFile("scripts/opaque-data-type.toy", &size);
|
||||
unsigned char* tb = Toy_compileString(source, &size);
|
||||
const char* source = (const char*)Toy_readFile("scripts/opaque-data-type.toy", &size);
|
||||
const unsigned char* tb = Toy_compileString(source, &size);
|
||||
free((void*)source);
|
||||
|
||||
if (!tb) {
|
||||
|
||||
+5
-5
@@ -11,7 +11,7 @@
|
||||
int main() {
|
||||
{
|
||||
//source
|
||||
char* source = "print null;";
|
||||
const char* source = "print null;";
|
||||
|
||||
//test init & quit
|
||||
Toy_Lexer lexer;
|
||||
@@ -24,7 +24,7 @@ int main() {
|
||||
|
||||
{
|
||||
//source
|
||||
char* source = "print null;";
|
||||
const char* source = "print null;";
|
||||
|
||||
//test parsing
|
||||
Toy_Lexer lexer;
|
||||
@@ -58,7 +58,7 @@ int main() {
|
||||
{
|
||||
//get the source file
|
||||
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)
|
||||
Toy_Lexer lexer;
|
||||
@@ -85,7 +85,7 @@ int main() {
|
||||
|
||||
{
|
||||
//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
|
||||
Toy_Lexer lexer;
|
||||
@@ -123,7 +123,7 @@ int main() {
|
||||
|
||||
{
|
||||
//test parsing of underscored numbers
|
||||
char* source = "print 1_000_000;";
|
||||
const char* source = "print 1_000_000;";
|
||||
|
||||
//test parsing
|
||||
Toy_Lexer lexer;
|
||||
|
||||
+15
-5
@@ -10,25 +10,32 @@
|
||||
int currentMemoryUsed = 0;
|
||||
int maxMemoryUsed = 0;
|
||||
int memoryAllocCalls = 0;
|
||||
int memoryAllocFree = 0;
|
||||
int memoryAllocRealloc = 0;
|
||||
|
||||
static void* trackerAllocator(void* pointer, size_t oldSize, size_t newSize) {
|
||||
//the number of raw calls
|
||||
memoryAllocCalls++;
|
||||
|
||||
//causes issues, so just skip out with a NO-OP
|
||||
if (newSize == 0 && oldSize == 0) {
|
||||
//causes issues, so just skip out with a NO-OP
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memoryAllocCalls++;
|
||||
|
||||
//track the changes
|
||||
currentMemoryUsed = currentMemoryUsed - oldSize + newSize;
|
||||
maxMemoryUsed = currentMemoryUsed > maxMemoryUsed ? currentMemoryUsed : maxMemoryUsed;
|
||||
|
||||
if (newSize == 0) {
|
||||
//the number of frees
|
||||
memoryAllocFree++;
|
||||
free(pointer);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//the number of reallocations
|
||||
memoryAllocRealloc++;
|
||||
void* mem = realloc(pointer, newSize);
|
||||
|
||||
if (mem == NULL) {
|
||||
@@ -39,11 +46,14 @@ static void* trackerAllocator(void* pointer, size_t oldSize, size_t newSize) {
|
||||
return mem;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
int main(int argc, const char* argv[]) {
|
||||
if (argc <= 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
//not used, except for print
|
||||
Toy_initCommandLine(argc, argv);
|
||||
|
||||
//setup for runner
|
||||
Toy_initDriveDictionary();
|
||||
|
||||
@@ -66,7 +76,7 @@ int main(int argc, char* argv[]) {
|
||||
Toy_freeDriveDictionary();
|
||||
|
||||
//report output
|
||||
printf("Memory report: %d max bytes, %d calls\n", maxMemoryUsed, memoryAllocCalls);
|
||||
printf("Heap Memory Report:\n\t%d max bytes\n\t%d calls to the allocator\n\t%d calls to realloc()\n\t%d calls to free()\n\t%d discrepancies\n", maxMemoryUsed, memoryAllocCalls, memoryAllocRealloc, memoryAllocFree, memoryAllocCalls - memoryAllocRealloc - memoryAllocFree);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user