-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathformat.go
More file actions
110 lines (103 loc) · 2.82 KB
/
Copy pathformat.go
File metadata and controls
110 lines (103 loc) · 2.82 KB
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
package main
import (
"strconv"
"strings"
)
// format renders an AST node back to kraM source. It is a display tool (for
// :invert, errors, traces), not a strict serializer — expressions are printed
// flat, relying on precedence rather than wrapping everything in parens.
func format(n Node) string {
switch v := n.(type) {
case NumberLit:
return strconv.FormatFloat(v.Val, 'g', -1, 64)
case StrLit:
return strconv.Quote(v.Val)
case BoolLit:
return strconv.FormatBool(v.Val)
case Var:
return v.Name
case Unary:
if v.Op == NOT {
return "!" + format(v.Right)
}
return "-" + format(v.Right)
case Binary:
return format(v.Left) + " " + opSym(v.Op) + " " + format(v.Right)
case Assign:
return v.Name + " = " + format(v.Value)
case CompoundAssign:
op := "+="
if v.Op == MINUS {
op = "-="
}
return v.Name + " " + op + " " + format(v.Value)
case XorAssign:
return v.Name + " ^= " + format(v.Value)
case Swap:
return loc(v.A, v.AI) + " <=> " + loc(v.B, v.BI)
case ArrayLit:
parts := make([]string, len(v.Elems))
for i, e := range v.Elems {
parts[i] = format(e)
}
return "[" + strings.Join(parts, ", ") + "]"
case Index:
return format(v.Arr) + "[" + format(v.Idx) + "]"
case IdxAssign:
return v.Name + "[" + format(v.Idx) + "] = " + format(v.Value)
case IdxUpdate:
op := map[TokKind]string{PLUSEQ: "+=", MINUSEQ: "-=", CARETEQ: "^="}[v.Op]
return v.Name + "[" + format(v.Idx) + "] " + op + " " + format(v.Value)
case Local:
return "local " + v.Name + " = " + format(v.Value)
case Delocal:
return "delocal " + v.Name + " = " + format(v.Value)
case Print:
return "print " + format(v.Value)
case Assert:
return "assert " + format(v.Cond)
case Block:
parts := make([]string, len(v.Stmts))
for i, s := range v.Stmts {
parts[i] = format(s)
}
return "{ " + strings.Join(parts, "; ") + " }"
case If:
s := "if " + format(v.Cond) + " " + format(v.Then)
if v.Else != nil {
s += " else " + format(v.Else)
}
if v.Exit != nil {
s += " assert " + format(v.Exit)
}
return s
case While:
return "while " + format(v.Cond) + " " + format(v.Body)
case ReversibleLoop:
return "from " + format(v.Entry) + " " + format(v.Do) +
" loop " + format(v.Rest) + " until " + format(v.Exit)
case Reverse:
return "reverse " + format(v.Body)
case ProcDef:
return "proc " + v.Name + nameList(v.Params) + " " + format(v.Body)
case Call:
return "call " + v.Name + nameList(v.Args)
case Uncall:
return "uncall " + v.Name + nameList(v.Args)
}
return "<?>"
}
// loc renders an lvalue: "a" or "a[i]".
func loc(name string, idx Node) string {
if idx == nil {
return name
}
return name + "[" + format(idx) + "]"
}
// nameList renders "(a, b, c)", or "" when empty.
func nameList(names []string) string {
if len(names) == 0 {
return ""
}
return "(" + strings.Join(names, ", ") + ")"
}