aboutsummaryrefslogtreecommitdiff
path: root/lib/metaprogramming.nom
blob: 7c643a963c6ad3ce4552b97eb44603ed9b681908 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#..
    This File contains rules for making rules and macros and some helper functions to make
    that easier.

# Rule to make rules:
lua code ".."
    |nomsu:def("escaped rule %rule_def = %body", function(nomsu, vars)
    |    local aliases = nomsu:typecheck(vars, "rule_def", "Block").value
    |    local body = nomsu:typecheck(vars, "body", "Block")
    |    local thunk = nomsu:tree_to_value({type="Thunk", value={type="Statements", value=body.value, src=body.src}, src=body.src})
    |    local canonical = aliases[1]
    |    nomsu:def(canonical, thunk, body.src)
    |    local function rewriter(nomsu, vars)
    |        return nomsu:tree_to_lua(nomsu:replaced_vars(canonical, vars))
    |    end
    |    for i=2,#aliases do
    |        nomsu:defmacro(aliases[i], rewriter, body.src)
    |    end
    |end)

# Rule to make nomsu macros:
escaped rule \(escaped parse %shorthand as %longhand) = \:
    lua code ".."
        |local aliases = nomsu:typecheck(vars, "shorthand", "Block").value
        |local template = nomsu:typecheck(vars, "longhand", "Block")
        |local function parsing_as(nomsu, vars)
        |    local replacement = nomsu:replaced_vars(template, vars)
        |    return nomsu:tree_to_lua(replacement)
        |end
        |for _,call in ipairs(aliases) do
        |    nomsu:defmacro(call, parsing_as, template.src)
        |end
escaped parse \(parse %shorthand as %longhand) as \: escaped parse \%shorthand as \%longhand
parse (rule %rule_def = %body) as: escaped rule \%rule_def = \%body

# Rule to make lua macros:
rule (escaped compile %macro_def to %body) =:
    lua code ".."
        |local aliases = nomsu:typecheck(vars, "macro_def", "Block").value
        |local body = nomsu:typecheck(vars, "body", "Block")
        |local thunk = nomsu:tree_to_value({type="Thunk", value={type="Statements", value=body.value, src=body.src}, src=body.src})
        |for _,alias in ipairs(aliases) do
        |    nomsu:defmacro(alias, thunk, body.src)
        |end
rule (escaped compile %macro_def to code %body) =:
    lua code ".."
        |local aliases = nomsu:typecheck(vars, "macro_def", "Block").value
        |local body = nomsu:typecheck(vars, "body", "Block")
        |local thunk = nomsu:tree_to_value({type="Thunk", value={type="Statements", value=body.value, src=body.src}, src=body.src})
        |local thunk2 = function(nomsu, vars) return nil, thunk(nomsu, vars) end
        |for _,alias in ipairs(aliases) do
        |    nomsu:defmacro(alias, thunk2)
        |end
parse (compile %macro_def to %body) as: escaped compile \%macro_def to \%body
parse (compile %macro_def to code %body) as: escaped compile \%macro_def to code \%body
parse (compile %macro_def to block %body) as: escaped compile \%macro_def to code\: ".."
    |do
    |    \(%body)
    |end

rule (%tree as lua) =:
    lua expr "nomsu:tree_to_lua(\(%tree))"
rule (%tree as value) =:
    lua expr "nomsu:tree_to_value(\(%tree), vars)"
compile (repr %obj) to:
    "nomsu:repr(\(%obj as lua))"

parse (lua block %block) as: lua code ".."
    |do
    |    \(%block)
    |end
rule (%tree as lua statement) =:
    lua block ".."
        |local _,statement = nomsu:tree_to_lua(\(%tree))
        |return statement
rule (%tree as lua statements) =:
    lua block ".."
        |local statements_tree = {type='Statements', value=\(%tree).value, src=\(%tree).src}
        |local _,statements = nomsu:tree_to_lua(statements_tree)
        |return statements

compile (nomsu) to: "nomsu"
compile (nomsu's %key) to: "nomsu[\(%key as lua)]"
compile (nomsu %method %args) to: "nomsu[\(%method as lua)](nomsu, unpack(\(%args as lua)))"

# Get the source code for a function
rule (help %rule) =:
    lua block ".."
        |local fn_def = nomsu:get_fn_def(vars.rule)
        |if not fn_def then
        |    nomsu:writeln("Rule not found: "..nomsu:repr(vars.rule))
        |else
        |    nomsu:writeln("rule "..nomsu:repr(nomsu.utils.keys(fn_def.invocation))
        |        .." ="..(fn_def.src or ":\\n    <unknown source code>"))
        |end

# Compiler tools
parse (eval %code; run %code) as: nomsu "run" [%code]
rule (source code from tree %tree) =:
    lua block ".."
        |local _,_,leading_space = vars.tree.src:find("\\n(%s*)%S")
        |if leading_space then
        |    local chunk1, chunk2 = vars.tree.src:match(":%s*([^\\n]*)(\\n.*)")
        |    chunk2 = chunk2:gsub("\\n"..leading_space, "\\n")
        |    return chunk1..chunk2.."\\n"
        |else
        |    return vars.tree.src:match(":%s*(%S.*)").."\\n"
        |end
parse (source code %body) as: source code from tree \%body

parse (parse tree %code) as: nomsu "tree_to_str" [\%code]

parse (enable debugging) as: lua code "nomsu.debug = true"
parse (disable debugging) as: lua code "nomsu.debug = false"