2020

From Esolang
Jump to navigation Jump to search

Everybody's favorite year! [nope] def("signature")..{}defEnd("From enilKoder" )}{; signature() (talk) 01:55, 18 March 2021 (UTC)
This is not a derivative of 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, or 2019; this is, in fact, a theoretically usable programming language, but it currently does not have any implementations. It is compiled and loosely based on Java and C.

Primitive Types

In each list of numerical primitives below, the name of the type is followed by the number of bits it uses followed by _* followed by the letter(s) that can be used in a literal. Variables and array elements can be assigned with << in the same way as = in other languages. Statements end with a period just like regular English sentences end with a period; if there are digits on both sides, it is a floating literal.

Unsigned Integers

*The range of values goes in the blank. Their literals can be a decimal int within their supported range (no - or + sign) optionally followed by one or two letters (capitalization doesn't matter). The smallest possible type is used without the letter(s). Another notation is consecutive bits surrounded by brackets. For the bracket notation, you can leave some bits off and put an asterisk at the beginning or the end to pad that side with 0's (then, the letter rule applies). [00011011] is the same as [*11011]; every whitespace character between the brackets is ignored. For types of a qbit size or greater can have hexadecimal digits between angle brackets and the whitespace and asterisk rules still apply. For the angle bracket notation, capitalization for a-f doesn't matter.

  • bit 1 [0, 1] b
  • dbit 2 [0, 3] db
  • qbit 4 [0, 15] qb
  • byte 8 [0, 255] y
  • dbyte 16 [0, 2^16-1] dy
  • qbyte 32 [0, 2^32-1] qy
  • long 64 [0, 2^64-1] l
  • dlong 128 [0, 2^128-1] dl
  • qlong 256 [0, 2^256-1] ql
  • mega 512 [0, 2^512-1] m
  • dmega 1024 [0, 2^1024-1] dm
  • qmega 2048 [0, 2^2048-1] qm

Two-Comp Integers

*The range of values goes in the blank. These follow two's-complement integers. Their literals can be a decimal int within their supported range (optional - or + sign) optionally followed by one, two, or three letters (capitalization doesn't matter). The smallest possible type is used without the letter(s) and the s can be omitted if there is a - or + sign. Another notation is consecutive bits surrounded by brackets. For the bracket notation, you can leave some bits off and put an asterisk at the beginning or the end to pad that side with 0's (then, the letter rule applies). [11100100] is the same as [111001*]; every whitespace character between the brackets is ignored. For types of an sqbit size or greater can have hexadecimal digits between angle brackets and the whitespace and asterisk rules still apply. For the angle bracket notation, capitalization for a-f doesn't matter.

  • sbit 1 [-1, 0] sb
  • sdbit 2 [-2, 1] sdb
  • sqbit 4 [-8, 7] sqb
  • sbyte 8 [-128, 127] sy
  • sdbyte 16 [-2^15, 2^15-1] sdy
  • sqbyte 32 [-2^31, 2^31-1] sqy
  • slong 64 [-2^63, 2^63-1] sl
  • sdlong 128 [-2^127, 2^127-1] sdl
  • sqlong 256 [-2^255, 2^255-1] sql
  • smega 512 [-2^511, 2^511-1] sm
  • sdmega 1024 [-2^1023, 2^1023-1] sdm
  • sqmega 2048 [-2^2047, 2^2047-1] sqm

IEEE Floats

*How the bits are divided goes in the blank. These follow the IEEE standard for floating-point representation and arithmetic. Their literals are either decimal numbers with at least one digit on both sides or scientific notation with e (or E) as other languages allow. You can optionally put a letter at the end of either notation just like the integers (capitalization doesn't matter); without it, the smallest possible type is used.

  • fpbyte 8 (1 sign, 2 exponent, 5 mantissa) b or y (either works; b is allowed because there is no floating bit, but y is also allowed because of the integer bytes)
  • fphalf 16 (1 sign, 5 exponent, 10 mantissa) h
  • fpsingle 32 (1 sign, 8 exponent, 23 mantissa) s
  • fpdouble 64 (1 sign, 11 exponent, 52 mantissa) d
  • fptriple 128 (1 sign, 14 exponent, 113 mantissa) t
  • fpquad 256 (1 sign, 17 exponent, 238 mantissa) q

Textual

Char

A char is a special kind of byte that represents a Unicode point. Their literals can be a non-negative integer followed by a c (or C), or a character or escape sequence after an apostrophe.

10c = '\xa //This returns 1

Chat

A chat is a String of chars. A chat literal is anything between double-quotes. Newline characters are allowed.

chat a << "Hello, world!".
chat b << "Look, ma
a multi-line chat!".
chat c <<
"This also works.".
chat d <<
"This can help with
 lining-up characters in the chat.".

Chats can escape characters. Quotes

\"

Backslash

\\

Backspace

\b

Form feed

\f

Newline (though you could actually type a newline, but if you have a single backslash before a newline, the newline is not included)

\n

Carriage return

\r

Tab

\t

Vertical tab

\v

Unicode character decimal (follow with four decimal digits to prevent a compiler error)

\u

Unicode character hexadecimal (follow with four hexadecimal digits to prevent a compiler error)

\x

Expression interpolation (put an expression between the parenthesis to prevent a compiler error; it will be masked to a chat)

\$()

Zooms

A zoom is a class. Declare a zoom with the zoom keyword followed by an identifier and the members between braces. An identifier consists of letters, digits (not first), dollar signs, underscores, and apostrophes (not first). Put !! after an identifier to make it final. Final zooms cannot be joined.

zoom HelloWorld {
 //Comments in 2020 are C-and-Java-and-JavaScript-styled
}

Declare a field by specifying its type followed by an identifier. Final fields must be assigned a value, or be assigned new to indicate that every constructor assigns to it.

zoom HelloWorld {
 chat hello << "Hello, world!".
}

Declare a method by optionally specifying its return type followed by an identifier, parenthesis, and a definition body in braces. A final method cannot be overridden in a sub-zoom.

zoom HelloWorld {
 bit one() {
   << 1. //Inside a method and without a reference on the left, this acts as a return statement.
 }
 noOp() {
   <<. //For methods without a return type, << is not required, but it can be used to return from a method before the bottom.
 }
}

A member can be accessed with the breakout reference followed by @ followed by the identifier. (Think dot notation but with an at sign instead.) By default, members have public access. If you want to make it zoom-private, put it in quarantine.

zoom HelloWorld {
 quarantine chat secretMessage << "Shh!!!".
 chat getSecretMessage() { //Getters are not required.
   << secretMessage.
 }
 setSecretMessage(chat newMessage) { //Setters are not required.
   secretMessage << newMessage.
 }
}

A zoom (class) can join (extend) another zoom (class). By default, a zoom joins the Breakout zoom (except for Breakout).

zoom Person {
 qbyte age.
 chat name.
}
zoom Teacher joins Person {
 //If a member is not overridden, the compiler points to the joinee's member.
 chat department.
 chat subject << "Computer science".
}

The main code of a zoom goes after a "start meeting." statement and before an optional "end meeting." statement or the end of the class. You can start a meeting multiple times.

zoom HelloWorld {
 quarantine chat hello << "Hello, world!".
 start meeting.
 std'out@println(hello).
 end meeting.
 chat answer.
 start meeting.
 std'out@println("What is your name?").
 std'out@println("Hello, " + std'in@scan() + "! It is nice to meet you.").
}

The compiler automatically creates final variables called std'in as an InputStream for standard input and std'out and std'err as OutputStreams for standard output and error.

Breakout

A breakout is a reference to an instance of a zoom. The keyword dead does not refer to a breakout (it equates to null). You can specify a variable with a specific zoom type to refer to breakouts of that zoom or breakout to refer to breakouts of any zoom. For each access of a generic breakout variable, the compiler will try to see the type of the last assignment. If the presence of an accessed member is indeterminate (e.g. set differently in an if-statement), its type will be checked at run-time.

zoom HelloWorld {
 HelloWorld hello.
 breakout main << new Breakout().
 OutputStream << dead. //dead = null
}

Suites

A suite is a group of related zooms. If you don't specify a suite, the default suite is used. The default suite is always automatically accessible. The get and from keywords are used to access zooms from other suites. Omit from to access the entire suite.

suite myZoo.
zoom Animal {
 //...
}
zoom Bear joins Animal {
 //...
}
zoom Panda joins Bear {
 //...
}
zoom Couger joins Animal {
 //...
}

In a separate suite:

suite Example.
get Bear from myZoo. //Without this, I don't have a Bear. If I wanted all of the animals, the statement would be: get myZoo.

Different parts of suites are separated with backslashes.

suite Example\SubSuite.
get myZoo.
zoom Grizzly joins Bear {
 //...
}

Arrays

(Work in Progress) An array variable is declared with brackets after the identifier with integers separated with commas for the dimensions.

byte myByteArray[5]. //They all start as 0.
myByteArray[0] << 8. //Now the first element is 8 and the rest are 0.

Constructors have new as the identifier. By default (inherited from Breakout), zooms have:

lounge new() {}

If a constructor does not have lounge, it treats instances like prototypes (the new instance starts by copying from the instance this constructor is called on instead of what is typed in the zoom). If a constructor is in quarantine, only this zoom and their methods can create instances.

Masking

The mask keyword is for casting between the numerical primitives and char, char and chat, chats and breakouts, and any primitive with its wrapper zoom. The syntax is a value followed by the mask keyword followed by the type to mask to.

"" mask char = '\0 //This is the null char
"Any other chat" mask char = 'A //The first char of the chat

Logic and Control Structures

There are bitwise operators. They cannot work with breakouts (except for numerical wrappers or Char) or chats.

~a //Not: This returns the same type as a but with all of its bits changed between 0 and 1.
//The following operators mask the type with the smaller space/precision to the type with the bigger space/precision.
a & b //And: The result has 1-bits where both operands have a 1-bit and 0-bits where either operand has a 0-bit.
a | b //Or: The result has 1-bits where either operand has a 1-bit and 0-bits where both operands have a 0-bit.
a ^ b //Xor: The result has 1-bits where either operand has a 1-bit and the other has a 0-bit, and 0-bits where both operands have a 1-bit or a 0-bit.
a ~& b //Nand: Applies Not to the result of And.
a ~| b //Nor: Applies Not to the result of Or.
a ~^ b //Xnor: Applies Not to the result of Xor.
//Notice the backticks in the shifts and rotations. $ can also be used in identifiers and @ is also used for member access.
a <`$ b //Left Shift: The bits in a are shifted to the left b spaces with 0's padded on the right side.
a >`$ b //Right Shift: The bits in a are shifted to the right b spaces with 0's padded on the left side.
a <`@ b //Left Rotate: The bits in a are rotated to the left b spaces; the bits from the left side come in on the right side.
a >`@ b //Right Rotate: The bits in a are rotated to the right b spaces; the bits from the right side come in on the left side.

There are logic operators that return bits. They cannot work with breakouts (except for numerical wrappers or Char) or chats.

!a //NOT: This returns 1 if a is 0, else returns 0
//The following operators mask the type with the smaller space/precision to the type with the bigger space/precision.
a && b //AND: This short-circuits to 0 if a is 0, else this returns b.
a || b //OR: This short-circuits to 1 if a is not 0, else this returns b.
a ^^ b //XOR: This returns 1 if either operand is 0 and the other isn't, else this returns 0.
a !& b //NAND: This returns NOT applied to the result of AND.
a !| b //NOR: This returns NOT applied to the result of OR.
a !^ b //XNOR: This returns NOT applied to the result of XOR.

There are also comparison operators. Breakouts are compared by passing to the first one's comp() method the second one. If overloaded, the param of the lowest applicable in the join chain is used. Comps can return signed integers or floats. If it returns an unsigned integer, then the comparison would never equate to greater than. Chats can be compared as Strings are in other languages. Chars and chats can be compared treating the char as a one-character chat. Chars and numerical primitives can be compared.

a < b //Returns 1 if a is less than b, else 0; the comp() method of breakout a would return a number greater than 0.
a > b //Returns 1 if a is greater than b, else 0; the comp() method of breakout a would return a number less than 0.
a = b //Returns 1 if a is equal to b, else 0; the comp() method of breakout a would return 0.
a <= b //Returns 1 if a is less than or equal to b, else 0; the comp() method of breakout a would return 0 or a number greater than 0.
a >= b //Returns 1 if a is greater than or equal to b, else 0; the comp() method of breakout a would return 0 or a number less than 0.
a <> b //Returns 1 if a is not equal to b, else 0; the comp() method of breakout a would not return 0.
a <=> b //Returns a.comp(b). The bigger the number, the bigger b is to a.

A primitive value can have brackets after it with a valid index (lit. or exp.) to get a char from a chat or a bit from another type.

"Hello, world!"[0] = 'H.
42y[3] = 0.
x[0] = x. //x is declared as a bit.

If statements and loops take bits as boolean values. You can use 0 and 1 for bit literals.

if(condition) {
 //This block executes if condition is 1.
}
while(condition) {
 //This executes if condition is 1 then condition is checked again; the loop stops if condition is checked and is 0.
}
while {
 //This executes first then works like while above; this is do while.
} (condition)
for(initializer. condition. incrementer) {
 //This works no different than for loops of other languages that have them.
 //The initializer's scope is everywhere between the () and the {}.
}
for(initializer. incrementer) {
 //First, initializer is executed.
 //Second, this runs.
 //Third, incrementer is executed.
 //Fourth, condition is checked: if 1, go to Second; else, break. (This is do while applied to for)
} (condition)

For the two loops, there are four kinds of statements that can be used inside them: conditional pass, unconditional pass, conditional break, and unconditional break.

while(someLoopCondition) {
 pass something. //something must be a bit; if it's 1, the rest of the current iteration is passed and control continues to the next iteration.
 pass. //this equates to pass 1.
 break something. //something must be a bit; if it's 1, the loop is broken.
 break. //this equates to break 1.
}

Even though Among Us had been around for two years, it was very popular in 2020. I can vote off two birds with one stone: What thing in the 2020 pl references Among Us? What am I going to call my switch statements?

crew(anything) {
 mate thing1: code. vote.
 mate thing2: moreCode. vote.
 mate thing3: yetMoreCode. vote.
 imposter: thisIsDefault. vote. //crew is switch, mate is case, and vote is break (this means it can be mixed with loops)
} //fall guys through still applies w/o vote.

Error Handling

What better way to handle potential computer bugs in 2020 than with keywords related to you-know-what? COVID is the name of a zoom that can infect.

infect aBreakout. //aBreakout is of COVID or a joiner (sub-zoom)
checkup {
 //code that could potentially infect
} sanitize(COVID virus) {
 //code that handles a potential "infection"
 /*You can have any number of sanitize blocks; COVID could be replaced with any sub-zoom of it.
   The same "infection" can be sanitized multiple times in order from top to bottom with every applicable "sanitation".
   Java would not compile, saying something like "this throwable is already handled."*/
} //There isn't an equivalent of a finally block because what's the point?
  //Really, what's the difference between code in a finally block and code that comes after the structure (I know about Java's and JavaScript's duplicate return situation.)

There is no need for a clause here because methods with a reachable infect statement outside of a checkup block are automatically treated like having Java's throws clause. But, according to CDC's regulations [just a joke], you have to have a checkup somewhere and sanitize all infectable COVID zooms.

Example Programs

Cat

zoom Cat {
 start meeting.
 std'out@println(std'in@scan()).
}

Factorial and Fibonacci

zoom Fact'Fib {
 lounge mega factIter(qbit n) { //lounge (what you might do in quarantine) is static //FIXME: remove this comment when I mention lounge elsewhere.
  mega ans << 1.
  for(qbit i << 1. i <= n. i <+ 1) {
   ans <* i.
  }
  << ans.
 }
 lounge mega factRecur(qbit n) {
  << (n < 2)? 1 : n * factRecur(n - 1).
 }
 lounge long fibIter(qbit n) { //Copied from: https://dev.to/khalilsaboor/fibonacci-recursion-vs-iteration--474l and modified
  qbit x << 0.
  qbit y << 0.
  qbit ans << 0.
  for(qbit i << 1. i < n. i <+ 1) {
   x << y.
   y < ans.
   ans << x + y.
  }
  << ans.
 }
 long fibRecur(qbit n) {
  << (n < 2)? n : fibRecur(n - 1) + fibRecur(n - 2).
 }
}

Hello, world!

zoom HelloWorld {
 start meeting.
 std'out@println("Hello, world!").
}

Truth Machine

zoom TruthMachine {
 start meeting.
 bit b << std'in@scan().
 while {
  std'out@println(b).
 } (b)
}

Standard Suites and Zooms

An implementation of 2020 should implement these zooms. Public members are shown. Method definitions and members in quarantine are implementation-dependent. The first group is in the default suite.

zoom Breakout {
 //WiP
}
zoom IOStream {
 //WiP
}
zoom InputStream joins IOStream {
 //WiP
}
zoom OutputStream joins IOStream {
 //WiP
}
zoom PrimitiveType {
 //WiP
}
zoom Bit joins PrimitveType {
 bit value !! << new.
 //WiP
}
zoon DBit joins PrimitiveType {
 dbit value !! << new.
 //WiP
}
zoom QBit joins PrimitiveType {
 qbit value !! << new.
 //WiP
}
zoom Byte joins PrimitiveType {
 byte value !! << new.
 //WiP
}
zoom DByte joins PrimitiveType {
 dbyte value !! << new.
 //WiP
}
zoom QByte joins PrimitiveType {
 qbyte value !! << new.
 //WiP
}
//WiP
suite IBALOFTLLAI.
zoom JellyBean {
 //WiP
}
//Work in Progress

(Work in Progress)