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