package main import ( "git.smesh.lol/moxie/pkg/mxutil" . "git.smesh.lol/moxie/pkg/types" ) func lIndexByte(b []byte, c byte) (n int32) { for i := int32(0); i < int32(len(b)); i++ { if b[i] == c { return i } } return -1 } func lIndex(s, sep []byte) (n int32) { n := len(sep) if n == 0 { return 0 } if n > len(s) { return -1 } c0 := sep[0] for i := int32(0); i <= int32(len(s))-int32(n); i++ { if s[i] == c0 { match := true for j := int32(1); j < int32(n); j++ { if s[i+j] != sep[j] { match = false; break } } if match { return i } } } return -1 } func lTrimSpace(s []byte) (buf []byte) { start := int32(0) for start < int32(len(s)) && (s[start] == ' ' || s[start] == '\t' || s[start] == '\n' || s[start] == '\r') { start++ } stop := int32(len(s)) for stop > start && (s[stop-1] == ' ' || s[stop-1] == '\t' || s[stop-1] == '\n' || s[stop-1] == '\r') { stop-- } return s[start:stop] } func lHasPrefix(s, prefix []byte) (ok bool) { if len(s) < len(prefix) { return false } for i := int32(0); i < int32(len(prefix)); i++ { if s[i] != prefix[i] { return false } } return true } func sortedKeys(m map[string]bool) (ss []string) { var keys []string for k := range m { push(keys, k) } for i := 1; i < len(keys); i++ { for j := i; j > 0 && keys[j] < keys[j-1]; j-- { keys[j], keys[j-1] = keys[j-1], keys[j] } } return keys } func safeSSAName(v SSAValue) (s string) { switch v.(type) { case *SSAAlloc: return v.SSAName() case *SSABinOp: return v.SSAName() case *SSAUnOp: return v.SSAName() case *SSACall: return v.SSAName() case *SSAConst: return v.SSAName() case *SSAConvert: return v.SSAName() case *SSAChangeType: return v.SSAName() case *SSAFieldAddr: return v.SSAName() case *SSAIndexAddr: return v.SSAName() case *SSAExtract: return v.SSAName() case *SSAGlobal: return v.SSAName() case *SSAFunction: return v.SSAName() case *SSAFreeVar: return v.SSAName() case *SSAMakeInterface: return v.SSAName() case *SSAMakeClosure: return v.SSAName() case *SSAMakeSlice: return v.SSAName() case *SSAMakeMap: return v.SSAName() case *SSAMakeChan: return v.SSAName() case *SSASlice: return v.SSAName() case *SSATypeAssert: return v.SSAName() case *SSAPhi: return v.SSAName() case *SSASelect: return v.SSAName() case *SSALookup: return v.SSAName() case *SSARange: return v.SSAName() case *SSANext: return v.SSAName() case *SSABuiltin: return v.SSAName() case *SSAInvoke: return v.SSAName() } mxutil.WriteStr(2, "BUG: unknown SSAValue type in safeSSAName\n") return "UNKNOWN" } func irEscapeString(s string) (sv string) { var buf []byte for i := 0; i < len(s); i++ { c := s[i] if c >= 32 && c < 127 && c != '\\' && c != '"' { push(buf, c) } else { push(buf, '\\') push(buf, "0123456789ABCDEF"[c>>4]) push(buf, "0123456789ABCDEF"[c&0xf]) } } return string(buf) } func irNeedsQuote(s string) (ok bool) { for i := 0; i < len(s); i++ { c := s[i] if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '.' || c == '_' || c == '$' { continue } return true } return false } func irGlobalSymbol(pkg, name string) (s string) { sym := pkg | "." | name if irNeedsQuote(sym) { return "@\"" | sym | "\"" } return "@" | sym } func needsSret(retType string) (ok bool) { return false } func parseStructFields(s string) (ss []string) { if len(s) < 2 || s[0] != '{' || s[len(s)-1] != '}' { return nil } inner := s[1 : len(s)-1] var fields []string depth := 0 start := int32(0) for i := int32(0); i < int32(len(inner)); i++ { switch inner[i] { case '{': depth++ case '}': depth-- case ',': if depth == 0 { fv := llvmTrimSpace(string(inner[start:i])) push(fields, fv) start = i + 1 } } } f := llvmTrimSpace(string(inner[start:])) if f != "" { push(fields, f) } return fields } func llvmTrimSpace(s string) (sv string) { i := int32(0) for i < int32(len(s)) && s[i] == ' ' { i++ } j := int32(len(s)) for j > i && s[j-1] == ' ' { j-- } return string(s[i:j]) } func looksLikeFloat(s string) (ok bool) { if len(s) == 0 { return false } if s[0] != '-' && s[0] != '+' && (s[0] < '0' || s[0] > '9') { return false } for i := 0; i < len(s); i++ { if s[i] == '.' || s[i] == 'e' || s[i] == 'E' { return true } } return false } func floatLitToInt(s string) (v int64, ok bool) { if len(s) == 0 { return 0, false } i := 0 neg := false if s[0] == '-' { neg = true i = 1 } else if s[0] == '+' { i = 1 } var intPart int64 for ; i < len(s); i++ { ch := s[i] if ch == '_' { continue } if ch < '0' || ch > '9' { break } intPart = intPart*10 + int64(ch-'0') } var fracDigits int32 if i < len(s) && s[i] == '.' { i++ for ; i < len(s); i++ { ch := s[i] if ch == '_' { continue } if ch < '0' || ch > '9' { break } if ch != '0' { return 0, false } fracDigits++ } } _ = fracDigits exp := 0 if i < len(s) && (s[i] == 'e' || s[i] == 'E') { i++ expNeg := false if i < len(s) && s[i] == '-' { expNeg = true i++ } else if i < len(s) && s[i] == '+' { i++ } for ; i < len(s); i++ { ch := s[i] if ch < '0' || ch > '9' { break } exp = exp*10 + int32(ch-'0') } if expNeg { return 0, false } } result := intPart for j := 0; j < exp; j++ { result = result * 10 if result < 0 { return 0, false } } if neg { result = -result } if result == 0 { return 0, false } return result, true } func isConstOperand(s string) (ok bool) { if len(s) == 0 { return false } return s[0] != '%' && s[0] != '@' } func ensureFloatLit(s string) (sv string) { if len(s) == 0 || s[0] == '%' || s[0] == '@' { return s } if len(s) >= 2 && s[0] == '0' && s[1] == 'x' { return s } hasDecimal := false for i := 0; i < len(s); i++ { if s[i] == '.' || s[i] == 'e' || s[i] == 'E' { hasDecimal = true break } } if !hasDecimal { return s | ".0" } return s } func isBareLiteral(s string) (ok bool) { if len(s) == 0 { return false } return s[0] >= '0' && s[0] <= '9' } func parseArrayType(lt string) (count int32, elem string) { if len(lt) < 5 || lt[0] != '[' { return 0, "" } i := 1 for i < len(lt) && lt[i] >= '0' && lt[i] <= '9' { i++ } n := 0 for j := 1; j < i; j++ { n = n*10 + int32(lt[j]-'0') } if i+3 >= len(lt) || lt[i] != ' ' || lt[i+1] != 'x' || lt[i+2] != ' ' { return 0, "" } et := lt[i+3 : len(lt)-1] return n, et } func isNumericLiteral(s string) (ok bool) { if len(s) == 0 { return false } c := s[0] if c == '-' && len(s) > 1 { c = s[1] } return c >= '0' && c <= '9' } func blockHasReturn(b *SSABasicBlock) (ok bool) { for _, instr := range b.Instrs { if _, ok2 := instr.(*SSAReturn); ok2 { return true } } return false } func isComparisonOp(op SSAOp) (ok bool) { return op == OpEql || op == OpNeq || op == OpLss || op == OpLeq || op == OpGtr || op == OpGeq } func extractTupleField(tupType string, index int32) (s string) { if len(tupType) < 3 || tupType[0] != '{' { return "" } inner := tupType[1 : len(tupType)-1] depth := 0 field := 0 start := 0 for i := 0; i < len(inner); i++ { c := inner[i] if c == '{' { depth++ } else if c == '}' { depth-- } else if c == ',' && depth == 0 { if field == index { sv := inner[start:i] for len(sv) > 0 && sv[0] == ' ' { sv = sv[1:] } for len(sv) > 0 && sv[len(sv)-1] == ' ' { sv = sv[:len(sv)-1] } return sv } field++ start = i + 1 } } if field == index { sv := inner[start:] for len(sv) > 0 && sv[0] == ' ' { sv = sv[1:] } for len(sv) > 0 && sv[len(sv)-1] == ' ' { sv = sv[:len(sv)-1] } return sv } return "" } func fnv1a64(s string) (h uint64) { h = 14695981039346656037 for i := 0; i < len(s); i++ { h = h ^ uint64(s[i]) h = h * 1099511628211 } return h } // hashToIntptr folds a 64-bit FNV-1a hash to intptr width (32-bit on wasm32). func irUitoa64(v uint64) (s string) { if v == 0 { return "0" } var buf [20]byte i := 19 for v > 0 { buf[i] = byte(v%10) + '0' v = v / 10 i-- } return string(buf[i+1:]) } func underlyingBasic(t Type) (b *Basic) { if t == nil { return nil } u := SafeUnderlying(t) if u == nil { return nil } b, ok := u.(*Basic) if !ok { return nil } return b } func newTCPackageWithUniverse(path, name string) (t *TCPackage) { return &TCPackage{ Path: path, Name: name, Scope: NewScope(Universe), } } func irParseIntWidth(t string) (n int32) { if len(t) < 2 || t[0] != 'i' { return 0 } n := 0 for i := 1; i < len(t); i++ { if t[i] < '0' || t[i] > '9' { return 0 } n = n*10 + int32(t[i]-'0') } return n } func irItoa(n int32) (s string) { if n == 0 { return "0" } neg := n < 0 if neg { n = -n } buf := []byte{:0:20} for n > 0 { push(buf, byte('0'+n%10)) n /= 10 } if neg { push(buf, '-') } for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 { buf[i], buf[j] = buf[j], buf[i] } return string(buf) } func irItoa64(n int64) (s string) { if n == 0 { return "0" } neg := n < 0 if neg { n = -n } if n < 0 { return "-9223372036854775808" } buf := []byte{:0:20} for n > 0 { push(buf, byte('0'+n%10)) n /= 10 } if neg { push(buf, '-') } for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 { buf[i], buf[j] = buf[j], buf[i] } return string(buf) } func irHex64(v uint64) (s string) { digits := "0123456789ABCDEF" buf := []byte{:16} for i := 15; i >= 0; i-- { buf[i] = digits[v&0xf] v >>= 4 } return string(buf) } func irFtoa(f float64) (s string) { return "0.0" } func irParseInt64(s string) (n int64) { for i := 0; i < len(s); i++ { c := s[i] if c < '0' || c > '9' { break } n = n*10 + int64(c-'0') } return n } func runeToUTF8(r rune) (s string) { if r < 0 || r > 0x10FFFF { r = 0xFFFD } var out []byte if r <= 0x7F { push(out, byte(r)) } else if r <= 0x7FF { push(out, byte(0xC0|(r>>6)), byte(0x80|(r&0x3F))) } else if r <= 0xFFFF { push(out, byte(0xE0|(r>>12)), byte(0x80|((r>>6)&0x3F)), byte(0x80|(r&0x3F))) } else { push(out, byte(0xF0|(r>>18)), byte(0x80|((r>>12)&0x3F)), byte(0x80|((r>>6)&0x3F)), byte(0x80|(r&0x3F))) } return string(out) } func simpleItoa(n int32) (s string) { if n == 0 { return "0" } neg := n < 0 if neg { n = -n } buf := []byte{:0:20} for n > 0 { push(buf, byte('0'+n%10)) n /= 10 } if neg { push(buf, '-') } for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 { buf[i], buf[j] = buf[j], buf[i] } return string(buf) } func simpleItoa64(n int64) (s string) { if n == 0 { return "0" } neg := n < 0 if neg { n = -n } buf := []byte{:0:20} for n > 0 { push(buf, byte('0'+n%10)) n /= 10 } if neg { push(buf, '-') } for i, j := int32(0), len(buf)-1; i < j; i, j = i+1, j-1 { buf[i], buf[j] = buf[j], buf[i] } return string(buf) }