Σάββατο, 13 Ιανουαρίου 2018

Αναθεώρηση 38 (Έκδοση 9.0) και νέο Range Object με SubRanges

Στην αναθεώρηση αυτή βρήκα (φτιάχνοντας το Range Object) ένα λάθος στην Compare() όπου υπήρχε περίπτωση να δώσουμε αρνητικό αριθμό και το μηδέν και να πάρουμε ότι ο αρνητικός είναι μεγαλύτερος! Φτιάχτηκε!

Παρακάτω είναι το νέο Range Object το οποίο δουλεύει με SubRanges, δηλαδή ορίζουμε υποπεριοχές, με συνάρτηση που δείχνει πως πάμε από την αρχή ως το τέλος κάθε περιοχής.

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

Κλάση Περιοχή {
Ιδιωτικό:
      Πίνακας ΥπόΠερ1()
      από$, έως$, πρώτο=Αληθές
      απόαριθμό, σεαριθμό, υποπεριοχή=0
      τύπος_περιοχής=0
      Συνάρτηση Έρευνα (κ$) {
             αντίγραφο1=Αυτό
             αντίγραφο1.Μηδένισε
             Ενώ αντίγραφο1 {
                  Αν κ$=αντίγραφο1.Αξία$ Τότε =Αληθές : Έξοδος
            }
      }
      Συνάρτηση ΈρευναΑριθμού (κ) {
             αντίγραφο1=Αυτό
             αντίγραφο1.Μηδένισε
             Ενώ αντίγραφο1 {
                  Αν κ=αντίγραφο1.αξ Τότε =Αληθές : Έξοδος
            }
      }
      ΕπόμενοΒήμα$=Λάμδα$ ->{Λάθος 500}
      ΕπόμενοΒήμαΑριθμ=Λάμδα ->{Λάθος 500}
Δημόσιο:
      Συνάρτηση Έχει {
                        Αν .τύπος_περιοχής=1 Τότε {
                        Διάβασε τι$
                        Διάβασε ? ΣυνάρτησηΧρήστη
                        Αν ΣυνάρτησηΧρήστη Τότε =.Έρευνα(τι$) : Έξοδος
                        υποπεριοχή=1
                        Επανέλαβε {
                              Στοκ .ΥποΠερ1(υποπεριοχή) σε από$, έως$
                              Αν τι$<>"" Τότε {
                                 Αν από$<=έως$ Τότε {
                                           ν=τι$>=από$ Και τι$<=έως$
                                    } Αλλιώς {
                                          ν=τι$>=έως$ Και τι$<=από$
                                    }
                              }
                              υποπεριοχή+=4
                        } Μέχρι υποπεριοχή>=Μήκος(.ΥποΠερ1()) Ή ν
                        =ν
                  } Αλλιώς {
                        Διάβασε τι
                        Διάβασε ? ΣυνάρτησηΧρήστη
                        Αν ΣυνάρτησηΧρήστη Τότε =.ΈρευναΑριθμού(τι) : Έξοδος
                        υποπεριοχή=1
                        Επανέλαβε {
                              Στοκ .ΥποΠερ1(υποπεριοχή) σε απόαριθμό, σεαριθμό ' these are locals too                        
                              Αν απόαριθμό<=σεαριθμό Τότε {
                                    ν=τι>=απόαριθμό Και τι<=σεαριθμό
                              } Αλλιώς {
                                    ν=τι>=σεαριθμό Και τι<=απόαριθμό
                              }
                        υποπεριοχή+=4
                        } Μέχρι υποπεριοχή>=Μήκος(.ΥποΠερ1()) Ή ν
                        =ν
                  }
      }
      Ιδιότητα Αξία$ { Αξία }
      Ιδιότητα Αξ { Αξία }
      Τμήμα Πήδα (κ){
            κ=Απολ(κ)
            Αν κ Αλλιώς Έξοδος
            Ένωσε Αυτό στο μ1
            Ενώ κ {
                  κ--
                  Αν μ1 Αλλιώς Έξοδος
            }
      }
      Τμήμα Μηδένισε {
            .υποπεριοχή<=0
            Αν Μήκος(.ΥποΠερ1())>1 Τότε {
                  Στοκ .ΥποΠερ1(.υποπεριοχή) σε .τύπος_περιοχής
                  Επίλεξε Με .τύπος_περιοχής
                  Με 1
                        {
                              Στοκ .ΥποΠερ1(.υποπεριοχή+1) σε .από$, .έως$, .ΕπόμενοΒήμα$
                              .[Αξία]$<=.από$
                        }
                  Αλλιώς
                        {
                              Στοκ .ΥποΠερ1(.υποπεριοχή+1) σε .απόαριθμό, .σεαριθμό, .ΕπόμενοΒήμαΑριθμ
                              .[Αξ]<=.απόαριθμό
                        }
                  Τέλος Επιλογής
            }       
            .πρώτο<=Αληθές
      }
      Αξία {
            ν=Ψευδές
            Αν .τύπος_περιοχής=1 Τότε {
                             Δες {
                                    μ$=.ΕπόμενοΒήμα$(.[Αξία]$)
                                    Αν Λάθος Τότε Έξοδος
                                    Αν .πρώτο Τότε .πρώτο~ : =Αληθές : Έξοδος
                                    Αν Απολ(Σύγκρινε(μ$, .έως$)+Σύγκρινε(.από$, .έως$))=0 Τότε ν~ : Έξοδος
                                    .[Αξία]$<=μ$
                                    =Αληθές
                                   }
            } Αλλιώς {
           
                       Δες {
                             μ=.ΕπόμενοΒήμαΑριθμ(.[Αξ])
                              Αν Λάθος Τότε Έξοδος
                              Αν .πρώτο Τότε .πρώτο~ : =Αληθές : Έξοδος
                              Αν Απολ(Σύγκρινε(μ, .σεαριθμό)+Σύγκρινε(.απόαριθμό, .σεαριθμό))=0 Τότε ν~ : Έξοδος
                              .[Αξ]<=μ
                              =Αληθές
                        }                  
            }
            Αν ν Αλλιώς Έξοδος
            .υποπεριοχή+=4
            Αν .υποπεριοχή>=Μήκος(.ΥποΠερ1()) Τότε Έξοδος
            Στοκ .ΥποΠερ1(.υποπεριοχή) σε .τύπος_περιοχής
            Επίλεξε Με .τύπος_περιοχής
            Με 1
                  {
                        Στοκ .ΥποΠερ1(.υποπεριοχή+1) σε .από$, .έως$, .ΕπόμενοΒήμα$
                        .[Αξία]$<=.από$
                  }
            Αλλιώς
                  {
                        Στοκ .ΥποΠερ1(.υποπεριοχή+1) σε .απόαριθμό, .σεαριθμό, .ΕπόμενοΒήμαΑριθμ
                         .[Αξ]<=.απόαριθμό
                  }
            Τέλος Επιλογής
            .πρώτο<=Ψευδές
            =Αληθές
      }
      Κλάση:
      Τμήμα Περιοχή {
            Ενώ Όχι Κενό {
                   Αν Ταύτιση("SS") Και Όχι .τύπος_περιοχής=2 Τότε {
                        .τύπος_περιοχής<=1
                        Διάβασε .από$, .έως$
                        Αν Ταύτιση("F") Τότε Διάβασε .ΕπόμενοΒήμα$
                        .[Αξία]$<=.από$
                  } Αλλιώς.Αν Ταύτιση("NN") Και Όχι .τύπος_περιοχής=1 Τότε {
                       Διάβασε .απόαριθμό, .σεαριθμό
                       .τύπος_περιοχής<=2
                       Αν Όχι Ταύτιση("F") Τότε {
                             .ΕπόμενοΒήμαΑριθμ<=Αν(.απόαριθμό<=.σεαριθμό -> (Λάμδα (χ) ->χ+1), (Λάμδα (χ) ->χ-1))
                        } Αλλιώς{
                                    Διάβασε .ΕπόμενοΒήμαΑριθμ
                        }
                        .[Αξ]<=.απόαριθμό
                 } Αλλιώς Λάθος "Δεν υποστηρίζονται οι τύποι στο σωρό:"+Φάκελος$()
                  Αν .τύπος_περιοχής<>0 Τότε {
                        που=Μήκος(.ΥποΠερ1())
                        Πίνακας Βάση 0, .ΥποΠερ1(που+4)
                        Επίλεξε Με .τύπος_περιοχής
                        Με 1
                              Στοκ .ΥποΠερ1(που) από .τύπος_περιοχής, .από$, .έως$, .ΕπόμενοΒήμα$
                        Αλλιώς
                              Στοκ .ΥποΠερ1(που) από .τύπος_περιοχής, .απόαριθμό, .σεαριθμό, .ΕπόμενοΒήμαΑριθμ
                        Τέλος Επιλογής
                  }
            }
            Αν Μήκος(.ΥποΠερ1())>1 Τότε {
                  .τύπος_περιοχής<=.ΥποΠερ1(0)
                  Επίλεξε Με .τύπος_περιοχής
                  Με 1
                        {
                              Στοκ .ΥποΠερ1(1) σε .από$, .έως$, .ΕπόμενοΒήμα$
                              .[Αξία]$<=.από$
                        }
                  Αλλιώς
                        {
                              Στοκ .ΥποΠερ1(1) σε .απόαριθμό, .σεαριθμό, .ΕπόμενοΒήμαΑριθμ
                              .[Αξ]<=.απόαριθμό
                        }
                  Τέλος Επιλογής
            }
      }
}
ΕπόμενοςΧαρακτήρας$=Λάμδα$ (χ$) -> ΧαρΚωδ$(ΧαρΚωδ(χ$)+1)
ΠροηγούμενοςΧαρακτήρας$=Λάμδα$ (χ$) -> ΧαρΚωδ$(ΧαρΚωδ(χ$)-1)
μ=Περιοχή("A", "Z", ΕπόμενοςΧαρακτήρας$, "z", "a", ΠροηγούμενοςΧαρακτήρας$)
Τύπωσε Μ.Αξία$
Τύπωσε Μ.Έχει("A"), Μ.Έχει("z", Αληθές)
Ενώ μ {
      Τύπωσε μ.Αξία$;
}
Τύπωσε  "",,       \\ σπάει το ; και βάζει άλλη γραμμή
μ.Μηδένισε
Ενώ μ {
      Τύπωσε μ.Αξία$;
}
Τύπωσε  "",,       \\ σπάει το ; και βάζει άλλη γραμμή
μ1=Περιοχή(20, 1, 2, 20)
Ενώ μ1 {
      Τύπωσε μ1.Αξ,
}
Τύπωσε
Τύπωσε Μ1.Έχει(500), Μ1.Έχει(15)
Ενώ μ1 {
      Τύπωσε μ1.Αξ,
}
Τύπωσε
Στη μ1=Περιοχή(30, 20, 50, 60, 90, 100)
Ενώ μ1 {
      Τύπωσε μ1.Αξ,
}
Τύπωσε
Στη μ1=Περιοχή(30, 20, Λάμδα (α)->α-2, 10,1)
Ενώ μ1 {
      Τύπωσε μ1.Αξ,
      μ1.Πήδα 3
}
Τύπωσε
Ενώ μ1 {
      Τύπωσε μ1.Αξ,
}
Για μ1 {
      .Μηδένισε
      .Πήδα 2
}
Ενώ μ1 {
      Τύπωσε μ1.Αξ,
}
Τύπωσε
Κατάσταση κ=10,40,50,70,1000
Σετ1=Περιοχή( 0, Μήκος(κ)-1, Μήκος(κ)-2, 0)
Σετ2=Περιοχή(1, Μήκος(κ)-2, Μήκος(κ)-1, 1)
Ενώ Σετ1 {
      Τύπωσε κ(Σετ1.αξ!),
      Σετ1.Πήδα 1
}
Τύπωσε
\\  10 50 1000 50 10
Ενώ Σετ2 {
      Τύπωσε κ(Σετ2.αξ!),
      Σετ2.Πήδα 1 ' Πήδα
}
Τύπωσε
\\  40, 70, 70, 40

Μετρητής=Περιοχή("100", "110", Λάμδα$ (α$)->Γραφή$(Τιμή(α$)+2,"000"), "108", "100", Λάμδα$ (α$)->Γραφή$(Τιμή(α$)-2,"000"))
Τύπωσε Μετρητής.Έχει("108"), Μετρητής.Έχει("109", Αληθές), Μετρητής.Έχει("104", Αληθές) \\ Αληθές Ψευδές Αληθές
Ενώ Μετρητής {
      Τύπωσε Μετρητής.Αξία$,
}
Τύπωσε




\\ Multi Range object version 1
\\ Need revision 38, version 9.0 and up
\\ We can make a range with subranges.
\\ Constructor: Range( value_From, value_to [, lambda function] [,value_From, value_to [, lambda function]])
\\      For srtings we have to supply lambda function, for numbers we can skip lambda function and place number or close parenthesis.
\\      value types numbers or strings, lambda function must be the same type also
\\      lambda function produce the next item
\\  Properties
\\      Value$  : used if we have a range of strings
\\      Val : used if we have a range of numbers
\\ Function
\\      Has(string or number [, True]) : return True if in any sub range, object has value without check lambda function,
\\      if optional second argument is True then scan all values using lambda function. This is slow but accurate
\\ Method
\\      Reset
\\            reset val or value$ to match the first item of first subrange
\\      Skip number
\\            skip a number of items, and maybe change to new item, can change subrange too, or set state to false
\\            skip can used before using Value, see below, or in a while loop using Value.
\\ Value
\\      We use value of Range, value of object, as a state flag, and this call lambda for next item
\\            state False means object go out of range. Use Reset to begin again. Use Skip to skip some items.
\\            We use While RangeObj { } to walk through all items in all subranges

Class Range {
Private:
       \\ this is an array for store subranges, in each 4 items
       \\ we use Stock command to store a list of variables, and to read a list of variables too.
       \\ Arrays using Stock can used with any type. Here we store numbers, strings, lambda functions.
       \\ Stock statement has final form from revision 37, version 9.0
      Dim link1()
      from$, to$, begin=True
      fromnum, tonum, subrange=0
      option=0
      Function Inspect (k$) {
             copy1=This
             copy1.reset
             While copy1 {
                  if k$=copy1.value$ then =True : exit
            }
      }
      Function InspectNum (k) {
             copy1=This
             copy1.reset
             While copy1 {
                  if k=copy1.val then =True : exit
            }
      }
      NextStep$=Lambda$ ->{Error 500}
      NextStepNum=Lambda ->{Error 500}
Public:
      Function Has {
                        if .option = 1 Then {
                        Read what$
                        Read ? UseFunc ' optional
                        If UseFunc then =.Inspect(what$) : exit
                        subrange=1 ' this is local
                        Repeat {
                              Stock .Link1(subrange) out from$, to$ ' these are locals too
                              If what$<>"" Then {
                                 if from$<=to$ Then {
                                           v=what$>=from$ and what$<=to$
                                    } else {
                                          v=what$>=to$ and what$<=from$
                                    }
                              }
                              subrange+=4
                        } until subrange>=len(.Link1()) or v
                        =v
                  } Else {
                        Read what
                        Read ? UseFunc ' optional
                        If UseFunc then =.InspectNum(what) : exit
                        subrange=1
                        Repeat {
                              Stock .Link1(subrange) out fromnum, tonum ' these are locals too                        
                              If fromnum<=tonum then {
                                    v=what>=fromnum and what<=tonum
                              } else {
                                    v=what>=tonum and what<=fromnum
                              }
                        subrange+=4
                        } until subrange>=len(.Link1()) or v
                        =v
                  }
      }
      Property Value$ { Value }
      Property Val { Value }
      Module Skip (k){
            k=abs(k)
            if k Else Exit
            Link This to M1
            While k {
                  k--
                  If M1 Else Exit
            }
      }
      Module Reset {
            .subrange<=0
            If Len(.Link1())>1 then {
                  Stock .Link1(.subrange) out .option
                  Select Case .option
                  Case 1
                        {
                              Stock .Link1(.subrange+1) out .from$, .to$, .NextStep$
                              .[Value]$<=.from$
                        }
                  Else
                        {
                              Stock .Link1(.subrange+1) out .fromnum, .tonum, .NextStepNum
                              .[Val]<=.fromnum
                        }
                  End Select
            }       
            .begin<=True
      }
      Value {
            v=False
            If .option=1 Then {
                             Try {
                                    m$=.NextStep$(.[Value]$)
                                    if Error Then Exit
                                    if .begin Then .begin~ : =True : Exit
                                    If abs(compare(m$, .to$)+compare(.from$, .to$))=0 Then v~ : Exit
                                    .[Value]$<=m$
                                    =True
                                   }
            } Else {
                       Try {
                              m=.NextStepNum(.[Val])
                              if Error Then Exit
                              if .begin Then .begin~ : =True : Exit
                              If abs(compare(m, .tonum)+compare(.fromnum, .tonum))=0 Then v~ : Exit
                              .[Val]<=m
                              =True
                        }                  
            }
            if v Else Exit
            .subrange+=4
            if .subrange>=len(.Link1()) then exit
            Stock .Link1(.subrange) out .option
            Select Case .option
            Case 1
                  {
                        Stock .Link1(.subrange+1) out .from$, .to$, .NextStep$
                        .[value]$<=.from$
                  }
            Else
                  {
                        Stock .Link1(.subrange+1) out .fromnum, .tonum, .NextStepNum
                         .[val]<=.fromnum
                  }
            End Select
            .begin<=false
            =true
      }
      class:
      Module Range {
            While Not Empty {
                   If match("SS") and not .option=2 Then {
                        .option<=1
                        Read .from$, .to$
                        If match("F") Then Read .NextStep$
                        .[Value]$<=.from$
                  } Else.if match("NN") and not .option=1 Then {
                       Read .fromnum, .tonum
                       .option<=2
                       If Not match("F") Then {
                             .NextStepNum<=if(.fromnum<=.tonum -> (lambda (x) ->x+1), (lambda (x) ->x-1))
                        } Else{
                                    Read .NextStepNum
                        }
                        .[Val]<=.fromnum
                 } Else Error "not supported stack types:"+Envelope$()
                  if .option<>0 then {
                        where=len(.Link1())
                        Dim Base 0, .Link1(where+4)
                        Select Case .option
                        Case 1
                              Stock .Link1(where) in .option, .from$, .to$, .NextStep$
                        Else
                              Stock .Link1(where) in .option, .fromnum, .tonum, .NextStepNum
                        End Select
                  }
            }
            If Len(.Link1())>1 then {
                  .option<=.Link1(0)
                  Select Case .option
                  Case 1
                        {
                              Stock .Link1(1) out .from$, .to$, .NextStep$
                              .[Value]$<=.from$
                        }
                  Else
                        {
                              Stock .Link1(1) out .fromnum, .tonum, .NextStepNum
                              .[Val]<=.fromnum
                        }
                  End Select
            }
      }
}
NextChar$=lambda$ (x$) -> Chrcode$(Chrcode(x$)+1)
PrevChar$=lambda$ (x$) -> Chrcode$(Chrcode(x$)-1)
M=Range("A", "Z", NextChar$, "z", "a", PrevChar$)
Print M.Value$
Print M.Has("K"), M.Has("a", true)
While M {
      Print M.Value$;
}
Print  "",,       \\ break ; set next line using columns
M.Reset
While M {
      Print M.Value$;
}
Print  "",,       \\ break ; set next line using columns
M1=Range(20, 1, 2, 20)
While M1 {
      Print M1.val,
}
Print
Print M1.Has(500), M1.Has(15)
While M1 {
      Print M1.val,
}
Print
\\ using Let because M1 is a property now, and only LET can change it.
\\ Let a=b is same as Push b : Read a
let M1=Range(30, 20, 50, 60, 90, 100)
While M1 {
      Print M1.val,
}
Print
let M1=Range(30, 20, lambda (a)->a-2, 10,1)
While M1 {
      Print M1.val,
      M1.Skip 3
}
Print
\\ M1 is false now
While M1 {
      Print M1.val,
}
For M1 {
      .Reset
      .Skip 2 ' start from 3rd     
}
While M1 {
      Print M1.val,
}
Print
Inventory K=10,40,50,70,1000
Set1=Range( 0, Len(K)-1, Len(K)-2, 0)
Set2=Range(1, Len(K)-2, Len(K)-1, 1)
While Set1 {
      Print K(Set1.val!),   \\ using ! we pass index - from 0- not key
      Set1.Skip 1
}
Print
\\ we get 10 50 1000 50 10
While Set2 {
      Print K(Set2.val!),
      Set2.Skip 1 ' skip
}
Print
\\ we get 40, 70, 70, 40
\\ a lambda can be put in parenthesis, but not a lambda$.
Counter=Range("100", "110", lambda$ (a$)->Str$(val(a$)+2,"000"), "108", "100", lambda$ (a$)->Str$(val(a$)-2,"000"))
\\ using optional second argument as True (default false) we walk through all range using lambda function
Print Counter.Has("108"), Counter.Has("109", True), Counter.Has("104", True) \\ True false True
While Counter {
      Print Counter.Value$,
}
Print