Package: dreamberd
DreamBerd InterpreterThis is the interpreter for the perfect programming language. It is made in Python, for the sole reason that the interpreter can itself be interpreted. Future plans include creating a DreamBerd interpreter in DreamBerd, so that the DreamBerd Interpreter can be passed into the DreamBerd Interpreter Interpreter, which is then interpreted by the DreamBerd Interpreter Interpreter Interpreter (a.k.a. Python). This may or may not be created due to difficulty moving everything over and whatnot. I'll try though.This is incredibly slow. My implementation of DreamBerd is suboptimal, which itself runs on a subperformant language (Python), which runs on a pretty fast language (C). However, speed was never a focus in creating my interpreter for DreamBerd and shouldn't be - it's not a language meant for day-to-day use - it's a work of art.InstallationYou can install DreamBerd from PyPi, by doing any the following:$ pip install dreamberd 
$ pip install "dreamberd[input, globals]"
$ pip install "dreamberd[input]"
$ pip install "dreamberd[globals]"Each of these commands installs DreamBerd with the respective dependencies.inputinstalls thepynputpackage and allows the use ofafterstatements and event watchers.globalsinstallsPyGithuband allows you to declareconst const constvariables that are publically stored using GitHub. Note: to use the latter, you must enter aPersonal Access Tokenin theGITHUB_ACCESS_TOKENenvironment variable.UsageNow that you have installed DreamBerd, you can run the REPL using the$ dreamberdcommand, or you can run a file using$ dreamberd FILE. Usage instructions here:usage: dreamberd [-h] [-s] [file]

positional arguments:
  file                  the file containing your DreamBerd code

options:
  -h, --help            show this help message and exit
  -s, --show-traceback  show the full Python trackback upon errorsTODOAdd another expression type which is just the dot operator, used for indexing and accessing namesBetter debugging (pretty limited for the time being)A much better standard libraryAllow for declaring basic objects with {} and other things.Add a way to deal with file objectsAbsent FeaturesThe goal of this project is to implement every feature from the DreamBerd language. A list of features is in the README file of the project, linkedhere. Here is a working list of features that there is no chance I will implement (new features may be added - or I should say, removed - as I work on this project and realize I'm too stupid to implement them):DB3X: I am not going to even try to parse XML AND parse DB code.Regex: Since type hints seem to not even do anything there is no point in implementing a Regex parser."Variable Hoisting" (being able to declare variables with a negative lifetime): Given the fact that keywords can be renamed and reassigned in this language, it does not make sense to implement this as the following breaks:print(name)varconst="lol";constconstname<-2>="Jake";It is impossible to evaluate the expression on the right side of thenamedeclaration after the print statement. Additionally, doing so doesn't account for possible renaming of keywords in the second line.Any sort of autocomplete requires more brainpower than I am willing to put in.To my knowledge, everything else has been or will be implemented.Implemented FeaturesThese are features that are implemented according to theDreamBerd specificationin this interpreter.Exclamation Marks!Be bold! End every statement with an exclamation mark!print("Hello world")!If you're feeling extra-bold, you can use even more!!!print("Hello world")!!!If you're unsure, that's ok. You can put a question mark at the end of a line instead. It prints debug info about that line to the console for you.print("Hello world")?You might be wondering what DreamBerd uses for the 'not' operator, which is an exclamation mark in most other languages. That's simple - the 'not' operator is a semi-colon instead.if(;false){print("Hello world")!}DeclarationsThere are four types of declaration. Constant constants can't be changed in any way.constconstname="Luke"!Constant variables can be edited, but not re-assigned.constvarname="Luke"!name.pop()!name.pop()!Variable constants can be re-assigned, but not edited.varconstname="Luke"!name="Lu"!Variable variables can be re-assigned and edited.varvarname="Luke"!name="Lu"!name.push("k")!name.push("e")!Immutable DataNew for 2023!Mutable data is an anti-pattern. Use theconst const constkeyword to make a constant constant constant. Its value will become constant and immutable, and willnever change. Please be careful with this keyword, as it is very powerful, and will affect all users globally forever.constconstconstpi=3.14!Notes About ImplementationThis is added by me (the interpreter)! I wanted to share how this works.Thanks tothis repofor helpful reference for issues and actions in Python.To store public globals, the following steps are taken:On the user's side, open a GitHub issue with a title of the formatCreate Public Global: {name};;;{confidence}and the body containing the pickled version of the value.Then, run a GitHub workflow that puts the issue body into a file underglobal_objects/and add an entry topublic_globals.txtthat contains thename;;;id;;;confidenceFinally, to retrieve these values, the content of each of these files is fetched and converted back into values.NamingBoth variables and constants can be named with any Unicode character or string.constconstfirstAlphabetLetter='A'!varconst👍=True!varvar1️⃣=1!This includes numbers, and other language constructs.constconstunchanging=const!unchangingunchanging5=4!print(2+2===5)!//trueArraysSome languages start arrays at0, which can be unintuitive for beginners. Some languages start arrays at1, which isn't representative of how the code actually works. DreamBerd does the best of both worlds: Arrays start at-1.constconstscores=[3,2,5]!print(scores[-1])!//3print(scores[0])!//2print(scores[1])!//5New for 2022!You can now use floats for indexes too!constvarscores=[3,2,5]!scores[0.5]=4!print(scores)!//[3, 2, 4, 5]WhenIn case you really need to vary a variable, thewhenkeyword lets you check a variable each time it mutates.constvarhealth=10!when(health=0){print("You lose")!}Technical InfoHi! It's me again. I took some creative liberty implementing thewhenstatement, here's how it works:When defined, gather a list of names that are used in the expression of the statement.If a variable is detected, cause the when satement to watch that variable.This is done in order to avoid watching names instead of variables when, say, a different variable with the same name is defined in a different scope.Speaking of scope, when statements for which changes are detected in a different scope (from that of definition)use that scope within their code.Looking back on my design decision, I am probably going to change this to make them always use the scope where they were defined.Additionally, if a variable detected contains a mutable value, that mutable value is also watched, so the following code detects a change:constvarl=[1,2,3]!when(l.length===4){printl!}constvarl_alias=l!l_alias[1.5]=4!// triggers the when statementTherefore, the when statement can contain as complex an expression as desired. One small pitfall is that I've implemented it with recursion, which may cause performance issues (although I don't really care about performance, obvious in the fact that this is in Python).LifetimesDreamBerd has a built-in garbage collector that will automatically clean up unused variables (note: this is simply Python's garbage collector, I didn't implement anything). However, if you want to be extra careful, you can specify a lifetime for a variable, with a variety of units.constconstname<2>="Luke"!// lasts for two linesconstconstname<20s>="Luke"!// lasts for 20 secondsBy default, a variable will last until the end of the program. But you can make it last in between program-runs by specifying a longer lifetime.constconstname<Infinity>="Luke"!// lasts foreverYes, this is a thing. It stores your variables and values to a folder in your home directory.LoopsLoops are a complicated relic of archaic programming languages. In DreamBerd, there are no loops.BooleansBooleans can betrue,falseormaybe.constvarkeys={}!after"keydown"{keys[event.key]=true!}after"keyup"{keys[event.key]=false!}functionisKeyDown(key)=>{if(keys[key]=undefined){returnmaybe!}returnkeys[key]!}Technical info:Booleans are stored as one-and-a-half bits.ArithmeticDreamBerd has significant whitespace. Use spacing to specify the order of arithmetic operations.print(1+2*3)!//7print(1+2*3)!//9Unlike some other languages, DreamBerd allows you to use the caret (^) for exponentiation.print(1^1)!// 1print(2^3)!// 8You can also use the number name, for example:print(one+two)!// 3print(twentytwo+thirtythree)!// 55Yes, the second line is also valid. In an effort to preserve my sanity, I have limited this quirk to all numbers up to 99. After that, you're on your own.IndentsWhen it comes to indentation, DreamBerd strikes a happy medium that can be enjoyed by everyone: All indents must be 3 spaces long.functionmain()=>{print("DreamBerd is the future")!}-3 spaces is also allowed.functionmain()=>{print("DreamBerd is the future")!}Note: Your code will err if you have indents that are not a multiple of three.EqualityJavaScript lets you do different levels of comparison.==for loose comparison, and===for a more precise check. DreamBerd takes this to another level.You can use==to do a loose check.3.14=="3.14"!// trueYou can use===to do a more precise check.3.14==="3.14"!// falseYou can use====to be EVEN MORE precise!constconstpi=3.14!print(pi====pi)!// trueprint(3.14====3.14)!// falseprint(3.14====pi)!// falseIf you want to be much less precise, you can use=.3=3.14!//trueFunctionsTo declare a function, you can use any letters from the wordfunction(as long as they're in order):functionadd(a,b)=>a+b!funcmultiply(a,b)=>a*b!funsubtract(a,b)=>a-b!fndivide(a,b)=>a/b!functipower(a,b)=>a**b!unioninverse(a)=>1/a!Dividing by ZeroDividing by zero returnsundefined.print(3/0)!// undefinedStringsStrings can be declared with single quotes or double quotes.constconstname='Lu'!constconstname="Luke"!They can also be declared with triple quotes.constconstname="'Lu'"!In fact, you can use any number of quotes you want.constconstname='""""Luke"""'"!Even zero.constconstname=Luke!Technical InfoTo parse strings with many quotes, the interpreter scans the code for the shortest possible string.As soon as a pair of quote groups is found that is equal in terms of quote count on both sides, that is considered a string.For example,""""""reads the two first double quotes, detects that there is a pair ("and"), and returns the corresponding empty string. This is repeated twice for the two remaining pairs of double quotes.Therefore, to avoid premature detections of strings, simply create your starting quote with a single'and any number of", like so:'"""Hello world!'''''''This is as complicated as it is in order to allow the declaration of empty strings without many problems.String InterpolationPlease remember to use your regional currency when interpolating strings.constconstname="world"!print("Hello ${name}!")!print("Hello £{name}!")!print("Hello ¥{name}!")!Note: It was specified in the original repo to allow developers to follow their local typographical norms. While I think I could, that is not something I want to do and therefore I will not do it. Additionally, if the regional currency cannot be determined, the interpolation symbol defaults to the dollar sign.TypesType annotations are optional.constvarage:Int=28!By the way, strings are just arrays of characters.String==Char[]!Similarly, integers are just arrays of digits. Hello again! Because of this, you can index into integers!constvarmy_number=20!my_number[-0.5]=1!print(my_number)!If you want to use a binary representation for integers,Int9andInt99types are also available.constvarage:Int9=28!Technical info:Type annotations don't do anything, but they help some people to feel more comfortable.PreviousThepreviouskeyword lets you see into the past!Use it to get the previous value of a variable.constvarscore=5!score=score+1!print(score)!// 6print(previousscore)!// 5Similarly, thenextkeyword lets you see into the future!constvarscore=5!after("click"){score=score+1!}print(awaitnextscore)!// 6 (when you click)Additionally, thecurrentkeyword lets you see into the present!!constvarscore=5!print(currentscore)!// 5ExportingMany languages allow you to import things from specific files. In DreamBerd, importing is simpler. Instead, you exporttospecific files!=====add.db3==functionadd(a,b)=>{returna+b!}exportaddto"main.db3"!=====main.db3==importadd!add(3,2)!ClassesYou can make classes, but you can only ever make one instance of them. This shouldn't affect how most object-oriented programmers work.classPlayer{constvarhealth=10!}constvarplayer1=newPlayer()!constvarplayer2=newPlayer()!// Error: Can't have more than one 'Player' instance!This is how you could do this:classPlayerMaker{functionmakePlayer()=>{classPlayer{constvarhealth=10!}constconstplayer=newPlayer()!returnplayer!}}constconstplayerMaker=newPlayerMaker()!constvarplayer1=playerMaker.makePlayer()!constvarplayer2=playerMaker.makePlayer()!DeleteTo avoid confusion, thedeletestatement only works with primitive values like numbers, strings, and booleans (I actually decided to implement it to delete those and also non-primitive things like variables - really, anything in the namespace).delete3!print(2+1)!// Error: 3 has been deletedDreamBerd is a multi-paradigm programming language, which means that you candeletethe keywords and paradigms you don't like.deleteclass!classPlayer{}// Error: class was deletedWhen perfection is achieved and there is nothing left todelete, you can do this:deletedelete!OverloadingYou can overload variables. The most recently defined variable gets used.constconstname="Luke"!constconstname="Lu"!print(name)!// "Lu"Variables with more exclamation marks get prioritised.constconstname="Lu"!!constconstname="Luke"!print(name)!// "Lu"constconstname="Lu or Luke (either is fine)"!!!!!!!!!print(name)!// "Lu or Luke (either is fine)"ReversingYou can reverse the direction of your code.constconstmessage="Hello"!print(message)!constconstmessage="world"!reverse!Class NamesFor maximum compatibility with other languages, you can alternatively use theclassNamekeyword when making classes.This makes things less complicated.classNamePlayer{constvarhealth=10!}In response to some recent criticism about this design decision, we would like to remind you that this is part of the JavaScript specification, and therefore - out of our control.Semantic namingDreamBerd supports semantic naming.constconstsName="Lu"!constconstiAge=29!constconstbHappy=true!New for 2023:You can now make globals.constconstg_fScore=4.5!// Interpreter maker here... idk if this is supposed to do anything, I could implement this easily if I had toAsynchronous FunctionsIn most languages, it's hard to get asynchronous functions to synchronise with each other. In DreamBerd, it's easy: Asynchronous functions take turns running lines of code.asyncfunctcount(){print(1)!print(3)!}count()!print(2)!You can use thenoopkeyword to wait for longer before taking your turn.asyncfunccount(){print(1)!noop!print(4)!}count()!print(2)!print(3)!Note:In the program above, the computer interpretsnoopas a string and its sole purpose is to take up an extra line. You can use any string you want.SignalsTo use a signal, useuse.constvarscore=use(0)!When it comes to signals, the most important thing to discuss issyntax.In DreamBerd, you can set (and get) signals with just one function:constvarscore=use(0)!score(9)!// Set the valuescore()?// Get the value (and print it)CopilotIt's worth noting that Github Copilot doesn't understand DreamBerd, which means that Microsoft won't be able to steal your code.This is great for when you want to keep your open-sourced project closed-source.HighlightingSyntax highlighting is now available for DreamBerd in VSCode. To enable it, install ahighlighting extensionand then use theDreamBerd configuration file.This is what it looks like:const const name = "Luke"!
print(name)! // "Luke"Please note:The above code will only highlight correctly if you have the extension installed.ParenthesesWait, I almost forgot!Parentheses in DreamBerd do nothing. They get replaced with whitespace.The following lines of code all do the same thing.add(3,2)!add3,2!(add(3,2))!add)3,2(!Lisp lovers will love this feature. Use as many parentheses as you want!(add(3,(add(5,6))))!Lisp haters will also love it.(add(3,(add(5,6)!Due to certain design decisions,"("is replaced with" "while")"is replaced with"".