Πέμπτη, 29 Ιουνίου 2017

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

Βελτίωση στο σύστημα φόρτωσης αρχείων κειμένου, στον διορθωτή και σε αντικείμενα Έγγραφο. Τώρα υπάρχει αυτόματη αναγνώριση για UTF-8 αρχεία όταν λείπουν τα bytes (BOM) που καθορίζουν ως σήμανση αυτά τα αρχεία.
δοκιμάστε το παρακάτω:

Έγγραφο α$={<?xml version="1.0"?>
<Ονόματα>
      <στοιχείο αα="69">
      <όνομακωδ>VB6</όνομακωδ>
      <ποσότητα>2</ποσότητα>
      </στοιχείο>
      <στοιχείο αα="70">
      <όνομακωδ>C++</όνομακωδ>
      <ποσότητα>3</ποσότητα>
      </στοιχείο>
      <στοιχείο αα="71">
      <όνομακωδ>Μ2000</όνομακωδ>
      <ποσότητα>10</ποσότητα>
      </στοιχείο>
</Ονόματα>
}
Σώσε.Έγγραφο α$,"άλφα.xml", -2
Καθαρό α$
Έγγραφο α$="Привет игровая площадка!"
Σώσε.Έγγραφο α$,"russian.txt", 1049
Έγγραφο β$
Φόρτωσε.Έγγραφο β$ ,"russian.txt", 1049
Τύπωσε β$


Καθαρό α$, β$
Έγγραφο α$="Привет игровая площадка! Ελληνικά δεν μπορούν να αποθηκευτούν"
Σώσε.Έγγραφο α$,"russian.txt", 1049
Έγγραφο β$
Φόρτωσε.Έγγραφο β$ ,"russian.txt", 1049
Τύπωσε β$
\\ Μπορούμε να επιλέξουμε χωρίς αριθμό (UTF-16)
\\ 0 UTF-16LE
\\ 1 UTF-16BE
\\ 2 UTF-8  ***  εξ ορισμού (δες παρακάτω)
\\ -2 UTF-8 χωρίς ΒΟΜ (χωρίς τα τρια πρώτα bytes που δηλώνουν ότι είναι UTF8)
\\ 3 ANSI   (εδώ αντί για 3 μπορούμε να δώσουμε 1049 πχ για ρώσικα, θα βγει ANSI ρώσικο)
\\ στην ανάγνωση Φόρτωσε.Έγγραφο υπάρχει αυτόματη ανανγνώριση
\\ αν θέλουμε όμως δίνουμε αριθμό για ANSI γλώσσα, πχ το 1049 για τα ρώσικα.


\\ Εσωτερικά το έγγραφο έχει κωδικοποίηση UTF-16LE


\\ στην εγγραφή Σώσε.Έγγραφο:
\\ αν δεν δώσουμε αριθμό ενώ είχαμε φορτώσει το έγγραφο τότε θα χρησιμοποιθεί το σύστημα που φορτώθηκε
\\ αν δεν έχει φορτωθεί, αλλά δημιουργήθηκε εδώ τότε εξ ορισμού θα είναι το 2 (UTF-8)
\\ αν δώσουμε όμως αριθμό το αλλάζουμε! Αν είναι Ansi τότε έχει ήδη πάρει στη φόρτωση τον αριθμό, οπότε για ..
\\ ... να αλλάξουμε σε άλλο ANSI θα πρέπει να δώσουμε αριθμό (πράγμα απίθανο να το θέλουμε όμως)
\\ έτσι το παρακάτω θα γράψει
Καθαρό α$, β$
Έγγραφο α$="Привет игровая площадка! Ελληνικά τώρα μπορούν να αποθηκευτούν"
Σώσε.Έγγραφο α$,"russian.txt", -2
Έγγραφο β$
Φόρτωσε.Έγγραφο β$ ,"russian.txt"
Τύπωσε β$
\\ η μεταβλητή μόνο για ανάγνωση κατ$ δίνει τον τρέχον κατάλογο
\\ Μπορούμε να επιστρέφουμε στο κατάλογο χρήστη ακόμα και αν δεν θυμόμαστε που είναι!
Κατάλογος χρήστη
' δοκιμάστε να σώσετε από το notepad. Θα εμφανιστεί η προεπιλογή UTF-8
Σύστημα "notepad", κατ$+"russian.txt"
Σώσε.Έγγραφο α$,"russian1.txt", 0
'Εδώ θα εμφανιστεί η προεπιλογή Unicode
Σύστημα "notepad", κατ$+"russian1.txt"
'Η μεταβλητή τοπικό μας δίνει τον αριθμό για τον σύστημα
α$={
      english always are visible in ansi mode
}
Σώσε.Έγγραφο α$,"russian2.txt", τοπικό
'Εδώ θα εμφανιστεί η προεπιλογή ansi
Σύστημα "notepad", κατ$+"russian2.txt"




Όλο ξεκίνησε από το παρακάτω πρόγραμμα όπου το αντικείμενο Msxml2.DOMDocument.6.0 κάνει οικονομία 3 bytes και δεν βάζει το BOM. Φαίνεται παρακάτω πως χρησιμοποιούμε ένα αντικείμενο των Windows μέσα από την Μ2000. Τα αντικείμενα αυτά μένουν μέσα στο τμήμα όσο το τμήμα εκτελείται, και μετά διαγράφονται. Οι εντολές Όρισε όνομα_αντικειμένου Τίποτα εδώ είναι πλεονασμός. Ορισμένα ονόματα αντικειμένων είναι στα αγγλικά, για να μπορεί κανείς να τα βρει αν μελετήσει το αντικείμενο για αρχεία XML 6 της Microsoft.



Έγγραφο α$={<?xml version="1.0"?>
<Ονόματα>
      <στοιχείο αα="69">
      <όνομακωδ>VB6</όνομακωδ>
      <ποσότητα>2</ποσότητα>
      </στοιχείο>
      <στοιχείο αα="70">
      <όνομακωδ>C++</όνομακωδ>
      <ποσότητα>3</ποσότητα>
      </στοιχείο>
      <στοιχείο αα="71">
      <όνομακωδ>Μ2000</όνομακωδ>
      <ποσότητα>10</ποσότητα>
      </στοιχείο>
</Ονόματα>
}
Σώσε.Έγγραφο α$,"άλφα.xml", -2
Έγγραφο α$
Φόρτωσε.Έγγραφο α$,"άλφα.xml"
Αναμονή 100
Όρισε ΑντικείμενοXml "Msxml2.DOMDocument.6.0"
Μέθοδος ΑντικείμενοXml, "Load", κατ$+"άλφα.xml" ως οκ
Αν οκ τότε {
      Όρισε ΣτοιχείοXML με ΑντικείμενοXml, "documentElement"
      Μέθοδος ΣτοιχείοXML, "selectSingleNode", "στοιχείο[@αα=70]" ως ΕπιλεγμένοΣτοιχείο
      Μέθοδος ΕπιλεγμένοΣτοιχείο, "selectSingleNode", "όνομακωδ" ως ΕπιλεγμένοΠεδίο
      \\ αυτή η Με είναι διαφορετική από την Με στην δομή Επίλεξε Με
      \\ εδώ έχουμε εντολή ενώ εκεί είναι στοιχείο της δομής
      Με ΕπιλεγμένοΠεδίο, "text" ως η_τιμή_μου$
      Τύπωσε η_τιμή_μου$
      \\ Μπορώ να αλλάξω τιμή
      η_τιμή_μου$="George"
      \\ Και μπορώ να σώσω -- αλλά δεν βάζει BOM
      Μέθοδος ΑντικείμενοXml, "Save", κατ$+"alfa.xml" ως οκ
      Μέθοδος ΣτοιχείοXML, "getElementsByTagName", "στοιχείο" ως objNodeList
      Με objNodeList , "length" ως objNodeList.length
      Τύπωσε objNodeList.length
      Για ι=0 έως objNodeList.length-1 {
            Μέθοδος objNodeList , "item", ι ως objNodeList.item
            Μέθοδος objNodeList.item, "getElementsByTagName", "όνομακωδ" ως objNodeList2
            Μέθοδος objNodeList2 , "item", 0 ως objNodeList.item2
            'δοκιμάστε και το παρακάτω (σκιάστε την επόμενη με σημείωση)
            'Με  objNodeList.item2 , "xml" ως α12$
            Με objNodeList.item2 , "text" ως α12$
            Πένα 12 {
                  Τύπωσε α12$
            }
            Όρισε objNodeList.item2 Τίποτα
            Όρισε objNodeList2 Τίποτα
            Όρισε objNodeList.item Τίποτα
      }
      Όρισε objNodeList Τίποτα
      Όρισε ΕπιλεγμένοΠεδίο Τίποτα
      Όρισε ΕπιλεγμένοΣτοιχείο Τίποτα
      Όρισε ΣτοιχείοXML Τίποτα
}
Όρισε ΑντικείμενοXml Τίποτα
Εγγραφο ααα$
Φόρτωσε.Έγγραφο ααα$, "alfa.xml"
Αναφορά ααα$


έξω από το τμήμα μετά την εκτέλεση μπορούμε να δώσουμε αυτήν την εντολή:
Σ "alfa.xml"

ενώ μέσα στο τμήμα θα δίναμε την παρακάτω εντολή για να ανοίξει ο διορθωτής στο αντικείμενο έγγραφο.

Διόρθωσε ααα$ 

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






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

Json Library for M2000 rev 3

Json Library for M2000
All code is in one class. We can change, append and delete values.

From M2000 console:
Edit "jsonex.gsb"
Now open a file as jsonex.gsb and we can place the code by drag and drop, or copy.
Load jsonex
Now we load these modules and we start the example
A



MODULE A {' Process data in json format

' we can load from external file with Inline "libName"
' or multiple files Inline "file1" && "file2"
' but here we have the library in a module
Inline Code Lib1
' So now we make a Parser object (a group type in M2000)
Parser=ParserClass()
' We can display any function, module that is public and known list
Modules ?
' And this are all known variables (or and objects)
List !
'exit
Document json$
' We can load from file
'Load.Doc json$, "alfa.json"
json$={{
      "zero": 0,
      "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 display lines and stop after 3/4 of console height lines
' just press a key or click mouse button
Report json$
' so now we get text to a new object
alfa=Parser.Eval(json$)
' check t
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"
Report Parser.Ser$(Parser.Eval(Parser.ReadAnyString$(alfa,"array", 2)), 1)
' We get a copy of an array as a Group (a group which return an array)
Alfa3=Parser.Eval(Parser.ReadAnyString$(alfa,"array", 2))
' First value is for actual object, second value is a reafonly property of this object
Print type$(Alfa3), Alfa3.type$
Dim B()
' Now Alfa3 run Value part and pass a pointer of array
' B()  is an array and here take a pointer to Alfa3 array (as value of Alfa3)
B()=Alfa3
' each() make an iterator for B()
N=each(B())
While N {
      \\ Using B() we get values always. but if we have "object" or "array" then Print prints items **
      Print B(N^)
}
' ** Print show here nothing because if value is object then "print" just leave a column and continue to next one
Print B()
' we have to use Group() to get group not value of group (if any).
' Group() works for "named" group, not for stored in an array or an inventory or a stack
Print Parser.StringValue$(Group(Alfa3), 0)
Print Parser.StringValue$(Group(Alfa3), 1)
' Now we want to pass a new value
' Interpreter want to match type of expression from left side to right side
' Because Parser.StringValue$ is actuall a Group (As property),
' we have a second linked name:  Parser.StringValue
' we have to use Parser.StringValue()
' and all values must be groups, as those provided by Parser
Parser.StringValue(Group(Alfa3), 1)=Parser.Numeric(1234)
Print Parser.StringValue$(Group(Alfa3), 1)
Print Parser.StringValue$(Group(Alfa), "array", 2, 0)
' we have to use Parser.StringValue$()
Parser.StringValue$(Group(Alfa), "array", 2, 0)=Parser.JString$("Changed to String")
Print Parser.StringValue$(Group(Alfa), "array", 2,0)
Try ok {
      Print Parser.StringValue$(Group(Alfa), "array", 2)
}
If Error or not ok Then Print Error$
Parser.StringValue.Add = True
Parser.StringValue$(Group(Alfa), "array", 2, 10)=Parser.JString$("Changed to String 2")
Parser.StringValue(Group(Alfa), "Last value")=Parser.Boolean(true)
Report "as multiline"
Report Parser.Ser$(alfa3, 1)
Report Parser.Ser$(alfa, 1)
Parser.StringValue.Add = False
Parser.StringValue.Del = True
Parser.StringValue(Group(Alfa), "array", 0)=Parser.Null()
Parser.StringValue(Group(Alfa), "delta")=Parser.Null()
Parser.StringValue.Del = False
For Parser {
      .StringValue(Group(Alfa), "array", 1,5)=.Arr((.Numeric(10), .Jstring$("ok 20"), .Boolean(true)))
}
Report Parser.Ser$(alfa, 1)

}
MODULE LIB1 {
      Class ParserClass {
      Private:
            Class bStream {
                  Private:
                  cnt, Buffer A
                  Public:
                  Value (&c) {Try { c=eval(.A, .cnt) : .cnt++:=true}}
                  Class:
                  Module 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 IsId {
                  If .char=34 Then =.IsString(false)
            }
            Function 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 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 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 IsSemiCol {
                    If .char=0x3a Then =true
            }
            Function IsComma {
                    If .char=0x2c Then =true
            }
            Function 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 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 {
                        ? "what", .char
                        Stack .obj { Stack}
                        .func<=lambda->0
                  }
            }
            Function Digits (private_stack){
                  While .func() {
                        Select Case .char
                        Case 48 to 57
                        {
                              =true
                             Stack private_stack { Data .char}
                        }
                        Else
                             break
                        End Select
                  }    
            }
            Function 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 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
                                    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 {
                                    If Chrcode(.char) ~ "[0123456789ABCDEFabcdef]"  Then {
                                          D$=Chrcode(.char)
                                    } Else 3000
                              }
                        }
                        If i<>5 Then 3000
                        .Char=Eval(D$)
      3000 End Sub
            }
            Function 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 Trim {
                  While .func() {
                         If .char<33 or .char=160 Else exit
                  }
            }
            Function IsContainer {
                 .Trim
                 Select Case chrcode$(.char)
                 Case "{"
                        =.IsObject()
                 Case "["
                        =.IsArray()
                 end select
            }
      ' merge a foreign group here
            Module ReadArrayItem (temp){
                   Select Case temp.type$
                        Case "String","Boolean","Number", "Null"
                        {
                              Push temp.str$
                        }
                        Case "Object"
                        {
                              If not Empty Then {
                                 Call .ReadObject temp, letter$
                              } Else {
                                    Push .ser$(group(temp),0)
                              }
                        }
                        Case "Array"
                        {
                              If not Empty Then {
                                    ' recursion only with Call statement for modules
                                    Call .ReadArrayItem, Array(temp, number)
                              } Else {
                                    Push .ser$(group(temp),0)
                              }
                        }
                        End Select
            }
            Module ReadObject (json){
                  If type$(json)="Inventory" Then {
                        If exist(json, Letter$) Then {
                              temp=eval(json)
                        } Else {
                             push "none"
                             Break  ' exit Module  (Break do something Else in Select End Select)
                        }
                  } Else temp=json
                        Select Case temp.type$
                        Case "String","Boolean","Number", "Null"
                        {
                              Push temp.str$
                        }
                        Case "Object"
                        {
                              If not Empty Then {
                                    Call .ReadObject temp, letter$
                              } Else {
                                    Push .ser$(group(temp),0)
                              }
                        }
                        Case "Array"
                        {
                              If not Empty Then {
                                    Call .ReadArrayItem array(temp, number)
                              } Else {
                                    Push .ser$(group(temp),0)
                              }
                        }
                        End Select
            }
            Module Worker {
                         If match("IN") Or match("IS") Then { ' inventory & number or inventory and string
                         '    maybe we have more items in Stack
                              .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)
                                    } Else {
                                          Push .ser$(Temp,0)
                                    }
                              } Else {
    
                                    If not Empty Then {
                                                Call .ReadObject Temp, letter$
                                    } Else {
                                          If not Empty Then {
                                                Call .ReadObject Temp, letter$
                                          } Else {
                                                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 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 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 Numeric {
                  If match("S") Then {
                        Read .MyValue$
                  } Else {
                        value$=trim$(str$(Number))
                        ' M2000 return -.35 for -0.35
                        ' using ? str$(MyValue, "0.#############")
                        ' we get locale decimal char - maybe is comma
                        ' so using str$(MyValue) we get integer or float with char "." for decimal always
                        ' so we have to add 0
                        If left$(value$, 1)="." Then {
                              value$="0"+value$
                        } Else If value$ ~ "-.*" Then value$=replace$("-.","-0.", value$)
                        .Myvalue$<=value$
                  }
                  }
            }
            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 Boolean (.MyValue) {}
            }
            Class Object {
            Private:
                  Inventory MyValue
            Public:
                  Property Type$ {Value} ="Object"
                  Value {
                        =.MyValue
                  }
            Class:
                  Module 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 SetSpace (.ser.space) { ' set space for values - 6 by default
            }
            Function UseDecimalPoint$ {
                  ' use this to change standard decimal point to local decimal point character
                  =str$(val(letter$),"")
            }
            Function ReadNumber$ {
                        .Worker    'modules get caller Stack
                        =.UseDecimalPoint$( Letter$)
            }           
            Function ReadAnyString$ {
                        \\ read an inventory
                        .Worker
                        =Letter$
            }
            Function Eval {
                  ' Letter$  pop a string ftom 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
                  ' from revision 12 we can place temp in parameter block
                  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()
                        ' or we can hard code the Null object
'                        Group Null {
'                                  Property Type$ {Value} ="Null"
'                                  Property Str$ {Value}="null"
'                                  Value { =0}
'                       }
                        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 ths 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 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 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 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 ParserClass {
                  \ constructor
                  \ Let work as Push .CreatSerialize$() : Read .Ser
                  \ So now Group Ser loaded from CreatSerialize$()
                  \ Class CreatSerialize$ is a function, and because it is after Class:
                  \ Deleted before ParserClass return Group
                  Let .Ser=.CreatSerialize$()
            }
      }
}