nomsu/core/math.nom
Bruce Hill 652c29bdef Major overhaul, splitting nomsu_compiler into nomsu_environment,
nomsu_compiler, and nomsu_decompiler. Also added comprehensions.
2018-11-08 15:24:15 -08:00

225 lines
8.0 KiB
Plaintext

#!/usr/bin/env nomsu -V4.8.10
#
This file defines some common math literals and functions
use "core/metaprogramming.nom"
use "core/text.nom"
use "core/operators.nom"
use "core/control_flow.nom"
use "core/collections.nom"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Literals:
test:
assume (all of [inf, NaN, pi, tau, golden ratio, e]) or barf "\
..math constants failed"
%nan = (NaN)
assume (%nan != %nan) or barf "NaN failed"
[infinity, inf] all compile to (Lua value "math.huge")
[not a number, NaN, nan] all compile to (Lua value "(0/0)")
[pi, Pi, PI] all compile to (Lua value "math.pi")
[tau, Tau, TAU] all compile to (Lua value "(2*math.pi)")
(golden ratio) compiles to (Lua value "((1+math.sqrt(5))/2)")
(e) compiles to (Lua value "math.exp(1)")
# Functions:
test:
assume (("5" as a number) == 5)
[% as a number, % as number] all compile to (..)
Lua value "tonumber(\(% as lua expr))"
test:
assume (..)
all of [..]
abs 5, | 5 |, sqrt 5, √ 5, sine 5, cosine 5, tangent 5, arc sine 5, arc cosine 5
arc tangent 5, arc tangent 5 / 10, hyperbolic sine 5, hyperbolic cosine 5
hyperbolic tangent 5, e^ 5, ln 5, log base 2 of 5, floor 5, ceiling 5, round 5
..or barf "math functions failed"
[absolute value %, | % |, abs %] all compile to (..)
Lua value "math.abs(\(% as lua expr))"
[square root %, square root of %, √ %, sqrt %] all compile to (..)
Lua value "math.sqrt(\(% as lua expr))"
[sine %, sin %] all compile to (Lua value "math.sin(\(% as lua expr))")
[cosine %, cos %] all compile to (Lua value "math.cos(\(% as lua expr))")
[tangent %, tan %] all compile to (Lua value "math.tan(\(% as lua expr))")
[arc sine %, asin %] all compile to (Lua value "math.asin(\(% as lua expr))")
[arc cosine %, acos %] all compile to (Lua value "math.acos(\(% as lua expr))")
[arc tangent %, atan %] all compile to (Lua value "math.atan(\(% as lua expr))")
[arc tangent %y / %x, atan2 %y %x] all compile to (..)
Lua value "math.atan2(\(%y as lua expr), \(%x as lua expr))"
[hyperbolic sine %, sinh %] all compile to (..)
Lua value "math.sinh(\(% as lua expr))"
[hyperbolic cosine %, cosh %] all compile to (..)
Lua value "math.cosh(\(% as lua expr))"
[hyperbolic tangent %, tanh %] all compile to (..)
Lua value "math.tanh(\(% as lua expr))"
[e^ %, exp %] all compile to (Lua value "math.exp(\(% as lua expr))")
[natural log %, ln %, log %] all compile to (..)
Lua value "math.log(\(% as lua expr))"
[log % base %base, log base %base of %] all compile to (..)
Lua value "math.log(\(% as lua expr), \(%base as lua expr))"
(floor %) compiles to (Lua value "math.floor(\(% as lua expr))")
[ceiling %, ceil %] all compile to (Lua value "math.ceil(\(% as lua expr))")
[round %, % rounded] all compile to (..)
Lua value "math.floor(\(% as lua expr) + .5)"
test:
assume ((463 to the nearest 100) == 500) or barf "rounding failed"
assume ((2.6 to the nearest 0.25) == 2.5) or barf "rounding failed"
externally (%n to the nearest %rounder) means (..)
=lua "(\%rounder)*math.floor((\%n / \%rounder) + .5)"
# Any/all
externally [all of %items, all %items] all mean:
for % in %items:
unless %: return (no)
return (yes)
[all of %items, all %items] all compile to:
unless (%items.type is "List"):
return %tree
%clauses = (((% as lua expr)::text) for % in %items)
return (Lua value "(\(%clauses::joined with " and "))")
[not all of %items, not all %items] all parse as (not (all of %items))
externally [any of %items, any %items] all mean:
for % in %items:
if %: return (yes)
return (no)
[any of %items, any %items] all compile to:
unless (%items.type is "List"):
return %tree
%clauses = (((% as lua expr)::text) for % in %items)
return (Lua value "(\(%clauses::joined with " or "))")
[none of %items, none %items] all parse as (not (any of %items))
# Sum/product
externally [sum of %items, sum %items] all mean:
%total = 0
for % in %items: %total += %
return %total
[sum of %items, sum %items] all compile to:
unless (%items.type is "List"):
return %tree
%clauses = (((% as lua expr)::text) for % in %items)
return (Lua value "(\(%clauses::joined with " + "))")
externally [product of %items, product %items] all mean:
%prod = 1
for % in %items: %prod *= %
return %prod
[product of %items, product %items] all compile to:
unless (%items.type is "List"):
return %tree
%clauses = (((% as lua expr)::text) for % in %items)
return (Lua value "(\(%clauses::joined with " * "))")
externally [avg of %items, average of %items] all mean (..)
(sum of %items) / (size of %items)
# Shorthand for control flow
[if all of %items %body, if all of %items then %body] all parse as (..)
if (all of %items) %body
[unless all of %items %body, unless all of %items then %body] all parse as (..)
if (not (all of %items)) %body
[if any of %items %body, if any of %items then %body] all parse as (..)
if (any of %items) %body
[unless any of %items %body, unless any of %items then %body] all parse as (..)
if (not (any of %items)) %body
[if none of %items %body, if none of %items then %body] all parse as (..)
if (not (any of %items)) %body
[unless none of %items %body, unless none of %items then %body] all parse as (..)
if (any of %items) %body
[if all of %items %body else %else, if all of %items then %body else %else] all parse \
..as (if (all of %items) %body else %else)
[..]
unless all of %items %body else %else, unless all of %items then %body else %else
..all parse as (if (not (all of %items)) %body else %else)
[if any of %items %body else %else, if any of %items then %body else %else] all parse \
..as (if (any of %items) %body else %else)
[..]
unless any of %items %body else %else, unless any of %items then %body else %else
..all parse as (if (not (any of %items)) %body else %else)
[if none of %items %body else %else, if none of %items then %body else %else] all \
..parse as (if (not (any of %items)) %body else %else)
[..]
unless none of %items %body else %else, unless none of %items then %body else %else
..all parse as (if (any of %items) %body else %else)
# Min/max
externally [min of %items, smallest of %items, lowest of %items] all mean:
%best = (nil)
for % in %items:
if ((%best == (nil)) or (% < %best)):
%best = %
return %best
externally [max of %items, biggest of %items, largest of %items, highest of %items] all mean:
%best = (nil)
for % in %items:
if ((%best == (nil)) or (% > %best)):
%best = %
return %best
test:
assume ((min of [3, -4, 1, 2] by % = (% * %)) == 1)
assume ((max of [3, -4, 1, 2] by % = (% * %)) == -4)
(min of %items by %item = %value_expr) parses as (..)
result of:
%best = (nil)
%best_key = (nil)
for %item in %items:
%key = %value_expr
if ((%best == (nil)) or (%key < %best_key)):
%best = %item
%best_key = %key
return %best
(max of %items by %item = %value_expr) parses as (..)
result of:
%best = (nil)
%best_key = (nil)
for %item in %items:
%key = %value_expr
if ((%best == (nil)) or (%key > %best_key)):
%best = %item
%best_key = %key
return %best
# Random functions
externally (seed random with %) means:
lua> "\
..math.randomseed(\%);
for i=1,20 do math.random(); end"
(seed random) parses as (seed random with (=lua "os.time()"))
[random number, random, rand] all compile to (Lua value "math.random()")
[random int %n, random integer %n, randint %n] all compile to (..)
Lua value "math.random(\(%n as lua expr))"
[random from %low to %high, random number from %low to %high, rand %low %high] all \
..compile to (Lua value "math.random(\(%low as lua expr), \(%high as lua expr))")
externally [..]
random choice from %elements, random choice %elements, random %elements
..all mean (=lua "\%elements[math.random(#\%elements)]")