Τρίτη 27 Ιουνίου 2017

Αναθεώρηση 1 (Έκδοση 8.9)

Σε αυτήν την αναθεώρηση, είχα μάλλον το κέφι να επιλύσω ένα ζήτημα με το πώς θα μπορούσα να εξάγω ένα δείκτη σε αντικείμενο ομάδα χωρίς όμως να πάει σε μεταβλητή, αλλά να χρησιμοποιηθεί εντός του εκτιμητή παραστάσεων (evaluator). Και αυτό γιατί δεν θέλω οι ομάδες να δίνουν δείκτες προς τα έξω. Ο λόγος που δεν το θέλω είναι απλός για μένα αλλά δύσκολος σε κάποιον που δεν γνωρίζει τα αντικείμενα. Σε συνήθεις γλώσσες ένα αντικείμενο "ζει" όσο υπάρχει δείκτης να το κρατάει. Αυτό συμβαίνει και για τα αντικείμενα με δείκτες που υποστηρίζει η Μ2000. Υπάρχει μάλιστα και ειδικός συλλέκτης σκουπιδιών που βρίσκει κυκλικές αναφορές και τις εξαφανίζει. Όμως στα αντικείμενα Ομάδα θέλω να έχουμε δυο καταστάσεις. Ή να είναι "επώνυμα", να έχουν όνομα δηλαδή, ή να έχουν θέση (πχ σε έναν πίνακα). Σε καμία περίπτωση όμως δεν υπάρχει διπλός δείκτης. Πάντα θα υπάρχει ένας μοναδικός, είτε έχουμε επώνυμη ομάδα, είτε ομάδα σε θέση (ανώνυμη).
Επιπλέον οι ομάδες μπορούν να έχουν άλλες ομάδες εσωτερικά, οπότε αν είχα δώσει τρόπο να χειριζόμαστε τις ομάδες με δείκτες θα γίνονταν μεγάλο μπέρδεμα! Πχ θα μπορούσε κανείς να βάλει την εσωτερική ομάδα να δείχνει στην εξωτερική! Επειδή λοιπόν τα αντικείμενα Ομάδα, τα επώνυμα, έχουν λειτουργία συγχώνευσης  (δηλαδή στην εκχώρηση Α=Β θα έχουμε ένα A με όλα τα μέρη του Β σε αυτό), αν είχαμε τέτοιους δείκτες ίσως να μην τελείωνε ποτέ η αντιγραφή.
Άλλα γνωρίσματα των αντικειμένων Ομάδα
Τα μέλη στα αντικείμενα ομάδα δεν γράφονται σε συνεχόμενη μνήμη. Στις επώνυμες ομάδες τα μέλη είναι ξεχωριστά, και για το λόγο αυτό μεταβλητές της ομάδας μπορούμε να τις περάσουμε με αναφορά, χωρίς να περάσουμε την ομάδα μαζί. Στις ανώνυμες ομάδες (δηλαδή ομάδες σε θέση), έχουμε κλειστό αντικείμενο, δηλαδή όλα τα μέλη βρίσκονται σε λίστα εντός της ομάδας και δεν είναι προσπελάσιμα. Αν για παράδειγμα στο Α(3) έχουμε μια ομάδα με μεταβλητή Χ, τότε το:
Τύπωσε Α(3).Χ
 θα δημιουργήσει ένα ανοικτό αντικείμενο θα διαβάσει το Χ και μετά θα κλείσει το αντικείμενο (γίνεται γρήγορα). Ομοίως αν θέλουμε να αλλάξουμε τιμή:
Α(3).Χ++
Α(3).Χ+=10
Α(3).Χ=1000
θα έχουμε άνοιγμα και κλείσιμο για κάθε περίπτωση. Για να κάνουμε πιο γρήγορη τη διαδικασία υπάρχει η εντολή Για (όχι η απαρίθμηση):
Για Α(3) {
      .Χ++
      Τύπωσε .Χ
}

Μπαίνουν και φωλιασμένα με ξεχωριστές ή μη αγκύλες:
(εδώ βάζουμε διπλή τελεία για το δεύτερο)
Για Α(3), Α(4) {
     Τύπωσε .Χ, ..Χ
}
ή το οποίο φαίνεται μεν ίδιο αλλά εδώ έχουμε δυο μπλοκ "προσωρινών ορισμών"
Για Α(3) {

 Για Α(4) {
     Τύπωσε .Χ, ..Χ
 }
}

Ότι νέο φτιάξουμε στην Για αντικείμενο { } θα διαγραφεί στο πέρας αυτού.
Υπάρχει και αυτό:
Για Αυτό {
' εδώ βάζουμε προσωρινούς ορισμούς.
}

Τα αντικείμενα Ομάδα σε θέση δεν κάνουν συγχώνευση όταν εκχωρούμε νέο αντικείμενο. Αντίθετα πετάνε το παλιό και παίρνουν το νέο (όπως θα γίνονταν και με δείκτες, με τη διαφορά πως αν βάζαμε το δείκτη σε δυο θέσεις, τότε η αλλαγή δείκτη σε μια από αυτές θα διατηρούσε στην άλλη θέση το αντικείμενο, ή χωρίς αλλαγή ότι κάναμε στο ένα αντικείμενο θα φαίνονταν και στο άλλο αφού θα είχαμε δυο θέσεις δεικτών με κοινό δείκτη σε ένα αντικείμενο). Με τις ομάδες στη Μ2000 ξέρουμε σίγουρα ότι δεν υπάρχει δείκτης σε αυτές, και πως κάθε θέση έχει μοναδικό αντικείμενο.
'Οταν στην Για αντικείμενο {} ανοίξουμε ένα αντικείμενο στην ουσία βγάζουμε ένα αντίγραφο, κάνουμε τη δουλειά μας και το κλείνουμε διαγράφοντας το παλιό. Αν κάποιος διαβάσει το αντικείμενο στη θέση αυτή (μπορεί να γίνει στην Μ2000 αν υπάρχει μια αναμονή και τρέχει στο μεταξύ ένα  νήμα) πριν τερματίσει η Για τότε θα πάρει την αποθηκευμένη τιμή και όχι αυτήν στην Για. Για να την πάρει θα πρέπει να κλείσει η Για και να την μεταγράψει στη θέση της.





Eκδοση 8.9

Μια μικρή διόρθωση πάνω στη προηγούμενη αναθεώρηση ώστε τα ορίσματα στις ιδιότητες των αντικειμένων όταν δεν καθαρίζονται επακριβώς να έρχονται στη σειρά που πρέπει, κατά την εκχώρηση τιμής! Επειδή όμως ολοκληρώθηκε η προσθήκη άλλαξε ο αριθμός έκδοσης από 8.8 σε 8.9

Μπορεί κανείς να αφήσει τις χρωματισμένες παραγράφους! Αναφέρονται στην Ομάδα και στα αντικείμενα της Μ2000 γενικότερα.


Τα αντικείμενα τύπου ομάδα, έχουν μερικές ιδιαιτερότητες στη Μ2000. Εξ ορισμού επιστρέφουν αντίγραφο. Δηλαδή δεν έχουμε δείκτη στο αντικείμενο. Μπορούμε όμως να ορίσουμε Αξία, δηλαδή να επιστρέφει αυτό που θέλουμε (και πάλι δεν μπορούμε να επιστρέψουμε δείκτη σε αυτό).

Η συνάρτηση Ομάδα() δέχεται μια "επώνυμη" ομάδα και δίνει αντίγραφο ακόμα και αν έχει τμήμα Αξία (δεν το εκτελεί). Οι επώνυμες ομάδες αν πάρουν με εκχώρηση άλλη ομάδα, τότε δεν αντιγράφονται με την εκχωρούμενη αλλά συγχωνεύει την εκχωρούμενη στην υπάρχουσα. Αυτό σημαίνει ότι ενδέχεται να αποκτήσει νέα μέλη, και σε όσα υπάρχει κοινό μέλος τότε εκεί θα γίνει αντιγραφή.

Οι ανώνυμες (ή κλειστές) ομάδες (δεν έχουμε φανερές τέτοιες στα παραδείγματα, αλλά κάθε ομάδα όταν μπει στο σωρό τιμών, ως όρισμα μπαίνει ως κλειστή ή ανώνυμη ομάδα. Κλειστές ομάδες (χωρίς όνομα) είναι όσες έχουν μόνο θέση. Θέση μπορούν να έχουν στο σωρό τιμών, σε αντικείμενο σωρό, σε πίνακα και σε κατάσταση (με ζευγάρια κλειδιών και τιμών). Όταν σε μια θέση βάζουμε μια νέα ομάδα τότε η παλιά διαγράφεται.

Παρόλο που φαίνεται ότι "όλα" αντιγράφονται στην εκχώρηση, στην ουσία όπου υπάρχει μεταβλητή με δείκτη (όπως σε μεταβλητές που έχουν δείκτες σε αντικείμενα σωρός, πίνακας και κατάσταση) τότε μόνο ο δείκτης αντιγράφεται (οπότε τα αντικείμενα αυτά παραμένουν σε χρήση ακόμα και αν αυτό που τα έδωσε διαγραφεί, επειδή τα αντικείμενα αυτά έχουν μετρητή για τον αριθμό των δεικτών προς αυτά).

Οι πίνακες στις ομάδες αντιγράφονται επίσης. (Οι πίνακες διαφέρουν με τα αντικείμενα πίνακες, ως προς το τρόπο χειρισμού). Σε καμία περίπτωση δεν έχουμε αριθμητική δεικτών, δηλαδή να αλλάξουμε τιμή σε δείκτη. Η αλλαγές γίνονται μόνο με δείκτη προς άλλο αντικείμενο, ίδιο με αυτό που εκείνη τη στιγμή έχει η μεταβλητή ή η θέση (πχ σε αντικείμενο πίνακα, ή σε σωρό ή σε κατάσταση)

Τα τρία βασικά αντικείμενα με δείκτη είναι ο Πίνακας (ως μονοδιάστατος, ακόμα και αν είναι δείκτης σε πολυδιάστατο),, ο σωρός (λίστα συνδεδεμένων τιμών με ευκολη μετακίνηση, προσθήκη και διαγραφή, βάσει θέσης), η κατάσταση (λίστα με μοναδικά κλειδιά, αριθμούς ή αλφαριθμητικά και τιμές, για γρήγορη εύρεση, διαγραφή, εισαγωγή, αλλά δεν διατηρεί τη σειρά στις διαγραφές), και υπάρχει μια παραλλαγή της κατάστασης, την κατάσταση ουρά, όπου δέχεται ίδια κλειδιά αλλά δεν επιτρέπει διαγραφή όπουδήποτε αλλά μόνο από το τέλος, σε ένα η περισσότερα στοιχεία, και διατηρεί την σειρά,ενώ όταν έχουμε όμοιο κλειδί η εύρεση δείχνει πάντα το τελευταίο)

Μπορούμε λοιπόν να έχουμε μια ομάδα που να έχει μια κατάσταση και στην αντιγραφή θα μεταφέρει απλά το δείκτη σε αυτήν. Και στην κατάσταση αυτή να υπάρχουν άλλες ομάδες.

Η Μ2000 έχει τρόπο (έναν συλλέκτη σκουπιδιών) για να βρίσκει και να σπάει όταν χρειάζεται κυκλικές αναφορές δεικτών (δηλαδή αντικείμενα που δείχνουν άμεσα ή μέσω άλλων αντικειμπένων στο αρχικό αντικείμενο). Έτσι θα μπορούσαμε να βάλουμε μια ομάδα σε μια κατάσταση με δείκτη σε αυτήν την κατάσταση.


Στο τμήμα set (ή θέσε) το πρώτο διάβασμα γίνεται πάντα στην τιμή εκχώρησης. Εδώ η εκχώρηση δεν πάει πουθενά, απλά τυπώνουμε τα νούμερα που βάζουμε. Στην πρώτη περίπτωση η λίστα παραμέτρων είναι μηδενική, αυτό σημαίνει ότι μπορεί να πάρει ή όχι ορίσματα. Αν ζητάμε περισσότερα και δώσουμε λιγότερα θα βγει λάθος. Αν αντί για την Read βάλουμε την Read ? τότε δεχόμαστε προεραιτικά τιμές και αν δεν υπάρχουν δεν βγαίνει λάθος, θα φτιαχτούν μεταβλητές με μηδενικές τιμές (ή αν ήδη υπάρχουν θα παραμείνουν ως έχει).
Φαίνονται τρεις περιπτώσεις, με κενή λίστα παραμέτρων, με πλήρης, και με μερική. Σε κάθε περίπτωση το πρώτο διάβασμα θα είναι η τιμή εκχώρησης.

Το group alfa (ομάδα alfa) μπορεί να είναι μέσα σε άλλο group (ομάδα). Όπως το έχουμε εδώ παίρνει τιμή αλλά δεν δίνει (δεν έχουμε το value ή αξία μέρος)


Με αγγλικές εντολές:

group alfa {
      set () {
            read d,a,b,c
            Print a,b,c,d
      }
  
}

alfa(1,2,3)=4
group alfa1 {
      set (a,b,c) {
            read d
            Print a,b,c,d
      }
  
}
alfa1(1,2,3)=4

group alfa2 {
      set (a,b) {
            read d, c
            Print a,b,c,d
      }
  
}
alfa2(1,2,3)=4

Με ελληνικές εντολές:

Ομάδα alfa {
      Θέσε () {
            Διάβασε d,a,b,c
            Τύπωσε a,b,c,d
      }
  
}

alfa(1,2,3)=4
Ομάδα alfa1 {
      Θέσε (a,b,c) {
            Διάβασε d
            Τύπωσε a,b,c,d
      }
  
}
alfa1(1,2,3)=4

Ομάδα alfa2 {
      Θέσε (a,b) {
            Διάβασε d, c
            Τύπωσε a,b,c,d
      }
  
}
alfa2(1,2,3)=4

Θα δούμε τώρα στο μέρος Value ή Αξία
Εδώ δεν έχουμε τιμή εκχώρησης, αλλά έχουμε επιστροφή τιμής (με το =)

Στα Αγγλικά
group alfa {
      value () {
            read a, b, c
            print a, b, c
            =100
      }
}
m=alfa(1,2,3)
group alfa1 {
      value (a,b,c) {
            print a, b, c
            =100
      }
}
m=alfa1(1,2,3)
group alfa2 {
      value (a) {
            read b, c
            print a, b, c
            =100
      }
}
m=alfa2(1,2,3)
Print m


Στα Ελληνικά
Ομάδα alfa {
      Αξία () {
            Διάβασε a, b, c
            Τύπωσε a, b, c
            =100
      }
}
m=alfa(1,2,3)
Ομάδα alfa1 {
      Αξία (a,b,c) {
            Τύπωσε a, b, c
            =100
      }
}
m=alfa1(1,2,3)
Ομάδα alfa2 {
      Αξία (a) {
            Διάβασε b, c
            Τύπωσε a, b, c
            =100
      }
}
m=alfa2(1,2,3)
Τύπωσε m



Υπάρχει μια "μακροεντολή" για τους ορισμούς ομάδων, η Ιδιότητα ή Property, η οποία φτιάχνει group (ομάδες) σε υπάρχον ομάδα. Κάνει μερικά πράγματα ώστε στη γονική ομάδα (σε αυτήν που θα βάλουμε την ιδιότητα), να υπάρχει η μεταβλητή με όνομα ίδιο με αυτό της ιδιότητας, πχ αν η ιδιότητα είναι το Αλφα θα υπάρχει το [Αλφα]  (οι χαρακτήρες [ και ] είναι αποδεκτοί για ονόματα μεταβλητών), ενώ αν είναι αλφαριθμητικό πχ Βήτα$ θα φτιαχτεί η [βήτα]$  (το $ στο τέλος), και θα είναι κρυφά (Ιδιωτικά ή Private).
Μια ομάδα σε γονική ομάδα δεν βλέπει τις μεταβλητές της γονικής (ούτε τις συναρτήσεις ή ότι άλλο έχει). Όμως η εντολή Ένωσε (ή Link) ενώνει με αναφορά και από γονική ομάδα όταν όμως του το ζητάμε, οπότε η μακροεντολή βάζει την εντολή αυτή και  λύνεται το ζήτημα του πώς από την εσωτερική ομάδα θα επιδράσουμε στην εξωτερική. Αν προσπαθήσει κάποιος να περάσει με αναφορά την ομάδα που έχουμε ως ιδιότητα τότε η ένωση θα αποτύχει (η ομάδα θα περαστεί χωρίς να έχει "γνώση" της γονικής ομάδα). Έτσι θα πρέπει να περάσει την ομάδα που περιέχει την ιδιότητα και τότε θα λειτουργήσει. Αυτό δεν συμβαίνει με τις απλές μεταβλητές μιας ομάδας. Αυτές μπορούν να περαστούν με αναφορά (έτσι και αλλιώς δεν επιδρούν άμεσα στο αντικείμενο, όπως κάνει η ιδιότητα). Επίσης μπορεί να περαστεί με αναφορά μια συνάρτηση ομάδας και αυτή μπορεί να επιδράσει στο αντικείμενο κατά την εκτέλεση. Η ιδιότητα όμως είναι ομάδα που γυρνάει τιμή (έχει δηλαδή μια ειδική συνάρτηση, κρυφή, για τη δουλειά αυτή), αν και μοιάζει να είναι συνάρτηση.

Κάθε ιδιότητα μπορεί να έχει μια από τις παρακάτω μορφές όπως φαίνεται στα παραδείγματα:

Στα αγγλικά
Group Alfa {
      Property Beta=10
}
Print Alfa.Beta
' we can change value
Alfa.Beta=50
Print Alfa.Beta
' poperty is not the same as a variable in group
Try ok {
      Alfa.Beta++
}
'  Group Alfa.Beta has no operator ++
If Error or not ok Then Print Error$
' We can't erase a group if it has a name (erased after this module terminate)
Group Alfa1 {
      Property Beta {Value}=10
      Module SetToBeta {
            Read .[Beta]
            ' assign value with <=
            ' else interpeter make a local [Beta]
            ' .[Beta]<=50
      }
}
Print Alfa1.Beta
Try ok {
      Alfa1.Beta=50
}
' No group in each side
If Error or not ok Then Print Error$
Alfa1.SetToBeta 50
Print Alfa1.Beta

Group Alfa2 {
      Property Beta {
            Set {
                  ' internal  there is a Read Value
                  Value=Value*2
                  ' Internal there is a [Beta]=Value
                  '  and [beta] is linked to Alfa2.[Beta] a pivate variable
            },
            Value
      }=10
}
Alfa2.Beta=100
Print Alfa2.Beta
Group Alfa0 {
      Value {
            =12345
      }
}

Group Alfa3 {
      Property Beta {
            Set {
                  If Type$(Value)="Group" Then {
                        Push Value*2 '  pass to stack the Value*2  (Value is group which return double)
                        Local Value ' shadow value with a new one
                        Print Type$(Value) ' type double
                        Read Value
                        Print Type$(Value) 'type double
                  } Else {
                        Value=Value*2
                  }
            },
            Value
      }=10
}
' always groups pass copies of them if no  value part exist
Alfa3.Beta=Group(Alfa0)
Print Alfa3.Beta
' pass a value from Alfa0 not object
Alfa3.Beta=Alfa0
Print Alfa3.Beta

' One parametet fot Set

Group Alfa4 {
      Property Beta {
            Set (n) {
                  If Type$(Value)="Group" Then {
                        Push Value*n
                        Local Value
                        Read Value
                  } Else {
                        Value=Value*n
                  }
            },
            Value
      }=10
}
Alfa4.Beta(10)=Alfa0
Print Alfa4.Beta

Group Alfa5 {
      Property Beta {
            Set () {
                  n=1
                  Read ? n
                  If Type$(Value)="Group" Then {
                        Push Value*n
                        Local Value ' shadow previous Value
                        Read Value
                        ' so now Value is not object but number
                  } Else {
                        Value=Value*n
                  }
            },
            Value
         
      }=10
}
Alfa5.Beta=1000
Print Alfa5.Beta
Alfa5.Beta(2)=1000
Print Alfa5.Beta
Alfa5.Beta(3)=1000
Print Alfa5.Beta

Στα ελληνικά
Ομάδα Άλφα {
      Ιδιότητα Βήτα=10
}
Τύπωσε Άλφα.Βήτα
' εδώ αλλάζουμε τιμή
Άλφα.Βήτα=50
Τύπωσε Άλφα.Βήτα
Δες οκ {
      Άλφα.Βήτα++
}
' θα πάρουμε λάθος γιατί η ομάδα Άλφα.Βήτα δεν υποστηρίζει τον τελεστή ++
Αν λάθος ή όχι οκ Τότε Τύπωσε Λάθος$
' Δεν μπορούμε να σβήσουμε την Άλφα, οπότε θα φτιάξουμε την Άλφα1
Ομάδα Άλφα1 {
      Ιδιότητα Βήτα {Αξία}=10
      Τμήμα ΘέσεΣτηΒήτα {
            Διάβασε .[Βήτα]
            ' με εκχώρηση θέλει το <=
            ' αλλιώς θα φτιάξει ο διερμηνευτής τοπική [Βήτα]
            ' .[Βήτα]<=50
      }
}
Τύπωσε Άλφα1.Βήτα
Δες οκ {
      Άλφα1.Βήτα=50
}
' δίνει λάθος γιατί ο διερμηνευτής βλέπει ομάδα στα αριστερά και τιμή στα δεξιά
' ενώ έχει δει ότι η ομάδα δεν έχει τμήμα Θέσε
Αν λάθος ή όχι οκ Τότε Τύπωσε Λάθος$
Άλφα1.ΘέσεΣτηΒήτα 50
Τύπωσε Άλφα1.Βήτα

' Πάμε στο τρίτο αντικείμενο Αλφα2
Ομάδα Άλφα2 {
      Ιδιότητα Βήτα {
            Θέσε {
                  ' Εδώ η τιμή που δίνοιυμε πάει στο Αξία
                  Αξία=Αξία*2
                  ' Εδώ  η Αξία είναι αριθμητική μεταβλητή
            },
            Αξία
      }=10
}
Άλφα2.Βήτα=100
Τύπωσε Άλφα2.Βήτα
                  ' Αν ήταν ομάδα ίσως να  μη την αφήναμε να καταχωρηθεί
                  ' γιατί στην επόμενη διάβασε θα κάνει συγχώνευση, και αυτό μπορεί να μην το θέλουμε
                  ' για να μην το επιτρέψουμε αυτό, δίνουμε μια εντοιλή Τοπική Αξία
                  ' οπότε σκιάζουμε την υπάρχουσα και δίνουμε μια άλλη με τιμή 0
Ομάδα Αλφα0 {
      Αξία {
            =12345
      }
}

Ομάδα Αλφα3 {
      Ιδιότητα Βήτα {
            Θέσε {
                  Αν Τύπος$(Αξία)="Group" Τότε {
                        Βάλε Αξία*2 ' γυρνάμε στο σωρό την αξία της ομάδας
                        Τοπική Αξία ' σκιάζουμε την Αξία με νεα μεταβλητή
                        Τύπωσε Τύπος$(Αξία) 'είνα τύπου double
                        Διάβασε Αξία ' διαβάζουμε την τιμή
                        Τύπωσε Τύπος$(Αξία) 'είνα τύπου double
                  } Αλλιώς {
                        Αξία=Αξία*2
                  }
            },
            Αξία
      }=10
}
Αλφα3.Βήτα=Ομάδα(Αλφα0)
Τύπωσε Αλφα3.Βήτα
' εδώ δώσαμε απευθείας τιμή και όχι ομάδα
Αλφα3.Βήτα=Αλφα0
Τύπωσε Αλφα3.Βήτα

' Εδώ βάζουμε μια παράμετρο στην Θέσε

Ομάδα Αλφα4 {
      Ιδιότητα Βήτα {
            Θέσε (ν) {
                  Αν Τύπος$(Αξία)="Group" Τότε {
                        Βάλε Αξία*ν
                        Τοπική Αξία
                        Διάβασε Αξία
                  } Αλλιώς {
                        Αξία=Αξία*ν
                  }
            },
            Αξία
      }=10
}
Αλφα4.Βήτα(10)=Αλφα0
Τύπωσε Αλφα4.Βήτα

Ομάδα Αλφα5 {
      Ιδιότητα Βήτα {
            Θέσε () {
                  ν=1
                  Διάβασε ? ν
                  Αν Τύπος$(Αξία)="Group" Τότε {
                        Βάλε Αξία*ν
                        Τοπική Αξία
                        Διάβασε Αξία
                  } Αλλιώς {
                        Αξία=Αξία*ν
                  }
            },
            Αξία
         
      }=10
}
Αλφα5.Βήτα=1000
Τύπωσε Αλφα5.Βήτα
Αλφα5.Βήτα(2)=1000
Τύπωσε Αλφα5.Βήτα
Αλφα5.Βήτα(3)=1000
Τύπωσε Αλφα5.Βήτα



Και εδώ μια επιπλέον προσθήκη (γράψτε το σε άλλο τμήμα έστω B). Η κλάση είναι συνάρτηση που επιστρέφει ομάδα. Είναι δηλαδή ένα "Εργοστάσιο" ομάδων!

Στα ελληνικά
Κλάση Άλφα {
      μετρητής=0
      ιδιότητα Βήτα {
            Θέσε () {
                  Διάβασε α
                  Ένωσε γονικό μετρητής στο μετ
                  μετ++
                  Διάβασε β,γ
                  Τύπωσε Αξία, α, β, γ
            },
            Αξία (α,β,γ) {
                  Αξία=10*α-500*β+γ**10
            }
      }
}
Δέλτα=Άλφα()
Δέλτα.Βήτα(1,2,3)=100
Τύπωσε Δέλτα.μετρητής
Πίνακας Α(10)
Α(1)= Άλφα()
Α(1).Βήτα(1,2,3)=200
Α(1).Βήτα(1,2,3)=300
Τύπωσε Α(1).Βήτα(1,2,3)
Τύπωσε Α(1).μετρητής
Κατάσταση έψιλον=1:=100,"α":="500", "β":=Άλφα()
έψιλον("β").Βήτα(1,2,3)=200
Τύπωσε έψιλον("β").Βήτα(1,2,3), έψιλον("β").μετρητής
έψιλον("β").Βήτα(1,2,3)=300
Τύπωσε έψιλον("β").Βήτα(1,2,3), έψιλον("β").μετρητής


Στα αγγλικά

Class Alpha {
      counter=0
      Property Beta {
            Set () {
                  read a
                  link parent counter to cc
                  cc++
                  Read b,c
                  Print value, a, b, c
            },
            value (a,b,c) {
                  value=10*a-500*b+c**10
            }
      }
}
delta=Alpha()
delta.Beta(1,2,3)=100
Print delta.counter
Dim A(10)
A(1)= Alpha() ' or give this group(delta) which counter is now equal to 1
A(1).Beta(1,2,3)=200
A(1).Beta(1,2,3)=300
Print A(1).Beta(1,2,3)
Print A(1).counter
inventory epsilon=1:=100,"a":="500", "b":=Alpha()
epsilon("b").Beta(1,2,3)=200
Print epsilon("b").Beta(1,2,3), epsilon("b").counter
epsilon("b").Beta(1,2,3)=300
Print epsilon("b").Beta(1,2,3), epsilon("b").counter



Δευτέρα 26 Ιουνίου 2017

Αναθεώρηση 11 (Έκδοση 8.8)

Μερκά Bugs διορθώθηκαν. Ειδικά ένα που είχε μπεί στην αναθεώρηση 10 (λάθος όνομα μεταβλητής, έπεφτε πάνω σε μια γενική μεταβλητή που ρύθμιζε την ανανέωση της οθόνης)

Αρκετές Προσθήκες:
Μια βασική προσθήκη είναι η δυνατότητα να έχουμε προαιρετικές παρεμέτρους σε ιδιότητες αντικειμένων τύπου ομάδα.
Αυτό είναι ένα μεγάλο παράδειγμα:

global inventory z=10,20,30,40
\\ class is a function which return object
\\ class is a global function until this module end
class AnObject {
      type$="AnObject"
      ttt=12345678
      value {
            =1000
      }
}
Group alfa {
      type$="alfa"
      inventory m=1,"hello":=10,3:=z,4:=1000, "ok":="yes", "object":=AnObject()
      Property kappa {
            set () {
                 link parent m to m
                  If Empty Then {
                        If type$(value)="Inventory" Then {
                                  m=value
                                  ' we don't want  this value saved to .[Kappa]
                                  ' so we make a local value, to shadow current value
                                  ' by default Local value make a double with value 0
                                  local value
                        } else Error "Wrong type, need Inventroy"
                  } Else.If islet Then {
                       Read k$
                       If exist(m, k$) Then {
                              If type$(value)="Group" Then {
                                    Return m, k$:=Group(value)
                              } else Return m, k$:=value
                        } else {
                              If type$(value)="Group" Then {
                                    Append m, k$:=Group(value)
                              } else Append m, k$:=value
                        }
                 } else {
                       Read k
                       If exist(m, k) Then {
                              If type$(value)="Group" Then {
                                    Return m, k:=Group(value)
                              } else Return m, k:=value
                        } else {
                              If type$(value)="Group" Then {
                                    Append m, k:=Group(value)
                              } else Append m, k:=value
                        }
                 }
            }
            value () {
                link parent m to m
                 If empty Then {
                         value=m
                 } Else.If islet Then {
                      value=m(Letter$)
                     } else {
                     value=m(Number)
                 }
            }
      }
      ' Make a clean property , no use of value
      Group objKappa {
            value () {
                link parent m to m
                 If empty Then {
                         =m
                 } Else.If islet Then {
                        if exist(m, Letter$) then {
                              =eval(m)
                        }
                 } else {
                        if exist(m, Number) then {
                              =eval(m)
                        }
                 }
            }
      }
      Property strkappa$ {
            value () {
                 link parent m to m
                  If islet Then {
                       value$=m$(Letter$)
                 } else {
                       value$=m$(Number)
                 }
            }
      }
      Property typekappa$ {
            value () {
                 link parent m to m
                  If islet Then {
                       value$=type$(m(Letter$))
                 } else {
                       value$=type$(m(Number))
                 }
            }
      }
      value (x) {
            =.m(x!)
      }
}
' Part 1
'  Group Alfa return an indexed (from 0) value (number or object)
' .m(x!) always return object
Print alfa(2)
Print alfa.type$
Function check$ (m) {
      Print type$(m)
      =str$(m(0!))
}
Print check$(alfa(2))
Print alfa.typeKappa$("object") ' is a group
For this {
     temp=alfa.Kappa("object")
     Print type$(temp), temp ' we get 1000, because object return value
     temp2=alfa.objKappa("object")
     Print type$(temp2), temp2.type$
}
z= alfa.Kappa()
Print z("object").type$, z("object").ttt
Print alfa.Kappa()("object").ttt
Print alfa.Kappa()("object").ttt
Print alfa.Kappa()("object").type$
Print alfa.Kappa("object")
Print alfa.Kappa("object")

k=each(alfa.m)
while k {
      Print eval$(k, k^),
}
Print
Print alfa.Kappa(4)
Print alfa.Kappa("hello"), alfa.strKappa$("ok")
Print alfa.typeKappa$("hello"), alfa.typeKappa$("ok"), alfa.typeKappa$(3)
M=alfa.Kappa(3)
Print m(1!)
Return alfa.Kappa(3), 20:=12345
' it is the same because we have pointer
' read from m(3), inventory so we get key 20
Print alfa.m(3)(20)
\\ using ! we pass position in inventory
Print m(1!)
alfa.Kappa(333)=200
Print alfa.Kappa(333)
alfa.Kappa("Price A")=100.23
Print alfa.Kappa("Price A")
' Part 3, change inventory
inventory allo=1:="ok", 200:=1234
alfa.Kappa()=allo
Print len(alfa.Kappa())
Print alfa.strKappa$(1)
Print alfa.Kappa(200)




 Και εδώ είναι η δημιουργία και η ανάγνωση πίνακα σε μορφή json. Προς το παρόν δεν αλλάζουμε τα στοιχεία στη δομή, αλλά μπορούμε να εξάγουμε όποιο τμήματα, ή μια τιμή θέλουμε. Έχει φτιατχεί για να διαβάζει βάσει των κανόνων του json. Όλη η κατασκευή είναι μια κλάση μεγάλη (οι κλάσεις στη Μ2000 δημιουργούν ομάδες) και μια εντολή Parser=ParserClass() δημιουργέι το αντικείμενο Parser. 

Μια ενδιαφέρουσα εντολή είναι αυτή:
Report Parser.Ser$(Parser.Eval(Parser.ReadAnyString$(alfa,"array", 2)), 1)
όπου η εντολή Report (Αναφορά) εμφανίζει κείμενο στη κονσόλα. Δείτε όμως ότι το κείμενο βγαίνει από τρεις κλήσεις στο αντικείμενο Parser. Το διαβάζουμε από το εσωτερικό:
 η  Parser.ReadAnyString$(alfa,"array", 2)  δίνει από το json αντικείμενο. εκείνο με το αναγνωριστικό "arrray" και ειδικότερα το 3ο στοιχείο (η βάση είναι το 0, άρα το 2 είναι το 3ο στοιχείο). Αυτή η αυνάρτηση επιστρέφει το στοιχείο σε αλφαριθμητικό. χωρίς να βάλει αλλαγές γραμμών και εσοχές.
Μετά το δίνουμε στην Parser.Eval(). Αυτή παίρνει το κείμενο και δίνει μια δομή δεδομένων. 
Αμέσως όμως την δίνουμε στην Parser.Ser$() με δεύτερο όρισμα το 1 (θα βάλει αλλαγές γραμμών και εσοχές).
Οι δομές δεδομένων είναι δυο βασικές, η Κατάσταση (Inventory) και ο δείκτης σε Πίνακα (στην ουσία πίνακας με διαφοτετικές εντολές και χειρισμό). Οι κανονικοί πίνακες στη Μ2000 αντιγράφονται με το σύμβολο εκχώρησης. Δεν συμβαίνει το ίδιο με το δείκτη σε πίνακα. Ουσιαστικά οι Καταστάσεις και οι δείκτες σε πίνακα περνούν με αντιγραφή ενώ είναι με αναφορά (αφπύ περνάμε δείκτη). Στη Μ2000 δεν μπορούμε να χειριστούμε τους δείκτες βάζοντας ότι θέλουμε, υπάρχει εσωτερικός έλεγχος.
Στην Eval() δίνουμε το αλφαριθμητικό που θα το φτιάξει δομή δεδομένων (δηλαδή με εντολές θα διαβάζουμε άμεσα το στοιχείο που θέλουμε). Αυτό λοιπόν μπαίνει ως κλείσιμο σε μια συνάρτηση λάμδα, και μάλιστα σε Διάρθρωση μνήμης (Buffer) όπου την δηλώνουμε ότι θα έχει ακέραιους (στη διάρθρωση οι ακέραιοι (integer) είναι των δυο bytes και unsign, δηλαδή δεν παίρνουν αρνητική τιμή. Και οι διαρθρώσεις είναι δείκτες σε αντικείμενο που εσωτερικά "χειρίζονται" μνήμη. Οπότε αν βγάλουμε αντίγραφο της λάμδα, θα έχουμε απλά αντίγραφο του δείκτη, και στην ουσία αυτό που κάνουμε με την αντιγραφή είναι να αποθηκεύσουμε την τιμή δου δείκτη ανάγνωσης, ώστε αν θέλουμε να επιστρέψουμε στο σημείο της αποθήκευσης.

Στον Parser έχουμε κοινές μεταβλητές ως μεταβλητές του αντικειμένου (αντικείμενο και παρουσία είναι το ίδιο πράγμα για τις ομάδες, οι ομάδες δεν είναι αντικείμενα με δείκτε), Δείτε εδώ το char το οποίο διαβάζει τον επόμενο χαρακτήρα.

Όταν καταχωρούμε αριθμούς, από το κείμενο στη  δομή,. διατηρούμε την μορφή που είχε σε αλφαριθμητικό. Μπορούμε όμως να το διαβάσουμε και ως αριθμό.

Για να κρατάμε "σημειώσεις" χρησιμοποιούμε ιδιωτικούς σωρούς, οι οποίοι είναι και αυτοί αντικείμενα με δείκτη, και είναι όπως ο σωρός τιμών, μέσω του οποίου περνάμε τα ορίσματα των συναρτήσεων. Πχ με την εντολή αυτή   obj=Stack λέμε ότι η μεταβλητή obj θα έχει ένα αντικείμενο σωρού (άδειο).
Revision 2 ( problem was: if number was 0 then without ." we get error, and nothing parsing)
Revision 3 (empty array not allowed in previous revision)
Revision 4 (u0000 now work perfect)

 
Class ParserClass {
Private:
      Class bStream {
            Private:
            cnt, Buffer A
            Public:
            Value (&c) {Try {c=eval(.A, .cnt) : .cnt++:=true}}
            Class:
            Module final bStream (a$){
                  Buffer .A as Integer*Len(a$)
                  Return .A, 0:=a$
            }
      }
      Func=Lambda->false
      char=0
      \\ using obj as pointer to Stack
      obj=Stack
      Function final IsId {
            If .char=34 Then =.IsString(false)
      }
      Function final IsTrue {
            \\ U+0074 U+0072 U+0075 U+0065
            If .char=0x74 Then If .func() Then If .char=0x72 Then If .func() Then If .char=0x75 Then If .func() Then If .char=0x65 Then PushIt() : =True
            Sub PushIt()
                  Stack .obj {
                        Push .Boolean(True)
                  }
            End Sub
      }
      Function final IsFalse {
            \\ U+0066 U+0061 U+006c U+0073 U+0065
            If .char=0x66 Then If .func() Then If .char=0x61 Then If .func() Then If .char=0x6c Then If .func() Then If .char=0x73 Then If .func() Then If .char=0x65 Then PushIt() : =True
            Sub PushIt()
                  Stack .obj {
                        Push .Boolean(False)
                  }
            End Sub
      }
      Function final IsNull {
            \\ U+006E U+0075 U+006C U+006C
            If .char=0x6e Then If .func() Then If .char=0x75 Then If .func() Then If .char=0x6c Then If .func() Then If .char=0x6c Then PushIt() : =True
            Sub PushIt()
                  Stack .obj {
                        Push .Null()
                  }
            End Sub
      }
      Function final IsSemiCol {
              If .char=0x3a Then =true
      }
      Function final IsComma {
              If .char=0x2c Then =true
      }
      Function final IsObject {
            If .char=123 Else exit
            inventory objinv
           \\ we push object with a pointer to objinv
           Stack .obj { Push .Object(objinv)}
           .Trim
           While .IsId() {
                 .Trim
                 If .IsSemiCol() Then {
                       .Trim
                       If .IsValue() Then {
                             Stack .obj {
                                    Shift 2 ' move top as second
                                    ' letter$ is ok If top is string, and throw it
                                    Append objinv, Letter$:=Group
                              }
                        }
                 } Else Exit
                 .Trim
                  If not .IsComma() Then exit
                 .Trim
            }
            If .char=125 Then { =true } Else .obj<=Stack : .func<=lambda->0
      }
      Function final IsValue {
            If .IsString(True) Then {
                   =True
            } Else.if .IsNumber() Then {
                  =True
            } Else.If .IsTrue() Then {
                  =True
            }  Else.If .IsFalse() Then {
                  =True
            } Else.If .IsNull() Then {
                  =True
            } Else.if .IsArray() Then {
                  =True
            } Else.if .IsObject() Then {
                  =True
            } Else {
                  Print "what", .char
                  Stack .obj { Stack}
                  .func<=lambda->0
            }
      }
      Function final Digits (private_stack){
            While .func() {
                  Select Case .char
                  Case 48 to 57
                  {
                        =true
                       Stack private_stack { Data .char}
                  }
                  Else
                       break
                  End Select
            }    
      }
      Function final IsNumber {
            a=Stack
            Select Case .char
            Case 45 ' -
            {
                        oldfunc=.func
                        Stack a { Data .char}
                        If .Func() Then {
                              Select Case .char
                              Case 48
                              {
                                      Stack a { Data .char}
                                      If .func() Then {
                                          If .char=46 Then {
                                                Fraction()
                                                Exponent()
                                          }
                                    }
                              }
                              Case 49 to 57
                              {
                                    Stack a { Data .char}
                                    If .Digits(a) Then {}
                                    Fraction()
                                    Exponent()
                              }
                              Else
                                    a=stack
                              End Select
                        }
            }
            Case 48 ' 0
            {
                  oldfunc=.func
                  Stack a { Data .char}
                  If .func() Then {
                      If .char=46 Then {
                            Fraction()
                            Exponent()
                      }
                }
            }
            Case 49 to 57
            {
                        oldfunc=.func
                        Stack a { Data .char}
                        If .Digits(a) Then {}
                        Fraction()
                        Exponent()
            }
            End Select
           
            If len(a)>0 Then {
                  b=each(a)
                  Document D$
                  While b {
                        D$=chrcode$(StackItem(b))
                  }
                  .func<=oldfunc
                  If len(D$)>1 Then For i=2 to len(D$) { .Trim}
                  Stack .obj { Push .Numeric(D$) }
                  =True
            }
            '  here is an auto exit from function. Sub as command is an exit
            Sub Fraction()
                  If .char=46 Then Stack a { Data .char}
                  If .Digits(a) Then { }
            End Sub
            Sub Exponent()
                  If .char=101 or .char=61 Then {
                        Stack a { Data .char}
                        If .func() Then {
                              If .char=43 or .char=45 Then {
                                    Stack a { Data .char }
                                    If .Digits(a) Else {
                                          a=Stack ' cleat by point to new Stack
                                    }
                              }  Else.If .char>47 and .char<58 Then {
                                    Stack a { Data .char}
                                    If .Digits(a) Then {}
                              }   Else { a=Stack }
                        }
                  }
            End Sub
      }
      Function final IsString (as_object){
      If .char=34 Else exit
            Document D$
            While .func() {
                  If .char=34 Then 2000
                  If .char=92 Then {
                        ' special care
                        If .func() Then {
                              Select Case .Char
                              Case 117 'u
                              GetHex()
                              Case 114 ' r
                              .char<=0x0d
                              Case 110 ' n
                              .char<=0x0a
                              Case 116 ' t
                              .char<=0x09
                              Case 98 ' b
                              .char<=0x08
                              Case 102 ' f
                              .char<=0x0c
                              Case 0x22, 0x2f , 0x5c
                              rem  ' need a line always - revision 4
                              Else
                              Exit   ' not normal
                              End Select
                        }
                  }
                  D$=chrcode$(.char)
            }
            Exit
2000 Stack .obj {
                  If as_object Then {Push .JString$(D$)} Else Push D$
            } : =True
            Sub GetHex()
                  Local D$
                  Document D$="0x"
                  For i=1 to 4 {
                        If .func() Then {
                        \\ Chrcode$()  - was an error here in previous code as Chrcode()
                              If Chrcode$(.char) ~ "[0123456789ABCDEFabcdef]"  Then {
                                    D$=Chrcode$(.char)
                              } Else 3000
                        }
                  }
                  If i<>5 Then 3000
                  .Char<=Eval(D$)
3000 End Sub
      }
      Function final IsArray {
         
            If .char=91 Else exit
            Dim Gr()
            ' We place a pointer ro Array
            .Trim
            If .char=93 Then =true : Stack .obj { Push .Arr(Gr())} : exit
                  While .IsValue() {
                        Stack .obj {
                              Dim Gr(Len(Gr())+1)
                              Gr(len(Gr())-1)=Group
                        }
                        .Trim
                        If not .IsComma() Then exit
                        .Trim
                  }
            ' Push later pointer to array (maybe altered in redimension)
            If .char=93 Then { =true : Stack .obj { Push .Arr(Gr())} } Else .Func<=lambda->false
      }
      Module final Trim {
            While .func() {
                   If .char<33 or .char=160 Else exit
            }
      }
      Function final IsContainer {
           .Trim
           Select Case chrcode$(.char)
           Case "{"
                  =.IsObject()
           Case "["
                  =.IsArray()
           end select
      }
' merge a foreign group here
      Module final ReadArrayItem (temp, object){
             Select Case temp.type$
                  Case "String","Boolean","Number", "Null"
                  {
                        If object Then Error "No object "+quote$(temp.type$)
                        Push temp.str$
                  }
                  Case "Object"
                  {
                        If not Empty Then {
                           Call .ReadObject temp, object, letter$
                        } Else {
                              If object Then Push Temp : exit
                              Push .ser$(group(temp),0)
                        }
                  }
                  Case "Array"
                  {
                        If not Empty Then {
                              ' recursion only with Call statement for modules
                              Call .ReadArrayItem, Array(temp, number), object
                        } Else {
                              If object Then Push Temp : exit
                              Push .ser$(group(temp),0)
                        }
                  }
                  End Select
      }
      Module final ReadObject (json, object){
            If type$(json)="Inventory" Then {
                  If exist(json, Letter$) Then {
                        temp=eval(json)
                  } Else {
                       push "none"
                       Break  ' exit Module final  (Break do something Else in Select End Select)
                  }
            } Else temp=json
                  Select Case temp.type$
                  Case "String","Boolean","Number", "Null"
                  {
                        If object Then Error "No object "+quote$(temp.type$)
                        Push temp.str$
                  }
                  Case "Object"
                  {
                        If not Empty Then {
                              Call .ReadObject temp, object
                        } Else {
                              If object Then Push Temp : exit
                              Push .ser$(group(temp),0)
                        }
                  }
                  Case "Array"
                  {
                        If not Empty Then {
                              Call .ReadArrayItem array(temp, number), object
                        } Else {
                              If object Then Push Temp : exit
                              Push .ser$(group(temp),0)
                        }
                  }
                  End Select
      }
      Module final Worker (object){
                   If match("IN") Or match("IS") Then { ' inventory & number or inventory and string
                   '    maybe we have more items in Stack
                         Push object : ShiftBack 2
                        .ReadObject
                  } Else {
                        read Temp ' get  a group which returns Iventoty or an mArray
                        If Type$(Temp)="mArray" Then {
                              If not Empty Then {
                                    Call .ReadArrayItem, Array(Temp, number), object
                              } Else {
                                    If object Then Push Temp : exit
                                    Push .ser$(Temp,0)
                              }
                        } Else {
                              If not Empty Then {
                                          Call .ReadObject Temp, object
                              } Else {
                                    If not Empty Then {
                                          Call .ReadObject Temp, object
                                    } Else {
                                          If object Then Push Temp : exit
                                          If Type$(Temp)="Inventory" Then {
                                                Push .ser$(.Object(Temp),0)
                                          } Else {
                                                Push .ser$(group(Temp),0)
                                          }
                                    }
                              }
                        }
                  }
      }
Public:
\\ This is the Public part
\\ First we set Public some class for later use
\\ Using Pointer to Array in Class Arr
      Class Arr {
      Private:
            MyValue
      Public:
            Property Type$ {Value} ="Array"
            Value {
                  =.MyValue
            }
      Class:
            Module final Arr (.MyValue) {}
      }
      Class Null {
           Property Type$ {Value} ="Null"
           Property Str$ {Value}="null"
           Value { =0}
      }
      Class JString$ {
      Private:
            MyValue$=""
      Public:
            Property Type$ {Value} ="String"
            Property Str$ {
                  Value{
                        Link parent MyValue$ to MyValue$
                        value$=quote$(string$(MyValue$ as json))
                  }
            }
            Value {
                  =.MyValue$
            }
      Class:
            Module final JString (.MyValue$) {}
      }
      Class Numeric {
      Private:
            MyValue$=""
      Public:
            Property Type$ {Value} ="Number"
            Property Str$ {
                  Value{
                        Link parent MyValue$ to MyValue$
                        value$=MyValue$
                  }
            }
            Value {
                  =Val(.MyValue$)
            }
      Class:
            Module final Numeric {
            If match("S") Then {
                  Read .MyValue$
            } Else {
                  \\ using locale 1033 for dot always
                  .Myvalue$<=trim$(str$(Number, 1033))
            }
            }
      }
      Class Boolean {
      Private:
            MyValue=false
      Public:
            Property Type$ {Value} ="Boolean"
            Property Str$ {
                  Value{
                        Link parent MyValue to MyValue
                        If MyValue Then {
                              value$="true"
                        } Else value$="false"
                  }
            }
            Value {
                  =.MyValue
            }
      Class:
            Module final Boolean (.MyValue) {}
      }
      Class Object {
      Private:
            Inventory MyValue
      Public:
            Property Type$ {Value} ="Object"
            Value {
                  =.MyValue
            }
      Class:
            Module final Object (.MyValue) {}
      }
\\ Empty group, with $, so we get two vars, Ser and Ser$ ( Ser$ we want to return a value type String)
      Group Ser$
      Module final SetSpace (.ser.space) { ' set space for values - 6 by default
      }
      Function final UseDecimalPoint$ {
            ' use this to change standard decimal point to local decimal point character
            =str$(val(letter$),"")
      }
      Function final ReadNumber$ {
                  .Worker false 'modules get caller Stack
                  =.UseDecimalPoint$( Letter$)
      }           
      Function final ReadAnyString$ {
                  \\ read an inventory
                  .Worker false
                  =Letter$
      }
      Function final ReadAny {
                  \\ read an inventory
                  .Worker true
                  Read A
                  =A
      }
      Function final Eval {
            ' Letter$  pop a string from Stack Else give error
             .func<=Lambda z=.bStream(Letter$) -> {
                   link .char to c
                   ' we can't pass reference in a private member
                   =z(&c)
             }
            ' In this Parser we use a dedicated Stack
            ' for use from recuirsive memberts
            ' .obj is a pointer to Stack
            ' we can delete it simply setting a new Stack
            ' .obj<=Stack
            ' or we can flush all elements Using a command Flush
            ' .obj,  char and .func() are visible from group members
            ' test
            Stack .obj { Flush}
            .char<=0
            If .IsContainer() Then {
            ' we get the pointer
            =StackItem(.obj)
            .obj<=Stack
            } Else {
            ' return an Empty object
            inventory emptinv
            =.Object(emptinv)
            }
      }
      Group StringValue$ {
            Add=false
            Del=false
            Set (temp) {
                  ' always first read is for the assigned value to Group
                  Read temp1
                  If type$(temp)<>"Group" Then error "Need a group"
                  If not valid(temp.type$="") Then error "not a proper group"
                  If not valid(temp1.type$="") Then error "not a proper group for value"
                  ' because Null() is out of this scope we have to link
                  Link parent Null() to MyNull()
                  Null=MyNull()
                  Dim Base 1, A(1)
                  \\ now we get the second interface for arrays
                  \\ bb() has a reference to b (one reference allowed)
                  \\ but b is pointer to array and can change to point to other arrrays
                  \\ we need this to perform some tasks which belong to standard arrray interface
                  b=(,) : Link b to bb()
                  A(1)=Group(temp)
                  Do {
                        again=false
                        Select Case A(1).type$
                        Case "Array"
                        {
                              If match("N") Then {
                                    Read where
                                    If len(A(1))<=where and Empty Then {
                                    ' only the last array we can redimension
                                          If .add and not .del Then {
                                          cursize=Len(A(1))
                                          b=A(1) ' A(1) has a pointer so now b has the same pointer
                                          ' dim preserve values
                                          Dim bb(where+1) ' need one more because all "automatic arrays" have base 0
                                          Stock bb(cursize) sweep Len(b)-cursize, Group(Null)
                                          } Else Error "Index out of limits"+str$(where)
                                    } Else If where<0 Then Error "Index out of limits "+str$(where)
                                    If Empty Then {
                                          If .del Then {
                                                cursize=Len(A(1))
                                                b=A(1) ' A(1) has a pointer so now b has the same pointer
                                                If where<cursize-1 Then {
                                                      Stock bb(where+1) Keep cursize-where, bb(where)
                                                }
                                                Dim bb(cursize-1) ' bb(0) is an empty array
                                          } Else Return A(1), where:=Group(temp1)
                                    } Else {
                                          A(1)=Array(A(1),where)
                                          again=True
                                    }
                              } Else Error "No Index Found"
                        }
                        Case "Object"
                        {
                              If match("S") Then {
                                    Read k$
                                    If Exist(A(1), k$) Then {
                                          If Empty Then {
                                                If .del Then {
                                                     Delete A(1) , k$
                                                } else {
                                                      Return A(1), k$:=Group(temp1)
                                                }
                                          } Else {
                                                A(1)=Eval(A(1)) ' Eval(inventory_pointer) return  object pointer
                                                again=True
                                          }
                                  } else.if .add and not .del Then {
                                           If Empty Then {
                                                      Append A(1), k$:=Group(temp1)
                                          } Else Error "No such Tag "+k$
                                    } Else Error "No such Tag "+k$
                              } Else Error "No Tag Found"
                        }
                        End Select
                  } until not again
            }
            Value (temp) {
                  If type$(temp)<>"Group" Then error "Need a group"
                  If not valid(temp.type$="") Then error "not a proper group"
                  Dim Base 1, A(1)
                  A(1)=Group(temp)
                  Do {
                        again=false
                        Select Case A(1).type$
                        Case "String", "Number", "Null", "Boolean"
                              Exit
                        Case "Array"
                        {
                              If match("N") Then {
                                    A(1)=Array(A(1), Number)
                              } Else Error "No Index Found"
                              again=True
                        }
                        Case "Object"
                        {
                              If match("S") Then {
                                    If Exist(A(1), Letter$) Then {
                                          A(1)=Eval(A(1)) ' Eval(inventory_pointer) return  object pointer
                                    } Else Error "No such Tag"
                              } Else Error "No Tag Found"
                              again=True
                        }
                        End Select
                  } until not again
                   =A(1).str$
            }
      }
Class:
\ one time definitions
      Class CreatSerialize$ {
      Private:
            usen=0
            n=0
            nl1$={
            }
            Function final Jarray$ (json1, n){
                  \\ json1 is group type Array
                           A=json1
                        \\ A is mArray (pointer to Array)
                        nl$=.nl1$
                        If .usen>0 Then {
                          '    If n<.space Then n=.space
                              nl$=nl$+string$(" ", n+.space)
                        }
                        document a$
                        a$="["
                        If Len(A)>0 Then {
                              If .usen>0 Then a$=nl$
                               k=each(A)
                               M=len(A)-1
                               while k {
                                    For This {
                                          \\ temporary group
                                          Temp=array(k)
                                          select Case temp.type$
                                          Case "Number", "Null","Boolean", "String"
                                          a$=temp.str$
                                          Case "Array"
                                          {
                                                nn=0
                                                If .usen>0 Then {
                                                      nn=n +.space
                                                }
                                                a$=.Jarray$(Temp, nn, "")
                                          }
                                          Case "Object"
                                          {
                                               nn=0
                                                If .usen>0 Then {
                                                      nn=n +.space
                                                }
                                                a$=.Jobject$(Temp, nn,"")
                                          }
                                          Else
                                                a$=" "+temp.type$
                                          end select
                                           If k^<M Then {
                                               a$=", "
                                                If .usen>0 Then a$=nl$
                                          } Else {
                                                If .usen>0 Then a$=.nl1$
                                          }
                                    }
                              }
                        }  else If .usen>0 Then a$=.nl1$
                         If .usen>0 Then a$=string$(" ", n)
                  a$="]"
                     =a$+letter$
            }
            Function final Jobject$ (json1, n){
                              json=json1
                              \\ json has to be an object inventory
                              nl$=.nl1$
                              If .usen>0 Then {
                                   ' If n<.space Then n=.space
                                    nl$=nl$+string$(" ", n+.space)
                              }
                              document a$
                              a$="{"
                              If .usen>0 Then a$=nl$
                               k=each(json)
                               M=len(json)-1
                               while k {
                                    a$=quote$(eval$(json, k^)) +" : "
                                    select Case json(k^!).type$
                                    Case "Array"
                                    {
                                          nn=0
                                          If .usen>0 Then {
                                                nn=n +.space
                                          }
                                          a$=.Jarray$(eval(k), nn, "")
                                    }
                                    Case  "Boolean", "Null", "Number", "String"
                                          a$=json(k^!).str$
                                    Case "Object"
                                    {
                                          nn=0
                                          If .usen>0 Then {
                                                nn=n +.space
                                          }
                                          a$=.Jobject$(eval(k), nn, "")
                                    }
                                    Else
                                          a$=" "+json( k^!).type$
                                    end select
                                     If k^<M Then {
                                         a$=", "
                                          If .usen>0 Then a$=nl$
                                    } Else {
                                          If .usen>0 Then a$=.nl1$
                                    }
                              }
                         If .usen>0 Then a$=string$(" ", n)
                        a$="}"
                        =a$+letter$
            }
            Class Object {
            Private:
                  Inventory MyValue
            Public:
                  Property Type$ {Value} ="Object"
                  Value {
                        =.MyValue
                  }
            Class:
                  Module final Object (.MyValue) {}
            }
      Public:
            space=10
            Value (json, n) {
                        a$=.nl1$
                        b$=""
                        .usen<=n
                        n--
                        If n<=0 Then { a$="" : n=0 } Else b$=string$(" ", n)
                        If type$(json)<>"Group" Then {
                              If type$(json)="Inventory" Then {
                                    =b$+.Jobject$(.Object(json),n, a$)
                              } else.if type$(json)="mArray" Then {
                                    =b$+.Jarray$(json, n, a$)
                              }
                        } Else {
                              If json.type$="Object" Then {
                                    =b$+.Jobject$(json, n,a$)
                              } else.if json.type$="Array" Then {
                                    =b$+.Jarray$(json, n, a$)
                              }
                        }
            }
      }
      Module final ParserClass {
            \ constructor
            \ Let work as Push .CreatSerialize$() : Read .Ser
            \ So now Group Ser loaded from CreatSerialize$()
            \ Class CreatSerialize$ is a Function final, and because it is after Class:
            \ Deleted before ParserClass return Group
            Let .Ser=.CreatSerialize$()
      }
}



Parser=ParserClass()
Modules ? \\ Display the name of  module and public parts of Parser

Document json$
' We can load from file
'Load.Doc json$, "alfa.json"
json$={{
      "alfa":-0.11221e+12,
      "array" : [
            -0.67,
            "alfa1",
            [
                  10,
                  20
            ],
            "beta1",
            1.21e12,
            [
            ],
            21.12145,
            "ok"
      ],
      "delta": false, "epsilon" : true, "Null Value" : null
}}
Save.Doc json$, "json2.json"    \\ by default in Utf-8 with BOM
' just show multiline text
Report json$
\ so now we get text to a new object
alfa=Parser.Eval(json$)
Print Type$(alfa) ' it is a group
Print "alfa.type$=";alfa.type$ \\ this is a read only property
Report "as one line"
Report Parser.Ser$(alfa, 0)
Report "as multiline"
Report Parser.Ser$(alfa, 1)
Print "Using Print"
Print Parser.ReadAnyString$(alfa)
Print "Value for alfa, id alfa"
Print Parser.ReadAnyString$(alfa,"alfa")
Report "as multiline"
\\ here a string returned from Parser.ReadAnyString$(alfa,"array", 2)
\\ Then a group returned ftom Parser.Eval()
\\ Then string returned from that group.
\\ We get specific 0
Report Parser.Ser$(Parser.Eval(Parser.ReadAnyString$(alfa,"array", 2)), 1)
' We get a copy of array
Alfa3=Parser.Eval(Parser.ReadAnyString$(alfa,"array", 2))
Dim B()
B()=Alfa3
N=each(B())
While N {
      Print B(N^)
}