main.mx raw
1 package main
2
3 import "unsafe"
4
5 //export write
6 func cWrite(fd int32, buf unsafe.Pointer, count uint32) (n int32)
7
8 //export mxc_readfile
9 func cReadfile(path unsafe.Pointer, pathLen int32, buf unsafe.Pointer, bufCap int32) (n int32)
10
11 //export mxc_filesize
12 func cFilesize(path unsafe.Pointer, pathLen int32) (n int32)
13
14 func out(s string) {
15 if len(s) > 0 {
16 cWrite(1, unsafe.Pointer(&[]byte(s)[0]), uint32(len(s)))
17 }
18 }
19
20 func fatal(s string) {
21 if len(s) > 0 {
22 cWrite(2, unsafe.Pointer(&[]byte(s)[0]), uint32(len(s)))
23 }
24 }
25
26 func readFile(path string) (data []byte, ok bool) {
27 sz := cFilesize(unsafe.Pointer(&[]byte(path)[0]), int32(len(path)))
28 if sz < 0 {
29 return nil, false
30 }
31 buf := []byte{:sz+1}
32 n := cReadfile(unsafe.Pointer(&[]byte(path)[0]), int32(len(path)),
33 unsafe.Pointer(&buf[0]), sz+1)
34 if n < 0 {
35 return nil, false
36 }
37 return buf[:n], true
38 }
39
40 func getArgs() (ss []string) {
41 buf := []byte{:4096}
42 n := cReadfile(unsafe.Pointer(&[]byte("/proc/self/cmdline")[0]), 18,
43 unsafe.Pointer(&buf[0]), 4096)
44 if n <= 0 {
45 return nil
46 }
47 var args []string
48 start := int32(0)
49 for i := int32(0); i < n; i++ {
50 if buf[i] == 0 {
51 if i > start {
52 args = append(args, string(buf[start:i]))
53 }
54 start = i + 1
55 }
56 }
57 return args
58 }
59
60 func escapeStr(s string) (r string) {
61 r = ""
62 for i := int32(0); i < int32(len(s)); i++ {
63 c := s[i]
64 switch c {
65 case '\n':
66 r = r | "\\n"
67 case '\r':
68 r = r | "\\r"
69 case '\t':
70 r = r | "\\t"
71 case '\\':
72 r = r | "\\\\"
73 case ' ':
74 r = r | "\\s"
75 default:
76 r = r | string(s[i:i+1])
77 }
78 }
79 return r
80 }
81
82 func main() {
83 args := getArgs()
84 if len(args) < 2 {
85 fatal("usage: mxlex <file.mx>\n")
86 return
87 }
88 path := args[1]
89 data, ok := readFile(path)
90 if !ok {
91 fatal("error: cannot read " | path | "\n")
92 return
93 }
94
95 errh := func(line, col uint32, msg string) {
96 fatal("E " | ItoaU32(line) | ":" | ItoaU32(col) | " " | msg | "\n")
97 }
98
99 var s Scanner
100 s.InitBytes(data, errh, 0)
101
102 for {
103 s.Next()
104 ln := ItoaU32(s.Line)
105 cl := ItoaU32(s.Col)
106 tok := s.Tok
107
108 if tok == EOF {
109 out(ln | ":" | cl | " EOF\n")
110 break
111 }
112
113 switch tok {
114 case NameType:
115 out(ln | ":" | cl | " NAME " | s.Lit | "\n")
116 case Literal:
117 k := "?"
118 switch s.Kind {
119 case IntLit:
120 k = "INT"
121 case FloatLit:
122 k = "FLOAT"
123 case ImagLit:
124 k = "IMAG"
125 case RuneLit:
126 k = "RUNE"
127 case StringLit:
128 k = "STRING"
129 }
130 out(ln | ":" | cl | " LIT:" | k | " " | escapeStr(s.Lit) | "\n")
131 case OperatorType, AssignOp, IncOp:
132 out(ln | ":" | cl | " OP " | s.Op.String() | "\n")
133 case Semi:
134 out(ln | ":" | cl | " SEMI\n")
135 case Assign:
136 out(ln | ":" | cl | " ASSIGN\n")
137 case Define:
138 out(ln | ":" | cl | " DEFINE\n")
139 case Arrow:
140 out(ln | ":" | cl | " ARROW\n")
141 case Star:
142 out(ln | ":" | cl | " STAR\n")
143 default:
144 out(ln | ":" | cl | " " | tok.String() | "\n")
145 }
146 }
147 }
148