mul · My Useless Language, a simple interpreted programming language
Project description
mul
mul
(my useless language) is a useless, interpreted programming language.
I created it to learn more about programming languages without any
utility expectation whatsoever.
It features:
- dynamic, strong typing
- lambda functions
- functional paradigm
- easy to write interpreter (≈26Kb/742 LOC of python)
- REPL
Hello, world!
greeter = {:(who) print('Hello, ' + who + '!');};
greeter("world");
Main characteristics
The implementation is in Python, but in the future I'd like to port it to a compiled language (maybe Rust).
The language is designed to be easy to write an interpreter for (therefore its uselessness).
By default, every variable is read-only. You can overwrite variables by
consciously using the set
function.
a = 5;
a = 6; # error Cannot re-assign symbol 'a'.
set('a', 6);
print(a); # prints '6.0'
There are no statements, and everything is an expression, with a return value. If you play around with the REPL you will get what I mean:
$ python -m mul
> nickname = 'mattmezza';
Type.STR
mattmezza
> f = {};
Type.FN
<function>
- an assignment returns the assigned value
- a fn call returns the last expression in the fn definition
Syntax
Whitespaces
Whitespace is not influencing parsing. All whitespaces are stripped out after lexical analysis.
Symbols
Identifiers can only use [_a-zA-Z0-9]
and they have to start with [_a-zA-Z]
.
Literals
Numbers can only use [.0-9]
(so no negative numbers – use 0 - num;
instead).
Strings can be created with either double "..."
or single '...'
quotes.
Escaping is not implemented but you can have multiline strings.
You can mix quotes within string to accomplish something like this:
> '"Hello", she said.'
"Hello", she said.
Types
There are just a few types baked into the language: None
, Number
, String
and Function
.
None
None
is a type that you can instantiate from the literal none
.
Number
No distinction between integer or float, everything is a number
num = 4.3;
another_num = 5;
Negative numbers are not supported (sorry). You can use the following:
negative_num = 0 - 4;
0
is considered false
and anything else is considered true
even without
having the explicit concept of a Boolean
type.
true
and false
themselves are implemented as functions like so:
true = {1;};
false = {0;};
String
Strings can be created with single or double quotes.
name = 'Matteo';
nickname = "mattmezza";
Strings can be concatenated with +
.
Function
Functions can be defined like so:
fullname = {
fname = 'Matteo';
lname = 'M';
fname + lname;
};
The last expression is what the function will return when called. Functions can be called like so:
fullname();
Functions can have arguments defined as formal params like so:
fullname = {:(fname, lname)
fname + lname;
};
As you would expect, such function can be called like so:
fullname('Matt', 'M');
Operators and precedence
mul
only has diadic operations implemented (so no monadic ops for now).
This means you can't do -2;
but you'd rather do 0-2;
.
The implemented operators are:
+
as in2+3;
returning5
-
as in2-3;
returning-1
*
as in2*3;
returning6
/
as in2/3;
returning0.6666666666666666
The precedence is what you'd expect:
2+3*4;
returning14
2+3/3;
returning3
3*4/12;
returning1
Control flow
There are no other constructs in the language (no if
, no for
, no while
,
etc...). In order to make the language a little bit more useful, such
constructs are implemented in a native way in the form of a function.
For instance, there is an if
function that you can use like so:
if(boolean, function, function_else);
Comments
Single line comments are allowed by prepending the comment text with a #
.
# this is a comment
a = 5; # this is a comment too
The standard library
A very small std
has been built so far. It includes things like:
list
a pair based list implementationlogic
things likeand
,or
,all
, etc...operator
functions likesum
,sub
,mul
,div
, etc...
The std
lib is extremely sparse and unstructured, beware.
Native hooks implementation
mul
is implemented via native function call hooks that make it possible to
export host language feature to mul
itself (as done for the if
function).
Native hooks implementation can be leveraged to quickly fill holes in the
std
lib.
A number of functions are implemented via native hooks:
char_at
concat
equals
lt
gt
if
len
print
set
Tooling
Execution
mul
programs can be run via python -m mul program.mul
.
Given hello_world.mul
containing:
greeter = {:(who) print('Hello, ' + who + '!');};
greeter('world');
$ python -m mul hello_world.mul
Hello, world!
There is also a REPL
interface:
$ python -m mul
> a = 5;
Type.NUM
5.0
ctrl+d
quits the REPL
.
Development
python -m mul program.mul -t
: prints the tokens as parsed by the lexerpython -m mul program.mul -a
: prints the AST as parsed by the parser
Code Examples
pow =
{:(b, e)
if(equals(0, e), {1;}, {
pow(b, e - 1) * b;
});
};
print(pow(2, 3)); # prints 8
true = {1;};
false = {0;};
not = {:(v) if(v, false, true);};
and = {:(a,b) if(a, {if(b, true, false);}, false);};
or = {:(a,b) if(a, true, {if(b, true, false);});};
le = {:(v1, v2) if(or(lt(v1, v2), equals(v1, v2)), true, false);};
ge = {:(v1, v2) if(or(gt(v1, v2), equals(v1, v2)), true, false);};
For more examples, browse through the std lib.
Installation
pip install mul
installs the latest version of mul
. Make sure
you have a virtual env with python3.11.0rc2
or newer.
Programmatic usage
mul
can be used within python projects as a library.
import mul
i = mul.Interpreter.with_std()
a = i.eval('a = 5;')
b = i.eval('b = 10;')
res = i.eval('res = a + b;')
print(res.val) # prints 15
Contributing
I don't know if I will have time to review PRs and contributions but you can have fun with the language and maybe port it to other host languages. If you do, let me know, I'm a sucker for programming languages and I would enjoy checking out what you did.
Acknowledgement
mul
is inspired by cell. Thanks to Andy
explaining rather difficult concepts in such a simple way.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file mul-0.1.3.tar.gz
.
File metadata
- Download URL: mul-0.1.3.tar.gz
- Upload date:
- Size: 13.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.2.2 CPython/3.10.8 Darwin/22.1.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 5abfafdaf56fb9063562acd23fb94f2adcb3bd910960a1df3753de70b59f6df6 |
|
MD5 | 394e0133b769dfc34569c92ff166690a |
|
BLAKE2b-256 | d1aee97967c5702c24a457ceab1f5febef699fc3dae75cb6fed2c14627752930 |
File details
Details for the file mul-0.1.3-py3-none-any.whl
.
File metadata
- Download URL: mul-0.1.3-py3-none-any.whl
- Upload date:
- Size: 16.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.2.2 CPython/3.10.8 Darwin/22.1.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | c1bf977de8cd694df81b1eecdee563f09054fd8642dc62f821630d0294a2abed |
|
MD5 | c503bde4706ad7a04b78388819a8f7da |
|
BLAKE2b-256 | 64ef50a2685e3e63d57f57780c6d0c00f216e8edac218376d3795409359f84dc |