tc_universe.mx raw

   1  package types
   2  
   3  import "git.smesh.lol/moxie/pkg/mxutil"
   4  
   5  // UniverseState holds all predeclared type system state.
   6  // Owned by the caller. No globals - all access through this struct.
   7  type UniverseState struct {
   8  	Scope         *Scope
   9  	Typ           [UntypedNil + 1]*Basic
  10  	Error         *TypeName
  11  	Registry      map[string]*TCPackage
  12  	DirectImports map[string][]string
  13  	ByName        map[string]*TCPackage // name -> package cache
  14  	byNameSeq     int32
  15  }
  16  
  17  // LookupByName returns the package with the given short name, or nil.
  18  func (u *UniverseState) LookupByName(name string) (pkg *TCPackage) {
  19  	if u.ByName == nil || u.byNameSeq != int32(len(u.Registry)) {
  20  		u.ByName = map[string]*TCPackage{}
  21  		for _, p := range u.Registry {
  22  			if p != nil {
  23  				u.ByName[p.Name] = p
  24  			}
  25  		}
  26  		u.byNameSeq = int32(len(u.Registry))
  27  	}
  28  	return u.ByName[name]
  29  }
  30  
  31  // Global bridge - DEPRECATED. Will be removed once all call sites
  32  // thread UniverseState as a parameter. Do not add new reads.
  33  var Universe *Scope
  34  var Typ [UntypedNil + 1]*Basic
  35  var universeError *TypeName
  36  
  37  
  38  // InitUniverse creates the universe scope with predeclared types.
  39  // Returns all products. Caller owns the returned state.
  40  // Also sets globals for backward compat during migration.
  41  func InitUniverse() (u *UniverseState) {
  42  	if Universe != nil {
  43  		return &UniverseState{
  44  			Scope:         Universe,
  45  			Typ:           Typ,
  46  			Error:         universeError,
  47  			Registry:      ImportRegistry,
  48  			DirectImports: PkgDirectImports,
  49  		}
  50  	}
  51  	return buildUniverse()
  52  }
  53  
  54  // SetUniverseGlobals sets the package-level globals from a UniverseState.
  55  // Called by the program's main after receiving the return value from
  56  // InitUniverse. The caller's arena owns the data.
  57  func SetUniverseGlobals(u *UniverseState) {
  58  	Universe = u.Scope
  59  	Typ = u.Typ
  60  	universeError = u.Error
  61  	ImportRegistry = u.Registry
  62  	PkgDirectImports = u.DirectImports
  63  }
  64  
  65  // buildUniverse constructs the universe scope. No globals touched.
  66  // All products returned by value.
  67  func buildUniverse() (u *UniverseState) {
  68  	u = &UniverseState{}
  69  	u.Registry = map[string]*TCPackage{}
  70  	u.DirectImports = map[string][]string{}
  71  	u.Scope = NewScope(nil)
  72  
  73  	// Initialize Basic types in Typ table.
  74  	infos := [...]struct {
  75  		kind BasicKind
  76  		info BasicInfo
  77  		name string
  78  	}{
  79  		{Invalid, 0, "invalid type"},
  80  
  81  		{Bool, IsBoolean, "bool"},
  82  
  83  		{Int8, IsInteger | IsOrdered | IsNumeric, "int8"},
  84  		{Int16, IsInteger | IsOrdered | IsNumeric, "int16"},
  85  		{Int32, IsInteger | IsOrdered | IsNumeric, "int32"},
  86  		{Int64, IsInteger | IsOrdered | IsNumeric, "int64"},
  87  		{Uint8, IsInteger | IsUnsigned | IsOrdered | IsNumeric, "uint8"},
  88  		{Uint16, IsInteger | IsUnsigned | IsOrdered | IsNumeric, "uint16"},
  89  		{Uint32, IsInteger | IsUnsigned | IsOrdered | IsNumeric, "uint32"},
  90  		{Uint64, IsInteger | IsUnsigned | IsOrdered | IsNumeric, "uint64"},
  91  
  92  		{Float32, IsFloat | IsOrdered | IsNumeric, "float32"},
  93  		{Float64, IsFloat | IsOrdered | IsNumeric, "float64"},
  94  
  95  		// string and []byte share kind TCString in Moxie.
  96  		{TCString, IsString | IsOrdered, "string"},
  97  
  98  		{UnsafePointer, 0, "Pointer"}, // lives in unsafe package
  99  
 100  		{UntypedBool, IsBoolean | IsUntyped, "untyped bool"},
 101  		{UntypedInt, IsInteger | IsNumeric | IsUntyped, "untyped int32"},
 102  		{UntypedRune, IsInteger | IsNumeric | IsUntyped, "untyped rune"},
 103  		{UntypedFloat, IsFloat | IsNumeric | IsUntyped, "untyped float"},
 104  		{UntypedString, IsString | IsUntyped, "untyped string"},
 105  		{UntypedNil, IsUntyped, "untyped nil"},
 106  	}
 107  	for i, info := range infos {
 108  		u.Typ[i] = &Basic{Kind: info.kind, Info: info.info, Name: info.name}
 109  	}
 110  
 111  	s := u.Scope
 112  	s.Insert(NewTypeName(nil, "bool", u.Typ[Bool]))
 113  	s.Insert(NewTypeName(nil, "int8", u.Typ[Int8]))
 114  	s.Insert(NewTypeName(nil, "int16", u.Typ[Int16]))
 115  	s.Insert(NewTypeName(nil, "int32", u.Typ[Int32]))
 116  	s.Insert(NewTypeName(nil, "int64", u.Typ[Int64]))
 117  	s.Insert(NewTypeName(nil, "uint8", u.Typ[Uint8]))
 118  	s.Insert(NewTypeName(nil, "uint16", u.Typ[Uint16]))
 119  	s.Insert(NewTypeName(nil, "uint32", u.Typ[Uint32]))
 120  	s.Insert(NewTypeName(nil, "uint64", u.Typ[Uint64]))
 121  	s.Insert(NewTypeName(nil, "float32", u.Typ[Float32]))
 122  	s.Insert(NewTypeName(nil, "float64", u.Typ[Float64]))
 123  	s.Insert(NewTypeName(nil, "string", u.Typ[TCString]))
 124  
 125  	for _, b := range []*Basic{
 126  		u.Typ[Bool],
 127  		u.Typ[Int8], u.Typ[Int16], u.Typ[Int32], u.Typ[Int64],
 128  		u.Typ[Uint8], u.Typ[Uint16], u.Typ[Uint32], u.Typ[Uint64],
 129  		u.Typ[Float32], u.Typ[Float64],
 130  		u.Typ[TCString],
 131  	} {
 132  		addBasicStringMethod(b, u.Typ[TCString])
 133  	}
 134  
 135  	byteType := NewNamed(NewTypeName(nil, "byte", nil), u.Typ[Uint8])
 136  	s.Insert(byteType.Obj)
 137  	byteType.Obj.Typ = byteType
 138  	addStringMethod(byteType, u.Typ[TCString])
 139  
 140  	runeType := NewNamed(NewTypeName(nil, "rune", nil), u.Typ[Int32])
 141  	s.Insert(runeType.Obj)
 142  	runeType.Obj.Typ = runeType
 143  	addStringMethod(runeType, u.Typ[TCString])
 144  
 145  	uintptrUnderlying := u.Typ[Uint64]
 146  	if mxutil.TargetArch == "wasm" {
 147  		uintptrUnderlying = u.Typ[Uint32]
 148  	}
 149  	uintptrType := NewNamed(NewTypeName(nil, "uintptr", nil), uintptrUnderlying)
 150  	s.Insert(uintptrType.Obj)
 151  	uintptrType.Obj.Typ = uintptrType
 152  	addStringMethod(uintptrType, u.Typ[TCString])
 153  
 154  	errSig := NewSignature(nil, nil, NewTuple(NewTCVar(nil, "", u.Typ[TCString])), false)
 155  	strMeth := &IfaceMethod{Name: "String", Sig: errSig}
 156  	errMeth := &IfaceMethod{Name: "Error", Sig: errSig}
 157  	errIface := NewTCInterface([]*IfaceMethod{errMeth, strMeth}, nil)
 158  	errIface.Complete()
 159  	u.Error = NewTypeName(nil, "error", errIface)
 160  	s.Insert(u.Error)
 161  
 162  	complex64Type := NewNamed(NewTypeName(nil, "complex64", nil), u.Typ[Invalid])
 163  	s.Insert(complex64Type.Obj)
 164  	complex128Type := NewNamed(NewTypeName(nil, "complex128", nil), u.Typ[Invalid])
 165  	s.Insert(complex128Type.Obj)
 166  
 167  	anyIface := NewTCInterface(nil, nil)
 168  	anyIface.Complete()
 169  	s.Insert(NewTypeName(nil, "any", anyIface))
 170  
 171  	comparableIface := NewTCInterface(nil, nil)
 172  	comparableIface.Complete()
 173  	s.Insert(NewTypeName(nil, "comparable", comparableIface))
 174  
 175  	s.Insert(NewTCConst(nil, "true", u.Typ[UntypedBool], untypedBool(true)))
 176  	s.Insert(NewTCConst(nil, "false", u.Typ[UntypedBool], untypedBool(false)))
 177  	s.Insert(NewTCConst(nil, "iota", u.Typ[UntypedInt], untypedInt(0)))
 178  	s.Insert(NewTCConst(nil, "nil", u.Typ[UntypedNil], untypedNil()))
 179  
 180  	builtinNames := [18]string{
 181  		BuiltinAppend:  "append",
 182  		BuiltinCap:     "cap",
 183  		BuiltinClear:   "clear",
 184  		BuiltinClose:   "close",
 185  		BuiltinComplex: "complex",
 186  		BuiltinCopy:    "copy",
 187  		BuiltinDelete:  "delete",
 188  		BuiltinImag:    "imag",
 189  		BuiltinLen:     "len",
 190  		BuiltinMake:    "__slicealloc",
 191  		BuiltinNew:     "__ptralloc",
 192  		BuiltinPanic:   "panic",
 193  		BuiltinPrint:   "print",
 194  		BuiltinPrintln: "println",
 195  		BuiltinReal:    "real",
 196  		BuiltinRecover: "recover",
 197  		BuiltinSpawn:   "spawn",
 198  	}
 199  	for id, name := range builtinNames {
 200  		s.Insert(newBuiltin(name, BuiltinID(id)))
 201  	}
 202  	s.Insert(newBuiltin("min", BuiltinMin))
 203  	s.Insert(newBuiltin("max", BuiltinMax))
 204  	return u
 205  }
 206  
 207  
 208  func defTypeName(name string, typ Type) {
 209  	tn := NewTypeName(nil, name, typ)
 210  	Universe.Insert(tn)
 211  }
 212  
 213  func addStringMethod(named *Named, strType *Basic) {
 214  	stringSig := NewSignature(
 215  		NewTCVar(nil, "", named),
 216  		nil,
 217  		NewTuple(NewTCVar(nil, "", strType)),
 218  		false,
 219  	)
 220  	stringFn := NewTCFunc(nil, "String", stringSig)
 221  	if named.Methods == nil {
 222  		named.Methods = []*TCFunc{:0:1}
 223  	}
 224  	named.AddMethod(stringFn)
 225  }
 226  
 227  func addBasicStringMethod(b *Basic, strType *Basic) {
 228  	stringSig := NewSignature(
 229  		NewTCVar(nil, "", b),
 230  		nil,
 231  		NewTuple(NewTCVar(nil, "", strType)),
 232  		false,
 233  	)
 234  	stringFn := NewTCFunc(nil, "String", stringSig)
 235  	if b.Methods == nil {
 236  		b.Methods = []*TCFunc{:0:1}
 237  	}
 238  	b.AddMethod(stringFn)
 239  }
 240  
 241  func defObj(obj Object) {
 242  	Universe.Insert(obj)
 243  }
 244  
 245  func defConst(name string, typ Type, val ConstVal) {
 246  	Universe.Insert(NewTCConst(nil, name, typ, val))
 247  }
 248  
 249  func defNil() {
 250  	Universe.Insert(NewTCConst(nil, "nil", Typ[UntypedNil], untypedNil()))
 251  }
 252  
 253  // Placeholder constant values. These wrap go/constant values. In B4 they
 254  // become native Moxie values.
 255  type ConstBool struct{ V bool }
 256  type ConstInt struct{ V int64 }
 257  type ConstFloat struct {
 258  	V   float64
 259  	Lit string
 260  }
 261  type ConstStr struct{ S string }
 262  type ConstNil struct{}
 263  
 264  func untypedBool(v bool) (c ConstVal) { return &ConstBool{V: v} }
 265  func untypedInt(v int64) (c ConstVal) { return &ConstInt{V: v} }
 266  func untypedFloat(v float64) (c ConstVal) { return &ConstFloat{V: v} }
 267  func untypedStr(s string) (c ConstVal) { return &ConstStr{S: s} }
 268  func untypedNil() (c ConstVal) { return &ConstNil{} }
 269  
 270  func (c *ConstBool) String() (s string) { if c.V { return "true" }; return "false" }
 271  func (c *ConstInt) String() (s string) {
 272  	n := c.V
 273  	if n == 0 {
 274  		return "0"
 275  	}
 276  	neg := n < 0
 277  	if neg {
 278  		n = -n
 279  		if n < 0 {
 280  			return "-9223372036854775808"
 281  		}
 282  	}
 283  	buf := []byte{:0:20}
 284  	for n > 0 {
 285  		push(buf, byte('0'+n%10))
 286  		n /= 10
 287  	}
 288  	if neg {
 289  		push(buf, '-')
 290  	}
 291  	for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 {
 292  		buf[i], buf[j] = buf[j], buf[i]
 293  	}
 294  	return string(buf)
 295  }
 296  func (c *ConstFloat) String() (s string) {
 297  	if c.Lit != "" {
 298  		return NormalizeLLVMFloat(c.Lit)
 299  	}
 300  	if c.V == 0.0 {
 301  		return "0.0"
 302  	}
 303  	return "0.0"
 304  }
 305  func (c *ConstStr) String() (s string) { return c.S }
 306  func (c *ConstNil) String() (s string) { return "nil" }
 307  
 308  func NormalizeLLVMFloat(s string) (sv string) {
 309  	if len(s) == 0 {
 310  		return "0.0"
 311  	}
 312  	start := 0
 313  	if s[0] == '-' || s[0] == '+' {
 314  		start = 1
 315  	}
 316  	hasDot := false
 317  	ePos := -1
 318  	for i := start; i < len(s); i++ {
 319  		if s[i] == '.' {
 320  			hasDot = true
 321  		}
 322  		if s[i] == 'e' || s[i] == 'E' {
 323  			ePos = i
 324  			break
 325  		}
 326  	}
 327  	if !hasDot {
 328  		if ePos >= 0 {
 329  			return s[:ePos] | ".0" | s[ePos:]
 330  		}
 331  		return s | ".0"
 332  	}
 333  	dotIdx := -1
 334  	for i := start; i < len(s); i++ {
 335  		if s[i] == '.' {
 336  			dotIdx = i
 337  			break
 338  		}
 339  	}
 340  	if dotIdx == start {
 341  		s = s[:start] | "0" | s[start:]
 342  		dotIdx++
 343  	}
 344  	afterDot := dotIdx + 1
 345  	if afterDot >= len(s) || s[afterDot] == 'e' || s[afterDot] == 'E' {
 346  		s = s[:afterDot] | "0" | s[afterDot:]
 347  	}
 348  	return s
 349  }
 350  
 351  // Predeclared returns the universe-scope object with the given name, or nil.
 352  func Predeclared(name string) (o Object) {
 353  	return Universe.Lookup(name)
 354  }
 355