From 7ea8df652c1e36423c5cd57fa37877062a973bd7 Mon Sep 17 00:00:00 2001 From: Thakee Nathees Date: Sat, 8 May 2021 16:24:07 +0530 Subject: [PATCH] language name changed to pocketlang --- .gitignore | 17 +- README.md | 12 +- SConscript | 54 +++--- SConstruct | 13 +- include/miniscript.h | 50 ++++-- ms_configure.py | 59 ------- src/common.h | 24 --- src/core.c | 6 +- {test => src/main}/main.c | 0 src/types/.gitignore | 8 +- .../{buffer.template.c => buffer.c.template} | 0 .../{buffer.template.h => buffer.h.template} | 0 src/types/buffergen.py | 4 +- src/vm.c | 2 + TODO.txt => test/TODO.txt | 0 test/benchmark/fib/fib.ms | 2 +- test/benchmark/fib/fib.py | 2 +- test/msvcmake.bat | 167 ++++++++++++++++++ 18 files changed, 270 insertions(+), 150 deletions(-) delete mode 100644 ms_configure.py rename {test => src/main}/main.c (100%) rename src/types/{buffer.template.c => buffer.c.template} (100%) rename src/types/{buffer.template.h => buffer.h.template} (100%) rename TODO.txt => test/TODO.txt (100%) create mode 100644 test/msvcmake.bat diff --git a/.gitignore b/.gitignore index f9bc0d7..70d3329 100644 --- a/.gitignore +++ b/.gitignore @@ -1,21 +1,20 @@ -# MiniScript ignore list +# PocketLang ignore list + build/ -MiniScript/test/ -src/test/ -MiniScript/.import/ -release/ -debug/ +bin/ +test/bin/ +[Rr]elease/ +[Dd]ebug/ *__pycache__/ .vs/ .vscode/ +x64/ -build.py -config.json -run.bat *.dblite *.idb *.pdb +*.exp *.sln *.vcxproj *.vcxproj.filters diff --git a/README.md b/README.md index 784e912..835414b 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,14 @@ -## MiniScript Language +# PocketLang -MiniScript is a simple, fast, embeddable, functional, dynamic-typed, bytecode-interpreted, scripting language written in C. It uses the [mark-and-sweep](https://en.wikipedia.org/wiki/Tracing_garbage_collection) method for garbage collection. MiniScript is is syntactically similar to Ruby. The frontend and expression parsing techniques were written using [Wren Language](https://wren.io/) and their wonderful book [craftinginterpreters](http://www.craftinginterpreters.com/) as a reference. +

+ +

-### What MiniScript looks like +**PocketLang** is a simple and fast programming language written in C. It's syntactically similar to Ruby, but compatibility isn't the goal and it can be learned in less than an hour. Including the compiler, bytecode VM and runtime, it's a standalone executable with zero external dependecies just as it's self descriptive name. The pocketlang VM can be embedded in another hosting program very easily, as static/shared library or a generated single header version of the source, which makes it even effortless. + +The language is written using [Wren Language](https://wren.io/) and their wonderful book [craftinginterpreters](http://www.craftinginterpreters.com/) as a reference. + +### What PocketLang looks like ```ruby diff --git a/SConscript b/SConscript index 08c04e4..a8cd84a 100644 --- a/SConscript +++ b/SConscript @@ -1,34 +1,44 @@ Import('env') import os -env.PROJECT_NAME = "MiniScript" -env.RUN_TARGET = os.path.join(env['variant_dir'], 'bin/miniscript') +env.PROJECT_NAME = "pocketlang" +env.RUN_TARGET = os.path.join(env['variant_dir'], 'bin/pocket') -## MiniScript source files +## TODO: automate types file generation. + +## PocketLang source files SOURCES = [ Glob('src/*.c'), - Glob('src/types/*.c'), Glob('src/types/gen/*.c'), ] -## Compile miniscript lib. -vm = env.Library( - target = 'bin/miniscript', - source = SOURCES, - CPPPATH = ['include/'], -) +if env['lib_shared']: + ## Compile pocketlang dynamic lib. + dll = env.SharedLibrary( + target = 'bin/pocket' + env['bin_suffix'], + source = SOURCES, + CPPPATH = ['include/'], + CPPDEFINES = [env['CPPDEFINES'], 'MS_DLL', 'MS_COMPILE'], + ) +else: + ## Compile pocketlang static lib. + lib = env.Library( + target = 'bin/pocket' + env['bin_suffix'], + source = SOURCES, + CPPPATH = ['include/'], + ) -## Test executable -test = env.Program( - target = 'bin/miniscript', - source = ['test/main.c'], - CPPPATH = ['include/'], - LIBPATH = 'bin', - LIBS = 'miniscript', -) - -env.Append(CPPPATH=['include/']) - -Requires(test, vm) + ## Test executable + test = env.Program( + target = 'bin/pocket' + env['bin_suffix'], + source = ['src/main/main.c'], + CPPPATH = ['include/'], + LIBPATH = 'bin', + LIBS = 'pocket' + env['bin_suffix'], + ) + + env.Append(CPPPATH=['include/']) + + Requires(test, lib) diff --git a/SConstruct b/SConstruct index a2356bd..fac047b 100644 --- a/SConstruct +++ b/SConstruct @@ -1,12 +1,6 @@ #!python import os, subprocess, sys -def get_variant_dir(env): - ret = 'build/' + env['platform'] + '/' + env['target'] + '/' - if env['platform'] == 'windows': - return ret + env['bits'] + '/' - return ret - opts = Variables([], ARGUMENTS) ## Define our options opts.Add(EnumVariable('platform', "Compilation platform", '', ['', 'windows', 'x11', 'linux', 'osx'])) @@ -16,9 +10,9 @@ opts.Add(BoolVariable('use_llvm', "Use the LLVM / Clang compiler", False)) opts.Add(BoolVariable('use_mingw', "Use Mingw compiler", False)) opts.Add(BoolVariable('vsproj', "make a visual studio project", False)) -opts.Add(BoolVariable('verbose', "use verbose build command", False)) +opts.Add(BoolVariable('verbose', "use verbose build command", True)) -opts.Add(BoolVariable('libs', "include unit tests in main", False)) +opts.Add(BoolVariable('lib_shared', "Compile as a shared library (only).", False)) ## Setup the Environment DefaultEnvironment(tools=[]) ## not using any tools @@ -145,7 +139,8 @@ if not env['verbose']: no_verbose(sys, env) Export('env') -env['variant_dir'] = get_variant_dir(env) +env['variant_dir'] = 'build/' + env['target'] + '/' +env['bin_suffix'] = '' ## TODO: Maybe '.%s.%s' % (env['platform'], env['bits']) SConscript('SConscript', variant_dir=env['variant_dir'], duplicate=0) ## -------------------------------------------------------------------------------- diff --git a/include/miniscript.h b/include/miniscript.h index 78854fa..d81a866 100644 --- a/include/miniscript.h +++ b/include/miniscript.h @@ -21,6 +21,30 @@ extern "C" { // String representation of the value. #define MS_VERSION_STRING "0.1.0" +// miniscript visibility macros. define MS_DLL for using miniscript as a +// shared library and define MS_COMPILE to export symbols. + +#ifdef _MSC_VER + #define _MS_EXPORT __declspec(dllexport) + #define _MS_IMPORT __declspec(dllimport) +#elif defined(__GNUC__) + #define _MS_EXPORT __attribute__((visibility ("default"))) + #define _MS_IMPORT +#else + #define _MS_EXPORT + #define _MS_IMPORT +#endif + +#ifdef MS_DLL + #ifdef MS_COMPILE + #define MS_PUBLIC _MS_EXPORT + #else + #define MS_PUBLIC _MS_IMPORT + #endif +#else + #define MS_PUBLIC +#endif + // MiniScript Virtual Machine. // it'll contain the state of the execution, stack, heap, and manage memory // allocations. @@ -123,7 +147,7 @@ typedef struct { // Initialize the configuration and set ALL of it's values to the defaults. // Call this before setting any particular field of it. -void msInitConfiguration(msConfiguration* config); +MS_PUBLIC void msInitConfiguration(msConfiguration* config); typedef enum { RESULT_SUCCESS = 0, @@ -132,34 +156,34 @@ typedef enum { } MSInterpretResult; // Allocate initialize and returns a new VM -MSVM* msNewVM(msConfiguration* config); +MS_PUBLIC MSVM* msNewVM(msConfiguration* config); // Clean the VM and dispose all the resources allocated by the VM. -void msFreeVM(MSVM* vm); +MS_PUBLIC void msFreeVM(MSVM* vm); // Compile and execut file at given path. -MSInterpretResult msInterpret(MSVM* vm, const char* file); +MS_PUBLIC MSInterpretResult msInterpret(MSVM* vm, const char* file); // Set a runtime error to vm. -void msSetRuntimeError(MSVM* vm, const char* format, ...); +MS_PUBLIC void msSetRuntimeError(MSVM* vm, const char* format, ...); // Returns the associated user data. -void* msGetUserData(MSVM* vm); +MS_PUBLIC void* msGetUserData(MSVM* vm); // Update the user data of the vm. -void msSetUserData(MSVM* vm, void* user_data); +MS_PUBLIC void msSetUserData(MSVM* vm, void* user_data); // Encode types to var. // TODO: user need to use vmPushTempRoot() for strings. -Var msVarBool(MSVM* vm, bool value); -Var msVarNumber(MSVM* vm, double value); -Var msVarString(MSVM* vm, const char* value); +MS_PUBLIC Var msVarBool(MSVM* vm, bool value); +MS_PUBLIC Var msVarNumber(MSVM* vm, double value); +MS_PUBLIC Var msVarString(MSVM* vm, const char* value); // Decode var types. // TODO: const char* should be copied otherwise it'll become dangling pointer. -bool msAsBool(MSVM* vm, Var value); -double msAsNumber(MSVM* vm, Var value); -const char* msAsString(MSVM* vm, Var value); +MS_PUBLIC bool msAsBool(MSVM* vm, Var value); +MS_PUBLIC double msAsNumber(MSVM* vm, Var value); +MS_PUBLIC const char* msAsString(MSVM* vm, Var value); #ifdef __cplusplus } // extern "C" diff --git a/ms_configure.py b/ms_configure.py deleted file mode 100644 index 6cbd4e9..0000000 --- a/ms_configure.py +++ /dev/null @@ -1,59 +0,0 @@ -import sys, os - -## A simple version of the build script. -MINI_BUILD_SCRIPT = '''\ -import os - -cc = 'gcc' ## '"tcc\\tcc"' - -sources = [ - 'src/types/name_table.c', - 'test/main.c', -] - -def add_sources(path): - for file in os.listdir(path): - if file.endswith('.c'): - sources.append( - path + '/' + file if path != '.' else file) -add_sources('src/') -add_sources('src/types/gen') - -cmd = '%s -Wno-int-to-pointer-cast -o miniscript -Iinclude %s' % (cc, ' '.join(sources)) -print(cmd) -os.system(cmd) - -''' - -def main(): - generate_files() - -def log(*msg): - print("[ms:configure.py]", end='') - for _msg in msg: - print(' ' + _msg, end='') - print() - -def generate_files(): - log("generating types/buffer source files") - sys.path.insert(1, 'src/types/') - import buffergen - ec = buffergen.gen() - - ## .bat files are just for quick rebuild of the buffer templates in windows. - if sys.platform == 'win32': - with open('src/types/gen.bat', 'w') as f: - f.write('python buffergen.py') - with open('src/types/clean.bat', 'w') as f: - f.write('python buffergen.py --clean') - - with open('build.py', 'w') as f: - f.write(MINI_BUILD_SCRIPT) - log('build.py generated') - - log("buffer source files generated") - - return ec - -if __name__ == '__main__': - main() \ No newline at end of file diff --git a/src/common.h b/src/common.h index a667696..d9ba18b 100644 --- a/src/common.h +++ b/src/common.h @@ -15,30 +15,6 @@ #include #include -// miniscript visibility macros. define MS_DLL for using miniscript as a -// shared library and define MS_COMPILE to export symbols. - -#ifdef _MSC_VER - #define _MS_EXPORT __declspec(dllexport) - #define MS_IMPORT __declspec(dllimport) -#elif defined(__GNUC__) - #define _MS_EXPORT __attribute__((visibility ("default"))) - #define _MS_IMPORT -#else - #define _MS_EXPORT - #define _MS_IMPORT -#endif - -#ifdef MS_DLL - #ifdef MS_COMPILE - #define MS_PUBLIC _MS_EXPORT - #else - #define MS_PUBLIC _MS_IMPORT - #endif -#else - #define MS_PUBLIC -#endif - // Set this to dump compiled opcodes of each functions. #define DEBUG_DUMP_COMPILED_CODE 0 diff --git a/src/core.c b/src/core.c index f15d765..03be80a 100644 --- a/src/core.c +++ b/src/core.c @@ -322,18 +322,20 @@ Var varAdd(MSVM* vm, Var v1, Var v2) { } break; case OBJ_LIST: + TODO; + case OBJ_MAP: case OBJ_RANGE: case OBJ_SCRIPT: case OBJ_FUNC: case OBJ_FIBER: case OBJ_USER: - TODO; + break; } } - vm->fiber->error = stringFormat(vm, "Unsupported operand types for operator '-' " + vm->fiber->error = stringFormat(vm, "Unsupported operand types for operator '+' " "$ and $", varTypeName(v1), varTypeName(v2)); return VAR_NULL; diff --git a/test/main.c b/src/main/main.c similarity index 100% rename from test/main.c rename to src/main/main.c diff --git a/src/types/.gitignore b/src/types/.gitignore index 555baf5..fb113d8 100644 --- a/src/types/.gitignore +++ b/src/types/.gitignore @@ -1,6 +1,4 @@ -## Ignore all generated source files. -*.gen.h -*.gen.c -gen/ -*.bat \ No newline at end of file +## Ignore the generated sources. +## TODO: use template and macros instead of generating the source. +gen/ \ No newline at end of file diff --git a/src/types/buffer.template.c b/src/types/buffer.c.template similarity index 100% rename from src/types/buffer.template.c rename to src/types/buffer.c.template diff --git a/src/types/buffer.template.h b/src/types/buffer.h.template similarity index 100% rename from src/types/buffer.template.h rename to src/types/buffer.h.template diff --git a/src/types/buffergen.py b/src/types/buffergen.py index 72690d2..8b91a4f 100644 --- a/src/types/buffergen.py +++ b/src/types/buffergen.py @@ -50,9 +50,9 @@ def _gen(): header = '' source = '' - with open('buffer.template.h', 'r') as f: + with open('buffer.c.template', 'r') as f: header = f.read() - with open('buffer.template.c', 'r') as f: + with open('buffer.h.template', 'r') as f: source = f.read() for _data in GEN_LIST: diff --git a/src/vm.c b/src/vm.c index 74a4935..10b1c14 100644 --- a/src/vm.c +++ b/src/vm.c @@ -60,6 +60,8 @@ void msInitConfiguration(msConfiguration* config) { MSVM* msNewVM(msConfiguration* config) { + // TODO: If the [config] is NULL, initialize a default one. + msReallocFn realloc_fn = defaultRealloc; void* user_data = NULL; if (config != NULL) { diff --git a/TODO.txt b/test/TODO.txt similarity index 100% rename from TODO.txt rename to test/TODO.txt diff --git a/test/benchmark/fib/fib.ms b/test/benchmark/fib/fib.ms index 25af6f9..f76d5e4 100644 --- a/test/benchmark/fib/fib.ms +++ b/test/benchmark/fib/fib.ms @@ -10,5 +10,5 @@ start = os.clock() for i in 0..10 print(fib(28)) end -print('elapsed: ', os.clock() - start, 's') +print('elapsed:', os.clock() - start, 's') diff --git a/test/benchmark/fib/fib.py b/test/benchmark/fib/fib.py index 2b7548a..768ac58 100644 --- a/test/benchmark/fib/fib.py +++ b/test/benchmark/fib/fib.py @@ -7,4 +7,4 @@ def fib(n): start = time.process_time() for i in range(0, 10): print(fib(28)) -print("elapsed: " + str(time.process_time() - start), 's') +print("elapsed: " + str(time.process_time() - start), ' s') diff --git a/test/msvcmake.bat b/test/msvcmake.bat new file mode 100644 index 0000000..54a0a28 --- /dev/null +++ b/test/msvcmake.bat @@ -0,0 +1,167 @@ +@rem ------------------------------------------------------------------------------ +@rem MIT License +@rem ------------------------------------------------------------------------------ +@rem +@rem Copyright (c) 2021 Thakee Nathees +@rem +@rem Permission is hereby granted, free of charge, to any person obtaining a copy +@rem of this software and associated documentation files (the "Software"), to deal +@rem in the Software without restriction, including without limitation the rights +@rem to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +@rem copies of the Software, and to permit persons to whom the Software is +@rem furnished to do so, subject to the following conditions: +@rem +@rem The above copyright notice and this permission notice shall be included in all +@rem copies or substantial portions of the Software. +@rem +@rem THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +@rem IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +@rem FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +@rem AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +@rem LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +@rem OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +@rem SOFTWARE. +@rem ------------------------------------------------------------------------------ + +@echo off + +:: TODO: Usage. +setlocal + +:: To set color. (Ref : https://stackoverflow.com/questions/2048509/how-to-echo-with-different-colors-in-the-windows-command-line) +SETLOCAL EnableDelayedExpansion +for /F "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do ( + set "DEL=%%a" +) + +if "%~1"=="" goto :ARGS_DONE +if "%~1"=="-h" goto :DISPLAY_HELP +if "%~1"=="-d" goto :SET_DLL_BUILD +goto :ARGS_DONE + +:DISPLAY_HELP +echo Usage: msvcbuild [opt] +echo -h Display the help message +echo -d Compile as a dynamic library +goto :END + +:SET_DLL_BUILD +set BUILD_DLL=true +goto :ARGS_DONE + +:ARGS_DONE + +if not defined INCLUDE goto :MSVC_INIT +goto :START + +:MSVC_INIT +call :ColorText 0f "Not running on MSVM prompt, searching for one..." +echo. + +:: Find vswhere +if exist "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" ( + set VSWHERE_PATH="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" +) else ( if exist "%ProgramFiles%\Microsoft Visual Studio\Installer\vswhere.exe" ( + set VSWHERE_PATH="%ProgramFiles%\Microsoft Visual Studio\Installer\vswhere.exe" +) else ( + call :ColorText 0c "Can't find vswhere.exe" + echo. + goto :NO_VS_PROMPT +)) + +:: Get the VC installation path +%VSWHERE_PATH% -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -latest -property installationPath > _path_temp.txt +set /p VSWHERE_PATH= < _path_temp.txt +del _path_temp.txt +if not exist "%VSWHERE_PATH%" ( + echo Error: can't find VisualStudio installation directory + goto :NO_VS_PROMPT +) + +call :ColorText 0f "Found at - " +echo %VSWHERE_PATH% + +:: Initialize VC for X86_64 +call "%VSWHERE_PATH%\VC\Auxiliary\Build\vcvars64.bat" +if errorlevel 1 goto :NO_VS_PROMPT +call :ColorText 0f "Initialized MSVC x86_64" +echo. +goto :START + +:NO_VS_PROMPT +echo You must open a "Visual Studio .NET Command Prompt" to run this script +goto :END + +:START + +if not exist "bin" md "./bin" + +set ADDNL_INCLUDE=/I..\include +set ADDNL_CPPFLAGS=/EHsc /MDd + +if "%BUILD_DLL%" neq "true" goto :COMPILE +set ADDNL_DEFINES=/DMS_DLL /DMS_COMPILE + +:COMPILE +call :ColorText 0f "Building porcess started" +echo. + +set object_files= +:: Recursively loop all files in '.' matching *.c and compile. +for /r "..\src" %%f in (*.c) do ( + for %%i in ("%%f") do ( + call set "object_files=%%object_files%% bin\%%~ni.obj" + cl /nologo /c %ADDNL_INCLUDE% %ADDNL_DEFINES% %ADDNL_CPPFLAGS% "%%f" /Fobin\%%~ni.obj + if errorlevel 1 goto :FAIL + ) +) + +if "%BUILD_DLL%"=="true" goto :LINK_DLL + +call :ColorText 0a "pocket.lib" +echo. +lib /nologo /OUT:bin\pocket.lib %object_files% +if errorlevel 1 goto :FAIL + +call :ColorText 0a "pocket.exe" +echo. + +cl /nologo %ADDNL_CPPFLAGS% %ADDNL_INCLUDE% %object_files% /Febin\pocket.exe +if errorlevel 1 goto :FAIL + +goto :CLEAN + +:LINK_DLL +call :ColorText 0a "pocket.dll" +echo. +link /nologo /dll /out:bin\pocket.dll /implib:bin\pocket.lib %object_files% + +:CLEAN + +for %%o in (%object_files%) do ( + del "%%o" +) + +echo. +call :ColorText 0a "Compilation Success" +echo. + +goto :END +:FAIL +call :ColorText 0c "Build failed. See the error messages." +echo. + +:END +endlocal + +goto :eof + +:: To set color. (Ref : https://stackoverflow.com/questions/2048509/how-to-echo-with-different-colors-in-the-windows-command-line) +:ColorText +echo off + "%~2" +findstr /v /a:%1 /R "^$" "%~2" nul +del "%~2" > nul 2>&1 +goto :eof + +