Overview
Pyr is a programming language based on Python.
Features
- Static type checking
- Can be interpreted
- Can be compiled into a native object file (using LLVM)
Quick Start
Pyr is written in Rust. To compile Pyr you need to have a Rust compiler and LLVM version 14.0.x.
To compile Pyr:
cargo build --release
To interpret a Pyr program:
pyr run foo.pyr
To compile a Pyr program:
pyr compile foo.pyr
clang foo.o -o foo
Turing Completeness
We have proved a Turing Completeness for Pyr by implementing Rule 110 which you can see here.
License
Pyr is under the license of Apache-2.0.
Command Line Interface
pyr [OPTIONS] <SUBCOMMAND> [SUBCOMMAND_OPTIONS] <source_file>
Options
--help
| -h
Prints the help message.
--link
| -l
Links a dynamic/shared library.
Subcommand
Run
Run/Interprets the program line by line.
Compile
Compiles the program into an object file.
Options
--out
| -o
Specifies the output file name.
--exe
| -e
Links the object file into an executable.
Literals
Pyr currently supports the following literals:
Integer
Integers in Pyr are 64 bit signed integers.
123
Type: int
Boolean
Booleans in Pyr are secretly integers with true
as 1 and false
as 0.
true # returns 1
false # returns 0
Type: int
String
Strings in Pyr are delimited by double quotes.
For escaping things like double quotes, you can use a backslash.
Multiline strings are also supported.
"Hello, World!"
"Newlines\n"
To see what are the supported escape sequences are, look at Supported Escape Sequences
You can also index into strings.
"Hello, World!"[0] # returns "H"
Type: string
Arrays
Arrays in Pyr starts with the types of the elements, followed by the elements delimited with square brackets and separated by commas.
int[] # returns an empty array of integers
int[123, 456] # returns an array of integers with two elements
string["Hello, World!"] # returns an array of strings with one element
When initializing an array, you can specify an element then clone the element by the given length.
int[0; 30] # returns an array of 30 zeros
int[1, 2, 3; 10] # returns int[1, 2, 3, 1, 2, 3, 1, 2, 3, 1]
You can index into an array with the index.
int[1, 2, 3; 10][1] # returns 2
Type: [type; len]
where type
is the type of the elements and len
is the length of the array.
Note: Currently, arrays cannot be converted to strings.
Keywords
Keywords in Pyr are as follows:
if
if
evaluates its condition and if it's truthy, it executes its body.
if 34 < 56:
print("34 is less than 56\n") # Executes this line
else
else
executes its body if the previous if
's condition is falsy.
if 100 < 50:
print("100 is less than 50\n") # Skips this line
else:
print("100 is greater than 50\n") # Executes this line
else
can also be continued with another if
:
if 100 < 50:
print("100 is less than 50\n") # Skips this line
else if 100 > 50:
print("100 is greater than 50\n") # Executes this line
else:
print("100 is equal to 50\n") # Skips this line
while
while
will execute its body until the condition is falsy.
i = 0
while i < 10: # Executes its body 10 times
print(i + "\n")
i += 1
and
and
with the same type of operands will return the left value if either is falsy and will return the right value if both are truthy.
and
with different types of operands will return false
if either is falsy and will true
if both are truthy.
and
will short circuit if left hand side is falsy.
10 > 2 and 10 < 20 # result is true
"hello" and "world" # result is "world"
123 and "" # result is false
or
or
with the same type of operands will return the left value if it is truthy otherwise it will return the right hand side.
or
with different types of operands will return true
if either is truthy and will return false
if both are falsy.
or
will short circuit if left hand side is truthy.
10 > 2 or 10 < 20 # result is true
"hello" or "world" # result is "hello"
123 or "" # result is true
func
func
defines a function.
For more information, see Functions.
func square(x: int):
print(x * x)
ret
ret
returns a value and breaks out of the function.
func square(x: int) -> int:
ret x * x
print(square(2)) # prints 4
break
break
breaks out of the current loop.
while true:
print("hello")
break
extern
extern
brings an external function into the current scope.
extern func exit(status: int)
exit(0)
Arithmetic
Addition
+
with integers will add the numbers together.
1 + 2 # result is 3
+
with strings is concatenation.
"Hello, " + "World!" # result is "Hello, World!"
Subtraction
-
will subtract the first number with the second.
1 - 2 # result is -1
Multiplication
*
with integers will multiply the numbers together.
1 * 2 # result is 2
*
between strings and integers is string repetition.
"Hello" * 3 # result is "HelloHelloHello"
Division
/
with integers will divide the first number by the second.
30 / 5 # result is 6
Negation
-
will either make its right hand side negative or positive.
!
will return true
if its right hand side is falsy, and false
if it is truthy.
-1 # result is -1
!true # result is 0
For more information about truthiness and falsiness, see Truthiness.
Exponent
^
will multiply its left hand side by itself the number of times on the right hand side.
2 ^ 3 # result is 8
Modulo / Remainder
%
will return the remainder of its left hand side subtracted by its right hand side multiple times until it is less than its original value.
30 % 5 # result is 0
4 % 3 # result is 1
12 % 5 # result is 2
Comparison
Less Than
<
will return true
if its left hand side is less than its right hand side.
1 < 2 # result is true
Greater Than
>
will return true
if its left hand side is greater than its right hand side.
1 > 2 # result is false
Less Than or Equal
<=
will return true
if its left hand side is less than or equal to its right hand side.
2 <= 2 # result is true
Greater Than or Equal
>=
will return true
if its left hand side is greater than or equal to its right hand side.
2 >= 2 # result is true
Equal
==
will return true
if its left hand side is equal to its right hand side.
1 == 2 # result is false
"Hello" == "Hello" # result is true
"Hello" == "World" # result is false
Not Equal
!=
will return true
if its left hand side is not equal to its right hand side.
1 != 2 # result is true
"Hello" != "Hello" # result is false
"Hello" != "World" # result is true
And and Or
Look at Keywords
Bitwise
<<
<<
shifts the bits of the left operand to the left by the number of bits specified by the right operand.
a = 2 # 00000010
b = 3
a << b # 00010000 or 16
>>
>>
shifts the bits of the left operand to the right by the number of bits specified by the right operand.
a = 2 # 00000010
b = 1
a >> b # 00000001 or 1
&
&
performs a bitwise AND operation on the two operands.
a = 2 # 00000100
b = 3 # 00000011
a & b # 00000000 or 0
|
|
performs a bitwise OR operation on the two operands.
a = 2 # 00000100
b = 3 # 00000011
a | b # 00000111 or 7
Truthiness
Integers
An integer is truthy if it is equal to 1.
!!0 # result is false
!!1 # result is true
!!2 # result is false
String
A string is truthy if it is not empty.
!!"" # result is false
!!"Hello" # result is true
Operator Precedence
The following are the precedence levels and associativity of the operators in the Pyr language. The higher the precedence, the faster the operation will be performed.
Operator | Description | Associativity | Precedence |
---|---|---|---|
() , [] |
Function Call, Indexing | Left-to-right | 11 |
- , ! |
Negation | Right-to-left | 10 |
^ |
Exponent | 9 | |
* , / , % |
Multiply, Division, Modulo | Left-to-right | 8 |
+ , - |
Addition, Subtraction | 7 | |
<< , >> |
Bitwise Shift Left, Bitwise Shift Right | 6 | |
< , <= , > , >= |
Less Than, Less Than or Equal, Greater Than, Greater Than or Equal | Not chainable | 5 |
== , != |
Equal, Not Equal | 4 | |
& |
Bitwise AND | Left-to-right | 3 |
| |
Bitwise OR | 2 | |
and , or |
Logical And, Logical Or | 1 | |
= |
Variable Assignment | Right-to-left | 0 |
For more information about each of the operators, see Arithmetic, Comparison and Bitwise.
Variable
Declaration and assignment in Pyr use the same syntax.
foo = "bar"
To access a variable, use the following syntax.
print(var_name) # prints "bar"
Functions
Functions in Pyr are defined with the func
keyword.
Function arguments are explicitly typed, and are separated by commas.
The maximum count of arguments/parameters for function declaring/calling is 255.
func foo(a: int, b: int) -> int:
print(a + b + "\n")
To call a function, simply use the function name and parentheses with the arguments.
foo(1, 2) # prints 3
Functions and variables have different scopes.
So you can have both a variable named foo
and a function named foo
.
foo = "bar"
func foo():
print(foo + "\n")
foo() # prints "bar"
foo = "baz"
foo() # prints "baz"
Functions can also return a value.
func sum_of_squares(a: int, b: int) -> int:
return a ^ 2 + b ^ 2
print(sum_of_squares(2, 3)) # prints 9
To overload a function, you can define a function with the same name and different arguments.
func foo(a: int) -> string:
return "int"
func foo(a: string) -> string:
return "string"
foo(1) # returns "int"
foo("foo") # returns "string"
Comments
Comments in Pyr starts with a #
and go to the end of the line.
# This is a comment
# print("Hello World")
# ^ Skipped
Multiline comments are currently not supported but are planned.
Supported Escape Sequences
Below are the supported escape sequences in Pyr.
Escape Sequence | Description |
---|---|
\ then newline | a trailing slash for escaping newline at the end |
\' | single quote |
\" | double quote |
\\ | backslash |
\a | audible bell |
\b | backspace |
\f | form feed |
\n | newline |
\r | carriage return |
\t | tab |
\v | vertical tab |
\ then 3 octal numbers | octal value in ascii |
\x then 2 hex numbers | hexadecimal value in ascii |
\u then 4..=6 hex numbers | unicode char |
Functions
print
print
prints the v
to the console without appendding a newline.
Signature:
def print(v: int | str):
...
Example:
print("Hello, World!")
print(123)
sqrt
sqrt
returns the square root of the n
Signature:
def sqrt(n: int) -> int:
...
Example:
sqrt(64) == 8
sqrt(16) == 4
to_int
to_int
converts s
into an integer then returns it
Signature:
def to_int(s: str) -> int:
...
Example:
to_int("123") == 123