diff --git a/blombly.exe b/blombly.exe index 9fbc6ec..e4cb721 100755 Binary files a/blombly.exe and b/blombly.exe differ diff --git a/docs/advanced/libraries.md b/docs/advanced/libraries.md index 9a338ca..fdf7f43 100644 --- a/docs/advanced/libraries.md +++ b/docs/advanced/libraries.md @@ -7,8 +7,6 @@ detailed here. ## env -**Currently the env library is not working properly** - This library provides an alternative to traditional import statements helps organizes and versions dependencies. It essentially forms a programmatically-managed diff --git a/docs/advanced/semitypes.md b/docs/advanced/semitypes.md index b2cf4d4..b8528a4 100644 --- a/docs/advanced/semitypes.md +++ b/docs/advanced/semitypes.md @@ -6,7 +6,7 @@ or are transformed to appropriate data, therefore introducing type correctness g for subsequent code. At its core, this is equivalent to expressing method calls of one argument. However, code writting is drastically simplified: -- Conversions are easily chained using much fewer symbols. +- Conversions are chained using fewer symbols and less nesting. - Conversions are read as variable type semantics, which we dub semi-types. ## Type conversion diff --git a/libs/def/.bb b/libs/def/.bb new file mode 100644 index 0000000..f074968 --- /dev/null +++ b/libs/def/.bb @@ -0,0 +1,41 @@ +final def::INFO as { + name = "def"; + author = "Emmanouil Krasanakis"; + license = "Apache 2.0"; + version = "1.0"; + release = 0; + year = 2024; + doc = " + \n Introduces class and function definition semantics + \n that make code look similar to other languages. + \n + \n def::fn + \n ------- + \n Defines a final code block with a given name and + \n arguments. Positional arguments (in fact, a runnable + \n default code block) are also supported like below. + \n Additional arguments can also be provided. + \n + \n | def::fn adder(x, y|bias=0) \{return x+y+bias\} + \n + \n def::class + \n Defines a class through its constructor. The + \n constructor is final and callable. Here is an + \n example: + \n + \n | def::class Dog(name) \{def::uses name;\} + "; +} + + +#include "libs/def/fn" +#include "libs/def/class" + +// enables the +#macro {def::simplify;} as { + #macro {fn} as {def::fn} + #macro {module} as {def::module} + #macro {abstract} as {def::abstract} + #macro {uses} as {def::uses} + #macro {class} as {def::class} +} \ No newline at end of file diff --git a/libs/oop/class.bb b/libs/def/class.bb similarity index 69% rename from libs/oop/class.bb rename to libs/def/class.bb index 2318b80..d329b44 100644 --- a/libs/oop/class.bb +++ b/libs/def/class.bb @@ -1,24 +1,24 @@ // class definition -#macro (oop::class @name(@args) {@code}) = { - final @name(@args) = { +#macro {def::class @name(@args) {@code}} as { + def::fn @name(@args) { #spec type="class"; #spec name=#stringify(@name); return new { final type = @name; - oop::uses @name; + def::uses @name; @code } } } // uses definitition -#macro (oop::uses @name;) = { +#macro {def::uses @name;} as { final @name = @name; } // abstract definition -#macro (oop::abstract @name {@code}) = { +#macro {def::abstract @name {@code}} as { final @name = { #spec type="abstract"; #spec name=#stringify(@name); @@ -27,7 +27,7 @@ } // module definition -#macro (oop::module @name {@code}) = { +#macro {def::module @name {@code}} as { final @name = new { final type="module"; final name=#stringify(@name); diff --git a/libs/oop/fn.bb b/libs/def/fn.bb similarity index 79% rename from libs/oop/fn.bb rename to libs/def/fn.bb index d681075..cefce87 100644 --- a/libs/oop/fn.bb +++ b/libs/def/fn.bb @@ -1,5 +1,5 @@ // function with only positional arguments (overriden by subsequent versions) -#macro (oop::fn @name(@args){@code}) = { +#macro {def::fn @name(@args){@code}} as { final @name(@args) = { #spec type="fn"; #spec name=#stringify(@name); @@ -7,7 +7,7 @@ } } // function with no arguments -#macro (oop::fn @name(){@code}) = { +#macro {def::fn @name(){@code}} as { final @name = { #spec type="fn"; #spec name=#stringify(@name); @@ -15,7 +15,7 @@ } } // function with defaults -#macro (oop::fn @name(@args | @defaults){@code}) = { +#macro {def::fn @name(@args | @defaults){@code}} as { final @name(@args) = { #spec type="fn"; #spec name=#stringify(@name); @@ -24,7 +24,7 @@ } } // function with only defaults (identified because it has an assignment) -// #macro (oop::fn @name(@arg = @defaults){@code}) = { +// #macro (def::fn @name(@arg = @defaults){@code}) = { // final @name = { // #spec type="fn"; // #spec name=#stringify(@name); diff --git a/libs/env.bb b/libs/env.bb index 045cacf..b8038e7 100644 --- a/libs/env.bb +++ b/libs/env.bb @@ -2,7 +2,7 @@ final env::INFO as { name = "env"; author = "Emmanouil Krasanakis"; license = "Apache 2.0"; - version = "1.0"; + version = "1.1"; release = 0; year = 2024; doc = " @@ -18,7 +18,7 @@ final env::INFO as { \n - env::include(library); \n Includes a library by its name (as a string). \n - \n - env::include(library|version=...;minrelease=...); + \n - env::include(library|version=..;minrelease=..); \n Includes a library with a specific version and \n minimum release number. You may ommit the latter. \n @@ -64,12 +64,16 @@ final env::dependencies = list(new{env::INFO:}); // check whether imnported library satisfies the version or release while(dependency as std::next(#of iter(env::dependencies))) if(dependency.name==@info.name) { - if((version as version) and (dependency.version!=version)) - fail("Incompatible versions for library {@lib}: - \nimported version is {dependency.version} but {version} is required."); - if((minrelease as minrelease) and (dependency.release symbolUsageCount; + for (const auto& command : program) { + if(!command->enabled || command->args.size()==0) + continue; + if(command->args[0]=="END" || command->args[0]=="BEGIN" || command->args[0]=="BEGINFINAL" || command->args[0]=="final" || command->args[0]=="exists") + continue; + for (size_t j = 2; j < command->args.size(); ++j) { + const std::string& symbol = command->args[j]; + if (symbol == "LAST") + bberror("Internal error: the LAST keyword has been deprecated"); + if (symbol != "#") + symbolUsageCount[symbol]++; + } + } + changes = 0; + for (int i=0;ienabled) + continue; + if(command->args[0]=="exists" && command->args.size() && symbolUsageCount[command->args[1]]==0) { + command->enabled = false; + ++changes; + continue; + } + if(command->args.size()<=1) + continue; + if(command->args[0]=="final" && command->args.size()>=3 && symbolUsageCount[command->args[2]]==0) { + command->enabled = false; + ++changes; + continue; + } + if(command->args[0]=="BUILTIN" && command->args.size() && symbolUsageCount[command->args[1]]==0) { + command->enabled = false; + ++changes; + continue; + } + if((command->args[0]=="IS" || command->args[0]=="AS") && command->args.size() && symbolUsageCount[command->args[1]]==0) { + command->enabled = false; + ++changes; + continue; + } + if(command->args[0]!="BEGIN" && command->args[0]!="BEGINFINAL") + continue; + if(symbolUsageCount[command->args[1]]!=0) + continue; + // std::cout << "removing "<args[0]<<" "<args[1]<<" "<enabled<<"\n"; + i = i+1; + int depth = 1; + ++changes; + command->enabled = false; + while(ienabled = false; + if(program[i]->args[0]=="BEGIN" || program[i]->args[0]=="BEGINFINAL") + depth += 1; + if(program[i]->args[0]=="END") + depth -= 1; + if(depth==0) + break; + ++i; + } + } + } // save the compiled code to the destination file diff --git a/src/utils/tokenizer.cpp b/src/utils/tokenizer.cpp index 587135d..056a795 100644 --- a/src/utils/tokenizer.cpp +++ b/src/utils/tokenizer.cpp @@ -127,7 +127,7 @@ std::vector tokenize(const std::string& text, const std::string& file) { else inComment = false; } - if (c == '/' && i < text.size() - 1 && text[i + 1] == '/') { + if (c == '/' && i < text.size() - 1 && text[i + 1] == '/' && !inString) { wordStream.str(""); // Clear the stream inComment = true; continue; @@ -170,6 +170,11 @@ std::vector tokenize(const std::string& text, const std::string& file) { } if (inString) { + if (c == '\\' && i