nomsu/lib/things.nom

141 lines
5.3 KiB
Plaintext

#!/usr/bin/env nomsu -V4.11.12.8
#
A library for simple object oriented programming.
test:
an (Empty) is a thing
a (Dog) is a thing:
[%it, %its] = [Dog, Dog]
(%its::set up) means:
%its.barks or= 0
[%its::bark, %its::woof] all mean:
%barks = [: for % in 1 to %its.barks: add "Bark!"]
return (%barks::joined with " ")
(%it::gets pissed off) means: %it.barks += 1
(Dog).genus = "Canus"
%d = (a Dog with {barks: 2})
assume "\%d" == "Dog {barks: 2}"
assume (type of %d) == "Dog"
assume (%d is a "Dog")
assume %d.barks == 2
assume ((%d::bark) == "Bark! Bark!")
assume ((%d::woof) == "Bark! Bark!")
%d::gets pissed off
assume (%d.barks == 3)
assume ((%d::bark) == "Bark! Bark! Bark!")
assume (%d.genus == "Canus")
assume ("\(%d.class)" == "Dog")
assume (%d.genus == "Canus")
assume (%d.barks == 3)
%d2 = (a Dog)
assume (%d2.barks == 0) or barf "Default initializer failed"
with {%d: a Dog with {barks: 1}}:
assume ((%d::bark) == "Bark!")
a (Corgi) is a thing:
[%it, %its] = [Corgi, Corgi]
%it [set up, gets pissed off] like a (Dog)
(%it::as text) means "Dogloaf \{: for %k = %v in %it: add %k = %v}"
(%its::sploot) means "sploooot"
[%its::bark, %its::woof] all mean:
%barks = [: for % in 1 to %its.barks: add "Yip!"]
return (%barks::joined with " ")
%corg = (a Corgi)
assume (%corg.barks == 0)
assume "\%corg" == "Dogloaf {barks: 0}"
with {%d: a Corgi with {barks: 1}}:
assume ((%d::sploot) == "sploooot") or barf "subclass method failed"
assume ((%d::bark) == "Yip!") or barf "inheritance failed"
assume ((%d::woof) == "Yip!")
with {%d: a Dog with {barks: 2}}:
assume ((%d::bark) == "Bark! Bark!")
a (Vec) is a thing with {x, y}:
%its = (Vec)
(%its::+ %other) means (Vec {x: %its.x + %other.x, y: %its.y + %other.y})
assume ((Vec {x: 1, y: 2}) + (Vec {x: 10, y: 10})) == (Vec {x: 11, y: 12})
assume (((Vec {x: 1, y: 2}) + (Vec {x: 10, y: 10})) != (Vec {x: 0, y: 0}))
[..]
%it can %actions like a %class, %it can %actions like an %class
%it has %actions like a %class, %it has %actions like an %class
%it %actions like a %class, %it %actions like an %class
..all compile to:
%lua = (Lua "")
%class_expr = (%class as lua expr)
%lines = []
for %a in %actions:
%lines::add "\
..\(%it as lua expr).\(%a.stub::as lua id) = \%class_expr.\(%a.stub::as lua id)"
%lua::add %lines joined with "\n"
return %lua
%METAMETHOD_MAP = {..}
"as text": "__tostring", "clean up": "__gc", "+": "__add", "-": "__sub"
"*": "__mul", "/": "__div", negative: "__unm", "//": "__idiv", mod: "__mod"
"^": "__pow", "&": "__band", "|": "__bor", "~": "__bxor", "~": "__bnot"
"<<": "__bshl", ">>": "__bshr", "==": "__eq", "<": "__lt", "<=": "__le"
"set 1 =": "__newindex", size: "__len", iterate: "__ipairs", "iterate all": "__pairs"
((% as text like a dict)'s meaning) = ({}'s metatable).__tostring
externally (a class named %classname with %members ((initialize %it)'s meaning)) \
..means:
%class = {__type: %classname}
%class.__index = %class
%class.class = %class
%class.__tostring = (% -> "\(%.__type) \(% as text like a dict)")
%class.__eq = ({}'s metatable).__eq
%class.__len = ({}'s metatable).__len
if %members:
%class.__members = %members
%class.__newindex = (..)
for (%its %key = %value):
if %members.%key:
rawset %its %key %value
..else:
barf "Cannot set \%key, it's not one of the allowed member fields."
set %class's metatable to {..}
__tostring: %class -> %class.__type
__call: for (%class with %initial_values):
if (%initial_values == (nil)): return %class
set %initial_values's metatable to %class
if %initial_values.set_up:
%initial_values::set up
return %initial_values
if ((initialize)'s meaning):
initialize %class
for %stub = %metamethod in %METAMETHOD_MAP:
if %class.(%stub::as lua id):
%class.%metamethod = %class.(%stub::as lua id)
return %class
[..]
a %classname is a thing with %members %class_body
an %classname is a thing with %members %class_body
..all compile to:
%class_id = (%classname.stub::as lua id)
if %class_body:
%body_lua = (%class_body as lua)
%body_lua::remove free vars [%class_id]
%body_lua::declare locals
return (..)
Lua "\
..\%class_id = a_class_named_1_with(\(quote %classname.stub), \(%members as lua)\(..)
(Lua ", function(\%class_id)\n \%body_lua\nend") if %class_body else ""
..)
a_\%class_id = function(initial_values) return \(%classname.stub::as lua id)(initial_values or {}) end
an_\%class_id, a_\(%class_id)_with, an_\(%class_id)_with = \
..a_\%class_id, a_\%class_id, a_\%class_id"
[a %classname is a thing %class_body, an %classname is a thing] all parse as (..)
a %classname is a thing with (nil) %class_body