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