This repository has been archived by the owner on Jan 27, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ast_term.nim
133 lines (115 loc) · 3.54 KB
/
ast_term.nim
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import hmisc/helpers
import hnimast
import nimtrs/[trscore, trspprint, trsdsl]
import sequtils, strformat, strutils, macros
import hmisc/algo/halgorithm
import hmisc/types/colorstring
import unittest, sets, options
import hpprint, hpprint/hpprint_repr
type
AstKind* = enum
# Constant values
akStrLit
akIntLit
akIdent
# Functors
akCall
akCondition
Ast* = object
case kind*: AstKind
of akStrLit, akIdent:
strVal*: string
of akIntLit:
intVal*: int
else:
subnodes*: seq[Ast]
proc `==`*(lhs, rhs: Ast): bool =
lhs.kind == rhs.kind and
(
case lhs.kind:
of akStrLit, akIdent: lhs.strVal == rhs.strVal
of akIntLit: lhs.intVal == rhs.intVal
else: subnodesEq(lhs, rhs, subnodes)
)
type AstTerm* = Term[Ast, AstKind]
func nOp*(op: AstKind, subt: seq[AstTerm]): AstTerm =
case op:
of akStrLit .. akIdent:
assert false
else:
return makeFunctor[Ast, AstKind](op, subt)
func nVar*(n: string): AstTerm =
makeVariable[Ast, AstKind](n)
func mkOp*(op: AstKind, sub: seq[Ast]): Ast =
case op:
of akCall, akCondition:
Ast(kind: op, subnodes: sub)
else:
raiseAssert("12")
func objTreeRepr*(a: Ast): ObjTree =
case a.kind:
of akIntLit:
pptConst($a.intVal)
of akStrLit:
pptConst(a.strVal)
of akIdent:
pptObj("ident", pptConst(a.strVal))
else:
pptObj($a.kind, a.subnodes.mapIt(it.objTreeRepr()))
func objTreeRepr*(a: seq[Ast]): ObjTree =
a.mapIt(it.objTreeRepr()).pptSeq()
func mkVal*(val: int): Ast = Ast(kind: akIntLit, intVal: val)
func mkIdent*(val: string): Ast = Ast(kind: akIdent, strVal: val)
func mkLit*(val: string): Ast = Ast(kind: akStrLit, strVal: val)
func mkLit*(val: int): Ast = Ast(kind: akIntLit, intVal: val)
func nConst*(n: Ast): AstTerm = makeConstant(n, n.kind)
func mkCond*(a: Ast): Ast = Ast(kind: akCondition, subnodes: @[a])
func mkCall*(n: string, args: varargs[Ast]): Ast =
Ast(kind: akCall,
subnodes: @[mkIdent(n)] & args.mapIt(it))
func exprRepr*(a: Ast): string =
let color = not defined(plainStdout)
case a.kind:
of akIntLit:
($a.intVal).toCyan(color)
of akStrLit:
a.strVal.toYellow(color)
of akIdent:
a.strVal.toGreen(color)
else:
a.subnodes.mapIt(it.exprRepr()).join(", ").wrap("[ ]")
let astImpl* = TermImpl[Ast, AstKind](
getSym: (proc(n: Ast): AstKind = n.kind),
isFunctorSym: (
proc(kind: AstKind): bool =
result = kind in {akCall .. akCondition}
# debugecho "Kind is functor? ", kind, ": ", result
),
makeFunctor: (
proc(op: AstKind, sub: seq[Ast]): Ast =
# debugecho "making functor for kind ", op
result = Ast(kind: op)
result.subnodes = sub
),
getArguments: (proc(n: Ast): seq[Ast] = n.subnodes),
# setSubt: (proc(n: var Ast, sub: seq[Ast]) = n.subnodes = sub),
valStrGen: (proc(n: Ast): string = n.exprRepr()),
)
proc exprRepr*(a: AstTerm |
TermPattern[Ast, AstKind] |
TermEnv[Ast, AstKind]
): string = exprRepr(a, astImpl)
proc exprRepr(elems: seq[AstTerm]): string =
elems.mapIt(it.exprRepr(astImpl)).join(", ").wrap(("[", "]"))
proc cmpTerm*(term: AstTerm | Ast, val: Ast | AstTerm): void =
let ok =
(when term is AstTerm: term.fromTerm() else: term) ==
(when val is AstTerm: val.fromTerm() else: val)
if not ok:
echo "Found:"
echo treeRepr(term, astImpl)
echo "Expected:"
echo treeRepr(val, astImpl)
raiseAssert("Fail")
func toTerm*(val: int, impl: TermImpl[Ast, AstKind]): AstTerm =
toTerm(mkVal(val), impl)