|
hBasic Manual System
changes
|
||||||||||||||||||||||
|
Interrupt Scope Fixes
By 'scope' we mean the list/s that Basic! searches
through when trying to find a variable.
There are mainly two types of scopes which a basic program is running in. 1. The main scope i.e
the main
program or
the main block
of an interrupt e.g OnBackKey
or
2. A local
scope i.e
inside a
function
An interrupt could happen in the middle of a function. In 01.91, Basic would detect this and change the scope (from local) to the 'global' list which starts at the main program list. If the variable is not found, it would keep searching through the list of the first function that was called, then the next function, and so on until it reached the end of the last called function (the function that was interrupted). This normally works fine if the variable exists in the main list. Many uses of Interrupts rely on finding a variable in a convenient 'global' area such as the main list. There are two problems with this design; a) If the variable does not exist in the main list. Then it might (un-intentionally) be found in one of the other lists. This can lead to errors which could be difficult to trace. and b) If a function is called inside an interrupt's main block, e.g
OnBackKey:
myfunc ()
Back.resume
basic still thinks it's inside an interrupt (which it
is) and uses the 'global' scope. This means any local
variable inside the function would be searched starting
from 'main'. Only if the variable does not exist in
main or any other preceeding function call, would the
correct list be finally searched. In 01.91, Functions called by an interrupt block were getting wrong scope. This is clearly undesirable, and is a side-effect of an interrupt handling system not intended to call functions. The following fixes were done. Fixed scope during an interrupt. a) Variable searches inside the main-block or an interrupt-main-block will search only the main list and nothing but the main list. else b) Variable searches inside a function-block (no matter when they are called) will only search the function's local variable list. All that is needed is a flag to indicate which scope (a or b) the code is running in. This flag is implemented in this fix and is updated for each interrupt or function call and restored upon interrupt resumes and function exits. Fix scope for new variables created during an interrupt Make sure new variables in main-block and interrupt-main-block are always created in main scope. Make sure new variables in function-block are always created in local scope. This is a similar fix using the new scope flag for newly created variables.
Exceptions The only exception to these fixes is code run inside an ONERROR block. ONERROR is treated differently than other interrupts and it's behaviour (regarding scope) has been left alone. That is, it's scope is the scope that was interrupted. e,g If an error occurred in a function, then the scope of the ONERROR block is that of the function. The rationale behind being that it is sometimes useful to return to the error point with a GOTO, in which a flag or variable (in the same scope) is neccessary to transfer meaning. |
||||||||||||||||||||||
|
Fix for volkeys at start of
run
When VOLKEYS.OFF is run in
the editor, the next program that is run does not reset
a system flag, so volume keys stay blocked. Fix was to reset that flag at start of a run. |
||||||||||||||||||||||
|
Faster
BYTE.WRITE.BUFFER
BYTE.WRITE.BUFFER
<file_table_nexp>,
<buffer_sexp>
(Basic 01.91 writes
this output one low byte at a time, each time
ignoring the high byte ( each character is two
bytes).) which is rather slow. This enhancement converts the string to a byte array and writes the whole array at once. The conversion (from a string to a byte array) assumes this;
from UTF-16 (i.e a Basic/Java string) to ISO-8859-1 (by default -intentionally to save lower byte after translation). It is essentially a two-byte to one-byte conversion. If there's anything in the high byte of the source (i.e >255) then a question mark glyph (3F) is used to mark unknown data because it can't find anything to map to. |
||||||||||||||||||||||
|
Bundle
Expressions ** Bundle Expressions have been removed due to a bug. Below is for reference only **
The
interpreter will now accept bundle expressions of the
forms; Syntax
e.g
mybundle.key1 mybundle."Key 1" The first form has no quotes surrounding the key and conforms to rules simiar to variable names;
Will be converted to lowercase, Cannot have spaces Must begin with a letter, but can have numbers. The only allowable special characters are : "_" or "@" or '#" The second form has quotes and the key can be any string similar to bundle.put,
Is case sensitive, Is fully compatible with bundle.put Expression Rules - A bundle.key will evaluate to a value similar to: bundle.get e.g bundle.create mybundle bundle.put mybundle, "key1", 99 bundle.get mybundle, "key1", n % old way n = mybundle.key1 % new way - A bundle.key can also be the destination of an assignment e.g bundle.create mybundle bundle.put mybundle, "key1", 98 % old way mybundle.key1 = 99 % new way - A bundle.key value can either be a number or a string e.g bundle.create mybundle mybundle.key1 = 99 mybundle.key2 = "red" n = mybundle.key1 % value at key1 must exist and is a number s$= mybundle.key2 % value at key2 must exist and is a string If the index or key does not exist, you will get an error. - A bundle.key assignment can either be a number or a string and can also change the value type. bundle.create mybundle mybundle.key1 = n % value is a number mybundle.key1 = "wow" % value is no longer a number - A bundle.key will auto-create the key if the key is not found. bundle.create mybundle mybundle.newkey3 = "first value" - A bundle.key will NOT auto-create a new bundle if the index is not found. The bundle (i.e it's index) MUST exist either by creating the bundle with bundle.create or bundle.put. Otherwise an error occurs. (note: this is different to the normal bundle.put behaviour) e.g bundle.create mybundle % mandatory mybundle.key2 = "red" % assignment auto-creates key2 print mybundle.key2 % red print your_bundle.key2 % ERROR - A numeric bundle.key can be used with pre/post inc/dec operators similar to variables. e.g bundle.create mybundle mybundle.key1 = 99 n = mybundle.key1++ % n=99 a = mybundle.key1 % a=100 These operators will update the bundle value pointed to by bundle.key, in which the value must be numeric. - A bundle.key can have embedded keys i.e bundle indexes inside bundle keys (bundles within bundles). This is of the form
bundle.key1.key2.key3..
bundle is an
<nvar> and it's value is the bundle index of
key1. key1's value is the bundle index of key2. key2's value is the bundle index of key3. key3's value will be the value of the whole expression and any update will be to the value at key3. Only the last key (key3 in this case) can be auto-created (if it doesn't exist). Note that all keys must be literal, they cannot be expressions. e.g bundle.create location location.area = "Westminster" location.city = "London" bundle.create contact contact.name = "John" contact.phone = 55556666 contact.assigned = location bundle.create work work.sales = contact !work.dog = humpty ? work.sales.name; ? " will cover "; ? work.sales.assigned.area % embedded keys ! John will cover Westminster Known quirks If both the index and key are bad, you might get 2 errors reported. |
||||||||||||||||||||||
|
Array Pointers
Assignments e.g a[] = b[] or LET a[] = b[] e.g a$[] = b$[]
a[] = b[] Makes an exact copy of b[] to a[] including the size and dimensions Background references, i.e passed by referenced variables, are preserved for a[]. hBasic uses the term "array pointer" (e.g a[] )as representing the whole array. An array pointer has no indices within the brackets. It is a reference to an array as opposed to just one element. (This syntax is inline with traditional Basic 01.91 which already uses the syntax for some commands and functions.) Evaluation (place holder for future development).
Evaluation of a[] always returns
0 ( might be
changed in the future ) Evaluation of a$[] always returns "" ( might be changed in the future ) Evaluation of non-existent a[] leads to an error. e.g PRINT a[]$, b[] will print ", 0.0" |
||||||||||||||||||||||
|
Array
Functions
Functions can now return an Array (pointer) e.g fn.def func_a$(n)[] % define an Array Function dim b$[3] b$[2] = "nice" if n=1 then fn.rtn % returns a useless default array if n=2 then fn.rtn b$[] % return specified array fn.end % returns default array ! fn.def func_a$() % (error) Function previously defined at: a$[] = func_a$(99)[] % Array function assignment (deep copy) ! print func_a$(99)[] % Error> Array functions cannot be evaluated : print a$[2] % only normal arrays can be evaluated with an index |
||||||||||||||||||||||
|
TEXT/BYTE.OPEN change on
failure
Before, if TEXT.OPEN or BYTE.OPEN fails to open a file,
an unusable filetable entry was still created. This no longer happens for v2.80+, there is no new filetable entry upon failure. |
||||||||||||||||||||||
|
Shortcut Support
If the app is compiled as a StandAlone APK (i.e without
editor), then a shortcut (on the Android home screen)
can launch the app and send a string of data. Normally this is only possible for a non-standalone (standard) APK, and the data string is limited to <something>.bas. For a Standalone APK, the shortcut is normally ignored, moreover, some apk makers might also remove the shortcut-dialog code This feature will entertain any shortcut data string being sent by a shortcut launch and put the string into an undocumented function called COMMAND$(). For this to work, the APK maker must not remove the shortcut dialog code (e.g hSuite will support this). Shortcuts to standard APKs (non-standalone) will not be affected and have no effect to COMMAND$(). Note that COMMAND$() is also used for a file-share data string (e.g from a file-manager) , the difference between a shortcut and a file-share is that a file-share will prepend a relative path to a file-name. Shortcut data strings are not prepended with anything, the data string is what the user typed in and is clean. The string can be any text and can have spaces, e.g "Dark Theme". |
||||||||||||||||||||||
|
DEVICE Fix
Ack: dkal - forum
question. DEVICE command would
crash on devices with Android-10+ because Google
decided not to allow access to 'Non-resettable device
identifiers' which can potentially be tracked or
usedfor ads. So they are banned for normal apps. The two keys which did this was 'DeviceID' and 'SIM SN' They both require READ_PRIVILEGED_PHONE_STATE or hasCarrierPrivileges, of which normal apps/users are unlikely to get. To fix the crash -> If the device is < Android Q
DeviceID
is supposed to return the IMEI or MEID.
SIM SN is
supposed to return the card serial number. If the device is >= Android Q,
DeviceID
will return the Android_ID.
(ANDROID_ID is per device (not card) and is generated on device set-up. It is not 100% reliable and could change on a factory reset or after an OTA update + app re-install). SIM SN will return "Not available". |
||||||||||||||||||||||
|
Sensors Fix
Ack: dkal,daveacre
- forum question. SENSORS command would
crash on devices with Android-10+ if (internal)
parameters were less than 3.The fix code is from aFox from a github issue. |
||||||||||||||||||||||