-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathppawk.go
144 lines (131 loc) · 2.11 KB
/
ppawk.go
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
134
135
136
137
138
139
140
141
142
143
144
package main
import (
"bufio"
"fmt"
"io"
"os"
"unicode"
)
type kind uint8
const (
PLAIN kind = iota
SHEBANG
COMMENT
KEYWORD
)
var color = map[kind]string{
PLAIN: "\033[0m",
KEYWORD: "\033[0;32m",
}
type parslet struct {
what kind
text string
}
func parse(in <-chan string) <-chan parslet {
out := make(chan parslet)
go parse_run(in, out)
return out
}
func parse_run(in <-chan string, out chan parslet) {
for t := range in {
var k kind
switch {
case t == "print":
k = KEYWORD
}
out <- parslet{k, t}
}
close(out)
}
func kind_lex(x rune) rune {
switch {
case x == '_' || x == '\n':
return x
case unicode.IsLetter(x):
return '_'
case unicode.IsDigit(x):
return '_'
case unicode.IsSpace(x):
return ' '
case unicode.IsPunct(x) || unicode.IsSymbol(x):
return '!'
case unicode.IsControl(x):
return 0
default:
return 1
}
}
func lex(in <-chan rune) <-chan string {
ch := make(chan string)
go func() {
r := <-in
cur := string(r)
k := kind_lex(r)
for r := range in {
if kind_lex(r) == k {
cur += string(r)
} else {
ch <- cur
cur = string(r)
k = kind_lex(r)
}
}
ch <- cur
close(ch)
}()
return ch
}
func make_in_chan(args []string) (<-chan rune, error) {
in := os.Stdin
var err error
if len(args) == 2 && args[1] != "-" {
in, err = os.Open(args[1])
if err != nil {
return nil, err
}
}
ch := make(chan rune)
go func() {
buf := bufio.NewReader(in)
for {
b, _, err := buf.ReadRune()
if err != nil {
if err != io.EOF {
fmt.Fprintln(os.Stderr, "make_in_chan", err)
}
break
}
ch <- b
}
close(ch)
}()
return ch, nil
}
func print_chan(in <-chan string) {
for tok := range in {
fmt.Print(tok)
}
}
func color_parslets(in <-chan parslet) <-chan string {
ch := make(chan string)
go func() {
plain := color[PLAIN]
for p := range in {
c, ok := color[p.what]
if !ok {
c = plain
}
ch <- c + p.text + plain
}
close(ch)
}()
return ch
}
func main() {
in, err := make_in_chan(os.Args)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
print_chan(color_parslets(parse(lex(in))))
}