Skip to content

FunctionalBoys/PyHask

Repository files navigation

PyHask

PyHask is the project for compiler’s design class, it aims to build a small object oriented programming language using Haskell with syntax inspired on Python.

User’s manual

Language’s philosophy

This language aims to be an imperative styled and statically typed language with support for the basic control flow structures, declaration for primitive types, declaration of N-dimensional arrays (PyHask does not impose a limit on the number of dimensions for an array), primitive based functions and basic objected oriented functionality. PyHask believes in scopes with arbitraty depth and to allow variables declared in a scope to be redeclared outside of it.

PyHask borrows most of its syntax from Python, including type annotations for which it borrows Python’s type hints. The project aims for the feel of an scripting language by not imposing the creation of a main block, and to freely allow variable declarations anywhere in the code.

How to run PyHask

After cloning the repository please build it using:

stack build

After that source programs must be first compiled and the generated output can be executed in the following way

stack exec PyHask-exe compile example.ph
stack exec PyHask-exe execute example.phc

Please refer to Stack for more information related to the Haskell tool stack and how to use it.

Primitive types

This language supports int, float, char and bool as primitive types.

Variable declarations

Primitive declaration

Primivites are declared in PyHask by using the keyword let, specifying all the variables for that type; after that it is required to specify the primitive type for the variables and optionally and initial value for the variables. if no initial value is provided a default one will be given.

Default values

  • int : 0
  • float : 0.0
  • char : a
  • bool : True

Valid declaration with default value

let a : int := 10

Valid declaration no default value

let a : int

Invalid declaration

let a

Array declaration

An array is declared also by using the keyword let, specifying variables, and by specifying the type and dimensions of the array, arrays in PyHask are N-dimensional, arrays declaration do not support optional initial value as assigning an entire array is currently not supported in PyHask, all the values for the array have as initial value the default ones specified in the previous section of the document.

Valid array declaration with one dimension

let a : int[5]

Valid array declarations with more than one dimensions

  • let a : int[5][6]
  • let b : bool[3][9][10]

Object declaration

To create an object it is necessary to first declare a class for which to instantiate an object from, this topic is gonna be covered later in the manual, in the meantime an example is gonna be given with a hypotethical class called Home that receives a integer and a floating point value on its constructors

Object declaration uses the create keyword instead of the let keyword. The correct structure for object creation is to use create followed by the class from which the object will be instantiated, and in parenthesis the parameters to be passed to the constructor.

Valid object declaration

create h : Home(10,5.0)

Control flow structures

Conditionals

PyHask supports conditionals by means of having if, elif, and else blocks. These blocks work just like in Python, with if block optionally followed by a number of elif blocks and optionally an else block as a catch all.

After the if and elif keywords a boolean expression must be stated to evaluate if the block is going to be executed.

Valid conditonal - only if block

if 5 < 2:
  print(1)

Valid conditional - with multiple elif blocks

if 5 == 3:
  print(1)
elif 2 < 3:
  print(2)
elif 5 == 5:
  print(3)

Valid conditional - with an else block

if 5 == 3:
  print(1)
else
  print(2)

While loop

PyHask supports while loops the Python way, by using the keyword while followed by a boolean expression and a block of statements.

Valid while loop

while True:
  print(3)

For loop

For loops are one of the elements where PyHask differs from Python. For loops share some similarity with C-styled loops by first having variable declarations, followed by a boolean expression and an statement.

Valid for loop

for i : int := 0 : True : i := i + 1:
  print(i)

Functions

PyHask borrows its syntax for functions from Python, even the the type declarations for functions are based on Python’s optional type hinting. Functions are declared by first using the keyword def followed by the name of the function and a list of parameters for the function to receive; finally the function must mark the return type for it with -> and setting a primitive type or the void keyword.

Function with return type

def fact(i: int) -> int:
  if i == 0:
    return 1
  return i * fact(i-1)

Function without a return type

def no_return() -> void:
  print(10)

Classes

Classes are perhaps the most complicated construct which PyHask has to offer. Again the syntax for it somewhat resembles Python’s syntax. The class keyword must be used to indicate the start of a class declaration, optionally followed by a parent class enclosed in parenthesis. The class definition must be followed by an init block. Init blocks can contain member definitions and must always define a constructor named init. After the initialization block methods of the class can follow declared as regular functions while inside the indentantion of the class. Methods will have access to self referring to an instance of the object of the class for which the method belongs. Methods may have a super variable referring to the parent of the class, this can be used to call a parent’s method and it’s specially useful in constructors to initialize the variables the parent constructor initializes.

Simple class example

class Home:
  init:
    __init__(i:int):
      pass

  def f(d: float) -> int:
    return 1

Class declaration

class MemberedClass:
  init:
    let member1 : int
    let member2 : float

    __init__(i: int, f: float):
      self.member1 := i
      self.member2 := f

  def calc() -> float:
    return self.member1 * self.member2

Inheritance example

class SonClass(MemberedClass):
  init:
    __init__(i: int, f: float):
      super.__init__(i,f)

  def calc() -> float:
    return super.calc()

More examples

Please refer to the ph files in the repository for more examples of PyHask