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