-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathEval.bas
1930 lines (1818 loc) · 69.3 KB
/
Eval.bas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
B4A=true
Group=Default Group
ModulesStructureVersion=1
Type=StaticCode
Version=7.3
@EndOfDesignText@
'Code module
'Subs in this code module will be accessible from all modules.
Sub Process_Globals
'These global variables will be declared once when the application starts.
'These variables can be accessed from all modules.
Dim EvalError As String, EvalMoreData As String, OverFlowLimit As Int=128,opchars As String ="+-^&*|/=\!~<>",Delimeter As String ="|", AngleMode As Int=1 ,CurrentLevel As Int, Internals As Boolean ,OptionExplicit As Boolean = True
Dim ch_numeric As Int, ch_operand As Int=1, ch_routine As Int=2,ch_delimit As Int=3,ch_leftbrk As Int=4, ch_rigtbrk As Int=5,ch_strings As Int=6,ch_boolean As Int=7,ch_any As Int=8, ch_array As Int=9, ch_custom As Int=10
Dim vbRadians As Int , vbDegrees As Int =1,vbGradients As Int=2 , TXT As Int=ch_strings,NUM As Int=ch_numeric, BOOL As Int=ch_boolean ,ANY As Int=ch_any, ARR As Int=ch_array, vbQuote As String = Chr(34) ,Empty As String ="", None As String=""
Type Variable(name As String, varType As Int, Values As List, Scope As Int, isConst As Boolean,MinParams As Int, Equation As String )
Type Parameter(name As String, varType As Int, Default As String, varTypeS As String )
Dim VarList As List, CurrentScope As Int ,VarsLoaded As Boolean ,DoVoice As Boolean, C As Int = 299792458 'meters/second
'for LCARS UI
Dim EnumType As Int , VarStack As List, HelpText As String, HelpTopic As String , CurrentVar As Variable, CurrentPar As Parameter, VarIndex As Int =-1,ParIndex As Int ,IsEditing As Boolean
VarStack.Initialize:CurrentVar.Initialize :CurrentPar.Initialize :VarList.Initialize
End Sub
'START LCARS UI SPECIFIC API
Sub EnumStrings(ID As Int) As List
'Log("ENUMMING ID: " & ID)
Dim templist As List
Select Case ID
Case -1: Return Array As String("RADIANS", "DEGREES", "GRADIANTS" )
Case -2: Return Array As String("CONSTANTS", "NUMBERS", "BOOLEANS", "STRINGS", "CUSTOM", "INT. SUBS", "EXT. SUBS")
Case -3: Return Array As String("number", "operand", "sub", "delimeter", "left bracket", "right bracket", "text", "boolean", "any", "array", "custom")
Case -4'available types to edit/credit, so -5 for new, -4 for edit
templist.Initialize
templist.AddAll(EnumStrings(-5))' Array As String("NUMBER", "TEXT", "BOOLEAN"))
If Not(IsEditing) Then templist.AddAll( Array As String("SUB", "CUSTOM")) 'create only
'templist.AddAll( EnumStrings(4) )
Return templist
Case -5: Return Array As String("NUMBER", "TEXT", "BOOLEAN")
Case -6: Return Array As String("YES", "NO")
Case -7: Return Array As String("TRUE", "FALSE")
Case -8: Return Array As String("SQUARE", "CIRCLE")
Case 0: Return EnumVariables(True, ch_routine,False,0,False,0)'CONSTANTS
Case 1: Return EnumVariables(False,ch_numeric,True, 0,False,0)'NUMBERS
Case 2: Return EnumVariables(False,ch_boolean,True, 0,False,0)'BOOLEANS
Case 3: Return EnumVariables(False,ch_strings,True, 0,False,0)'STRINGS
Case 4: Return EnumVariables(True, ch_custom, True, 0,False,0)'CUSTOM type definitions
Case 5: Return EnumVariables(True, ch_routine,True, 0,False,0)'INT. SUBS
Case 6: Return EnumVariables(False,ch_routine,True, 0,False,0)'EXT. SUBS
Case 7: Return EnumCustomVariables(CurrentVar.Equation, 0,False,0)'variables of a custom type
End Select
End Sub
Sub MapVariableType(VarType As Int) As Int
Select Case VarType
Case ch_numeric: Return 1
Case ch_boolean: Return 2
Case ch_strings: Return 3
Case ch_custom: Return 4
Case ch_routine: Return 6
Case Else: Return 7
End Select
End Sub
Sub EnumCustomVariables(VarType As String, Scope As Int, FallbacktoZero As Boolean, FallbackScope As Int) As List
Dim temp As Int, Var As Variable, Vlist As List
RegisterInternals
Vlist.Initialize
For temp = 0 To VarList.Size-1
Var = VarList.Get(temp)
If Var.VarType=ch_custom And Not(Var.isConst) Then
If Var.Equation.EqualsIgnoreCase(VarType) Then
Vlist.Add(Var.name)
End If
End If
Next
Return Vlist
End Sub
Sub EnumVariables(Constants As Boolean, VarType As Int, Inclusive As Boolean, Scope As Int, FallbacktoZero As Boolean, FallbackScope As Int)As List
Dim temp As Int, Var As Variable, Vlist As List,Matches As Boolean
RegisterInternals
Vlist.Initialize
For temp = 0 To VarList.Size-1
Var = VarList.Get(temp)
'Log("CHECKING: " & var.name)
If Var.Scope = Scope Or Var.Scope = FallbackScope Or (FallbacktoZero And Var.Scope=0) Then
'Log(var.name & " passed scope test")
If Constants = Var.isConst Then
'Log(var.name & " passed const test")
Matches=False
If VarType = -1 Or VarType = Var.VarType Then
'Log(var.name & " passed inclusive test")
Matches=Inclusive
Else
'Log(var.name & " passed exclusive test")
Matches=Not(Inclusive)
End If
If Matches Then
Vlist.Add( Var.name.ToUpperCase )
End If
End If
End If
Next
Return Vlist
End Sub
Sub PushSubOntoStack(SubName As String)As Boolean
Dim temp As Int, Var As Variable, tempVar As Variable
temp = FindVariable(SubName, 0,False,0)
If temp>-1 Then
Var = VarList.Get(temp)
If Var.varType = ch_routine Then
If VarStack.Size=0 Then LCAR.BackupRestoreKB(True,"")
tempVar=CopyVar(Var)
tempVar.Equation = "0"
VarStack.Add (tempVar)
Return True
End If
End If
End Sub
Sub CheckForQuotes(Text As String) As String
Dim tempstr As String
Text=Text.Trim
tempstr=API.Left(Text,1)
Select Case tempstr
Case "'", vbQuote
If API.Right(Text,1) <> tempstr Then Return Text & tempstr
End Select
Return Text
End Sub
Sub SetStackItem(StackIndex As Int, ItemIndex As Int, Value As String)As Boolean
Dim Var As Variable, Par As Parameter ,tempstr As String
Value=CheckForQuotes(Value)
If StackIndex<0 Then StackIndex = VarStack.Size-1
If StackIndex< VarStack.Size And StackIndex>-1 Then
Var = VarStack.Get(StackIndex)
If ItemIndex=-1 Then
Var.Equation = Value
Else If ItemIndex < Var.Values.Size Then
If ItemIndex<0 Then ItemIndex = Var.Equation
Par = Var.Values.Get(ItemIndex)
Par.Default = Value
Else If ItemIndex = -999 Then
Var.name = Value
End If
Return True
End If
End Sub
Sub PullStackItem(doProcess As Boolean) As String
Dim tempstr As String
If doProcess Then
tempstr= MakeStackItem(-1)
VarStack.RemoveAt( VarStack.Size-1)
SetStackItem(-1,-2, tempstr)
Else
VarStack.RemoveAt( VarStack.Size-1)
tempstr = VarStack.Size
End If
If VarStack.Size=0 Then LCAR.BackupRestoreKB(False, tempstr)'last item in stack
Return tempstr
End Sub
Sub MakeStackItem(StackIndex As Int) As String
Dim Var As Variable, Par As Parameter , temp As Int, tempstr As StringBuilder
tempstr.Initialize
If StackIndex< VarStack.Size Then
If StackIndex<0 Then StackIndex = VarStack.Size-1
Var = VarStack.Get(StackIndex)
tempstr.Append( Var.name & "(")
'tempstr.Append( Var.name )
For temp = 0 To Var.Values.Size-1
Par = Var.Values.Get(temp)
'tempstr.Append( API.IIF(temp=0, "(", ", ") & Par.Default )
tempstr.Append( API.IIF(temp=0, "", ", ") & Par.Default )
Next
'If Var.Values.Size>0 Then tempstr.Append(")")
End If
'Return tempstr.ToString
Return tempstr.ToString & ")"
End Sub
Sub ShowStackItem(StackIndex As Int, ListID As Int, BG As Canvas)
Dim Var As Variable, Par As Parameter , temp As Int, temp2 As Int
If StackIndex< VarStack.Size And VarStack.Size>0 Then
If StackIndex<0 Then StackIndex = VarStack.Size-1
Var = VarStack.Get(StackIndex)
LCAR.LCAR_clearlist(ListID,0)
LCAR.LCAR_AddListItem(ListID, "INSERT SUB", LCAR.LCAR_Random, -1, "", False, Var.name.ToUpperCase, 0, False,-1)
LCAR.LCAR_AddListItem(ListID, "REMOVE SUB", LCAR.LCAR_Random, -1, "", False, Var.name.ToUpperCase, 0, False,-1)
DoHelp(BG,Var,-1)
For temp = 0 To Var.Values.Size-1
Par = Var.Values.Get(temp)
Select Case Par.varType'=1:=2:=3: =4:=5:=6:=7:ch_array=9:=10:
'case ch_operand, ch_delimit, ch_leftbrk, ch_rigtbrk, ch_array = system, should not be encountered
Case ch_numeric, ch_custom: temp2=0
Case ch_routine, ch_strings: temp2=1
Case ch_boolean: temp2=2
End Select
LCAR.LCAR_AddListItem(ListID, Par.name.ToUpperCase & " AS " & GetVarType( Par.varType ).ToUpperCase , LCAR.LCAR_Random, -1, temp2, False, Par.Default.ToUpperCase , 0,False,-1)
Next
End If
End Sub
Sub DoHelp(BG As Canvas, Var As Variable, ParameterID As Int)
Dim Par As Parameter
If ParameterID=-1 Then
Help(Var.name)
Else If ParameterID< Var.Values.Size Then
Par = Var.Values.Get(ParameterID)
Help(Var.name & "(" & Par.name & ")")
End If
If EvalError.Length =0 And HelpText.Length>0 Then LCAR.ToastMessage(BG, HelpText.ToUpperCase, 5)
End Sub
Sub Answer(Index As Int) As String
Dim ListCount As Int'list 25
ListCount= LCAR.GetListItemCount(25)
If Index=-999 Then
Return ListCount-1
Else If ListCount>0 Then
Index=Index-1
If Index<0 Or Index>=ListCount Then Index = ListCount-1
Return LCAR.LCAR_GetListItem(25,Index).side
End If
Return ""
End Sub
Sub ListValues(ListID As Int, Var As Variable)
Dim temp As Int,temp2 As Int, Par As Parameter, tempstr As String
If Not(Var.IsInitialized) Then Var.Initialize
If Not(Var.Values.IsInitialized) Then
Var.Values.Initialize
Else
temp2=-1
For temp = 0 To Var.Values.Size-1
If Var.varType = ch_routine Then
Par = Var.Values.Get(temp)
tempstr = Par.name & " AS " & GetVarType(Par.varType)
If Par.Default.Length>0 Then tempstr = tempstr & " = " & Par.Default
Else
tempstr = Var.Values.Get(temp)
temp2=temp
End If
LCAR.LCAR_AddListItem(ListID, tempstr.ToUpperCase , LCAR.LCAR_Random, temp2, "", False, "", 0, False,-1)
Next
End If
End Sub
Sub DeleteValue(Var As Variable, Index As Int)As Boolean
If Var.Values.Size>1 And Index < Var.Values.Size Then
Var.Values.RemoveAt(Index)
Return True
End If
End Sub
Sub AppendText(tempstr As StringBuilder, Text As String)
tempstr.Append(API.IIF(tempstr.Length=0, "", ", ") & Text)
End Sub
Sub AppendValue(Var As Variable)
If Var.varType=ch_routine Then
Var.Values.Add( MkP("NEWPAR" & (Var.Values.Size+1), ch_strings, ""))
Else
Var.Values.Add("")
End If
End Sub
'END LCARS UI SPECIFIC API
Sub SetTimeVariables As String
SetVariable("now", 0, False, 0, DateTime.Now, False)
SetVariable("today", 0, False, 0, API.OnlyDate(DateTime.Now), False)
SetVariable("yesterday", 0, False, 0, API.OnlyDate(DateTime.Now - DateTime.TicksPerDay), False)
SetVariable("tomorrow", 0, False, 0, API.OnlyDate(DateTime.Now + DateTime.TicksPerDay), False)
SetVariable("seconds", 0, False, 0, DateTime.TicksPerSecond, False)
SetVariable("minutes", 0, False, 0, DateTime.TicksPerMinute, False)
SetVariable("hours", 0, False, 0, DateTime.TicksPerHour, False)
SetVariable("days", 0, False, 0, DateTime.TicksPerDay, False)
Return "Now (variable) = " & GetVariable("now", 0, False, 0) & " (actual) = " & DateTime.Now'test
End Sub
Sub Val(Equation As String) As String
Dim Scope As Int, Left As Int, tempstr As String
EvalError=Empty
CurrentLevel=0
RegisterInternals
'SetTimeVariables
HelpText=""
Left = API.Instr(Equation, "@",0)
If Left>-1 Then
tempstr = API.Left(Equation, Left)
If IsNumber(tempstr) Then
Scope=tempstr
Equation = API.Right(Equation, Equation.Length-Left-1)
End If
End If
Try
tempstr = Evaluate(Equation, Scope,True,0)
If EvalError.Length=0 Then SetVariable("answer", Scope, True, 0, tempstr,False)
Catch
EvalError = LastException.Message
Log("ERROR: " & EvalError)
End Try
OptionExplicit = True
Return tempstr
End Sub
Sub Evaluate(Equation As String, Scope As Int, FallbackToZero As Boolean , FallbackScope As Int) As String
Dim Equ As List, tempstr2() As String , temp As Int ,tempstr As String , tempstr3 As String, PAR As Parameter , Var As Variable , isConst As Boolean
If CurrentLevel<OverFlowLimit Then
CurrentLevel=CurrentLevel+1
EvalError=Empty
'tempstr2 = Regex.Split(" ", Equation)
'tempstr= tempstr2(0)
Equ = splitbychartype(Equation, True, True, True)
If Equ.Size>0 Then
tempstr=Equ.Get(0)
Select Case tempstr.ToLowerCase
Case "const", "dim", "sub", "funct", "ifunct", "function", "internal", "var"
Equ.RemoveAt(0)
tempstr3=tempstr
tempstr=List2String(Equ, " ")
PAR =MkPFromString(tempstr) ' MkFromString(List2String(Equ, " ")).Get(0)
Select Case tempstr3.ToLowerCase
Case "const"
isConst=True
Case "sub", "ifunct", "internal"
isConst=True
PAR.varType = ch_routine
Case "funct", "function"
PAR.varType = ch_routine
End Select
If PAR.varType = ch_routine Then
If isinbrackets2( Equation ) Then
PAR.Default ="(" & GetFromBrackets(Equation,False) & ")"
PAR.name = JustTheName(PAR.name)
End If
Var = RegisterVariable(PAR.name, 0, ch_routine, isConst, MkFromString(PAR.Default))
If Not(isConst) Then
tempstr = API.GetBetween(Equation, "=", "(")
PAR.varTypeS = tempstr.Trim
End If
Else If isinbrackets( PAR.Default ) Then
Var = RegisterVariable(PAR.name, Scope, PAR.varType, isConst , splitparameters(GetFromBrackets(PAR.Default,False), True) )
Else
Var = RegisterVariable(PAR.name, Scope, PAR.varType, isConst , Array As String(PAR.Default))
End If
Var.Equation = PAR.varTypeS
Return EvalError.Length=0
Case "type"
Equ.RemoveAt(0)
tempstr=List2String(Equ, " ")
RegisterType(JustTheName(tempstr) , MkFromString(GetFromBrackets(tempstr, False)))
Return EvalError.Length=0
Case "set"
Equ.RemoveAt(0)'remove the word set
tempstr = Equ.Get(0)'List2String(Equ, " ")
'tempstr = JustTheName(tempstr)
Equ.RemoveAt(0)'remove the variable name
If Equ.Get(0) = "=" Then Equ.RemoveAt(0)'remove the = sign
tempstr3=List2String(Equ, " ")
tempstr3=Evaluate(tempstr3, Scope, FallbackToZero, FallbackScope)
If EvalError.Length> 0 Then
Return EvalError
else If VarExists(tempstr, Scope, FallbackToZero, FallbackScope) Then
SetVariable(tempstr, Scope, FallbackToZero, FallbackScope, tempstr3, False)
Else
RegisterVariable(tempstr, Scope, ch_strings, False, Array As String(tempstr3))
End If
'Log("SET '" & tempstr & "' TO: '" & tempstr3 & "' RESULTS: '" & GetVariable(tempstr, 0,False, 0) & "'")
Case Else
'preprocessor
ProcessSingles(Equ)
Process(Equ, Array As String("+=", "=+"), Scope, FallbackToZero, FallbackScope)
Process(Equ, Array As String("-="), Scope, FallbackToZero, FallbackScope)
Process(Equ, Array As String("=="), Scope, FallbackToZero, FallbackScope)
'evaluate sub-equations
For temp = 0 To Equ.Size-1
tempstr = Equ.Get(temp)
If temp>0 And tempstr = "++" Then
SetVariable(Equ.Get(temp-1),Scope,FallbackToZero,FallbackScope, "1", True)
Else If isinbrackets(tempstr) Then
'tempstr = EvaluateParameters(GetFromBrackets(tempstr,False),Scope, FallbackToZero, FallbackScope)
tempstr = Evaluate(GetFromBrackets(tempstr,False),Scope, FallbackToZero, FallbackScope)
Equ.Set(temp,tempstr)
Else
If CharType(tempstr) = ch_routine Then
tempstr= EvaluateParameters(tempstr,Scope, FallbackToZero, FallbackScope)
tempstr = GetVariable(tempstr, Scope, FallbackToZero, FallbackScope)
Equ.Set(temp,tempstr)
End If
End If
If EvalError.Length>0 Then Return Empty
Next
Process(Equ, Array As String("^"), 0, False, 0)
Process(Equ, Array As String("*", "/", "\", "~"), 0, False, 0)
Process(Equ, Array As String("+", "-"), 0, False, 0)
Process(Equ, Array As String("&", "|", "=", "!", "<", ">", "<>", "><", "!=", "=!", "~!","!~", ">=", "<=", "=<", "=>"), 0, False, 0)
CurrentLevel=CurrentLevel-1
Return Equ.Get(Equ.Size-1)
' If Equ.Size=1 Then
' Return Equ.Get(0)
' Else
' EvalError = "Formula did not evaluate to a single value"
' EvalMoreData = Equation & "=" & ListToString(Equ,True)
' End If
End Select
End If
Else
EvalError = API.getstring("calc_stackoverflow")
CurrentLevel=0
End If
Return Empty
End Sub
Sub ProcessSingles(Equation As List)
Dim Right As String, Op As String, temp As Int ,Value As String
If EvalError.Length =0 Then
For temp = 0 To Equation.Size - 2
If temp < Equation.Size And EvalError.Length=0 Then
Op = Equation.Get(temp)
Right = Equation.Get(temp+1)
If IsNumber(Right) Then
Select Case Op
Case "√": Value = Sqrt(Right)
Case Else: Value=""
End Select
If Value.Length>0 Then
Equation.Set(temp, Value)
Equation.RemoveAt(temp+1)
End If
End If
End If
Next
ProcessAdjacentVariables(Equation)
End If
End Sub
Sub ProcessAdjacentVariables(Equation As List)'separate variables with a *
Dim Left As String, Right As String, temp As Int, temp2 As Int
If EvalError.Length =0 Then
For temp = Equation.Size - 2 To 0 Step -1
Left = Equation.Get(temp)
temp2 = CharType(Left)
If temp2 = ch_routine Or temp2 = ch_numeric Then
Right = Equation.Get(temp+1)
temp2 = CharType(Right)
If temp2 = ch_routine Or temp2 = ch_numeric Then
Equation.InsertAt(temp+1, "*")
End If
End If
Next
End If
End Sub
Sub Process(Equation As List, Ops As List, Scope As Int, FallbackToZero As Boolean , FallbackScope As Int)
Dim Left As String, Right As String, Op As String, temp As Int ,Value As String
If EvalError.Length =0 Then
For temp = 1 To Equation.Size - 2
If temp < Equation.Size And EvalError.Length=0 Then
Op = Equation.Get(temp)
If DoOp(Ops,Op) Then
Left = Equation.Get(temp-1)
Right = Equation.Get(temp+1)
Value = ProcessOp(Left, Op, Right, Scope, FallbackToZero, FallbackScope)
Equation.Set(temp-1, Value)
Equation.RemoveAt(temp+1)
Equation.RemoveAt(temp)
temp=temp-1
End If
Else
Exit
End If
Next
End If
'Log("Processing: " & ListToString(Ops,True) & " becomes " & ListToString(Equation,True))
End Sub
Sub DoOp(Ops As List, Op As String) As Boolean
Return Ops.IndexOf(Op)>-1
End Sub
Sub ProcessOp(Left As String, Op As String, Right As String, Scope As Int, FallbackToZero As Boolean , FallbackScope As Int) As String
Dim DivisionByZero As Boolean
If isabool(Left,True) Then Left = toBool(Left)
If isabool(Right,True) Then Right = toBool(Right)
If IsNumber(Left) And IsNumber(Right) Then
Select Case Op
Case "^": Return Power(Left,Right)
Case "*": Return Left * Right
Case "/": If Right=0 Then DivisionByZero=True Else Return Left / Right
Case "~": If Right=0 Then DivisionByZero=True Else Return Floor(Left/Right)
Case "+": Return Left + Right
Case "-": Return Left - Right
Case "=": Return Left = Right
Case ">": Return Left > Right
Case "<": Return Left < Right
Case "<=", "=<": Return Left <= Right
Case ">=", "=>": Return Left >= Right
Case "!=", "<>", "><": Return Left <> Right
Case "&": Return Bit.And(Left,Right)' Left AND Right
Case "|": Return Bit.Or(Left,Right)' Left OR Right
Case ">>": Return Bit.ShiftRight(Left,Right)
Case "<<": Return Bit.ShiftLeft(Left,Right)
End Select
If DivisionByZero Then
EvalError = API.GetString("calc_dividebyzero")
EvalMoreData = Left & " / " & Right
Return Empty
End If
Else if Op.Length > 0 Then
Left = RemoveFromQuotes(Left)
Right = RemoveFromQuotes(Right)
Select Case Op
'preprocessor
Case "==": SetVariable(Left,Scope, FallbackToZero,FallbackScope, Right, False): Return EvalError.Length=0
Case "+=", "=+": SetVariable(Left,Scope, FallbackToZero,FallbackScope, Right, True): Return EvalError.Length=0
Case "-=": SetVariable(Left,Scope, FallbackToZero,FallbackScope, Right*-1, True): Return EvalError.Length=0
'is string data
Case "&", "+": Return PutInQuotes(RemoveFromQuotes(Left) & RemoveFromQuotes(Right))
Case "=": Return Left = Right
Case "~": Return Left.EqualsIgnoreCase(Right)
Case ">": Return Left.CompareTo(Right) > 0
Case "<": Return Left.CompareTo(Right) < 0
Case "<=", "=<": Return Left.CompareTo(Right) <= 0
Case ">=", "=>": Return Left.CompareTo(Right) >= 0
Case "!=", "<>", "><": Return Not(Left=Right)
Case "~!", "!~": Return Not(Left.EqualsIgnoreCase(Right))
End Select
End If
End Sub
Sub EvaluateParameters(Text As String, Scope As Int, FallbackToZero As Boolean , FallbackScope As Int) As String
Dim Values As String, ValueList As List ,temp As Int ,tempstr As StringBuilder ,tempstr2 As String
If API.Instr(Text,"(",0)>-1 Then
Values=GetFromBrackets(Text,False)
tempstr.Initialize
tempstr.Append (API.Left(Text, API.Instr(Text, "(",0)+1).Trim )
ValueList= splitparameters(Values, False)
For temp = 0 To ValueList.Size-1
tempstr2=Evaluate( ValueList.Get(temp), Scope, FallbackToZero,FallbackScope)
tempstr.Append( API.IIF(temp=0,Empty, ", ") & tempstr2)
Next
Return tempstr.ToString & ")"
Else
Return Text
End If
End Sub
'Variable creation
Sub SaveVar(Var As Variable) As String
Dim temp As Int,tempstr As StringBuilder,tempstr2 As String,tempstr3 As String, Value As String
tempstr.Initialize
If Var.IsInitialized Then
If Var.Scope <> 0 Then tempstr.Append (Var.Scope & "@")
If Var.varType = ch_routine Then'function, internal or user-defined
tempstr.Append (API.IIF(Var.isConst, "sub", "funct"))
Else If Var.varType = ch_custom And Var.Equation.Length=0 Then'custom type definition
tempstr.Append ("type")
Else'regular variable
tempstr.Append (API.IIF(Var.isConst, "const", "dim"))
End If
tempstr.Append( " " & Var.Name & " as " )
If Var.varType = ch_custom And Var.Equation.Length>0 Then
tempstr.Append(Var.Equation)
Else
tempstr.Append( GetVarType(Var.varType))
End If
If Var.varType = ch_routine And Not(Var.isConst) Then'user-defined sub
tempstr2 = SaveParameters(Var.Values)
tempstr3 = Var.Equation
Else If Var.Values.Size =1 Then
tempstr2= Var.Values.Get(0)
Else If Var.Values.Size>1 Then
tempstr2="(" & JoinList( Var.Values) & ")" 'Evaluate(Name,Scope,FallbackToZero,FallbackScope)
End If
If tempstr3.Length>0 Then tempstr.Append(" = " & tempstr3)
If tempstr2.Length>0 Then tempstr.Append(API.IIF(tempstr3.Length=0, " = ", " ") & tempstr2)
End If
Return tempstr.ToString
End Sub
Sub SaveParameters(pList As List) As String
Dim temp As Int,tempstr As StringBuilder,tempstr2 As String
tempstr.Initialize
For temp = 0 To pList.Size-1
tempstr2= MkPintoString( pList.Get(temp) )
tempstr.Append( API.IIF(temp=0, "(", ", ") & tempstr2)
Next
If pList.Size>0 Then tempstr.Append(")")
Return tempstr.ToString
End Sub
Sub SetVariable(Name As String, Scope As Int,FallbackToZero As Boolean, FallbackScope As Int, Contents As String, Relative As Boolean)
Dim Var As Variable , PAR As List, tempstr As String, temp As Int
Var = GetVariableData(Name,Scope, FallbackToZero,FallbackScope)
If Var.IsInitialized Then
If Var.isConst Then
EvalError = API.GetStringVars("calc_constant", Array As String(Name))
EvalMoreData = Name
Else
tempstr = GetFromBrackets(Name, False)
PAR= splitparameters(tempstr, True)
If Not(PAR.IsInitialized) Then PAR.Initialize
tempstr = GetFromPeriod(Name)
If tempstr.Length>0 And Var.varType= ch_custom Then
temp = GetMethodIndex(Var.Equation, tempstr)
If temp>-1 Then PAR.Add(temp)
End If
GetValue(PAR, Var.Values, Contents, Relative)
End If
Else 'If Not(OptionExplicit) Then
RegisterVariable(Name, Scope, TXT, False, splitparameters(Contents, True))
End If
End Sub
Sub MakeParFromArray(Values As List) As Parameter
Dim temp As Int, par As Parameter ,Key As String, Value As String
par.Initialize
For temp = 0 To Values.Size-1
Value = Values.Get(temp)
Key = API.GetSide(Value, "=",True,False)
Value = API.GetSide(Value, "=",False,False)
Select Case Key.ToLowerCase
Case "default": par.Default = Value
Case "vartypes": par.varTypeS= Value
Case "name": par.name = Value
Case "vartype": par.varType = Value
End Select
Next
Return par
End Sub
Sub GetMethodIndex(VarType As String, Method As String ) As Int
Dim Var As Variable, PAR As Parameter , temp As Int
Var = GetVariableData(VarType, 0, False,0)
If Var.IsInitialized Then
For temp = 0 To Var.Values.Size-1
PAR = Var.Values.Get(temp)
If PAR.name.EqualsIgnoreCase(Method) Then Return temp
Next
Else
EvalError = api.GetString("calc_customnotfound")
EvalMoreData=VarType
End If
Return -1
End Sub
Sub MkP(Name As String, varType As Int, Default As String) As Parameter
Dim temp As Parameter
temp.Initialize
temp.Name = Name.Trim
temp.varType=varType
temp.Default=Default.Trim
Return temp
End Sub
Sub MkFromString(Parameters As String) As List
Dim Plist As List, temp As Int , RetList As List , PAR As Parameter
If isinbrackets2(Parameters) Then Parameters = GetFromBrackets(Parameters,False)
Plist = splitparameters(Parameters, False)
RetList.Initialize
For temp = 0 To Plist.Size-1
PAR=MkPFromString(Plist.Get(temp))
If PAR.IsInitialized Then RetList.Add( PAR)
Next
Return RetList
End Sub
Sub MkPintoString(Par As Parameter) As String
Dim tempstr As String
tempstr = Par.name & " as " & API.IIF(Par.varType=ch_custom, Par.varTypeS , GetVarType(Par.varType))
If Par.Default.Length>0 Then tempstr = tempstr & " = " & Par.Default
Return tempstr
End Sub
Sub MkPFromString(Var As String) As Parameter
Dim Plist As List, temp As Int, PAR As Parameter ,tempstr As String ,temp2 As Int
Plist = splitbychartype(Var, False ,True,False)
If Plist.Size >0 Then
PAR.Initialize
PAR.name = Plist.Get(0)
For temp = 1 To Plist.Size-2
tempstr = Plist.Get(temp)
Select Case tempstr.ToLowerCase
Case "as"
PAR.varType = GetVarType(Plist.Get(temp+1))
If PAR.varType = ch_custom Then
temp2 = FindVariable(Plist.Get(temp+1), 0,False,0)
If temp2>-1 Then PAR.varTypeS = GetVariableData(Plist.Get(temp+1), 0,False,0).name
End If
Case "="
PAR.Default = Plist.Get(temp+1)
End Select
Next
End If
Return PAR
End Sub
'Name, vartype
Sub MkMethods(Parameters As List) As List
Dim temp As Int, Plist As List
Plist.Initialize
For temp =0 To Parameters.Size-1 Step 2
Plist.Add( MkP(Parameters.Get(temp), Parameters.Get(temp+1),""))
If Parameters.Get(temp+1) = ch_array Then Exit
Next
Return Plist
End Sub
'Name, vartype, [default]
Sub MkParameters(Parameters As List) As List
Dim temp As Int, Plist As List
Plist.Initialize
For temp =0 To Parameters.Size-1 Step 3
Plist.Add( MkP(Parameters.Get(temp), Parameters.Get(temp+1),Parameters.Get(temp+2) ))
If Parameters.Get(temp+1) = ch_array Then Exit
Next
Return Plist
End Sub
Sub ReplaceParameters(Equation As List, Parameters As List, MinRequired As Int, Scope As Int, Register As Boolean )As Boolean
Dim temp As Int , tempstr As String ,PAR As Parameter, Value As String ,Value2 As String ,MaxParameters As Int
'Equation is the split-up parameter portion of the equation, ie: functname(this, this2, this3)
'Parameters is the parameter list from the function data
'Use VerifyParameter to check
'adding missing values using default values
MaxParameters = Parameters.Size
If MaxParameters>0 Then
PAR= Parameters.Get(Parameters.Size-1)
If PAR.varType = ch_array Then MaxParameters = Equation.Size
End If
If Equation.Size < MinRequired Or Equation.Size > MaxParameters Then
If MinRequired<Parameters.Size Then
EvalError = API.GetStringVars("calc_range_params", Array As String(MinRequired, Parameters.Size, Equation.Size))
Else
EvalError = API.GetStringVars("calc_min_params", Array As String(MinRequired, Equation.Size))
End If
Return False
Else
For temp = 0 To Parameters.Size-1
PAR= Parameters.Get(temp)
If temp < Equation.Size Then
Value= Equation.Get(temp)
If Not( VerifyParameter(Value, PAR.varType, Scope, False, Scope)) Then
EvalError = API.GetStringVars("calc_typemismatch", Array As String(Value, GetVarType(PAR.varType)))
Return False
Else
If Register Then
Value = RemoveFromQuotes(Value)
Else If PAR.varType = ANY Or PAR.varType = TXT Then
Value2 = RemoveFromQuotes(Value)
If Value2.Length<Value.Length Then Equation.Set(temp, Value2)
End If
End If
Else
Value = PAR.Default
If Not(Register) Then Equation.Add(Value)
End If
If Register Then RegisterVariable(PAR.name, Scope, PAR.varType, False, Array As String(Value))
Next
End If
Return True
End Sub
Sub GetVarType(varType As String) As String
Dim temp As Int , Var As Variable
If IsNumber(varType) Then
Return API.IIFIndex(varType, EnumStrings(-3) )
Else
Select Case varType.ToLowerCase
Case "int", "integer", "long", "single", "double", "number", "num", "byte", "float", "val": Return NUM
Case "string", "text", "txt", "char": Return TXT
Case "yesno", "boolean", "bool", "bit": Return BOOL
Case "type", "custom": Return ch_custom
Case "sub", "funct", "ifunt", "function", "ifunction": Return ch_routine
Case Else
temp = FindVariable(varType, 0, False,0)
If temp=-1 Then
EvalError = API.GetString("calc_typenotfound")
EvalMoreData = varType
Else
Var= VarList.Get(temp)
If Var.varType = ch_custom And Var.Equation.Length = 0 Then
Return ch_custom
Else
EvalError = API.GetString("calc_notvalidtype")
EvalMoreData = Var.name
End If
End If
End Select
End If
Return Empty
End Sub
Sub isinbrackets2(Text As String) As Boolean
Dim temp As Int, temp2 As Int
temp = API.Instr(Text, "(",0)
temp2 = API.Instrrev(Text, ")")
Return temp2>temp And temp>-1
End Sub
Sub GetFromBrackets(Text As String, ProcessPeriod As Boolean ) As String
Dim temp As Int, temp2 As Int , FromBrackets As String
temp = API.Instr(Text, "(",0)
temp2 = API.Instrrev(Text, ")")
FromBrackets= API.Mid(Text, temp+1, temp2-temp-1)
If ProcessPeriod Then
Text=GetFromPeriod(Text)
If FromBrackets.Length =0 Then
Return Text
Else
Return FromBrackets & ", " & Text
End If
End If
Return FromBrackets
End Sub
Sub GetFromPeriod(Text As String) As String
Dim temp As Int
temp = API.Instrrev(Text,".")
If temp>-1 Then Return API.right(Text, Text.Length - temp - 1) Else Return Empty
End Sub
Sub JustTheName(Text As String) As String
Dim temp As Int
temp= API.Instr(Text,"(",0)
If temp>-1 Then Text = API.Left(Text, temp)
temp= API.Instr(Text,".",0)
If temp>-1 Then Text = API.Left(Text, temp)
'filter non-alphanumeric characters
Return Text
End Sub
Sub VarExists(Name As String, Scope As Int, FallbackToZero As Boolean , FallbackScope As Int) As Boolean
Return FindVariable(Name,Scope,FallbackToZero,FallbackScope)>-1
End Sub
Sub FindVariable(Name As String, Scope As Int, FallbackToZero As Boolean , FallbackScope As Int) As Int
Dim temp As Int, tempfunct As Variable , FallbackID As Int
FallbackID=-1
Name = JustTheName(Name)
For temp =0 To VarList.Size-1
tempfunct= VarList.Get(temp)
If tempfunct.Name.EqualsIgnoreCase(Name) Then' tempfunct.Scope = Scope Then Return temp
Select Case tempfunct.Scope
Case Scope: Return temp
Case 0: If FallbackID =-1 Then FallbackID=temp
Case FallbackScope: If FallbackScope <> 0 Then FallbackID=temp
End Select
End If
Next
Return FallbackID
End Sub
Sub DeleteVariable(Index As Int)
If Index>-1 And Index < VarList.Size Then VarList.RemoveAt(Index)
End Sub
Sub DeleteVariableByName(Name As String, Scope As Int, FallbackToZero As Boolean , FallbackScope As Int)As Boolean
Dim temp As Int
temp=FindVariable(Name,Scope,FallbackToZero,FallbackScope)
If temp>-1 Then
VarList.RemoveAt(temp)
Return True
End If
Return False
End Sub
'use MkMethods to make methods list
Sub RegisterType(name As String, Methods As List)As Boolean
Return RegisterVariable(name,0, ch_custom, True, Methods).IsInitialized
End Sub
'use MkParameters to make parameters list
Sub RegisterFunction(name As String, Parameters As List, Equation As String )As Boolean
Dim temp As Variable
temp = RegisterVariable(name,0, ch_routine, True, Parameters)
If temp.IsInitialized Then
temp.Equation = Equation
Return True
End If
End Sub
Sub CountMinParameters(Parameters As List) As Int
Dim temp As Int, Count As Int ,Par As Parameter
If Parameters.IsInitialized Then
For temp = 0 To Parameters.Size-1
Par= Parameters.Get(temp)
If Par.Default.Length =0 And Par.varType <> ch_array Then
Count=Count+1
Else
Exit
End If
Next
End If
Return Count
End Sub
Sub RegisterCustomVariable(name As String, Scope As Int, varType As String, isConst As Boolean, Values As List) As Variable
Dim tempfunct As Variable, temp As Int
tempfunct= GetVariableData(varType,0,False,0)
If tempfunct.IsInitialized Then
If Values.Size < tempfunct.Values.Size Then
For temp = Values.Size To tempfunct.Values.Size
Values.Add("")
Next
End If
tempfunct= RegisterVariable(name, Scope, ch_custom, isConst, Values)
If tempfunct.IsInitialized Then
tempfunct.Equation = varType
End If
End If
Return tempfunct
End Sub
Sub RegisterVariable(name As String, Scope As Int, varType As Int, isConst As Boolean, Values As List)As Variable
Dim tempfunct As Variable
If FindVariable(name, Scope, False,Scope)=-1 Then
tempfunct.Initialize
tempfunct.name=name
tempfunct.varType=varType
If varType = ch_routine Then
tempfunct.MinParams=CountMinParameters(Values)
Scope=0
End If
tempfunct.Scope=Scope
tempfunct.isConst=isConst'if it's a function/routine and isConst is true then it's an internal function not a user-defined one
tempfunct.Values = Values
If IsValidVar(tempfunct,True) Then VarList.Add(tempfunct)
Else
EvalError = API.GetString("calc_alreadydefined")
EvalMoreData = JustTheName(name)
End If
Return tempfunct
End Sub
Sub IsValidVar(Var As Variable, IsInternal As Boolean) As Boolean
Dim tempstr As StringBuilder, tempstr2 As String
EvalError = ""
EvalMoreData= ""
tempstr.Initialize
If Var.name.Length = 0 Then
AppendText(tempstr, API.GetString("calc_noname"))
Else
VarIndex = FindVariable(Var.name, 0,False,0)
If IsEditing Then
If VarIndex=-1 Then AppendText(tempstr, API.GetString("calc_varnotfound"))
Else
If VarIndex>-1 Then AppendText(tempstr, API.GetString("calc_alreadydefined"))
End If
End If
If (Var.varType <> ch_routine) Or (Var.varType = ch_routine And Not(Var.isConst)) Then
If Var.Values.Size=0 Then AppendText(tempstr, API.GetString("calc_novalues"))
End If
Select Case Var.varType
Case ch_routine:
If Var.Equation.Length=0 And Not(Var.isConst) And Not(IsInternal) Then AppendText(tempstr, API.GetString("calc_noequation"))
tempstr2 = CountDuplicateParameters(Var)
If tempstr2.Length>0 Then AppendText(tempstr, API.GetStringVars("calc_dupeparameter", Array As String(tempstr2)))
tempstr2=VerifyOptionalParameters(Var.Values)
If tempstr2.Length>0 Then AppendText(tempstr, API.GetStringVars("calc_nonoptional", Array As String(tempstr2)))
Case ch_custom:
If Not(Var.isConst) Then
If Var.Equation.Length=0 And Not(IsInternal) Then
AppendText(tempstr, API.GetString("calc_notype"))
Else If Not(VarExists(Var.Equation , 0,False,0)) Then
AppendText(tempstr, API.GetString("calc_typenotfound"))
End If
End If
End Select
EvalError = tempstr.ToString
If EvalError.Length>0 Then EvalMoreData = SaveVar(Var)
Return EvalError.Length=0
End Sub
Sub CountDuplicateParameters(Var As Variable) As String
Dim PLIST As List ,temp As Int, temp2 As Int ,Par As Parameter, tempstr As String
PLIST.Initialize
For temp = 0 To Var.Values.Size-1
Par = Var.Values.Get(temp)
tempstr=Par.name.ToLowerCase
For temp2 = temp+1 To Var.Values.Size-1
Par = Var.Values.Get(temp2)
If Par.name.EqualsIgnoreCase(tempstr) Then
If PLIST.IndexOf(tempstr)=-1 Then PLIST.Add(tempstr)
End If
Next
Next
Return JoinList(PLIST)
End Sub
Sub VerifyOptionalParameters(Parameters As List)As String
Dim temp As Int , PAR As Parameter , OptionalFound As Boolean
For temp = 0 To Parameters.Size-1
PAR = Parameters.Get(temp)
If PAR.Default.Length>0 Then
OptionalFound=True