Skip to main content

The Mys (/maɪs/) programming language.

Project description

buildstatus coverage

🐁 Mys

The Mys (/maɪs/) programming language - an attempt to create a statically typed Python-like language that produces fast binaries.

Mys is heavily inspired by Python’s syntax and Rust’s packaging.

Mys is mainly targeting resource constrained single and multi core embedded systems.

Project homepage: https://github.com/eerimoq/mys

🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧

IMPORTANT INFORMATION

The language and build system implementation is still in a very early stage. Some arithmetic, print and conditional statements works, but not much more.

🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧

Quick start

https://github.com/eerimoq/mys/raw/master/docs/quick-start.gif

Installation

Install Python 3.6 or later, and then install Mys using pip.

$ pip install mys

You must also have recent versions of g++, make and pylint installed.

Tutorial

First of all, create a package called foo with the command mys new foo, and then enter it. This package is used in throughout the tutorial.

https://github.com/eerimoq/mys/raw/master/docs/new.png

src/main.mys implements the hello world application. This file is only part of application packages (executables).

def main():
    print('Hello, world!')

Build and run the application with the command mys run. It prints Hello, world!, just as expected.

https://github.com/eerimoq/mys/raw/master/docs/run.png

src/lib.mys implements the function add() and it’s test test_add(). This file is normally part of both application and library packages.

def add(first: int, second: int) -> int:
    return first + second

@test
def test_add():
    assert_eq(add(1, 2), 3)

Build and run the tests with the command mys test.

https://github.com/eerimoq/mys/raw/master/docs/test.png

Add the bar package as a dependency and use it’s hello() function.

package.toml with the bar dependency added:

[package]
name = "foo"
version = "0.1.0"
authors = ["Mys Lang <mys.lang@example.com>"]

[dependencies]
bar = "*"

src/main.mys importing hello() from the bar module:

from bar import hello

def main(args: [str]):
    hello(args[1])

Build and run the new application. Notice how the dependency is downloaded and that mys run universe prints Hello, universe!.

https://github.com/eerimoq/mys/raw/master/docs/run-universe.png

Replace the code in src/main.mys with the code below. It examplifies how to use functions, classes, exceptions, types and command line arguments. The syntax is almost identical to Python, so most readers should easily understand it.

NOTE: This code does not yet work. This is just an example of what an application could look like in the future. The Fibonacci example works, so try that instead!

def func_1(a: int) -> (int, Final[str]):
    return 2 * a, 'Bar'

def func_2(a: int, b: int = 1) -> int:
    for i in range(b):
        a += i * b

    return a

def func_3(a: Optional[int]) -> int:
    if a is None:
        return 0
    else:
        return 2 * a

def func_4(a: int) -> {int: [float]}:
    return {
        1: [],
        10 * a: [7.5, -1.0]
    }

def func_5():
    try:
        raise Exception()
    except:
        print('func_5():      An exception occurred.')

class Calc:

    def __init__(self, value: int):
        self.value: int = value

    def triple(self):
        self.value *= 3

def main(args: [str]):
    value = int(args[1])
    print('func_1(value):', func_1(value))
    print('func_2(value):', func_2(value))
    print('func_3(None): ', func_3(None))
    print('func_3(value):', func_3(value))
    print('func_4(value):', func_4(value))
    func_5()
    calc = Calc(value)
    calc.triple()
    print('calc:         ', calc)

Build and run it.

$ mys run 5
func_1(value): (5, 'Bar')
func_2(value): 7
func_3(None):  0
func_3(value): 10
func_4(value): {1: [], 50: [7.5, -1,0]}
func_5():      An exception occurred.
calc:          Calc(value=15)

Built-in functions and classes

Built-in functions and classes

abs()

all()

any()

bool()

bytes()

chr()

dict()

enumerate()

float()

format()

int()

len()

list()

max()

min()

open()

ord()

print()

range()

reversed()

round()

str()

sum()

tuple()

zip()

All built-ins aims to behave like their Python counterparts, with the following differences.

  • abs() only supports integer and floating point numbers.

  • all() and any() only supports lists of bool().

  • min() and max() only supports lists of integer and floating point numbers, and a fixed number of integer and floating points parameters.

  • sum() only supports lists of integer and floating point numbers.

Types

Variables may all be set to None if declared as Optional.

Variables declared as Final can’t be modified.

Type

Example

Comment

int

1, -1000

An integer. Usually 32 or 64 bits.

float

5.5, -100.0

A floating point number. Usually 32 bits.

str

'Hi!'

A unicode string.

bytes

b'\x00\x43'

A sequence of bytes.

tuple(T1, T2, ...)

(5.0, 5, 'foo')

A tuple with items of types T1, T2, etc.

list(T)

[5, 10, 1]

A list with items of type T.

dict(TK, TV)

{5: 'a', -1: 'b'}

A dictionary with keys of type TK and values of type TV.

Packages

A package contains modules that other packages can use. All packages contains a file called lib.mys, which is imported from with from <package> import <function/class/variable>.

There are two kinds of packages; library packages and application packages. The only difference is that application packages contains a file called src/main.mys, which contains the application entry point def main(...). Application packages produces an executable when built (mys build), libraries does not.

A package:

my-package/
├── LICENSE
├── package.toml
├── pylintrc
├── README.rst
└── src/
    ├── lib.mys
    └── main.mys         # Only part of application packages.

The mys command line interface:

mys new      Create a new package.
mys build    Build the appliaction.
mys run      Build and run the application.
mys test     Build and run tests.
mys clean    Remove build output.
mys lint     Perform static code analysis.
mys publish  Publish a release.

Importing functions and classes

Import functions and classes with from <package>[.<sub-package>]*[.<module>] import <function/class/variable>.

Use from ... import ... as <name> to use a custom name.

Here are a few examples:

from mypkg1 import func1
from mypkg2.subpkg1.mod1 import func2 as func3
from mypkg2 import Class1
from mypkg2 import var1
from .mod1 import func4

def foo():
    func1()
    func3()
    Class1()
    print(var1)
    func4()

List of packages

  • random - Random numbers.

  • math - Basic math operations.

  • time - Date and time.

Extending Mys with C++

Extending Mys with C++ is extremly easy and flexible. Strings that starts with mys-embedded-c++ are inserted at the same location in the generated code.

def main():
    a: int = 0

    '''mys-embedded-c++

    int b = 2;
    a++;
    '''

    print('a + b:', a + b)

Memory management

Integers and floating point numbers are allocated on the stack, passed by value to functions and returned by value from functions, just as any C++ program.

Strings, bytes, tuples, lists, dicts and classes are normally allocated on the heap and managed by C++ shared pointers. Objects that are known not to outlive a function are allocated on the stack.

Reference cycles are not detected and will result in memory leaks.

There is no garbage collector.

Classes

  • Instance members are accessed with self.<variable/method>.

  • Class methods are accessed with <class>.<method>. They are distinguished from instance methods by not taking self as their first parameter. Class methods are normally only used to create instances of the class (and in that case called from_<value>).

class Foo:

    def __init__(self, value: int):
        self.value = value

    # Instance method.
    def inc(self):
        self.value += 1

    # Class method.
    def from_string(value: str) -> Foo:
        return Foo(int(value))

def main():
    f1 = Foo(1)
    f2 = Foo.from_string('2')

Message passing

See examples/wip/message_passing for some ideas.

Major differences to Python

  • All variables must have a known type at compile time. The same applies to function parameters and return value.

  • Threads can run in parallel. No GIL exists.

    WARNING: Data races will occur when multiple threads uses a variable at the same time, which will likely make the program crash.

  • Integers and floats have a platform dependent maximum size, usually 32 or 64 bits.

  • Decorators does not exist.

  • Variable function arguments *args and **kwargs are not supported, except to some built-in functions.

  • Async is not supported.

  • Generators are not supported.

  • The majority of the standard library is not implemented.

  • Dictionary keys must be integers, floats, strings or bytes.

  • Strings, bytes and tuple items are mutable by default. Mark them as Final to make them immutable.

  • Classes and functions are private by default. Decorate them with @public to make them public. Variables are always private.

  • Lambda functions are not supported.

Text editor settings

Visual Code

Use the Python language for *.mys files by modifying your files.associations setting.

See the official Visual Code guide for more detils.

"files.associations": {
    "*.mys": "python"
}

Emacs

Use the Python mode for *.mys files by adding the following to your .emacs configuration file.

(add-to-list 'auto-mode-alist '("\\.mys\\'" . python-mode))

Performance

ToDo: Create a benchmark and present its outcome in this section.

Build time

Mys should be slower.

Runtime

Mys should be faster.

Memory usage

Mys should use less memory.

Build process

mys build, mys run and mys test does the following:

  1. Uses Python’s parser to transform the source code to an Abstract Syntax Tree (AST).

  2. Generates C++ code from the AST.

  3. Compiles the C++ code with g++.

  4. Links the program with g++.

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mys-0.70.0.tar.gz (50.2 kB view details)

Uploaded Source

File details

Details for the file mys-0.70.0.tar.gz.

File metadata

  • Download URL: mys-0.70.0.tar.gz
  • Upload date:
  • Size: 50.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/50.3.0 requests-toolbelt/0.9.1 tqdm/4.49.0 CPython/3.6.7

File hashes

Hashes for mys-0.70.0.tar.gz
Algorithm Hash digest
SHA256 a57abebeea77e844e446f38572d36f1cdde12399019435fc10c42b21d2162e2c
MD5 edf15d25e372ed8ca6a0b095bcf714d2
BLAKE2b-256 78066eac6c9b32032989bc4e3302c7fcccf8b09f648bb9761f23c4f54ab30cc8

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page