🐐 First order functions
This commit is contained in:
158
tests.py
158
tests.py
@@ -12,9 +12,9 @@ from fractions import Fraction
|
||||
from centvrion.ast_nodes import (
|
||||
ArrayIndex, Bool, BinOp, BuiltIn, DataArray, DataDict, DataRangeArray,
|
||||
Defini, Continva, Designa, DesignaDestructure, DesignaIndex, DumStatement,
|
||||
Erumpe, ExpressionStatement, ID, InterpolatedString, Invoca, ModuleCall,
|
||||
Nullus, Numeral, PerStatement, Program, Redi, SiStatement, String,
|
||||
UnaryMinus, UnaryNot, Fractio, frac_to_fraction, fraction_to_frac,
|
||||
Erumpe, ExpressionStatement, Fvnctio, ID, InterpolatedString, Invoca,
|
||||
ModuleCall, Nullus, Numeral, PerStatement, Program, Redi, SiStatement,
|
||||
String, UnaryMinus, UnaryNot, Fractio, frac_to_fraction, fraction_to_frac,
|
||||
num_to_int, int_to_num, make_string,
|
||||
)
|
||||
from centvrion.compiler.emitter import compile_program
|
||||
@@ -2047,5 +2047,157 @@ class TestDictDisplay(unittest.TestCase):
|
||||
run_test(self, source, nodes, value, output)
|
||||
|
||||
|
||||
# --- First-class functions / FVNCTIO ---
|
||||
|
||||
fvnctio_tests = [
|
||||
# Lambda assigned to variable, then called
|
||||
(
|
||||
"DESIGNA f VT FVNCTIO (x) VT { REDI (x + I) }\nINVOCA f (V)",
|
||||
Program([], [
|
||||
Designa(ID("f"), Fvnctio([ID("x")], [Redi([BinOp(ID("x"), Numeral("I"), "SYMBOL_PLUS")])])),
|
||||
ExpressionStatement(Invoca(ID("f"), [Numeral("V")])),
|
||||
]),
|
||||
ValInt(6),
|
||||
),
|
||||
# IIFE: immediately invoked lambda
|
||||
(
|
||||
"INVOCA FVNCTIO (x) VT { REDI (x * II) } (III)",
|
||||
Program([], [
|
||||
ExpressionStatement(Invoca(
|
||||
Fvnctio([ID("x")], [Redi([BinOp(ID("x"), Numeral("II"), "SYMBOL_TIMES")])]),
|
||||
[Numeral("III")],
|
||||
)),
|
||||
]),
|
||||
ValInt(6),
|
||||
),
|
||||
# Zero-arg lambda
|
||||
(
|
||||
"INVOCA FVNCTIO () VT { REDI (XLII) } ()",
|
||||
Program([], [
|
||||
ExpressionStatement(Invoca(
|
||||
Fvnctio([], [Redi([Numeral("XLII")])]),
|
||||
[],
|
||||
)),
|
||||
]),
|
||||
ValInt(42),
|
||||
),
|
||||
# Function passed as argument
|
||||
(
|
||||
"DEFINI apply (f, x) VT { REDI (INVOCA f (x)) }\n"
|
||||
"DESIGNA dbl VT FVNCTIO (n) VT { REDI (n * II) }\n"
|
||||
"INVOCA apply (dbl, V)",
|
||||
Program([], [
|
||||
Defini(ID("apply"), [ID("f"), ID("x")], [
|
||||
Redi([Invoca(ID("f"), [ID("x")])])
|
||||
]),
|
||||
Designa(ID("dbl"), Fvnctio([ID("n")], [
|
||||
Redi([BinOp(ID("n"), Numeral("II"), "SYMBOL_TIMES")])
|
||||
])),
|
||||
ExpressionStatement(Invoca(ID("apply"), [ID("dbl"), Numeral("V")])),
|
||||
]),
|
||||
ValInt(10),
|
||||
),
|
||||
# Lambda uses caller-scope variable (copy-caller semantics)
|
||||
(
|
||||
"DESIGNA n VT III\n"
|
||||
"DESIGNA f VT FVNCTIO (x) VT { REDI (x + n) }\n"
|
||||
"INVOCA f (V)",
|
||||
Program([], [
|
||||
Designa(ID("n"), Numeral("III")),
|
||||
Designa(ID("f"), Fvnctio([ID("x")], [
|
||||
Redi([BinOp(ID("x"), ID("n"), "SYMBOL_PLUS")])
|
||||
])),
|
||||
ExpressionStatement(Invoca(ID("f"), [Numeral("V")])),
|
||||
]),
|
||||
ValInt(8),
|
||||
),
|
||||
# Named function passed as value
|
||||
(
|
||||
"DEFINI sqr (x) VT { REDI (x * x) }\n"
|
||||
"DESIGNA f VT sqr\n"
|
||||
"INVOCA f (IV)",
|
||||
Program([], [
|
||||
Defini(ID("sqr"), [ID("x")], [Redi([BinOp(ID("x"), ID("x"), "SYMBOL_TIMES")])]),
|
||||
Designa(ID("f"), ID("sqr")),
|
||||
ExpressionStatement(Invoca(ID("f"), [Numeral("IV")])),
|
||||
]),
|
||||
ValInt(16),
|
||||
),
|
||||
# Nested lambdas
|
||||
(
|
||||
"INVOCA FVNCTIO (x) VT { REDI (INVOCA FVNCTIO (y) VT { REDI (y + I) } (x)) } (V)",
|
||||
Program([], [
|
||||
ExpressionStatement(Invoca(
|
||||
Fvnctio([ID("x")], [
|
||||
Redi([Invoca(
|
||||
Fvnctio([ID("y")], [Redi([BinOp(ID("y"), Numeral("I"), "SYMBOL_PLUS")])]),
|
||||
[ID("x")],
|
||||
)])
|
||||
]),
|
||||
[Numeral("V")],
|
||||
)),
|
||||
]),
|
||||
ValInt(6),
|
||||
),
|
||||
# DICE on a function value
|
||||
(
|
||||
"DESIGNA f VT FVNCTIO (x) VT { REDI (x) }\nDICE(f)",
|
||||
Program([], [
|
||||
Designa(ID("f"), Fvnctio([ID("x")], [Redi([ID("x")])])),
|
||||
ExpressionStatement(BuiltIn("DICE", [ID("f")])),
|
||||
]),
|
||||
ValStr("FVNCTIO"),
|
||||
"FVNCTIO\n",
|
||||
),
|
||||
# Lambda stored in array, called via index
|
||||
(
|
||||
"DESIGNA fns VT [FVNCTIO (x) VT { REDI (x + I) }, FVNCTIO (x) VT { REDI (x * II) }]\n"
|
||||
"INVOCA fns[I] (V)",
|
||||
Program([], [
|
||||
Designa(ID("fns"), DataArray([
|
||||
Fvnctio([ID("x")], [Redi([BinOp(ID("x"), Numeral("I"), "SYMBOL_PLUS")])]),
|
||||
Fvnctio([ID("x")], [Redi([BinOp(ID("x"), Numeral("II"), "SYMBOL_TIMES")])]),
|
||||
])),
|
||||
ExpressionStatement(Invoca(
|
||||
ArrayIndex(ID("fns"), Numeral("I")),
|
||||
[Numeral("V")],
|
||||
)),
|
||||
]),
|
||||
ValInt(6),
|
||||
),
|
||||
# Lambda stored in dict, called via key
|
||||
(
|
||||
'DESIGNA d VT TABVLA {"add" VT FVNCTIO (x) VT { REDI (x + I) }}\n'
|
||||
'INVOCA d["add"] (V)',
|
||||
Program([], [
|
||||
Designa(ID("d"), DataDict([
|
||||
(String("add"), Fvnctio([ID("x")], [Redi([BinOp(ID("x"), Numeral("I"), "SYMBOL_PLUS")])])),
|
||||
])),
|
||||
ExpressionStatement(Invoca(
|
||||
ArrayIndex(ID("d"), String("add")),
|
||||
[Numeral("V")],
|
||||
)),
|
||||
]),
|
||||
ValInt(6),
|
||||
),
|
||||
# Multi-param lambda
|
||||
(
|
||||
"DESIGNA add VT FVNCTIO (a, b) VT { REDI (a + b) }\nINVOCA add (III, IV)",
|
||||
Program([], [
|
||||
Designa(ID("add"), Fvnctio([ID("a"), ID("b")], [
|
||||
Redi([BinOp(ID("a"), ID("b"), "SYMBOL_PLUS")])
|
||||
])),
|
||||
ExpressionStatement(Invoca(ID("add"), [Numeral("III"), Numeral("IV")])),
|
||||
]),
|
||||
ValInt(7),
|
||||
),
|
||||
]
|
||||
|
||||
class TestFvnctio(unittest.TestCase):
|
||||
@parameterized.expand(fvnctio_tests)
|
||||
def test_fvnctio(self, source, nodes, value, output=""):
|
||||
run_test(self, source, nodes, value, output)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user