# \\ <section:top>
## @file /distill.py
## @brief Distilled `metaL` / SICP chapter 4 / -- reference implementation
## <https://www.notion.so/metalang/Distilled-metaL-SICP-chapter-4-237378d385024f899e5a24597da7a19d>
from metaL import *
## metaL core implementation
py = pyFile('metaL')
# / <section:top>
# \\ <section:bot>
py.sync() # flush all changes to disk
# / <section:bot>
SICP Chapter 4 Exercises & Solutions
This chapter draft targets on a short description of the tiniest metaL core which is highly based on the [SICP] chapter 4. In SICP, this chapter is about implementing a Scheme/Lisp metacircular interpreter.
## inherit special Module type for metaLayer-based projects
class meModule(minpyModule):
## @param[in] V by default `pyModule` uses current `__file__` for module naming
def __init__(self, V=None):
# most Python project setup will be done by a parent `pyModule` constructor
super().__init__(V)
## will be called by `super().__init__` to generate `metaL.py`
def init_py(self): ## module master `.py` `File`
self['py'] = self.py = py
# module (project) root `Dir`ectory
self.diroot // self.py
# `File` does not reflects on disk until direct `.sync()` call is done
self.py.sync()
## patch default `Makefile` from `pyModule` with REPL
def init_mk(self):
super().init_mk()
# leave only one source code file: metaL.py
self.mk.src.dropall() // ('SRC += %s' % py.file())
# build Makefile/all section with REPL pattern
self.mk.all //\\
'.PHONY: all' //\\
'all: repl' //\\
'.PHONY: repl' //\\
('repl: $(PY) %s' % py.file()) //\\
('\\t$(PY) -i %s' % py.file()) //\\
'\\t$(MAKE) $@'
self.mk.sync()
MODULE = meModule('distill')
MODULE['ABOUT'] = ABOUT = "* [`metaL` manifest](<https://github.com/ponyatov/metaL/wiki/metaL-manifest>)"
Generated Makefile
will use recursive rule that restarts the interactive Python section every time when you send exit()
into Python's REPL console.
The parent pyModule
also generates /.vscode/settings.json
with F11 = 'make repl'
and F12 = 'exit()'
key bindings, and venv
ignore rules.
# \\ <section:all>
.PHONY: all
all: repl
.PHONY: repl
repl: $(PY) metaL.py
$(PYT) test_metaL.py
$(PY) -i metaL.py
$(MAKE) $@
# / <section:all>
As metaL is highly oriented on OOP and uses Python as a host language, the principles of a language implementation from Chapter 4 should be adapted to object-oriented concepts. It is clear that every object graph node type must be represented as classes in Python. Also, metaL manifest limits some core class fields. So, the first one and the root of all the universe is the Object class:
py.objs = Section('Object')
py.mid // py.objs
py.obj = Class('Object')
py.objs // py.obj
py.err = Class('Error', [py.obj])
py.objs // py.err
class Object: pass
class Error(Object): pass
Primitive
types mostly evaluate to itself but are not so primitive as classical types in other languages. All of them can have arbitrary nested elements and attributes, such as tolerance and units for numbers (useful for CAD and real-life applications). The only exception is the Symbol
, which acts as some sort of variable in classic languages -- it does value lookup in the execution context (environment) on its evaluation.
py.prims = Section('Primitive')
py.mid // py.prims
py.prim = Class('Primitive', [py.obj])
py.prims // py.prim
py.str = Class('String', [py.prim])
py.prims // py.str
py.num = Class('Number', [py.prim])
py.prims // py.num
py.int = Class('Integer', [py.prim])
py.prims // py.int
py.symbol = Class('Symbol',[py.prim])
py.prims // py.symbol
class Primitive(Object): pass
class Symbol(Primitive): pass
class String(Primitive): pass
class Number(Primitive): pass
class Integer(Primitive): pass
Data Containers
represent storage types that specify the universal Object
storage behavior to a more specific one.
py.conts = Section('Container')
py.mid // py.conts
py.cont = Class('Container', [py.obj])
py.conts // py.cont
py.vect = Class('Vector', [py.cont])
py.conts // py.vect
py.stack = Class('Stack', [py.cont])
py.conts // py.stack
py.dict = Class('Dict', [py.cont])
py.conts // py.dict
py.set = Class('Set', [py.cont])
py.conts // py.set
py.queue = Class('Queue', [py.cont])
py.conts // py.queue
class Container(Object): pass
class Vector(Container): pass
class Stack(Container): pass
class Dict(Container): pass
class Set(Container): pass
class Queue(Container): pass