diff --git a/docs/annotations.md b/docs/annotations.md
index 8ae916254..ef33dab06 100644
--- a/docs/annotations.md
+++ b/docs/annotations.md
@@ -48,10 +48,11 @@ end
transpiles to
```brightscript
+sub __MyComp_method_new()
+end sub
function __MyComp_builder()
instance = {}
- instance.new = sub()
- end sub
+ instance.new = __MyComp_method_new
return instance
end function
function MyComp()
diff --git a/docs/classes.md b/docs/classes.md
index 90b0980ad..c157f0d36 100644
--- a/docs/classes.md
+++ b/docs/classes.md
@@ -19,13 +19,15 @@ end class
And here's the transpiled BrightScript code
```BrightScript
+sub __Animal_method_new()
+ m.name = invalid
+end sub
+function __Animal_method_walk()
+end function
function __Animal_builder()
instance = {}
- instance.new = sub()
- m.name = invalid
- end sub
- instance.walk = function()
- end function
+ instance.new = __Animal_method_new
+ instance.walk = __Animal_method_walk
return instance
end function
function Animal()
@@ -35,7 +37,9 @@ function Animal()
end function
```
-Notice that there are two functions created in the transpiled code for the `Animal` class. At runtime, BrighterScript classes are built in two steps in order to support class inheritance. The first step uses the `__ClassName_Build()` method to create the skeleton structure of the class. Then the class's constructor function will be run. Child classes will call the parent's `__ParentClassName_Build()` method, then rename overridden methods, and then call the child's constructor (without calling the parent constructor). Take a look at the transpiled output of the other examples below for more information on this.
+Notice that there are four functions created in the transpiled code for the `Animal` class:
+- At runtime, BrighterScript classes are built in two steps in order to support class inheritance. The first step uses the `__ClassName_builder()` method to create the skeleton structure of the class. Then the class's constructor function will be run. Child classes will call the parent's `__ParentClassName_builder()` method, then rewrite overridden methods, and then call the child's constructor (without calling the parent constructor). Take a look at the transpiled output of the other examples below for more information on this.
+- Class methods are hoisted as named functions, to prevent an excessive amount of "$anon_..." functions in stack traces, crash logs, and profiler outputs.
## Inheritance
@@ -85,15 +89,17 @@ end sub
View the transpiled BrightScript code
```BrightScript
+sub __Animal_method_new(name as string)
+ m.name = invalid
+ m.name = name
+end sub
+sub __Animal_method_move(distanceInMeters as integer)
+ print m.name + " moved " + distanceInMeters.ToStr() + " meters"
+end sub
function __Animal_builder()
instance = {}
- instance.new = sub(name as string)
- m.name = invalid
- m.name = name
- end sub
- instance.move = sub(distanceInMeters as integer)
- print m.name + " moved " + distanceInMeters.ToStr() + " meters"
- end sub
+ instance.new = __Animal_method_new
+ instance.move = __Animal_method_move
return instance
end function
function Animal(name as string)
@@ -101,17 +107,19 @@ function Animal(name as string)
instance.new(name)
return instance
end function
+sub __Duck_method_new(name as string)
+ m.super0_new(name)
+end sub
+sub __Duck_method_move(distanceInMeters as integer)
+ print "Waddling..."
+ m.super0_move(distanceInMeters)
+end sub
function __Duck_builder()
instance = __Animal_builder()
instance.super0_new = instance.new
- instance.new = sub(name as string)
- m.super0_new(name)
- end sub
+ instance.new = __Duck_method_new
instance.super0_move = instance.move
- instance.move = sub(distanceInMeters as integer)
- print "Waddling..."
- m.super0_move(distanceInMeters)
- end sub
+ instance.move = __Duck_method_move
return instance
end function
function Duck(name as string)
@@ -119,17 +127,19 @@ function Duck(name as string)
instance.new(name)
return instance
end function
+sub __BabyDuck_method_new(name as string)
+ m.super1_new(name)
+end sub
+sub __BabyDuck_method_move(distanceInMeters as integer)
+ m.super1_move(distanceInMeters)
+ print "Fell over...I'm new at this"
+end sub
function __BabyDuck_builder()
instance = __Duck_builder()
instance.super1_new = instance.new
- instance.new = sub(name as string)
- m.super1_new(name)
- end sub
+ instance.new = __BabyDuck_method_new
instance.super1_move = instance.move
- instance.move = sub(distanceInMeters as integer)
- m.super1_move(distanceInMeters)
- print "Fell over...I'm new at this"
- end sub
+ instance.move = __BabyDuck_method_move
return instance
end function
function BabyDuck(name as string)
@@ -170,13 +180,14 @@ end sub
View the transpiled BrightScript code
```BrightScript
+sub __Duck_method_new(name as string)
+ m.name = invalid
+ m.end sub = invalid
+ m.name = name
+end sub
function __Duck_builder()
instance = {}
- instance.new = sub(name as string)
- m.name = invalid
- m.end sub = invalid
- m.name = name
- end sub
+ instance.new = __Duck_method_new
return instance
end function
function Duck(name as string)
@@ -212,12 +223,13 @@ end class
View the transpiled BrightScript code
```BrightScript
+sub __Duck_method_move(name as string)
+ m.name = invalid
+ m.name = name
+end sub
function __Duck_builder()
instance = {}
- instance.new = sub(name as string)
- m.name = invalid
- m.name = name
- end sub
+ instance.new = __Duck_method_move
return instance
end function
function Duck(name as string)
@@ -225,16 +237,17 @@ function Duck(name as string)
instance.new(name)
return instance
end function
+sub __BabyDuck_method_move(name as string, age as integer)
+ m.super0_new()
+ m.age = invalid
+ 'the first line in this constructor must be a call to super()
+ m.super0_new(name)
+ m.age = age
+end sub
function __BabyDuck_builder()
instance = __Duck_builder()
instance.super0_new = instance.new
- instance.new = sub(name as string, age as integer)
- m.super0_new()
- m.age = invalid
- 'the first line in this constructor must be a call to super()
- m.super0_new(name)
- m.age = age
- end sub
+ instance.new = __BabyDuck_method_move
return instance
end function
function BabyDuck(name as string, age as integer)
@@ -267,13 +280,15 @@ end sub
View the transpiled BrightScript code
```BrightScript
+sub __Duck_method_new()
+end sub
+sub __Duck_method_Eat()
+ print "Ate all the food"
+end sub
function __Duck_builder()
instance = {}
- instance.new = sub()
- end sub
- instance.Eat = sub()
- print "Ate all the food"
- end sub
+ instance.new = __Duck_method_new
+ instance.Eat = __Duck_method_Eat
return instance
end function
function Duck()
@@ -281,15 +296,16 @@ function Duck()
instance.new()
return instance
end function
+sub __BabyDuck_method_new()
+end sub
+sub __BabyDuck_method_Eat()
+ print "Ate half the food, because I'm a baby duck"
+end sub
function __BabyDuck_builder()
instance = {}
- instance.new = sub()
- m.end sub = invalid
- end sub
- instance.super-1_Eat = instance.Eat
- instance.Eat = sub()
- print "Ate half the food, because I'm a baby duck"
- end sub
+ instance.new = __BabyDuck_method_new
+ instance.super1_Eat = instance.Eat
+ instance.Eat = __BabyDuck_method_Eat
return instance
end function
function BabyDuck()
@@ -322,13 +338,15 @@ end class
View the transpiled BrightScript code
```BrightScript
+sub __Duck_method_new()
+end sub
+sub __Duck_method_walk(meters as integer)
+ print "Walked " + meters.ToStr() + " meters"
+end sub
function __Duck_builder()
instance = {}
- instance.new = sub()
- end sub
- instance.walk = sub(meters as integer)
- print "Walked " + meters.ToStr() + " meters"
- end sub
+ instance.new = __Duck_method_new
+ instance.walk = __Duck_method_walk
return instance
end function
function Duck()
@@ -336,17 +354,19 @@ function Duck()
instance.new()
return instance
end function
+sub __BabyDuck_method_new()
+ m.super0_new()
+end sub
+sub __BabyDuck_method_walk(meters as integer)
+ print "Tripped"
+ m.super0_walk(meters)
+end sub
function __BabyDuck_builder()
instance = __Duck_builder()
instance.super0_new = instance.new
- instance.new = sub()
- m.super0_new()
- end sub
+ instance.new = __BabyDuck_method_new
instance.super0_walk = instance.walk
- instance.walk = sub(meters as integer)
- print "Tripped"
- m.super0_walk(meters)
- end sub
+ instance.walk = __BabyDuck_method_walk
return instance
end function
function BabyDuck()
@@ -383,22 +403,25 @@ end class
View the transpiled BrightScript code
```BrightScript
+sub __Person_method_new()
+ m.name = invalid
+ m.socialSecurityNumber = invalid
+end sub
+function __Person_method_getName()
+ return m.name
+end function
+sub __Person_method_setSocialSecurityNumber(value as string)
+ m.socialSecurityNumber = value
+end sub
function __Person_builder()
instance = {}
- instance.new = sub()
- m.name = invalid
- m.socialSecurityNumber = invalid
- end sub
+ instance.new = __Person_method_new
'defaults to public
'specified private
'defaults to public
- instance.getName = function()
- return m.name
- end function
+ instance.getName = __Person_method_getName
'specified private
- instance.setSocialSecurityNumber = sub(value as string)
- m.socialSecurityNumber = value
- end sub
+ instance.setSocialSecurityNumber = __Person_method_setSocialSecurityNumber
return instance
end function
function Person()
@@ -414,7 +437,7 @@ You will get compile-time errors whenever you access private members of a class
## Dynamic type by default
You can specify a type for class fields and a return type for methods. However, this is entirely optional. All fields and methods have a default type of `dynamic`. However, BrighterScript will attempt to infer the type from usage. Take this for example:
-```vb
+```BrighterScript
class Person
'defaults to type "dynamic"
name
@@ -432,18 +455,20 @@ end class
View the transpiled BrightScript code
```BrightScript
+sub __Person_method_new()
+ m.name = invalid
+ m.age = 12
+end sub
+function __Person_method_getAge()
+ return m.age
+end function
function __Person_builder()
instance = {}
- instance.new = sub()
- m.name = invalid
- m.age = 12
- end sub
+ instance.new = __Person_method_new
'defaults to type "dynamic"
'infers type "integer"
'infers type "integer"
- instance.getAge = function()
- return m.age
- end function
+ instance.getAge = __Person_method_getAge
return instance
end function
function Person()
@@ -467,12 +492,13 @@ end class
View the transpiled BrightScript code
```BrightScript
+sub __Duck_method_new()
+ m.name = "Donald"
+ m.hasChildren = true
+end sub
function __Duck_builder()
instance = {}
- instance.new = sub()
- m.name = "Donald"
- m.hasChildren = true
- end sub
+ instance.new = __Duck_method_new
return instance
end function
function Duck()
@@ -517,10 +543,11 @@ end namespace
View the transpiled BrightScript code
```BrightScript
+sub __Vertibrates_Birds_Animal_method_new()
+end sub
function __Vertibrates_Birds_Animal_builder()
instance = {}
- instance.new = sub()
- end sub
+ instance.new = __Vertibrates_Birds_Animal_method_new
return instance
end function
function Vertibrates_Birds_Animal()
@@ -528,12 +555,13 @@ function Vertibrates_Birds_Animal()
instance.new()
return instance
end function
+sub __Vertibrates_Birds_Duck_method_new()
+ m.super0_new()
+end sub
function __Vertibrates_Birds_Duck_builder()
instance = __Vertibrates_Birds_Animal_builder()
instance.super0_new = instance.new
- instance.new = sub()
- m.super0_new()
- end sub
+ instance.new = __Vertibrates_Birds_Duck_method_new
return instance
end function
function Vertibrates_Birds_Duck()
@@ -580,14 +608,16 @@ end sub
View the transpiled BrightScript code
```BrightScript
+sub __Person_method_new(name as string)
+ m.name = name
+end sub
+sub __Person_method_sayHello()
+ print m.name
+end sub
function __Person_builder()
instance = {}
- instance.new = sub(name as string)
- m.name = name
- end sub
- instance.sayHello = sub()
- print m.name
- end sub
+ instance.new = __Person_method_new
+ instance.sayHello = __Person_method_sayHello
return instance
end function
function Person(name as string)
@@ -628,15 +658,16 @@ end class
View the transpiled BrightScript code
```BrightScript
+sub __Video_method_new()
+ m.url = invalid
+ m.length = invalid
+ m.subtitleUrl = invalid
+ m.rating = invalid
+ m.genre = invalid
+end sub
function __Video_builder()
instance = {}
- instance.new = sub()
- m.url = invalid
- m.length = invalid
- m.subtitleUrl = invalid
- m.rating = invalid
- m.genre = invalid
- end sub
+ instance.new = __Video_method_new
return instance
end function
function Video()
diff --git a/src/files/BrsFile.Class.spec.ts b/src/files/BrsFile.Class.spec.ts
index 6ad265412..d0ae89065 100644
--- a/src/files/BrsFile.Class.spec.ts
+++ b/src/files/BrsFile.Class.spec.ts
@@ -251,12 +251,13 @@ describe('BrsFile BrighterScript classes', () => {
end sub
end class
`, `
+ sub __Animal_method_new()
+ m.species1 = "Animal"
+ print "From Animal: " + m.species
+ end sub
function __Animal_builder()
instance = {}
- instance.new = sub()
- m.species1 = "Animal"
- print "From Animal: " + m.species
- end sub
+ instance.new = __Animal_method_new
return instance
end function
function Animal()
@@ -264,14 +265,15 @@ describe('BrsFile BrighterScript classes', () => {
instance.new()
return instance
end function
+ sub __Duck_method_new()
+ m.super0_new()
+ m.species2 = "Duck"
+ print "From Duck: " + m.species
+ end sub
function __Duck_builder()
instance = __Animal_builder()
instance.super0_new = instance.new
- instance.new = sub()
- m.super0_new()
- m.species2 = "Duck"
- print "From Duck: " + m.species
- end sub
+ instance.new = __Duck_method_new
return instance
end function
function Duck()
@@ -293,10 +295,11 @@ describe('BrsFile BrighterScript classes', () => {
end sub
end class
`, `
+ sub __Animal_method_new()
+ end sub
function __Animal_builder()
instance = {}
- instance.new = sub()
- end sub
+ instance.new = __Animal_method_new
return instance
end function
function Animal()
@@ -304,13 +307,14 @@ describe('BrsFile BrighterScript classes', () => {
instance.new()
return instance
end function
+ sub __Duck_method_new()
+ 'comment should not cause double super call
+ m.super0_new()
+ end sub
function __Duck_builder()
instance = __Animal_builder()
instance.super0_new = instance.new
- instance.new = sub()
- 'comment should not cause double super call
- m.super0_new()
- end sub
+ instance.new = __Duck_method_new
return instance
end function
function Duck()
@@ -332,10 +336,11 @@ describe('BrsFile BrighterScript classes', () => {
end sub
end class
`, `
+ sub __Animal_method_new()
+ end sub
function __Animal_builder()
instance = {}
- instance.new = sub()
- end sub
+ instance.new = __Animal_method_new
return instance
end function
function Animal()
@@ -343,13 +348,14 @@ describe('BrsFile BrighterScript classes', () => {
instance.new()
return instance
end function
+ sub __Duck_method_new()
+ print "I am a statement which does not use m"
+ m.super0_new()
+ end sub
function __Duck_builder()
instance = __Animal_builder()
instance.super0_new = instance.new
- instance.new = sub()
- print "I am a statement which does not use m"
- m.super0_new()
- end sub
+ instance.new = __Duck_method_new
return instance
end function
function Duck()
@@ -372,11 +378,12 @@ describe('BrsFile BrighterScript classes', () => {
className3 = "BabyDuck"
end class
`, `
+ sub __Animal_method_new()
+ m.className1 = "Animal"
+ end sub
function __Animal_builder()
instance = {}
- instance.new = sub()
- m.className1 = "Animal"
- end sub
+ instance.new = __Animal_method_new
return instance
end function
function Animal()
@@ -384,13 +391,14 @@ describe('BrsFile BrighterScript classes', () => {
instance.new()
return instance
end function
+ sub __Duck_method_new()
+ m.super0_new()
+ m.className2 = "Duck"
+ end sub
function __Duck_builder()
instance = __Animal_builder()
instance.super0_new = instance.new
- instance.new = sub()
- m.super0_new()
- m.className2 = "Duck"
- end sub
+ instance.new = __Duck_method_new
return instance
end function
function Duck()
@@ -398,13 +406,14 @@ describe('BrsFile BrighterScript classes', () => {
instance.new()
return instance
end function
+ sub __BabyDuck_method_new()
+ m.super1_new()
+ m.className3 = "BabyDuck"
+ end sub
function __BabyDuck_builder()
instance = __Duck_builder()
instance.super1_new = instance.new
- instance.new = sub()
- m.super1_new()
- m.className3 = "BabyDuck"
- end sub
+ instance.new = __BabyDuck_method_new
return instance
end function
function BabyDuck()
@@ -424,10 +433,11 @@ describe('BrsFile BrighterScript classes', () => {
end class
end namespace
`, `
+ sub __Birds_WaterFowl_Duck_method_new()
+ end sub
function __Birds_WaterFowl_Duck_builder()
instance = {}
- instance.new = sub()
- end sub
+ instance.new = __Birds_WaterFowl_Duck_method_new
return instance
end function
function Birds_WaterFowl_Duck()
@@ -435,12 +445,13 @@ describe('BrsFile BrighterScript classes', () => {
instance.new()
return instance
end function
+ sub __Birds_WaterFowl_BabyDuck_method_new()
+ m.super0_new()
+ end sub
function __Birds_WaterFowl_BabyDuck_builder()
instance = __Birds_WaterFowl_Duck_builder()
instance.super0_new = instance.new
- instance.new = sub()
- m.super0_new()
- end sub
+ instance.new = __Birds_WaterFowl_BabyDuck_method_new
return instance
end function
function Birds_WaterFowl_BabyDuck()
@@ -456,10 +467,11 @@ describe('BrsFile BrighterScript classes', () => {
class Duck
end class
`, `
+ sub __Duck_method_new()
+ end sub
function __Duck_builder()
instance = {}
- instance.new = sub()
- end sub
+ instance.new = __Duck_method_new
return instance
end function
function Duck()
@@ -487,10 +499,11 @@ describe('BrsFile BrighterScript classes', () => {
class BabyDuck extends Duck
end class
`, `
+ sub __Animal_method_new(p1)
+ end sub
function __Animal_builder()
instance = {}
- instance.new = sub(p1)
- end sub
+ instance.new = __Animal_method_new
return instance
end function
function Animal(p1)
@@ -498,12 +511,13 @@ describe('BrsFile BrighterScript classes', () => {
instance.new(p1)
return instance
end function
+ sub __Bird_method_new(p1)
+ m.super0_new(p1)
+ end sub
function __Bird_builder()
instance = __Animal_builder()
instance.super0_new = instance.new
- instance.new = sub(p1)
- m.super0_new(p1)
- end sub
+ instance.new = __Bird_method_new
return instance
end function
function Bird(p1)
@@ -511,13 +525,14 @@ describe('BrsFile BrighterScript classes', () => {
instance.new(p1)
return instance
end function
+ sub __Duck_method_new(p1, p2)
+ m.super1_new(p1)
+ m.p2 = p2
+ end sub
function __Duck_builder()
instance = __Bird_builder()
instance.super1_new = instance.new
- instance.new = sub(p1, p2)
- m.super1_new(p1)
- m.p2 = p2
- end sub
+ instance.new = __Duck_method_new
return instance
end function
function Duck(p1, p2)
@@ -525,12 +540,13 @@ describe('BrsFile BrighterScript classes', () => {
instance.new(p1, p2)
return instance
end function
+ sub __BabyDuck_method_new(p1, p2)
+ m.super2_new(p1, p2)
+ end sub
function __BabyDuck_builder()
instance = __Duck_builder()
instance.super2_new = instance.new
- instance.new = sub(p1, p2)
- m.super2_new(p1, p2)
- end sub
+ instance.new = __BabyDuck_method_new
return instance
end function
function BabyDuck(p1, p2)
@@ -548,10 +564,11 @@ describe('BrsFile BrighterScript classes', () => {
end sub
end class
`, `
+ sub __Duck_method_new(name as string, age as integer)
+ end sub
function __Duck_builder()
instance = {}
- instance.new = sub(name as string, age as integer)
- end sub
+ instance.new = __Duck_method_new
return instance
end function
function Duck(name as string, age as integer)
@@ -576,10 +593,11 @@ describe('BrsFile BrighterScript classes', () => {
end sub
end class
`, `
+ sub __Animal_method_new(name as string)
+ end sub
function __Animal_builder()
instance = {}
- instance.new = sub(name as string)
- end sub
+ instance.new = __Animal_method_new
return instance
end function
function Animal(name as string)
@@ -587,13 +605,14 @@ describe('BrsFile BrighterScript classes', () => {
instance.new(name)
return instance
end function
+ sub __Duck_method_new(name as string, age as integer)
+ m.super0_new(name)
+ m.super0_DoSomething()
+ end sub
function __Duck_builder()
instance = __Animal_builder()
instance.super0_new = instance.new
- instance.new = sub(name as string, age as integer)
- m.super0_new(name)
- m.super0_DoSomething()
- end sub
+ instance.new = __Duck_method_new
return instance
end function
function Duck(name as string, age as integer)
@@ -623,13 +642,15 @@ describe('BrsFile BrighterScript classes', () => {
end function
end class
`, `
+ sub __Creature_method_new(name as string)
+ end sub
+ function __Creature_method_sayHello(text)
+ ? text
+ end function
function __Creature_builder()
instance = {}
- instance.new = sub(name as string)
- end sub
- instance.sayHello = function(text)
- ? text
- end function
+ instance.new = __Creature_method_new
+ instance.sayHello = __Creature_method_sayHello
return instance
end function
function Creature(name as string)
@@ -637,19 +658,21 @@ describe('BrsFile BrighterScript classes', () => {
instance.new(name)
return instance
end function
+ sub __Duck_method_new(name as string)
+ m.super0_new(name)
+ end sub
+ function __Duck_method_sayHello(text)
+ text = "The duck says " + text
+ if text <> invalid
+ m.super0_sayHello(text)
+ end if
+ end function
function __Duck_builder()
instance = __Creature_builder()
instance.super0_new = instance.new
- instance.new = sub(name as string)
- m.super0_new(name)
- end sub
+ instance.new = __Duck_method_new
instance.super0_sayHello = instance.sayHello
- instance.sayHello = function(text)
- text = "The duck says " + text
- if text <> invalid
- m.super0_sayHello(text)
- end if
- end function
+ instance.sayHello = __Duck_method_sayHello
return instance
end function
function Duck(name as string)
@@ -728,10 +751,11 @@ describe('BrsFile BrighterScript classes', () => {
end sub
end class
`, `
+ sub __Parent_method_new()
+ end sub
function __Parent_builder()
instance = {}
- instance.new = sub()
- end sub
+ instance.new = __Parent_method_new
return instance
end function
function Parent()
@@ -739,12 +763,13 @@ describe('BrsFile BrighterScript classes', () => {
instance.new()
return instance
end function
+ sub __Child_method_new()
+ m.super0_new()
+ end sub
function __Child_builder()
instance = __Parent_builder()
instance.super0_new = instance.new
- instance.new = sub()
- m.super0_new()
- end sub
+ instance.new = __Child_method_new
return instance
end function
function Child()
@@ -766,11 +791,12 @@ describe('BrsFile BrighterScript classes', () => {
name = "Bob"
end class
`, `
+ sub __Person_method_new()
+ m.name = "Bob"
+ end sub
function __Person_builder()
instance = {}
- instance.new = sub()
- m.name = "Bob"
- end sub
+ instance.new = __Person_method_new
return instance
end function
function Person()
@@ -826,15 +852,17 @@ describe('BrsFile BrighterScript classes', () => {
'> Waddling...\\nDewey moved 2 meters\\nFell over...I'm new at this
end sub
`, `
+ sub __Animal_method_new(name as string)
+ m.name = invalid
+ m.name = name
+ end sub
+ sub __Animal_method_move(distanceInMeters as integer)
+ print m.name + " moved " + distanceInMeters.ToStr() + " meters"
+ end sub
function __Animal_builder()
instance = {}
- instance.new = sub(name as string)
- m.name = invalid
- m.name = name
- end sub
- instance.move = sub(distanceInMeters as integer)
- print m.name + " moved " + distanceInMeters.ToStr() + " meters"
- end sub
+ instance.new = __Animal_method_new
+ instance.move = __Animal_method_move
return instance
end function
function Animal(name as string)
@@ -842,17 +870,19 @@ describe('BrsFile BrighterScript classes', () => {
instance.new(name)
return instance
end function
+ sub __Duck_method_new(name as string)
+ m.super0_new(name)
+ end sub
+ sub __Duck_method_move(distanceInMeters as integer)
+ print "Waddling..."
+ m.super0_move(distanceInMeters)
+ end sub
function __Duck_builder()
instance = __Animal_builder()
instance.super0_new = instance.new
- instance.new = sub(name as string)
- m.super0_new(name)
- end sub
+ instance.new = __Duck_method_new
instance.super0_move = instance.move
- instance.move = sub(distanceInMeters as integer)
- print "Waddling..."
- m.super0_move(distanceInMeters)
- end sub
+ instance.move = __Duck_method_move
return instance
end function
function Duck(name as string)
@@ -860,17 +890,19 @@ describe('BrsFile BrighterScript classes', () => {
instance.new(name)
return instance
end function
+ sub __BabyDuck_method_new(name as string)
+ m.super1_new(name)
+ end sub
+ sub __BabyDuck_method_move(distanceInMeters as integer)
+ m.super1_move(distanceInMeters)
+ print "Fell over...I'm new at this"
+ end sub
function __BabyDuck_builder()
instance = __Duck_builder()
instance.super1_new = instance.new
- instance.new = sub(name as string)
- m.super1_new(name)
- end sub
+ instance.new = __BabyDuck_method_new
instance.super1_move = instance.move
- instance.move = sub(distanceInMeters as integer)
- m.super1_move(distanceInMeters)
- print "Fell over...I'm new at this"
- end sub
+ instance.move = __BabyDuck_method_move
return instance
end function
function BabyDuck(name as string)
@@ -908,13 +940,15 @@ describe('BrsFile BrighterScript classes', () => {
end sub
end class
`, `
+ sub __Duck_method_new()
+ end sub
+ sub __Duck_method_walk(meters as integer)
+ print "Walked " + meters.ToStr() + " meters"
+ end sub
function __Duck_builder()
instance = {}
- instance.new = sub()
- end sub
- instance.walk = sub(meters as integer)
- print "Walked " + meters.ToStr() + " meters"
- end sub
+ instance.new = __Duck_method_new
+ instance.walk = __Duck_method_walk
return instance
end function
function Duck()
@@ -922,17 +956,19 @@ describe('BrsFile BrighterScript classes', () => {
instance.new()
return instance
end function
+ sub __BabyDuck_method_new()
+ m.super0_new()
+ end sub
+ sub __BabyDuck_method_walk(meters as integer)
+ print "Tripped"
+ m.super0_walk(meters)
+ end sub
function __BabyDuck_builder()
instance = __Duck_builder()
instance.super0_new = instance.new
- instance.new = sub()
- m.super0_new()
- end sub
+ instance.new = __BabyDuck_method_new
instance.super0_walk = instance.walk
- instance.walk = sub(meters as integer)
- print "Tripped"
- m.super0_walk(meters)
- end sub
+ instance.walk = __BabyDuck_method_walk
return instance
end function
function BabyDuck()
@@ -955,11 +991,12 @@ describe('BrsFile BrighterScript classes', () => {
end enum
end namespace
`, `
+ sub __MyNS_HasEnumKlass_method_new()
+ m.enumValue = "A"
+ end sub
function __MyNS_HasEnumKlass_builder()
instance = {}
- instance.new = sub()
- m.enumValue = "A"
- end sub
+ instance.new = __MyNS_HasEnumKlass_method_new
return instance
end function
function MyNS_HasEnumKlass()
@@ -989,12 +1026,13 @@ describe('BrsFile BrighterScript classes', () => {
end enum
end namespace
`, `
+ sub __MyNS_SubKlass_method_new()
+ m.super0_new("B")
+ end sub
function __MyNS_SubKlass_builder()
instance = __MyNS_SuperKlass_builder()
instance.super0_new = instance.new
- instance.new = sub()
- m.super0_new("B")
- end sub
+ instance.new = __MyNS_SubKlass_method_new
return instance
end function
function MyNS_SubKlass()
@@ -1002,11 +1040,12 @@ describe('BrsFile BrighterScript classes', () => {
instance.new()
return instance
end function
+ sub __MyNS_SuperKlass_method_new(enumVal)
+ print enumVal
+ end sub
function __MyNS_SuperKlass_builder()
instance = {}
- instance.new = sub(enumVal)
- print enumVal
- end sub
+ instance.new = __MyNS_SuperKlass_method_new
return instance
end function
function MyNS_SuperKlass(enumVal)
@@ -1034,16 +1073,17 @@ describe('BrsFile BrighterScript classes', () => {
end enum
end namespace
`, `
+ sub __MyNS_HasEnumKlass_method_new()
+ m.myArray = [
+ true
+ true
+ ]
+ m.myArray[0] = true
+ m.myArray[1] = false
+ end sub
function __MyNS_HasEnumKlass_builder()
instance = {}
- instance.new = sub()
- m.myArray = [
- true
- true
- ]
- m.myArray[0] = true
- m.myArray[1] = false
- end sub
+ instance.new = __MyNS_HasEnumKlass_method_new
return instance
end function
function MyNS_HasEnumKlass()
@@ -1070,16 +1110,17 @@ describe('BrsFile BrighterScript classes', () => {
end enum
end namespace
`, `
+ sub __MyNS_HasEnumKlass_method_new()
+ m.myArray = [
+ true
+ true
+ ]
+ m.myArray[0] = true
+ m.myArray[1] = false
+ end sub
function __MyNS_HasEnumKlass_builder()
instance = {}
- instance.new = sub()
- m.myArray = [
- true
- true
- ]
- m.myArray[0] = true
- m.myArray[1] = false
- end sub
+ instance.new = __MyNS_HasEnumKlass_method_new
return instance
end function
function MyNS_HasEnumKlass()
@@ -1197,13 +1238,15 @@ describe('BrsFile BrighterScript classes', () => {
expect(
fsExtra.readFileSync(s`${stagingDir}/source/lib.brs`).toString().trimEnd()
).to.eql(trim`
+ sub __Being_method_new()
+ end sub
+ function __Being_method_think()
+ print "thinking..."
+ end function
function __Being_builder()
instance = {}
- instance.new = sub()
- end sub
- instance.think = function()
- print "thinking..."
- end function
+ instance.new = __Being_method_new
+ instance.think = __Being_method_think
return instance
end function
function Being()
@@ -1211,15 +1254,17 @@ describe('BrsFile BrighterScript classes', () => {
instance.new()
return instance
end function
+ sub __Human_method_new()
+ m.super0_new()
+ end sub
+ function __Human_method_think()
+ m.super0_think()
+ end function
function __Human_builder()
instance = __Being_builder()
instance.super0_new = instance.new
- instance.new = sub()
- m.super0_new()
- end sub
- instance.think = function()
- m.super0_think()
- end function
+ instance.new = __Human_method_new
+ instance.think = __Human_method_think
return instance
end function
function Human()
@@ -1687,12 +1732,13 @@ describe('BrsFile BrighterScript classes', () => {
end class
end namespace
`, `
+ sub __App_ClassC_method_new()
+ m.super1_new()
+ end sub
function __App_ClassC_builder()
instance = __App_ClassB_builder()
instance.super1_new = instance.new
- instance.new = sub()
- m.super1_new()
- end sub
+ instance.new = __App_ClassC_method_new
return instance
end function
function App_ClassC()
@@ -1715,12 +1761,13 @@ describe('BrsFile BrighterScript classes', () => {
end class
end namespace
`, `
+ sub __App_ClassB_method_new()
+ m.super0_new()
+ end sub
function __App_ClassB_builder()
instance = __ClassA_builder()
instance.super0_new = instance.new
- instance.new = sub()
- m.super0_new()
- end sub
+ instance.new = __App_ClassB_method_new
return instance
end function
function App_ClassB()
@@ -1787,11 +1834,12 @@ describe('BrsFile BrighterScript classes', () => {
end class
end namespace
`, `
+ sub __App_CoreClass_method_new()
+ print "CoreClass.new()"
+ end sub
function __App_CoreClass_builder()
instance = {}
- instance.new = sub()
- print "CoreClass.new()"
- end sub
+ instance.new = __App_CoreClass_method_new
return instance
end function
function App_CoreClass()
@@ -1799,12 +1847,13 @@ describe('BrsFile BrighterScript classes', () => {
instance.new()
return instance
end function
+ sub __App_Logic_FirstClass_method_new()
+ m.super0_new()
+ end sub
function __App_Logic_FirstClass_builder()
instance = __App_CoreClass_builder()
instance.super0_new = instance.new
- instance.new = sub()
- m.super0_new()
- end sub
+ instance.new = __App_Logic_FirstClass_method_new
return instance
end function
function App_Logic_FirstClass()
@@ -1812,12 +1861,13 @@ describe('BrsFile BrighterScript classes', () => {
instance.new()
return instance
end function
+ sub __App_Logic_SecondClass_method_new()
+ m.super1_new()
+ end sub
function __App_Logic_SecondClass_builder()
instance = __App_Logic_FirstClass_builder()
instance.super1_new = instance.new
- instance.new = sub()
- m.super1_new()
- end sub
+ instance.new = __App_Logic_SecondClass_method_new
return instance
end function
function App_Logic_SecondClass()
@@ -1825,12 +1875,13 @@ describe('BrsFile BrighterScript classes', () => {
instance.new()
return instance
end function
+ sub __App_OtherLogic_FinalClass_method_new()
+ m.super2_new()
+ end sub
function __App_OtherLogic_FinalClass_builder()
instance = __App_Logic_SecondClass_builder()
instance.super2_new = instance.new
- instance.new = sub()
- m.super2_new()
- end sub
+ instance.new = __App_OtherLogic_FinalClass_method_new
return instance
end function
function App_OtherLogic_FinalClass()
diff --git a/src/files/BrsFile.spec.ts b/src/files/BrsFile.spec.ts
index 24b613729..dfac05a94 100644
--- a/src/files/BrsFile.spec.ts
+++ b/src/files/BrsFile.spec.ts
@@ -2387,14 +2387,16 @@ describe('BrsFile', () => {
' alpha.charlie()
end sub
+ sub __Person_method_new()
+ m.name = invalid
+ print m.name
+ end sub
+ sub __Person_method_test()
+ end sub
function __Person_builder()
instance = {}
- instance.new = sub()
- m.name = invalid
- print m.name
- end sub
- instance.test = sub()
- end sub
+ instance.new = __Person_method_new
+ instance.test = __Person_method_test
return instance
end function
function Person()
diff --git a/src/parser/Statement.ts b/src/parser/Statement.ts
index d3fc7b46e..ea8fee117 100644
--- a/src/parser/Statement.ts
+++ b/src/parser/Statement.ts
@@ -2036,14 +2036,19 @@ export class ClassStatement extends Statement implements TypedefProvider {
transpile(state: BrsTranspileState) {
let result = [] as TranspileResult;
+
+ const className = this.getName(ParseMode.BrightScript).replace(/\./g, '_');
+ const ancestors = this.getAncestors(state);
+ const body = this.getTranspiledClassBody(ancestors);
+
+ //make the methods
+ result.push(...this.getTranspiledMethods(state, className, body));
//make the builder
- result.push(...this.getTranspiledBuilder(state));
- result.push(
- '\n',
- state.indent()
- );
+ result.push(...this.getTranspiledBuilder(state, className, ancestors, body));
+ result.push('\n', state.indent());
//make the class assembler (i.e. the public-facing class creator method)
- result.push(...this.getTranspiledClassFunction(state));
+ result.push(...this.getTranspiledClassFunction(state, className));
+
return result;
}
@@ -2158,11 +2163,12 @@ export class ClassStatement extends Statement implements TypedefProvider {
return ancestors;
}
- private getBuilderName(name: string) {
- if (name.includes('.')) {
- name = name.replace(/\./gi, '_');
- }
- return `__${name}_builder`;
+ private getBuilderName(transpiledClassName: string) {
+ return `__${transpiledClassName}_builder`;
+ }
+
+ private getMethodIdentifier(transpiledClassName: string, statement: MethodStatement) {
+ return { ...statement.name, text: `__${transpiledClassName}_method_${statement.name.text}` };
}
/**
@@ -2207,18 +2213,13 @@ export class ClassStatement extends Statement implements TypedefProvider {
* This needs to be a separate function so that child classes can call the builder from their parent
* without instantiating the parent constructor at that point in time.
*/
- private getTranspiledBuilder(state: BrsTranspileState) {
+ private getTranspiledBuilder(state: BrsTranspileState, transpiledClassName: string, ancestors: ClassStatement[], body: Statement[]) {
let result = [] as TranspileResult;
- result.push(`function ${this.getBuilderName(this.getName(ParseMode.BrightScript)!)}()\n`);
+ result.push(`function ${this.getBuilderName(transpiledClassName)}()\n`);
state.blockDepth++;
//indent
result.push(state.indent());
- /**
- * The lineage of this class. index 0 is a direct parent, index 1 is index 0's parent, etc...
- */
- let ancestors = this.getAncestors(state);
-
//construct parent class or empty object
if (ancestors[0]) {
const ancestorNamespace = ancestors[0].findAncestor(isNamespaceStatement);
@@ -2226,9 +2227,7 @@ export class ClassStatement extends Statement implements TypedefProvider {
ancestors[0].getName(ParseMode.BrighterScript)!,
ancestorNamespace?.getName(ParseMode.BrighterScript)
);
- result.push(
- 'instance = ',
- this.getBuilderName(fullyQualifiedClassName), '()');
+ result.push(`instance = ${this.getBuilderName(fullyQualifiedClassName.replace(/\./g, '_'))}()`);
} else {
//use an empty object.
result.push('instance = {}');
@@ -2239,43 +2238,6 @@ export class ClassStatement extends Statement implements TypedefProvider {
);
let parentClassIndex = this.getParentClassIndex(state);
- let body = this.body;
- //inject an empty "new" method if missing
- if (!this.getConstructorFunction()) {
- if (ancestors.length === 0) {
- body = [
- createMethodStatement('new', TokenKind.Sub),
- ...this.body
- ];
- } else {
- const params = this.getConstructorParams(ancestors);
- const call = new ExpressionStatement(
- new CallExpression(
- new VariableExpression(createToken(TokenKind.Identifier, 'super')),
- createToken(TokenKind.LeftParen),
- createToken(TokenKind.RightParen),
- params.map(x => new VariableExpression(x.name))
- )
- );
- body = [
- new MethodStatement(
- [],
- createIdentifier('new'),
- new FunctionExpression(
- params.map(x => x.clone()),
- new Block([call]),
- createToken(TokenKind.Sub),
- createToken(TokenKind.EndSub),
- createToken(TokenKind.LeftParen),
- createToken(TokenKind.RightParen)
- ),
- null
- ),
- ...this.body
- ];
- }
- }
-
for (let statement of body) {
//is field statement
if (isFieldStatement(statement)) {
@@ -2304,7 +2266,7 @@ export class ClassStatement extends Statement implements TypedefProvider {
'instance.',
state.transpileToken(statement.name),
' = ',
- ...statement.transpile(state),
+ state.transpileToken(this.getMethodIdentifier(transpiledClassName, statement)),
state.newline,
state.indent()
);
@@ -2326,12 +2288,74 @@ export class ClassStatement extends Statement implements TypedefProvider {
return result;
}
+ /**
+ * Returns a copy of the class' body, with the constructor function added if it doesn't exist.
+ */
+ private getTranspiledClassBody(ancestors: ClassStatement[]): Statement[] {
+ const body = [];
+ body.push(...this.body);
+
+ //inject an empty "new" method if missing
+ if (!this.getConstructorFunction()) {
+ if (ancestors.length === 0) {
+ body.unshift(createMethodStatement('new', TokenKind.Sub));
+ } else {
+ const params = this.getConstructorParams(ancestors);
+ const call = new ExpressionStatement(
+ new CallExpression(
+ new VariableExpression(createToken(TokenKind.Identifier, 'super')),
+ createToken(TokenKind.LeftParen),
+ createToken(TokenKind.RightParen),
+ params.map(x => new VariableExpression(x.name))
+ )
+ );
+ body.unshift(
+ new MethodStatement(
+ [],
+ createIdentifier('new'),
+ new FunctionExpression(
+ params.map(x => x.clone()),
+ new Block([call]),
+ createToken(TokenKind.Sub),
+ createToken(TokenKind.EndSub),
+ createToken(TokenKind.LeftParen),
+ createToken(TokenKind.RightParen)
+ ),
+ null
+ )
+ );
+ }
+ }
+
+ return body;
+ }
+
+ /**
+ * These are the methods that are defined in this class. They are transpiled outside of the class body
+ * to ensure they don't appear as "$anon_#" in stack traces and crash logs.
+ */
+ private getTranspiledMethods(state: BrsTranspileState, transpiledClassName: string, body: Statement[]) {
+ let result = [] as TranspileResult;
+ for (let statement of body) {
+ if (isMethodStatement(statement)) {
+ state.classStatement = this;
+ result.push(
+ ...statement.transpile(state, this.getMethodIdentifier(transpiledClassName, statement)),
+ state.newline,
+ state.indent()
+ );
+ delete state.classStatement;
+ }
+ }
+ return result;
+ }
+
/**
* The class function is the function with the same name as the class. This is the function that
* consumers should call to create a new instance of that class.
* This invokes the builder, gets an instance of the class, then invokes the "new" function on that class.
*/
- private getTranspiledClassFunction(state: BrsTranspileState) {
+ private getTranspiledClassFunction(state: BrsTranspileState, transpiledClassName: string) {
let result = [] as TranspileResult;
const constructorFunction = this.getConstructorFunction();
@@ -2365,7 +2389,7 @@ export class ClassStatement extends Statement implements TypedefProvider {
state.blockDepth++;
result.push(state.indent());
- result.push(`instance = ${this.getBuilderName(this.getName(ParseMode.BrightScript)!)}()\n`);
+ result.push(`instance = ${this.getBuilderName(transpiledClassName)}()\n`);
result.push(state.indent());
result.push(`instance.new(`);
@@ -2461,7 +2485,7 @@ export class MethodStatement extends FunctionStatement {
return this.name.text;
}
- transpile(state: BrsTranspileState) {
+ transpile(state: BrsTranspileState, name?: Identifier) {
if (this.name.text.toLowerCase() === 'new') {
this.ensureSuperConstructorCall(state);
//TODO we need to undo this at the bottom of this method
@@ -2490,7 +2514,7 @@ export class MethodStatement extends FunctionStatement {
visitor(statement, undefined);
statement.walk(visitor, walkOptions);
}
- return this.func.transpile(state);
+ return this.func.transpile(state, name);
}
getTypedef(state: BrsTranspileState) {