Created
April 13, 2024 21:43
-
-
Save adiee5/b87e0a3303b577d0122e12cb032101f1 to your computer and use it in GitHub Desktop.
An example of a object oriented programming in Prog8 language
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%import textio | |
%import lk_mem | |
%zeropage basicsafe | |
%option no_sysinit | |
main{ | |
sub start(){ | |
;sys.exit(0) | |
uword andrzej=human.new("andrzej","marecki") | |
uword poet=human.new("czes£aw","mi£osz") | |
uword girl=human.new("taylor","swift") | |
txt.print(human.get_name(andrzej)) | |
txt.chrout('\r') | |
txt.print(human.get_name(poet)) | |
txt.chrout('\r') | |
txt.print(human.get_name(girl)) | |
human.choose_job(girl,"singer",true) | |
human.choose_job(poet,"poet",true) | |
txt.chrout('\r') | |
human.marry(andrzej,girl) | |
human.marry(poet,human.new("carol","thigpen-mi£osz")) | |
human.set_statflag(poet,human.flags.dead) | |
andrzej[human.age]=20 | |
girl[human.age]=30 | |
poet[human.age]=80 | |
@(human.get_partner(poet)+human.age)=60 | |
human.print(andrzej) | |
human.print(poet) | |
human.print(girl) | |
human.print(human.get_partner(poet)) | |
uword guy=human.repurpose(human.get_partner(poet),"david","murray",false) | |
guy[human.age]=40 | |
human.choose_job(guy,"8-bit guy",true) | |
human.print(guy) | |
} | |
} | |
human{ | |
const ubyte SIZE=(2+1)+1+1+2+(2+1)+(2+1) | |
const ubyte name =0; &str + len() | |
const ubyte age=3; ubyte | |
const ubyte status=4; 8 bits | |
const ubyte partner=5; &obj | |
const ubyte last_name=7; &str + len() | |
const ubyte job=10; &str + len() | |
sub flags(){ ; IT'S NOT A FUNCTION!!!!!!, it's just a scope for constant bolean values of status atribute | |
const ubyte dead=$80 | |
const ubyte married=$40 | |
const ubyte employed=$20 | |
;$10 | |
;8 | |
;4 | |
;2 | |
;1 | |
} | |
;allocates memory for new object and names. returns the pointer to new object | |
sub new(str new_name, str new_last_name)->uword{ | |
void new_empty() | |
tempuword=mpg.copy(new_name) | |
if not tempuword{ | |
txt.color(10) | |
txt.print("there's no space left for the new 'human' object, the program's going to quit") | |
txt.color(1) | |
sys.exit(0) | |
} | |
tempresult[name]=lsb(tempuword) | |
tempresult[name+1]=msb(tempuword) | |
tempresult[name+2]=string.length(tempuword) | |
tempuword=mpg.copy(new_last_name) | |
if not tempuword{ | |
txt.color(10) | |
txt.print("there's no space left for the new 'human' object, the program's going to quit") | |
txt.color(1) | |
sys.exit(0) | |
} | |
tempresult[last_name]=lsb(tempuword) | |
tempresult[last_name+1]=msb(tempuword) | |
tempresult[last_name+2]=string.length(tempuword) | |
return tempresult | |
} | |
; similar to human.new(), but only allocates the object itself and you'll need to set name and last_name afterwards | |
sub new_empty()->uword{ | |
tempresult=mpg.alloc(SIZE,true) | |
if not tempresult{ | |
txt.color(10) | |
txt.print("there's no space left for the new 'human' object, the program's going to quit") | |
txt.color(1) | |
sys.exit(0) | |
} | |
return tempresult | |
} | |
;repurposes the existing human object to another one. | |
;last argument determines if you want to make new memory allocations | |
;in case old string buffers are too small. | |
;NOTE: since prog8 doesn't have any kind of pointer ownership management etc. | |
;variables, that already hold the reference to this object, are still going to reference it. | |
;it will however make sure, that there won't be any pointers in mariages | |
sub repurpose(uword old, str new_name, str new_last_name, bool new_buf)->uword{ | |
divorce(old) | |
lose_job(old,false) | |
old[age]=0 | |
old[status]=0 | |
change_name(old,new_name,new_buf) | |
change_last_name(old,new_last_name,new_buf) | |
return old | |
} | |
;this one completely anihilates all the data inside the object, | |
;so that it could be used as something else, for example a string or an ubyte array. | |
;the minimal size of this array is always equal to human.SIZE constant, however it can be even larger in some cases, | |
;therefore, this function returns the actual size of the usable array. | |
;in case the address is for some reason unavailable after the erasure, this function returns the address of the array inside @R1 | |
sub erase(uword obj)->ubyte{ | |
tempstr[-1]=SIZE-1 | |
if obj+SIZE==get_name(obj){ | |
tempstr[-1]+=obj[name+2]+1 | |
} | |
if obj+tempstr[-1]+1==get_last_name(obj){ | |
tempstr[-1]+=obj[last_name+2]+1 | |
} | |
if obj+tempstr[-1]+1==get_job_name(obj){ | |
tempstr[-1]+=obj[job+2]+1 | |
} | |
divorce(obj) | |
ubyte i; one byte wasted 3-( | |
for i in 0 to tempstr[-1]{ | |
obj[i]=0 | |
} | |
cx16.r1=obj | |
return tempstr[-1] | |
} | |
sub get_name(uword self )->uword{ | |
return mkword (self[name+1], self[name]) | |
} | |
; get_age == obj[age] | |
; get_status == obj[status] ;there are however helper functions | |
sub get_partner(uword self)->uword{ | |
return mkword(self[partner+1],self[partner]) | |
} | |
sub get_last_name(uword self )->uword{ | |
return mkword (self[last_name+1], self[last_name]) | |
} | |
sub get_job_name(uword self)->uword{ ;returns 0 of there's no buffer | |
return mkword (self[job+1], self[job]) | |
} | |
; returns true if they get married, false if marriage was unsuccesful. | |
; you can see marriage error message in `human.tempstr` variable | |
sub marry(uword az, uword buky)->bool{ | |
if az[status]&human.flags.married{ | |
tempstr[0]='"' | |
tempstr[1]=0 | |
void string.append(tempstr,human.get_name(az)) | |
void string.append(tempstr,"\"is already married, please call 'human.divorce()' first.") | |
return false | |
} | |
if buky[status]&human.flags.married{ | |
tempstr[0]='"' | |
tempstr[1]=0 | |
void string.append(tempstr,human.get_name(buky)) | |
void string.append(tempstr,"\"is already married, please call 'human.divorce()' first.") ;" ;vscode syntax coloring is broken 3-( | |
return false | |
} | |
@(az+status)|=human.flags.married | |
@(buky+status)|=human.flags.married | |
az[partner]=lsb(buky) | |
az[partner+1]=msb(buky) | |
buky[partner]=lsb(az) | |
buky[partner+1]=msb(az) | |
return true | |
} | |
; divorces a human. | |
sub divorce(uword self){ | |
if not (self[status]&human.flags.married){ | |
return | |
} | |
uword temppartner=get_partner(self);human.divorce() is often used internally, so it has it's own temp var... | |
@(self+status)&=~human.flags.married | |
@(temppartner+status)&=~human.flags.married | |
self[partner]=0 | |
self[partner+1]=0 | |
temppartner[partner]=0 | |
temppartner[partner+1]=0 | |
} | |
;changes the contents of name buffer. if new name is longer than the current buffer, | |
;it will either crop the name to fit (if not new_buf) or will create a new, bigger buffer (if new_buf) and old buffer will be discarded (which wastes memory!) | |
sub change_name(uword self, str new_name, bool new_buf){ | |
if string.length(new_name)>self[name+2]{ | |
if new_buf{ | |
tempresult=mpg.copy(new_name) | |
if tempresult{ | |
self[name]=lsb(tempresult) | |
self[name+1]=msb(tempresult) | |
self[name+2]=string.length(new_name) | |
}else if get_name(self){ | |
void string.copy(new_name,tempstr) | |
tempstr[self[name+2]]=0 | |
tempstr[self[name+2]-1]='_' | |
void string.copy(tempstr,get_name(self)) | |
} | |
}else if get_name(self){ | |
void string.copy(new_name,tempstr) | |
tempstr[self[name+2]]=0 | |
tempstr[self[name+2]-1]='_' | |
void string.copy(tempstr,get_name(self)) | |
} | |
} | |
else{ | |
void string.copy(new_name, get_name(self)) | |
} | |
} | |
; sets the name atribute to the address of a buffer, that user provides in the function. | |
; you also have to provide the length of the buffer (it's reccomended to place `len(buffer)` into that field if possible) | |
; it's not recommended to be used with string literals or temporary buffers, that are often used by your program. | |
; In most cases, it's more reccomended to use human.change_name() instead | |
sub assign_name(uword self, uword nameptr, ubyte namelen){ | |
self[name]=lsb(nameptr) | |
self[name+1]=msb(nameptr) | |
self[name+2]=namelen | |
} | |
;similar to human.change_name() | |
sub change_last_name(uword self, str new_last_name, bool new_buf){ | |
if string.length(new_last_name)>self[last_name+2]{ | |
if new_buf{ | |
tempresult=mpg.copy(new_last_name) | |
if tempresult{ | |
self[last_name]=lsb(tempresult) | |
self[last_name+1]=msb(tempresult) | |
self[last_name+2]=string.length(new_last_name) | |
}else if get_last_name(self){ | |
void string.copy(new_last_name,tempstr) | |
tempstr[self[last_name+2]]=0 | |
tempstr[self[last_name+2]-1]='_' | |
void string.copy(tempstr,get_last_name(self)) | |
} | |
}else if get_last_name(self){ | |
void string.copy(new_last_name,tempstr) | |
tempstr[self[last_name+2]]=0 | |
tempstr[self[last_name+2]-1]='_' | |
void string.copy(tempstr,get_last_name(self)) | |
} | |
} | |
else{ | |
void string.copy(new_last_name, get_last_name(self)) | |
} | |
} | |
; similar to human.assign_name() | |
; In most cases, it's more reccomended to use human.change_last_name() instead | |
sub assign_last_name(uword self, uword last_nameptr, ubyte last_namelen){ | |
self[last_name]=lsb(last_nameptr) | |
self[last_name+1]=msb(last_nameptr) | |
self[last_name+2]=last_namelen | |
} | |
;similar to human.change_name() | |
sub choose_job(uword self, str new_job, bool new_buf){ | |
@(self+status)|=human.flags.employed | |
if string.length(new_job)>self[job+2]{ | |
if new_buf{ | |
tempresult=mpg.copy(new_job) | |
if tempresult{ | |
self[job]=lsb(tempresult) | |
self[job+1]=msb(tempresult) | |
self[job+2]=string.length(new_job) | |
}else if get_job_name(self){ | |
void string.copy(new_job,tempstr) | |
tempstr[self[job+2]]=0 | |
tempstr[self[job+2]-1]='_' | |
void string.copy(tempstr,get_job_name(self)) | |
} | |
}else if get_job_name(self){ | |
void string.copy(new_job,tempstr) | |
tempstr[self[job+2]]=0 | |
tempstr[self[job+2]-1]='_' | |
void string.copy(tempstr,get_job_name(self)) | |
} | |
} | |
else{ | |
void string.copy(new_job, get_job_name(self)) | |
} | |
} | |
; similar to human.assign_name() | |
; In most cases, it's more reccomended to use human.choose_job() instead | |
sub assign_job(uword self, uword jobptr, ubyte joblen){ | |
@(self+status)|=human.flags.employed | |
self[job]=lsb(jobptr) | |
self[job+1]=msb(jobptr) | |
self[job+2]=joblen | |
} | |
sub lose_job(uword self, bool keepname){ | |
@(self+status)&=~human.flags.employed | |
if not keepname{ | |
@(get_job_name(self))=0 | |
} | |
} | |
;subroutines below are simple utility routines for managing human.status atribute, so that user doesn't need to use those inconvienient bitwise operators | |
;checks fo specific flag's value | |
sub is(uword self, ubyte flag)->bool{ | |
return self[status]&flag | |
} | |
;sets chosen flag(s) to true | |
sub set_statflag(uword self, ubyte flag){ | |
flag&=~human.flags.married | |
@(self+status)|=flag | |
} | |
;sets chosen flag(s) to false | |
sub clear_statflag(uword self, ubyte flag){ | |
flag&=~human.flags.married | |
@(self+status)&=~flag | |
} | |
;get_gender() ; decided to ditch the concept of gender, because it's kind of a controversial topic (on both sides of the political specrtum) in the 21st century... | |
sub print(uword self){ | |
txt.print("\rname: ") | |
txt.print(get_name(self)) | |
txt.print("\rlast name: ") | |
txt.print(get_last_name(self)) | |
txt.print("\rage: ") | |
txt.print_ub(self[age]) | |
txt.print("\rmarried: ") | |
if is(self, human.flags.married){ | |
txt.print("yes") | |
txt.print("\rpartner's name: ") | |
txt.print(get_name(get_partner(self))) | |
}else{ | |
txt.print("no") | |
} | |
txt.print("\remployed: ") | |
if is(self, human.flags.employed){ | |
txt.print("yes") | |
txt.print("\rjob: ") | |
txt.print(get_job_name(self)) | |
}else{ | |
txt.print("no") | |
} | |
txt.print("\rdead: ") | |
if is(self, human.flags.dead){ | |
txt.print("yes") | |
} | |
else{ | |
txt.print("no") | |
} | |
txt.chrout('\r') | |
} | |
ubyte[96] tempstr | |
uword tempuword | |
uword tempresult | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment