registry.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. // Copyright © 2019 - 2020 Oscar Campos <oscar.campos@thepimpam.com>
  2. // Copyright © 2017 - William Edwards
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. package gdnative
  16. import (
  17. "fmt"
  18. "strings"
  19. "unicode"
  20. )
  21. // Registrable is the interface external code communicates with registryClass
  22. type Registrable interface {
  23. GetBase() string
  24. GetConstructor() string
  25. GetDestructor() string
  26. GetMethods() []string
  27. GetProperties() []string
  28. SetConstructor(*registryConstructor)
  29. SetDestructor(*registryDestructor)
  30. Constructor() string
  31. Destructor() string
  32. AddMethod(*registryMethod)
  33. AddMethods([]*registryMethod)
  34. Methods() []*registryMethod
  35. AddSignal(*registrySignal)
  36. AddSignals([]*registrySignal)
  37. Signals() []*registrySignal
  38. AddProperties([]*registryProperty)
  39. Properties() []*registryProperty
  40. }
  41. type registryClass struct {
  42. base, alias string
  43. constructor *registryConstructor
  44. destructor *registryDestructor
  45. methods []*registryMethod
  46. properties []*registryProperty
  47. signals []*registrySignal
  48. }
  49. // GetBase returns back the Godot base class for this type as a string
  50. func (rc *registryClass) GetBase() string {
  51. return rc.base
  52. }
  53. // Alias returns the class alias
  54. func (rc *registryClass) Alias() string {
  55. return rc.alias
  56. }
  57. // GetConstructor returns back this type constructor as a string
  58. func (rc *registryClass) GetConstructor() string {
  59. if rc.constructor != nil {
  60. return fmt.Sprintf("func %s() *%s", rc.constructor.customFunc, rc.constructor.class)
  61. }
  62. return ""
  63. }
  64. // SetConstructor sets this type constructor
  65. func (rc *registryClass) SetConstructor(constructor *registryConstructor) {
  66. if constructor != nil {
  67. rc.constructor = constructor
  68. }
  69. }
  70. // HasConstructor returns true if this type has custom constructor
  71. func (rc *registryClass) HasConstructor() bool {
  72. return rc.constructor != nil
  73. }
  74. // Constructor returns the constructor custom function
  75. func (rc *registryClass) Constructor() string {
  76. if rc.constructor != nil {
  77. return rc.constructor.customFunc
  78. }
  79. return ""
  80. }
  81. // GetDestructor returns back this type destructor as a string
  82. func (rc *registryClass) GetDestructor() string {
  83. if rc.destructor != nil {
  84. return fmt.Sprintf("func %s()", rc.destructor.customFunc)
  85. }
  86. return ""
  87. }
  88. // SetDestructor sets this type destructor
  89. func (rc *registryClass) SetDestructor(destructor *registryDestructor) {
  90. if destructor != nil {
  91. rc.destructor = destructor
  92. }
  93. }
  94. // HasDestructor returns true if this type has custom destructor
  95. func (rc *registryClass) HasDestructor() bool {
  96. return rc.destructor != nil
  97. }
  98. // Destructor returns the destructor custom function
  99. func (rc *registryClass) Destructor() string {
  100. if rc.destructor != nil {
  101. return rc.destructor.customFunc
  102. }
  103. return ""
  104. }
  105. // GetMethods returns back this type exported methods as strings
  106. func (rc *registryClass) GetMethods() []string {
  107. methods := []string{}
  108. for _, method := range rc.methods {
  109. methods = append(methods, fmt.Sprintf("func %s(%s) %s", method.name, method.GetParams(), method.GetReturnValues()))
  110. }
  111. return methods
  112. }
  113. // Methods returns back this type list of registryMethods
  114. func (rc *registryClass) Methods() []*registryMethod {
  115. return rc.methods
  116. }
  117. // AddMethods adds a list of methods for this type
  118. func (rc *registryClass) AddMethods(methods []*registryMethod) {
  119. for i := range methods {
  120. rc.AddMethod(methods[i])
  121. }
  122. }
  123. // AddMethod adds a method to this type
  124. func (rc *registryClass) AddMethod(method *registryMethod) {
  125. if method != nil {
  126. rc.methods = append(rc.methods, method)
  127. }
  128. }
  129. // Signals returns back this type list of registrySignals
  130. func (rc *registryClass) Signals() []*registrySignal {
  131. return rc.signals
  132. }
  133. // AddSignals adds a list of signals to this type
  134. func (rc *registryClass) AddSignals(signals []*registrySignal) {
  135. for i := range signals {
  136. rc.AddSignal(signals[i])
  137. }
  138. }
  139. // AddSignal adds a signal to this type
  140. func (rc *registryClass) AddSignal(signal *registrySignal) {
  141. if signal != nil {
  142. rc.signals = append(rc.signals, signal)
  143. }
  144. }
  145. // GetProperties returns back this class properties as strings
  146. func (rc *registryClass) GetProperties() []string {
  147. properties := []string{}
  148. for _, property := range rc.properties {
  149. properties = append(properties, property.name)
  150. }
  151. return properties
  152. }
  153. // AddProperties adds a list of properties to this type
  154. func (rc *registryClass) AddProperties(properties []*registryProperty) {
  155. for i := range properties {
  156. rc.AddProperty(properties[i])
  157. }
  158. }
  159. // AddProperty adds a property to this type
  160. func (rc *registryClass) AddProperty(property *registryProperty) {
  161. if property != nil {
  162. rc.properties = append(rc.properties, property)
  163. }
  164. }
  165. // Properties returns back this class list of registryProperty
  166. func (rc *registryClass) Properties() []*registryProperty {
  167. return rc.properties
  168. }
  169. type registryConstructor struct {
  170. class, customFunc string
  171. }
  172. type registryDestructor struct {
  173. class, customFunc string
  174. }
  175. type registryMethod struct {
  176. class, name, alias string
  177. params []*registryMethodParam
  178. returnValues []*registryMethodReturnValue
  179. }
  180. // GetName returns the method name
  181. func (rm *registryMethod) GetName() string {
  182. return rm.name
  183. }
  184. // GodotName returns the Godot name for this virtual method
  185. func (rm *registryMethod) GodotName() string {
  186. if rm.name[0] == 'V' && unicode.IsUpper(rune(rm.name[1])) {
  187. return strings.ToLower(fmt.Sprintf("_%s", rm.name[1:]))
  188. }
  189. return rm.name
  190. }
  191. // Alias returns the method alias
  192. func (rm *registryMethod) Alias() string {
  193. return rm.alias
  194. }
  195. // GetParams returns this type method params as a string
  196. func (rm *registryMethod) GetParams() string {
  197. pairs := []string{}
  198. for _, param := range rm.params {
  199. pairs = append(pairs, fmt.Sprintf("%s %s", param.name, param.kind))
  200. }
  201. return strings.Join(pairs, ", ")
  202. }
  203. // GetReturnValues returns this type method return values as a string
  204. func (rm *registryMethod) GetReturnValues() string {
  205. values := []string{}
  206. for _, value := range rm.returnValues {
  207. values = append(values, value.kind)
  208. }
  209. return strings.Join(values, ", ")
  210. }
  211. // Arguments returns a slice of this method arguments structures
  212. func (rm *registryMethod) Arguments() []*registryMethodParam {
  213. return rm.params
  214. }
  215. // HasReturns returns true if this method has return values, otherwise returns false
  216. func (rm *registryMethod) HasReturns() bool {
  217. return len(rm.returnValues) > 0
  218. }
  219. // FunctionCallWithParams returns a string representing how this method should be called
  220. func (rm *registryMethod) FunctionCallWithParams() string {
  221. arguments := make([]string, len(rm.params))
  222. for i, arg := range rm.params {
  223. arguments[i] = arg.name
  224. }
  225. return fmt.Sprintf("%s(%s)", rm.name, strings.Join(arguments, ", "))
  226. }
  227. // NewVariantType returns the right NewVariant<Type> method from gdnative for our return type
  228. func (rm *registryMethod) NewVariantType() string {
  229. variant := "NewVariant%s(gdnative.%s(value))"
  230. conversions := map[string]string{
  231. "bool": fmt.Sprintf(variant, "Bool", "Bool"),
  232. "uint": fmt.Sprintf(variant, "Uint", "Uint64T"),
  233. "int": fmt.Sprintf(variant, "Int", "Int64T"),
  234. "float64": fmt.Sprintf(variant, "Real", "Double"),
  235. "string": fmt.Sprintf(variant, "String", "String"),
  236. }
  237. retLength := len(rm.returnValues)
  238. if retLength == 1 {
  239. result, ok := conversions[rm.returnValues[0].kind]
  240. if !ok {
  241. result = "value"
  242. }
  243. return result
  244. }
  245. if retLength >= 2 && retLength <= 3 {
  246. valid := make([]bool, retLength)
  247. for i, val := range rm.returnValues {
  248. switch val.kind {
  249. case "float32", "float64", "gdnative.Double", "gdnative.Real":
  250. valid[i] = true
  251. }
  252. }
  253. allValid := true
  254. for _, b := range valid {
  255. if !b {
  256. allValid = false
  257. break
  258. }
  259. }
  260. if allValid {
  261. return fmt.Sprintf(
  262. variant,
  263. fmt.Sprintf("Vector%d", retLength),
  264. fmt.Sprintf("NewVector%d", retLength),
  265. )
  266. }
  267. }
  268. return "value"
  269. }
  270. type registryProperty struct {
  271. name, alias, kind, gdnativeKind, hint, hintString, usage, rset, setFunc, getFunc string
  272. }
  273. // Name returns the name of the property back
  274. func (rp *registryProperty) Name() string {
  275. return rp.name
  276. }
  277. // Kind returns the property type back
  278. func (rp *registryProperty) Kind() string {
  279. return rp.gdnativeKind
  280. }
  281. // Alias returns the property alias back
  282. func (rp *registryProperty) Alias() string {
  283. return rp.alias
  284. }
  285. // Hint returns the hint of the property back
  286. func (rp *registryProperty) Hint() string {
  287. return rp.hint
  288. }
  289. // HintString returns the hint string of the property back
  290. func (rp *registryProperty) HintString() string {
  291. return rp.hintString
  292. }
  293. // Usage returns the usage of the property back
  294. func (rp *registryProperty) Usage() string {
  295. return rp.usage
  296. }
  297. // RsetType returns the rset of the property back
  298. func (rp *registryProperty) RsetType() string {
  299. return rp.rset
  300. }
  301. // SetConvert writes right syntax for conversion from gdnative.Variant into Go type
  302. func (rp *registryProperty) SetConvert() string {
  303. switch rp.gdnativeKind {
  304. case "gdnative.Int":
  305. return "gdnative.Int(property.AsInt())"
  306. default:
  307. return fmt.Sprintf("property.As%s()", strings.Replace(rp.gdnativeKind, "gdnative.", "", -1))
  308. }
  309. }
  310. // GetConvert writes right syntax for conversion from Go type into gdnative.Variant
  311. func (rp *registryProperty) GetConvert() string {
  312. switch rp.gdnativeKind {
  313. case "gdnative.Int":
  314. return fmt.Sprintf("gdnative.NewVariant%s(gdnative.Int64T(class.class.%s))", rp.gdnativeKind[9:], rp.name)
  315. default:
  316. return fmt.Sprintf("gdnative.NewVariant%s(class.class.%s)", rp.gdnativeKind[9:], rp.name)
  317. }
  318. }
  319. // SetFunc returns this property set function or default one
  320. func (rp *registryProperty) SetFunc(class, instance string) string {
  321. if rp.setFunc == "" {
  322. rp.setFunc = fmt.Sprintf(`gdnative.NewGodotPropertySetter("%s", %s, %sInstances)`, class, rp.kind, instance)
  323. }
  324. return rp.setFunc
  325. }
  326. // GetFunc returns this property Get function or default one
  327. func (rp *registryProperty) GetFunc(class, instance string) string {
  328. if rp.getFunc == "" {
  329. rp.getFunc = fmt.Sprintf(`gdnative.NewGodotPropertyGetter("%s", %s, %sInstances)`, class, rp.kind, instance)
  330. }
  331. return rp.getFunc
  332. }
  333. type registrySignal struct {
  334. name, args, defaults string
  335. }
  336. // Name returns this signal name back
  337. func (rs *registrySignal) Name() string {
  338. return rs.name
  339. }
  340. // Args returns this signal args back
  341. func (rs *registrySignal) Args() string {
  342. return rs.args
  343. }
  344. // Defaults returns this signal defaults back
  345. func (rs *registrySignal) Defaults() string {
  346. return rs.defaults
  347. }
  348. type registryMethodParam struct {
  349. name, kind string
  350. }
  351. // Name returns this param name
  352. func (rmp *registryMethodParam) Name() string {
  353. return rmp.name
  354. }
  355. // Kind returns this param kind
  356. func (rmp *registryMethodParam) Kind() string {
  357. return rmp.kind
  358. }
  359. // ConvertFunction returns the right GDNative 'As<Type>' function for this param kind as a string
  360. func (rmp *registryMethodParam) ConvertFunction() string {
  361. conversions := map[string]string{
  362. "bool": "AsBool()",
  363. "uint": "AsUint()",
  364. "int": "AsInt()",
  365. "float64": "AsReal()",
  366. "string": "AsString()",
  367. "vector2": "AsVector2()",
  368. "vector3": "AsVector3()",
  369. "rect2": "AsRect2()",
  370. "transform2d": "AsTransform2D()",
  371. "plane": "AsPlane()",
  372. "quat": "AsQuat()",
  373. "aabb": "AsAabb()",
  374. "basis": "AsBasis()",
  375. "transform": "AsTransform()",
  376. "color": "AsColor()",
  377. "nodepath": "AsNodePath()",
  378. "rid": "AsRid()",
  379. "object": "AsObject()",
  380. "dictionary": "AsDictionary()",
  381. "arraytype": "AsArray()",
  382. "arraytype_byte": "AsPoolByteArray()",
  383. "arraytype_int": "AsPoolIntArray()",
  384. "arraytype_float": "AsPoolRealArray()",
  385. "arraytype_string": "AsPoolStringArray()",
  386. "arraytype_vector2": "AsPoolVector2Array()",
  387. "arraytype_vector3": "AsPoolVector3Array()",
  388. "arraytype_color": "AsPoolColorArray()",
  389. }
  390. value, ok := conversions[rmp.kind]
  391. if ok {
  392. return value
  393. }
  394. switch rmp.kind {
  395. case "float32":
  396. value = conversions["float64"]
  397. case "int8", "int16", "int32", "int64", "byte":
  398. value = conversions["int"]
  399. case "uint8", "uint16", "uint32", "uint64":
  400. value = conversions["uint"]
  401. case "gdnative.Float", "gdnative.Double":
  402. value = conversions["float64"]
  403. case "gdnative.Int64T", "gdnative.SignedChar":
  404. value = conversions["int"]
  405. case "gdnative.Uint", "gdnative.Uint8T", "gdnative.Uint32T", "gdnative.Uint64T":
  406. value = conversions["uint"]
  407. case "gdnative.String", "gdnative.Char", "gdnative.WcharT":
  408. value = conversions["string"]
  409. default:
  410. if strings.HasPrefix(rmp.kind, "gdnative.") {
  411. value = rmp.kind
  412. }
  413. if strings.HasPrefix(rmp.kind, "godot.") || strings.HasPrefix(rmp.kind, "*godot.") {
  414. value = conversions["object"]
  415. }
  416. if strings.Contains(rmp.kind, "ArrayType") {
  417. value = conversions[parseArrayType(rmp.kind)]
  418. }
  419. if strings.Contains(rmp.kind, "MapType") {
  420. value = conversions["dictionary"]
  421. }
  422. }
  423. if value == "" {
  424. value = conversions["object"]
  425. }
  426. return value
  427. }
  428. type registryMethodReturnValue struct {
  429. kind string
  430. }
  431. func parseArrayType(array string) string {
  432. var arrayType string
  433. var openBracket bool
  434. var openBracketCount int
  435. for i := 0; i < len(array); i++ {
  436. if openBracket {
  437. if array[i] == ']' {
  438. openBracketCount--
  439. if openBracketCount == 0 {
  440. openBracket = false
  441. continue
  442. }
  443. }
  444. if array[i] == '[' {
  445. openBracketCount++
  446. }
  447. arrayType += string(array[i])
  448. continue
  449. }
  450. if array[i] == '[' {
  451. openBracket = true
  452. openBracketCount = 1
  453. }
  454. }
  455. return fmt.Sprintf("arraytype_%s", strings.ReplaceAll(arrayType, "gdnative.", ""))
  456. }