Τετάρτη 9 Σεπτεμβρίου 2026

Revision 42 Version 15 - Functions for Structures

With functions for structures we can declare buffers (memory area) attaching functions, and we can use them to apply values also. 

These functions stored to structure only and interpreter attach one when need to execute it. So we can't used them as normal functions passing them by reference. We use name of structure as the one item of structured populated by original buffer (as a copy). So everything we do applied to a copy of an item of a buffer. When we define a buffer using name of structure and then name of buffer we can apply the computed item to every item of buffer.   So, alfa kappa[20]#new(30,40)#mul(3)  make 20 copies of the result of #new(30,40)#mul(3), and later alfa kappa[200]#new(31,41)#mul(3)  make 180 copies of new(31,41)#mul(3) and apply these from items [20] to [199]. 

Also, structure can be used in classes, and now we can use the declaration format struct_name buffer_name.

structure alfa {
x as double,
y as double
function mul(a) {
alfa|x=alfa|x*a
alfa|y=alfa|y*a
=alfa
}
function new(a=100, b=200) {
alfa|x=a
alfa|y=b
=alfa
}
function str() {
="("+(alfa|x)+", "+(alfa|y)+")"
}
}
alfa kappa
[20]#new(30,40)#mul(3)
print kappa[3]#str()="(90, 120)", kappa=>items=20, len(kappa)=320 ' bytes
alfa kappa
[200]#new(31,41)#mul(3)
print kappa[19]#str()="(90, 120)"
print kappa[20]#str()="(93, 123)", kappa=>items=200, len(kappa)=3200 ' bytes


class beta {
structure alfa {
x as double,
y as double
function mul(a) {
alfa|x=alfa|x*a
alfa|y=alfa|y*a
=alfa
}
function new(a=100, b=200) {
alfa|x=a
alfa|y=b
=alfa
}
function str() {
="("+(alfa|x)+", "+(alfa|y)+")"
}
}
{read many}
alfa kappa[many]#new(30,40)#mul(3)
}
beta=beta(10)
print beta.kappa[3]#str()="(90, 120)", beta.kappa=>items=10, len(beta.kappa)=160 ' bytes




Another example:


structure alfa {
x as double
y as double
function inc() {
alfa|x++
alfa|y++
=alfa
}
function arr {
=(alfa|x, alfa|y)
}
function str(s as string="") {
="(" +alfa#arr()#str$(s)+")"
}
}
alfa kappa
for i=1 to 10
kappa=kappa#inc()
? kappa#arr()#stuff(0)
? kappa#str(", ")
next

Or we can use Str$() as function name:

structure alfa {
x as double
y as double
function inc() {
alfa|x++
alfa|y++
=alfa
}
function arr {
=(alfa|x, alfa|y)
}
function str$(s as string="") {
="(" +alfa#arr()#str$(s)+")"
}
}
alfa kappa
for i=1 to 10
kappa=kappa#inc()
? kappa#arr()#stuff(0)
? kappa#str$(", ")
next

Τρίτη 8 Σεπτεμβρίου 2026

Monads - Writer monad (a rosettacode.org task)

https://rosettacode.org/wiki/Monads/Writer_monad#M2000_Interpreter

I write 2 variants, one using tuple and lambda functions and lambda composition, and one using a class monad.

Variant 1

Module MonadWriter {
cr={
}
bind=lambda cr (a, b, c)->{
=(a, b+cr+"    "+field$(c,17)+" : "+a)
}
Initial=lambda bind (v, txt as string="") ->{
=bind(v, txt, "Initial value")
}
SquareRoot=lambda bind (v, txt as string="") ->{
=bind(sqrt(v), txt, "Took square root")
}
AddedOne=lambda bind (v, txt as string="") ->{
=bind(v+1, txt, "Added one")
}
DividebyTwo=lambda bind (v, txt as string="") ->{
=bind(v/2, txt, "Divided by two")
}
Result=lambda bind (v, txt as string="") ->{
=bind(v, txt, "Result")
}
composition=lambda -> {
dim a()
a()=array([])
=lambda a() (x)-> {
ret=(x,"")
for i=0 to len(a())-1
ret=a(i)(!ret)
next
=ret
}
}
GoldenRatio=composition(Initial, SquareRoot, AddedOne, DividebyTwo, Result)
(val, ret)=GoldenRatio(5)
msg="The Golden Ratio is "
msg2="This was derived as follows:-"
report msg+val+{
}+msg2+ret
clipboard msg+val+{
}+msg2+ret
}
MonadWriter


Rem {
The Golden Ratio is 1.61803398874989
This was derived as follows:-
    Initial value     : 5
    Took square root  : 2.23606797749979
    Added one         : 3.23606797749979
    Divided by two    : 1.61803398874989
    Result            : 1.61803398874989
}


 Variant 2 (same output)

The mystery from this program is; When we execute the value (value (.v) { }) function for all the "binds"? Look at function bind. We return m using =m. This not return immediate the object. Because m has a value part the interpreter call this part. We didn't get error (we didn't pass a value) because error happen if we didn't initialize the parameter, but the parameter is the member v (this.v or .v), which has a value 0. When we execute this function we process the strv and we return a copy of  THIS, the current object (this never call the value part).


Module MonadWriter {
class monad {
private:
boolean err=true
v=0, t="", c=""
f=lambda->0
strV=""
cr={
}
public:
function strvalue() {
if .err then error "not intialised"
if .c<>"" then
=.c+.cr+.strV
else
=.strV
end if
}
function bind (m as monad) {
m.v<=.f(.v)
m.c<=.strvalue(.t)
m.err<=false
=m ' this call value () { }
}
value () { ' need () to mark "i want argument"
if not empty or not .err then
read .v ' .v has value so if empty interpreter pass this
.err<=false
.strV<="    "+field$(.t,17)+" : "+(.f(.v))
end if
=this
}
property value {
value {
link parent err, v, f to err, v, f
if err then error "not intialised"
value=f(v)
}
}
class:
module monad (.f as lambda, .t) {
}
}
Initial=monad(lambda (x)->x,"Initial value")
SquareRoot=monad(lambda (x)->Sqrt(x), "Took square root")
AddedOne=monad(lambda (x)->x+1, "Added one")
DividebyTwo=monad(lambda (x)->x/2, "Divided by two")
Result=initial(5).bind(SquareRoot).bind(AddedOne).bind(DividebyTwo).bind(monad(lambda (x)->x,"Result"))
val=Result.value
ret=Result.strvalue()
msg="The Golden Ratio is "
msg2="This was derived as follows:-"+{
}
report msg+val+{
}+msg2+ret
clipboard msg+val+{
}+msg2+ret
}
MonadWriter


Better code. I remove the value { } part so now we can pass the object monad without start the value {} part. I change it as Unit so first time we call Unit to pass the first value v. Then in each Bind we get the next object until we get values a tuple with the final value plus the log

Module MonadWriter {
class monad {
private:
boolean err=true
v=0, t="", c=""
f=lambda->0
strV=""
public:
function bind(m as monad) {
(m.v, m.c)=.values
=m.unit()
}
function unit(.v) {
.err<=false
.strV<="    "+field$(.t,17)+" : "+(.f(.v))
=this
}
property values {
value {
link parent err, v, f, c, strV to err, v, f, c, strV
if err then error "not intialised"
if c<>"" then
cr={
}
value=(f(v),c+cr+strV)
else
value=(f(v),strV)
end if
}
}=(,) ' empty tuple
class:
module monad (.f as lambda, .t) {
}
}
Initial=monad(lambda (x)->x,"Initial value")
SquareRoot=monad(lambda (x)->Sqrt(x), "Took square root")
AddedOne=monad(lambda (x)->x+1, "Added one")
DividebyTwo=monad(lambda (x)->x/2, "Divided by two")
Result=monad(lambda (x)->x,"Result")
(val, ret)=initial.unit(5).bind(SquareRoot).bind(AddedOne).bind(DividebyTwo).bind(Result).values
msg="The Golden Ratio is "
msg2="This was derived as follows:-"+{
}
report msg+val+{
}+msg2+ret
clipboard msg+val+{
}+msg2+ret
}
MonadWriter


Δευτέρα 7 Σεπτεμβρίου 2026

Version 15 Revision 41 - Assembler Upgrade

 The build-in assembler is a remastered version of  x86 assembler of Arne Elster 2007 / 2008.

The old version convert all code to ANSI and write to a byte array. Now I change this to Integer and I change the range of alphanumeric, adding codes from 128 to 32767.

We can use m2000 local variables and functions (not those with $) which declated as external. These external functions need to process it via @ which translate to number, the address of function. Using just the name without @ we do nothing because these functions are not exist as local variables. We call SysAllocStringLen using Call @SysAllocStringLen.

Using code for just calling from M2000 we can't use Extern clause, we have to declare the functions and then use the address of the function.

See asmdll and asmdll2 in Info file for how to use assembler to make dll files with import functions and export functions too.  Declare name Code address can be used  for changing the function signature also.


print "chapter 1"
print "strings returned as BSTR, as is or in a VARIANT"
print "We use SysAllocStringLen from oleaut32.dll"
Declare SysAllocStringLen Lib "oleaut32.SysAllocStringLen" {
Long OleStr, Long BLen
} As Long
Print "  - using Variant - Calling with variant as return value M2000 automatic pass an empty variant"
mycode=assembly({
push dword 14 ; Length of "Hello World"
lea eax, [data1]        
push eax
call @SysAllocStringLen ; @ read address of SysAllocStringLen()
mov edx, [esp + 4]       ; get the address of hidden empty variant
mov word [edx], 8        ; vt type = 8 (string)
mov dword [edx + 2], 0   ; Clear reserved fields (Offset 2)
mov dword [edx + 6], 0   ; Clear reserved fields (Offset 6)
mov [edx + 8], eax       ; Place the BSTR pointer into the Variant data (Offset 8)
mov dword [edx + 12], 0 ; Clear reserved fields (Offset 12)
; so now 16bytes returned via edx
ret 4
align 4
data1: dw "Hello World 𐐷" ; no need 0
})
declare HelloWorld code mycode(0) as variant
Print HelloWorld()
Print "  - using String - just return pointer to BSTR in eax"
mycode2=assembly({
push dword 14  ; Length of "Hello World"
lea eax, [data1]
push eax
call @SysAllocStringLen
; string BSTR pointer is in EAX
ret
align 4
data1: dw "Hello World 𐐷"
})


mycode2=assembly({
push dword 14  ; Length of "Hello World"
lea eax, [data1]
push eax
call @SysAllocStringLen
; string BSTR pointer is in EAX
ret
align 4
data1: dw "Hello World 𐐷"
})


declare HelloWorld2 code mycode2(0) as string
Print HelloWorld2()


print "chapter 2 - no need for SysAllocStringLen"
print "strings returned as pointer which have length depend of position of zero"
print "M2000 automatic produce BSTR from pointers"
print "1 - unicode string returned"
mycode3=assembly({
lea eax, [data1]
ret
align 4
data1: dw "بيانات Hello World 𐐷", 0
})
print "declared only by name of function HelloWorld3$"
declare HelloWorld3$ code mycode3(0)
Print HelloWorld3$()

print "declared as string pointer"
declare HelloWorld4 code mycode3(0) as string pointer
Print HelloWorld4()


print "2 - ansi string returned - name of function HelloWorld3"
mycode4=assembly({
lea eax, [بيانات] ; we can use arabic also...
ret
align 4
بيانات: db "Hello World", 0  ; we use db not dw for ansi
})
print "  delcared as string pointer ansi"
declare HelloWorld5 code mycode4(0) as string pointer ansi
Print HelloWorld5()
print "  delcared as ansi"
declare HelloWorld6 code mycode4(0) as ansi
Print HelloWorld6()

Κυριακή 6 Σεπτεμβρίου 2026

CPU properties using winmgmts

I found itemindex property using this:

w=GetObject("winmgmts:")
objCPUItem =w=>InstancesOf("Win32_Processor")
cc=param(objCPUItem)
ec=each(cc)
while ec {
      Print eval$(ec) ' print every function/property of object x
}




Sub QueryInterface(in riid *GUID, out ppvObj **void)
Function AddRef as ULONG
Function Release as ULONG
Sub GetTypeInfoCount(out pctinfo *UINT)
Sub GetTypeInfo(in itinfo UINT, in lcid ULONG, out pptinfo **void)
Sub GetIDsOfNames(in riid *GUID, in rgszNames **char, in cNames UINT, in lcid ULONG, out rgdispid *Long)
Sub Invoke(in dispidMember Long, in riid *GUID, in lcid ULONG, in wFlags USHORT, in pdispparams *DISPPARAMS, out pvarResult *VARIANT, out pexcepinfo *EXCEPINFO, out puArgErr *UINT)
Property Get _NewEnum as IUnknown*
Function Item(in strObjectPath String, [in iFlags Long]) as *ISWbemObject
Property Get Count as Long
Property Get Security_ as *ISWbemSecurity
Function ItemIndex(in lIndex Long) as *ISWbemObject



This is the program (paste in an empty module)


rem {
[Dynamic, Provider("CIMWin32"), UUID("{8502C4BB-5FBB-11D2-AAC1-006008C78BC7}"), AMENDMENT]
class Win32_Processor : CIM_Processor
{
  uint16   AddressWidth;
  uint16   Architecture;
  string   AssetTag;
  uint16   Availability;
  string   Caption;
  uint32   Characteristics;
  uint32   ConfigManagerErrorCode;
  boolean  ConfigManagerUserConfig;
  uint16   CpuStatus;
  string   CreationClassName;
  uint32   CurrentClockSpeed;
  uint16   CurrentVoltage;
  uint16   DataWidth;
  string   Description;
  string   DeviceID;
  boolean  ErrorCleared;
  string   ErrorDescription;
  uint32   ExtClock;
  uint16   Family;
  datetime InstallDate;
  uint32   L2CacheSize;
  uint32   L2CacheSpeed;
  uint32   L3CacheSize;
  uint32   L3CacheSpeed;
  uint32   LastErrorCode;
  uint16   Level;
  uint16   LoadPercentage;
  string   Manufacturer;
  uint32   MaxClockSpeed;
  string   Name;
  uint32   NumberOfCores;
  uint32   NumberOfEnabledCore;
  uint32   NumberOfLogicalProcessors;
  string   OtherFamilyDescription;
  string   PartNumber;
  string   PNPDeviceID;
  uint16   PowerManagementCapabilities[];
  boolean  PowerManagementSupported;
  string   ProcessorId;
  uint16   ProcessorType;
  uint16   Revision;
  string   Role;
  boolean  SecondLevelAddressTranslationExtensions;
  string   SerialNumber;
  string   SocketDesignation;
  string   Status;
  uint16   StatusInfo;
  string   Stepping;
  string   SystemCreationClassName;
  string   SystemName;
  uint32   ThreadCount;
  string   UniqueId;
  uint16   UpgradeMethod;
  string   Version;
  boolean  VirtualizationFirmwareEnabled;
  boolean  VMMonitorModeExtensions;
  uint32   VoltageCaps;
};
}
// declare w "winmgmts:" ' or alternative use GetObject()
w=GetObject("winmgmts:") ' some objects use this GetObject("", "M2000.x86")  like assembler
objCPUItem =w=>InstancesOf("Win32_Processor")
for i=0 to objCPUItem=>count-1
Print "CPU#"+(i+1)
objCPU=objCPUItem=>itemindex(i)
? "Description: "; objCPU=>Name, objCPU=>CreationClassName
? "CpuStatus: "; check(objCPU=>CpuStatus)
? "ProcessorType: "; check(objCPU=>ProcessorType)
? "NumberOfCores: "; objCPU=>NumberOfCores
? "NumberOfLogicalProcessors: "; objCPU=>NumberOfLogicalProcessors
? "LoadPercentage: ";str$(objCPU=>LoadPercentage,"#0.0");"%"
? "Frequency (MHz): ";objCPU=>MaxClockSpeed
? "SocketDesignation: "; objCPU=>SocketDesignation
? "CPU-ID: "; objCPU=>ProcessorId
? "SerialNumber (PartNumber): "; objCPU=>SerialNumber;" ("+objCPU=>PartNumber+")"
? "UniqueId: "; check(objCPU=>UniqueId)
? "Status: "; check(objCPU=>Status)
? "VoltageCaps: "; check(objCPU=>VoltageCaps)
? "InstallDate: "; check(objCPU=>InstallDate)
? "L2CacheSize: "; check(objCPU=>L2CacheSize)
? "L2CacheSpeed: "; check(objCPU=>L2CacheSpeed)
? "L3CacheSize: "; check(objCPU=>L3CacheSize)
? "L3CacheSpeed: "; check(objCPU=>L3CacheSpeed)
? "PNPDeviceID: "; check(objCPU=>PNPDeviceID)
next
function check(a)
if type(a)="Null" then
="Null"
else
=a
end if
end function