Skip to content

mmichie/m28

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1,194 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

M28 - A Lispy-Pythonic Programming Language

Version License Go Version

M28 is a modern programming language that blends the elegant s-expression syntax of Lisp with the pragmatic design and extensive ecosystem of Python. It offers the best of both worlds: the power of homoiconic code and macros with Python's clean semantics and familiar keywords.

Quick Start

# Variables use = (never def)
(= message "Hello, M28!")
(print message)

# Functions use def
(def greet (name)
  (print "Hello," name))

(greet "World")

# Python-style data structures with Lisp syntax
(= numbers [1, 2, 3, 4, 5])
(= doubled (map (lambda (x) (* x 2)) numbers))
(print doubled)  # [2, 4, 6, 8, 10]

Installation

# Clone the repository
git clone https://github.com/mmichie/m28.git
cd m28

# Build the interpreter
make build

# Run the REPL
./bin/m28

# Run a script
./bin/m28 script.m28

Language Features

S-Expression Syntax

Everything is an expression in prefix notation:

(+ 1 2 3)           # 6
(print "Hello")     # Hello
(= x 5)
(if (> x 0) "positive" "non-positive")  # "positive"

Python Semantics

  • # for comments (Python-style)
  • def only for functions
  • = only for variables
  • Python keywords: if, elif, else, for, in, while, try, except, class, import, etc.
  • Python built-ins: len, range, sum, map, filter, print, etc.

Modern Data Structures

# Lists
(= fruits ["apple", "banana", "orange"])

# Dictionaries  
(= person {"name": "Alice", "age": 30})

# Sets
(= unique {1, 2, 3})

# Tuples
(= point (tuple [10, 20]))

Object-Oriented Programming

(class Person
  (def __init__ (self name)
    (= self.name name))
  
  (def greet (self)
    (print f"Hi, I'm {self.name}")))

(= alice (Person "Alice"))
(alice.greet)  # Hi, I'm Alice

Functional Programming

# First-class functions
(= numbers [1, 2, 3, 4, 5])
(= evens (filter (lambda (x) (== (% x 2) 0)) numbers))
(= squared (map (lambda (x) (* x x)) evens))

# List comprehensions
(= squares [(** x 2) for x in (range 10) if (== (% x 2) 0)])

Exception Handling

(try
  (/ 1 0)  # This will raise an error
  (except
    (print "Caught an error!")))

# With finally block
(try
  (print "Attempting operation...")
  (/ 10 2)
  (except
    (print "Error occurred"))
  (finally
    (print "Cleanup complete")))

Module System

(import math)
(import pandas as pd)
(from datetime import date)

(= root (math.sqrt 16))
(= df (pd.DataFrame data))

Documentation

Examples

Hello World

(print "Hello, World!")

Factorial

(def factorial (n)
  (if (<= n 1)
      1
      (* n (factorial (- n 1)))))

(print (factorial 5))  # 120

File I/O

(with (open "data.txt" "r") as f
  (for line in f
    (print (strip line))))

Quick Sort

(def quicksort (lst)
  (if (<= (len lst) 1)
      lst
      (let pivot (first lst)
           rest (rest lst)
           less (filter (lambda (x) (< x pivot)) rest)
           greater (filter (lambda (x) (>= x pivot)) rest)
        (+ (quicksort less) [pivot] (quicksort greater)))))

(print (quicksort [3, 1, 4, 1, 5, 9, 2, 6]))  # [1, 1, 2, 3, 4, 5, 6, 9]

New in v0.2.0: Protocol System

M28 now supports Python-style protocols for creating extensible custom types:

Iterator Protocol

(class Counter
  (def __init__ (self max)
    (= self.max max)
    (= self.current 0))
  
  (def __iter__ (self)
    self)  # Return self as iterator
  
  (def __next__ (self)
    (if (< self.current self.max)
      (let ((val self.current))
        (= self.current (+ self.current 1))
        val)
      (raise StopIteration))))

# Use in for loop
(for i in (Counter 5)
  (print i))  # Prints 0, 1, 2, 3, 4

Container Protocols

(class MyList
  (def __init__ (self)
    (= self.data {}))
  
  (def __getitem__ (self index)
    (get-item self.data (str index)))
  
  (def __setitem__ (self index value)
    (set-item self.data (str index) value))
  
  (def __delitem__ (self index)
    (del-item self.data (str index))))

(= ml (MyList))
(set-item ml 0 "hello")
(print (get-item ml 0))  # "hello"

Other Protocols

  • Arithmetic: __add__, __sub__, __mul__, __div__ for operator overloading
  • Comparison: __eq__, __lt__, __le__ for custom comparisons
  • String: __repr__, __str__ for string representations
  • Boolean: __bool__ for truthiness
  • Length: __len__ for container size
  • Contains: __contains__ for membership testing

Why M28?

  1. S-expressions - Code is data, enabling powerful metaprogramming
  2. Python semantics - Familiar and pragmatic design choices
  3. Prefix notation - Consistent, unambiguous syntax
  4. Functional programming - First-class functions, map/filter/reduce
  5. Modern features - List comprehensions, context managers, generators
  6. Simple implementation - Easy to understand and extend

Contributing

Contributions are welcome! Please read our Contributing Guide for details.

License

M28 is licensed under the MIT License. See LICENSE for details.

Acknowledgments

M28 stands on the shoulders of giants:

  • Lisp for s-expressions and homoiconicity
  • Python for pragmatic design and clear semantics
  • Scheme for minimalism and elegance
  • Clojure for modern Lisp innovations

About

No description, website, or topics provided.

Resources

License

Contributing

Stars

Watchers

Forks

Packages

No packages published

Languages