diff --git a/README.md b/README.md index 291e8ee..5439a1c 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,15 @@

-**Pocketlang** is a small (~3000 semicollons) and fast functional programming language written in C. It's syntactically similar to Ruby 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. +**Pocketlang** is a small (~3000 semicollons) and fast functional programming +language written in C. It's syntactically similar to Ruby 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. -The language is written using [Wren Language](https://wren.io/) and their wonderful book [craftinginterpreters](http://www.craftinginterpreters.com/) as a reference. +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 @@ -25,31 +31,52 @@ for i in 0..10 end ``` -## Performance! +## Performance -The source files used to run benchmarks could be found at `test/benchmarks/` directory. They were ran using a small python script in the test directory. -- PC: ASUS N552VX, Intel Core i7-6700HQ 2.6GHz, 12GB SODIMM Ram -- Lnaguages: pocketlang (pre-alpha), wren v0.3.0, python v3.7.4, ruby v2.7.2, +All the tests are ran on, Windows10 (64bit), ASUS N552VX, Intel Core i7-6700HQ 2.6GHz +with 12GB SODIMM Ram. And the language versions are: pocketlang (pre-alpha), wren v0.3.0, +python v3.7.4, ruby v2.7.2. -![preformance2](https://user-images.githubusercontent.com/41085900/120123257-6f043280-c1cb-11eb-8c20-a42153268a0f.png) - - -When it comes to loops pocketlang much faster (even faster than [wren](https://wren.io/), the language I'm using as a reference) because we have dedicated opcode instructions for iterations and calling builtin functions. And it's is a functional language, which makes is possible to avoid object orianted/ class instance creation overhead. +![preformance](https://user-images.githubusercontent.com/41085900/120123257-6f043280-c1cb-11eb-8c20-a42153268a0f.png) +The source files used to run benchmarks could be found at `test/benchmarks/` +directory. They were ran using a small python script in the test directory. ## Building From Source -It can be build from source easily without any depencency, requirenments or even a build system, just a c99 compatible compiler is enough. It can be compiled with the following command. +It can be build from source easily without any depencency, or additional +requirenments except for a c99 compatible compiler. And build systems are +optional. It can be compiled with the following command. -#### gcc/mingw +#### GCC ``` gcc -o pocket cli/*.c src/*.c -Isrc/include -lm -Wno-int-to-pointer-cast ``` -#### msvc +#### MSVC ``` cl /Fepocket cli/*.c src/*.c /Isrc/include && rm *.obj ``` -For other compilers it's the same (If you weren't able to compile it, please report by [opening an issue](https://github.com/ThakeeNathees/pocketlang/issues/new)). In addition you can use some of our build scripts (Makefile, batch script for MSVC, SCons) in the `build/` directory. For more see [build from source docs](https://thakeenathees.github.io/pocketlang/Getting%20Started/build%20from%20source.html). +### For other compiler/IDE + +1. Create an empty project file / makefile. +2. Add all C files in the src directory. +3. Add all C files in the cli directory (**not** recursively). +4. Add src/include to include path. +5. Compile. + +If you weren't able to compile it, please report by [opening an issue](https://github.com/ThakeeNathees/pocketlang/issues/new)). +In addition you can use some of our build scripts (Makefile, batch script for MSVC, SCons) +in the `build/` directory. For more see [build from source docs](https://thakeenathees.github.io/pocketlang/Getting%20Started/build%20from%20source.html). + + +## References +- Bob Nystrom.(2021) *craftinginterpreters* [online] Available at: www.craftinginterpreters.com/ (Accessed January 2021) + +- leonard schütz. (2020) *Dynamic Typing and NaN Boxing* [online] Available at: https://leonardschuetz.ch/blog/nan-boxing/ (Accessed December 2020) + +- Bob Nystrom.(2011) *Pratt Parsers: Expression Parsing Made Easy* [online] Avaliable at: http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/ (Accessed December 2020) + +- Carol E. Wolf of Pace University, adapted by P. Oser. *The Shunting Yard Algorithm* [online] Available at: http://mathcenter.oxford.emory.edu/site/cs171/shuntingYardAlgorithm/ (Accessed September 2020) diff --git a/docs/pages/Getting Started/build from source.md b/docs/pages/Getting Started/build from source.md index e24b123..13e64f7 100644 --- a/docs/pages/Getting Started/build from source.md +++ b/docs/pages/Getting Started/build from source.md @@ -3,11 +3,13 @@ ## Without a build script -Pocketlang has zero dependencies and you don't even require a build system, just a c99 compiler is enought, and it can be compiled with the following command. +It can be build from source easily without any depencency, or additional +requirenments except for a c99 compatible compiler. And build systems are +optional. It can be compiled with the following command. Using gcc ``` -gcc -o pocket cli/*.c src/*.c -Isrc/include -lm +gcc -o pocket cli/*.c src/*.c -Isrc/include -lm -Wno-int-to-pointer-cast ``` Using MSVC @@ -15,11 +17,22 @@ Using MSVC cl /Fepocket cli/*.c src/*.c /Isrc/include && rm *.obj ``` -For other compilers it's the same (If you weren't able to compile it with any c99 compatible compiler, please report by [opening an issue](https://github.com/ThakeeNathees/pocketlang/issues/new)). And add ` -Wno-int-to-pointer-cast` for gcc to suppress those warnings emitted when nan-tagging is enabled. +For other compiler/IDE + +1. Create an empty project file / makefile. +2. Add all C files in the src directory. +3. Add all C files in the cli directory (**not** recursively). +4. Add src/include to include path. +5. Compile. + +If you weren't able to compile it, please report by [opening an issue](https://github.com/ThakeeNathees/pocketlang/issues/new)). ## Using a build script -You could find some of the build script for different build system in the `build/` direcroty. If you don't find a scirpt for your prifered system, request on github by [opening an issue](https://github.com/ThakeeNathees/pocketlang/issues/new) or feel free to contribute one. +You could find some of the build script for different build system in the `build/` +direcroty. If you don't find a scirpt for your prifered system, request on github +by [opening an issue](https://github.com/ThakeeNathees/pocketlang/issues/new) or +feel free to contribute one. ## Makefile @@ -27,19 +40,37 @@ You could find some of the build script for different build system in the `build cd build && make ``` +I haven't tested the makefile on different platforms except for "windows subsystem for linux". +And the makefile is still need to be imporved. If you find any problems with the script or +have any improvements, let us know in [github](https://github.com/ThakeeNathees/pocketlang). + + ## Batch script with MSVC ``` cd build && build ``` -You don't require to run the script from a Visual Studio .NET Command Prompt, It'll search for the MSVS installation path and use it to compile. But if it can't, try running on VS command prompt. + +You don't need to run the script from a Visual Studio .NET Command Prompt, +It'll search for the MSVS installation path and use it to compile. But if it +can't, try running on VS command prompt. ## SCons -pocketlang mainly focused on [scons](https://www.scons.org/), and it's recommended to use it for contributions since it has various configurations and compiler support. It's a python based build system. You need to have python 3.6+ installed in your development environment. To install scons run `python3 -m pip install scons`. Make sure it's version is 3.0+ and for Visual Studio 2019 it require v3.1.1+. In Linux if scons using python2 instead of 3 you'll have to edit `/usr/local/bin/scons` or `~/.local/bin/scons` to ensure that it points to `/usr/bin/env python3` and not `python` +pocketlang mainly focused on [scons](https://www.scons.org/), and it's +recommended to use it for contributions since it has various configurations +and compiler support. It's a python based build system. You need to have +python 3.6+ installed in your development environment. To install scons run +`python3 -m pip install scons`. Make sure it's version is 3.0+ and for Visual +Studio 2019 it require v3.1.1+. In Linux if scons using python2 instead of 3 +you'll have to edit `/usr/local/bin/scons` or `~/.local/bin/scons` to ensure +that it points to `/usr/bin/env python3` and not `python` ``` cd build && scons ``` -You can specify the number of jobs scons to use to speed up the building process using the -j flag (-j6, -j8). To generate Visual Studio project files add `vsproj=true` argument when building. To compile using mingw in windows use `use_mingw=true` argument. If your build failed feel free to [open an issue](https://github.com/ThakeeNathees/pocketlang/issues/new). +You can specify the number of jobs scons to use to speed up the building process +using the -j flag (-j6, -j8). To generate Visual Studio project files add `vsproj=true` +argument when building. To compile using mingw in windows use `use_mingw=true` argument. +If your build failed feel free to [open an issue](https://github.com/ThakeeNathees/pocketlang/issues/new). diff --git a/docs/pages/Getting Started/contributing.md b/docs/pages/Getting Started/contributing.md index 5d6d891..00adde6 100644 --- a/docs/pages/Getting Started/contributing.md +++ b/docs/pages/Getting Started/contributing.md @@ -1,4 +1,3 @@ # Contributing - -Lorem **ipsum** dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. \ No newline at end of file +TODO diff --git a/docs/pages/Language API/functions.md b/docs/pages/Language API/functions.md index 84e62c3..3e521d6 100644 --- a/docs/pages/Language API/functions.md +++ b/docs/pages/Language API/functions.md @@ -1,22 +1,4 @@ # Functions -```ruby -def f() - print('test') -end -``` - -## Another title - -Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud - -```ruby -fn = func print('test') end - -f2 = func(arg) print('arg =', arg) end -``` - -Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud - - +TODO diff --git a/docs/pages/Language API/variables.md b/docs/pages/Language API/variables.md index 492055b..9e42f83 100644 --- a/docs/pages/Language API/variables.md +++ b/docs/pages/Language API/variables.md @@ -1,17 +1,5 @@ # Variables -Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud -```ruby -from os import clock as c - -some_variable = 12 -print(some_variable) ## prints 12 -some_variable = 'testing' -print(some_variable) ## prints 'testing' -``` - -## More lorem ipsum - -Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud \ No newline at end of file +TODO diff --git a/src/buffers.c b/src/buffers.c index 09bbcb2..b7660d4 100644 --- a/src/buffers.c +++ b/src/buffers.c @@ -8,8 +8,8 @@ #include "utils.h" #include "vm.h" -// TODO: Replace bufferFill with bufferWrite, and (maybe) shrink the buffer if -// it's more than enough. +// The buffer "template" implementation of diferent types, defined in the +// buffers.h header. #define DEFINE_BUFFER(M__NAME, M__NAME_L, M__TYPE) \ void M__NAME_L##BufferInit(M__NAME##Buffer* self) { \ diff --git a/src/buffers.h b/src/buffers.h index 5b59baf..ce58029 100644 --- a/src/buffers.h +++ b/src/buffers.h @@ -7,7 +7,16 @@ #define BUFFERS_TEMPLATE_H #include "common.h" -#include "include/pocketlang.h" + +// The macro 'DECLARE_BUFFER()' emulate the C++ template to declare and define +// different types of buffer objects. + +// A buffer of type 'T' will contain a heap allocated array of 'T' with the +// capacity of 'Tbuffer.capacity' as 'T* Tbuffer.data'. When the capacity is +// filled with 'T' values (ie. Tbuffer.count == Tbuffer.capacity) the buffer's +// internal data array will be reallocate to a capacity of 'GROW_FACTOR' times +// it's last capacity. + #define DECLARE_BUFFER(M__NAME, M__NAME_L, M__TYPE) \ typedef struct { \ diff --git a/src/compiler.c b/src/compiler.c index a1a4e79..44f38b4 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -39,6 +39,10 @@ // available in C++98. #define ERROR_MESSAGE_SIZE 256 +/***************************************************************************** + * TOKENS * + *****************************************************************************/ + typedef enum { TK_ERROR = 0, @@ -157,40 +161,44 @@ typedef struct { // List of keywords mapped into their identifiers. static _Keyword _keywords[] = { - { "module", 6, TK_MODULE }, - { "from", 4, TK_FROM }, - { "import", 6, TK_IMPORT }, - { "as", 2, TK_AS }, - { "def", 3, TK_DEF }, - { "native", 6, TK_NATIVE }, - { "func", 4, TK_FUNC }, - { "end", 3, TK_END }, - { "null", 4, TK_NULL }, - { "in", 2, TK_IN }, - { "and", 3, TK_AND }, - { "or", 2, TK_OR }, - { "not", 3, TK_NOT }, - { "true", 4, TK_TRUE }, - { "false", 5, TK_FALSE }, - { "do", 2, TK_DO }, - { "then", 4, TK_THEN }, - { "while", 5, TK_WHILE }, - { "for", 3, TK_FOR }, - { "if", 2, TK_IF }, - { "elif", 4, TK_ELIF }, - { "else", 4, TK_ELSE }, - { "break", 5, TK_BREAK }, + { "module", 6, TK_MODULE }, + { "from", 4, TK_FROM }, + { "import", 6, TK_IMPORT }, + { "as", 2, TK_AS }, + { "def", 3, TK_DEF }, + { "native", 6, TK_NATIVE }, + { "func", 4, TK_FUNC }, + { "end", 3, TK_END }, + { "null", 4, TK_NULL }, + { "in", 2, TK_IN }, + { "and", 3, TK_AND }, + { "or", 2, TK_OR }, + { "not", 3, TK_NOT }, + { "true", 4, TK_TRUE }, + { "false", 5, TK_FALSE }, + { "do", 2, TK_DO }, + { "then", 4, TK_THEN }, + { "while", 5, TK_WHILE }, + { "for", 3, TK_FOR }, + { "if", 2, TK_IF }, + { "elif", 4, TK_ELIF }, + { "else", 4, TK_ELSE }, + { "break", 5, TK_BREAK }, { "continue", 8, TK_CONTINUE }, - { "return", 6, TK_RETURN }, + { "return", 6, TK_RETURN }, { NULL, 0, (TokenType)(0) }, // Sentinal to mark the end of the array }; -// Compiler Types //////////////////////////////////////////////////////////// +/***************************************************************************** + * COMPILIER INTERNAL TYPES * + *****************************************************************************/ // Precedence parsing references: // https://en.wikipedia.org/wiki/Shunting-yard_algorithm +// http://mathcenter.oxford.emory.edu/site/cs171/shuntingYardAlgorithm/ +// http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/ typedef enum { PREC_NONE, diff --git a/src/compiler.h b/src/compiler.h index b86e921..5edce88 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -9,10 +9,21 @@ #include "common.h" #include "var.h" +// Pocketlang compiler is a single pass compiler, which means it doesn't go +// throught the basic compilation pipline such as lexing, parsing (AST), +// analyzing, intermediate codegeneration, and target codegeneration one by one +// instead it'll generate the target code as it reads the source (directly from +// lexing to codegen). Despite it's faster than multipass compilers, we're +// restricted syntax-wise and from compiletime optimizations, yet we support +// "forward names" to call functions before they defined (unlike C/Python). typedef struct Compiler Compiler; +// This will take source code as a cstring, compiles it to pocketlang bytecodes +// and append them to the script's implicit main (the $SourceBody function). bool compile(PKVM* vm, Script* script, const char* source); +// Mark the heap allocated ojbects of the compiler at the garbage collection +// called at the marking phase of vmCollectGarbage(). void compilerMarkObjects(PKVM* vm, Compiler* compiler); #endif // COMPILER_H diff --git a/src/utils.c b/src/utils.c index bac9b2f..45d7ae2 100644 --- a/src/utils.c +++ b/src/utils.c @@ -64,14 +64,21 @@ uint32_t utilHashNumber(double num) { uint32_t utilHashString(const char* string) { // FNV-1a hash. See: http://www.isthe.com/chongo/tech/comp/fnv/ - uint32_t hash = 2166136261u; + +#define FNV_prime_32_bit 16777619u +#define FNV_offset_basis_32_bit 2166136261u + + uint32_t hash = FNV_offset_basis_32_bit; for (const char* c = string; *c != '\0'; c++) { hash ^= *c; - hash *= 16777619; + hash *= FNV_prime_32_bit; } return hash; + +#undef FNV_prime_32_bit +#undef FNV_offset_basis_32_bit } /**************************************************************************** diff --git a/src/var.h b/src/var.h index 6a07427..73a19d6 100644 --- a/src/var.h +++ b/src/var.h @@ -203,7 +203,7 @@ struct Object { struct String { Object _super; - uint32_t hash; //< Hash value of the string. + uint32_t hash; //< 32 bit hash value of the string. uint32_t length; //< Length of the string in \ref data. uint32_t capacity; //< Size of allocated \ref data. char data[DYNAMIC_TAIL_ARRAY]; diff --git a/src/vm.h b/src/vm.h index 4e99822..db5c178 100644 --- a/src/vm.h +++ b/src/vm.h @@ -133,12 +133,12 @@ PkHandle* vmNewHandle(PKVM* self, Var value); // working set '------------------------' // // First we preform a tree traversel from all the vm's root objects. such as -// temp references, handles, vm's running fiber, current compiler (if it has -// any) etc. Mark them (ie. is_marked = true) and add them to the working set -// (the gray_list). Pop the top object from the working set add all of it's -// referenced objects to the working set and mark it black (try-color marking) -// We'll keep doing this till the working set become empty, and at this point -// any object which isn't marked is a garbage. +// stack values, temp references, handles, vm's running fiber, current +// compiler (if it has any) etc. Mark them (ie. is_marked = true) and add +// them to the working set (the gray_list). Pop the top object from the +// working set add all of it's referenced objects to the working set and mark +// it black (try-color marking) We'll keep doing this till the working set +// become empty, and at this point any object which isn't marked is a garbage. // // Every single heap allocated objects will be in the VM's link list. Those // objects which are reachable have marked (ie. is_marked = true) once the