I've made a simple command set generator (like noels I assume) which runs through selected files and spits out the nescessary invoker + command set along with some very basic documentation.
Tag functions, types, fields, or methods with 'expose to let the script access them.
Here's the source along with a simple example which uses the source code itself as a demonstration...
Remember to copy bvmtools.dll and briskvm.dll to the same folder as the source code, otherwise it won't run...
BriskVM2 is superb!
Tag functions, types, fields, or methods with 'expose to let the script access them.
Here's the source along with a simple example which uses the source code itself as a demonstration...
' ' Simple BriskVM Command Set Assistant for BlitzMax ' ' created by Mikkel Fredborg ' use as you please! ' SuperStrict Import koriolis.briskvm ' ' Start of Demo ' Init() ' ' Replace with your own files etc. Local source:String = AppArgs[0].Replace(".debug","").Replace(".exe",".bmx") ' find the source file :) ScanSource(source) ' ' You can add as many source files as you need. Imports and Includes are automatically checked as well. ' ' Write all the output WriteCommandSet("example.bcs") WriteCSS("example.css") WriteDocs("example.htm","example.css") GenerateBMXInvoker("example.bcs", "example_invoker.bmx") Print "DONE" End ' ' End of demo ' Type TType 'expose Global _list:TList = New TList Field name:String Field fields:TList = New TList Field methods:TList = New TList Method New() _list.AddLast Self EndMethod Method AddField(s:String) 'expose fields.AddLast s EndMethod Method AddMethod(s:String) 'expose methods.AddLast s EndMethod EndType Type TFunc 'expose Global _list:TList = New TList Field name:String 'expose Method New() _list.AddLast Self EndMethod EndType Global fun_count:Int Global met_count:Int Global typ_count:Int Global files:TList Function Init() 'expose files = New TList fun_count = 0 met_count = 0 typ_count = 0 EndFunction ' ' Just for convenience... Function WriteCSS(output:String) 'expose Local out:TStream = WriteStream(output) If out = Null Then Throw "Error!" WriteLine(out,"body {") WriteLine(out," margin: 0px 0px 0px 0px;") WriteLine(out," padding: 0px 0px 0px 0px;") WriteLine(out," background-color: #FFFFFF;") WriteLine(out," color: #000000;") WriteLine(out," font-family: verdana, arial, sans-serif;") WriteLine(out," font-size: 10px;") WriteLine(out,"}") WriteLine(out,".header {") WriteLine(out," padding-Left: 10px;") WriteLine(out," margin-top: 10px;") WriteLine(out," margin-bottom: 10px;") WriteLine(out," font-size: 20px;") WriteLine(out,"}") WriteLine(out,".Type, .Function, .Const, .stat {") WriteLine(out," padding-Left: 20px;") WriteLine(out," font-weight: bold;") WriteLine(out,"}") WriteLine(out,".End {") WriteLine(out," padding-bottom: 20px;") WriteLine(out,"}") WriteLine(out,".Method, .Field {") WriteLine(out," padding-Left: 40px;") WriteLine(out,"}") CloseFile out EndFunction Function WriteDocs(output:String,style:String) 'expose Print "Generating Documentation!" Local out:TStream = WriteStream(output) If out = Null Then Throw "Error!" WriteLine(out,"<html><head>") WriteLine(out,"<title>Script Reference</title>") WriteLine(out,"<link href='"+style+"' rel='stylesheet' Type='text/css' />") WriteLine(out,"</head><body>") WriteLine(out,"<div class='header'>Functions</div>") For Local f:TFunc = EachIn TFunc._list WriteLine(out,"<div class='function'>Function "+f.name.Replace(" Final","")+"</div>") Next Local met:Int = 0 WriteLine(out,"<div class='header'>Types</div>") For Local t:TType = EachIn TType._list If t.fields.IsEmpty() And t.methods.IsEmpty() Then Continue WriteLine(out,"<div class='type'>Type "+t.name+"</div>") For Local f:String = EachIn t.fields WriteLine(out,"<div class='field'>"+f+"</div>") Next WriteLine(out,"") For Local m:String = EachIn t.methods WriteLine(out,"<div class='method'>"+m.Replace(" Final","")+"</div>") met:+1 Next WriteLine(out,"<div class='end type'>EndType</div>") WriteLine(out,"") Next WriteLine(out,"<div class='header'>Constants</div>") For Local f:TConstant = EachIn TConstant._list WriteLine(out,"<div class='const'>Const "+f.name+":Int = "+f.value+"</div>") Next WriteLine(out,"<div class='header'>Stats</div>") WriteLine(out,"<div class='stat'>"+TFunc._list.Count()+" Functions</div>") WriteLine(out,"<div class='stat'>"+TType._list.Count()+" Types</div>") WriteLine(out,"<div class='stat'>"+met+" Methods</div>") WriteLine(out,"<div class='stat'>"+TConstant._list.Count()+" Constants</div>") WriteLine(out,"<div class='end'></div>") WriteLine(out,"</body></html>") CloseFile out EndFunction Function WriteCommandSet(output:String) 'expose Print "Writing Command Set!" Local out:TStream = WriteStream(output) If out = Null Then Throw "Error!" WriteLine(out,".set ~q"+StripAll(output)+"~q") WriteLine(out,"") WriteLine(out,"!annotations") ' when on, allows to specify meta data in the form of annotations (@MyAnnotation = "SomeValue") WriteLine(out,"!explicit") ' when on, forces explicit declaration of variables WriteLine(out,"!classes") ' when on, enables objective oriented programming WriteLine(out,"!serialization") ' when on, enables serializing (loading/saving) of objects WriteLine(out,"!scoping") ' when on, enables to use access specifiers for type fields and methods WriteLine(out,"!funcpointers") ' when on, enables to use function pointers WriteLine(out,"!reflection") ' when on, enables to use reflection (ie determine at runtime the existing classes, examine their fields and access them) WriteLine(out,"!altsyntax") ' when on, scripts use a slightly different syntax WriteLine(out,"!properties") WriteLine(out,"!assertions") WriteLine(out,"!typeInference") WriteLine(out,"") WriteLine(out,"FlushMem<BVM_FlushMem>()") WriteLine(out,"FlushDebugLog<BVM_FlushDebugLog>()") ' WriteLine(out,"DebugLog<BVM_DebugLog>(txt$)") WriteLine(out,"") WriteLine(out,"Abstract Type THostObject<Object>") WriteLine(out,"~tMethod ToString:String()") WriteLine(out,"End Type") WriteLine(out,"") ' The not so obvious part: ' Let's declare the host TList type, and its accompanying enumerator (will allow us to use EachIn in scripts, on host language lists) WriteLine(out,"Type THostListEnum<TListEnum> Extends THostObject") WriteLine(out,"~tMethod MoveNext<HasNext>%()") WriteLine(out,"~tMethod GetItem<NextObject>:THostObject()") WriteLine(out,"End Type") WriteLine(out,"") WriteLine(out,"Type THostList<TList> Extends THostObject") WriteLine(out,"~tMethod AddLast( value:THostObject )") WriteLine(out,"~tMethod AddFirst( value:THostObject )") WriteLine(out,"~tMethod First:THostObject()") WriteLine(out,"~tMethod Last:THostObject()") WriteLine(out,"~tMethod RemoveFirst:THostObject()") WriteLine(out,"~tMethod RemoveLast:THostObject()") WriteLine(out,"~tMethod GetEnumerator<ObjectEnumerator>:THostListEnum()") WriteLine(out,"~tMethod IsEmpty%()") WriteLine(out,"~tMethod Clear()") WriteLine(out,"~tMethod Contains%( value:THostObject )") WriteLine(out,"~tMethod ValueAtIndex:THostObject( index% )") WriteLine(out,"~tMethod Count%()") WriteLine(out,"~tMethod Remove( value:THostObject )") WriteLine(out,"~tMethod Reverse()") WriteLine(out,"~tMethod Reversed:THostList()") WriteLine(out,"End Type") WriteLine(out,"") For Local f:String = EachIn files Local t:String = ExposeSource( f ) If t Local ts:String[] = t.split("~n") For Local s:String = EachIn ts WriteLine(out,s) Next EndIf Next CloseStream(out) EndFunction Type TConstant 'expose Global _list:TList = New TList Field name:String 'expose Field value:String 'expose Method New() _list.AddLast Self EndMethod EndType Function ExposeSource:String(f:String) 'expose Global const_list:TList = New TList Local out:String Local tab:Int = 0 Local expose:Int = 0 Local func_list:TList = New TList Local intype:String Local ty:TType Local s:TStream = ReadStream(f) If s While Not Eof(s) Local t:String = (ReadLine(s)).Trim() t = t.Replace(":Object",":THostObject") t = t.Replace(":TList",":THostList") If t.Contains("'expose") If t.Contains("script_") Local a:Int = t.find(":") Local b:Int = t.find("(") Local c:String = ":" If b<a And b>-1 Then c = "(" Local bob:String bob = (t[..t.find(c)]).Replace("Function","").Trim() bob = "<"+bob+">" t = t.Replace("script_","") Local i:Int = t.find(c) t = t[..i]+bob+t[i..] ' Print t EndIf EndIf Local l:String = t.tolower().Replace("end ","end") If l.Find("endtype") = 0 tab:-1 ty = Null If expose expose = False out :+ (RSet("",tab).Replace(" ","~t"))+"End Type"+"~n" out :+ "~n" EndIf For Local f:String = EachIn func_list out :+ (RSet("",tab).Replace(" ","~t"))+f+"~n" Next intype = "" func_list.Clear() EndIf If t.Contains("'expose") t = t.Replace("#",":Float") t = t.Replace("%",":Int") t = t.Replace("$",":String") Local pos:Int = t.find("'expose") Local opt:String = (t[pos+7..]).Trim() t = (t[..pos]).Trim() If opt If opt.contains("params=") Local p2:Int = opt.find("params=") Local v:Int = Int(opt[p2+7..]) Local a:Int = t.find("(")+1 While v>0 a = t.find(",",a+1) v:-1 Wend t = t[..a]+")" ' Print "Modified: "+t ' Print "Options: Parameters = "+v EndIf EndIf If l.Find("type") = 0 expose = True If l.contains("extends") = False t :+ " Extends THostObject" EndIf Local a:Int = l.find("'") Local b:Int = l.find("extends") If b<a And b>-1 Then a = b intype = (t[t.find("Type")+4..a]).Trim() ty = New TType ty.name = intype.Replace("Abstract","") typ_count:+1 EndIf If l.Find("const") = 0 Local c:TConstant = New TConstant c.name = t.Replace("Const","") c.name = c.name[..c.name.find("=")] c.name = c.name.Replace(":Int","") c.name = c.name.Replace(":Float","") c.name = c.name.Replace(":Byte","") c.name = c.name.Replace(":Long","") c.name = c.name.Replace(":String","") c.name = c.name.Replace("%","") c.name = c.name.Replace("#","") c.name = c.name.Replace("$","") c.name = c.name.Replace("!","") c.name = c.name.Replace("&","") c.name = c.name.Trim() c.value = (t[ t.find("=")+1 .. ]).Trim() t = t.Replace(c.value,Int(c.value)) c.value = Int(c.value) const_list.AddLast c Else For Local c:TConstant = EachIn const_list t = t.Replace(c.name,c.value) Next ' ' Replace | variable stuff While t.contains("|") Local a:Int = t.find("=") Local b:Int = t.find("|",a) Local c:Int = t.find("|",b+1) Local d:Int = t.find(",",b+1) Local e:Int = t.find(")",b+1) If c<0 Then c = d If d<0 Then d = e If d<0 Then d = c If e<0 Then d = c c = Min(c,Min(d,e)) Local vala:Int = Int(t[a+1..b]) Local valb:Int = Int(t[b+1..c]) t = t.Replace( t[a+1..c], (vala|valb)) 't = "" Wend EndIf If l.find("function") = 0 t = t.Replace("#",":Float") t = t.Replace("%",":Int") t = t.Replace("Function","").Trim() t = t[..1].toupper()+t[1..] If intype Local s:String = t Local a:Int = t.Find(":") Local b:Int = t.Find("(") Local c:Int = a If b<a And b>-1 Then c = b Local funcname:String = t[..c] ' Print intype+","+funcname Local fu:TFunc = New TFunc fu.name = intype[1..]+t s = intype[1..]+t[..c]+"<"+intype+"."+funcname+">"+t[c..] func_list.AddLast s Else Local fu:TFunc = New TFunc fu.name = t out :+ (RSet("",tab).Replace(" ","~t"))+t+"~n" EndIf fun_count :+ 1 EndIf If l.find("method") = 0 met_count :+ 1 ty.AddMethod(t) EndIf If l.find("field") = 0 ty.AddField(t) EndIf ' If l.Find("type") = 0 .. Or l.find("global") = 0 .. Or l.find("const") = 0 .. Or l.find("method") = 0 .. Or l.find("field") = 0 If t.Find("Abstract")>-1 t = t.Replace("Abstract","") If t.Find("Type")>-1 t = "Abstract "+t EndIf EndIf t = t.Trim() out :+ (RSet("",tab).Replace(" ","~t"))+t+"~n" EndIf EndIf If l.Find("type") = 0 tab:+1 EndIf Wend CloseStream s EndIf Return out EndFunction Function ScanSource(m:String,trace:Int=True) 'expose For Local f:String = EachIn files If StripAll(f).ToLower() = StripAll(m).ToLower() ' Print "File: "+m+" ALREADY PROCESSED!" Return EndIf Next files.AddLast m Local comment:Int = 0 Local s:TStream = ReadStream(m) If s Print "Scanning: "+m While Not Eof(s) Local t:String = (ReadLine(s)).ToLower().Trim().Replace("end ","end") If t.Find("'") = 0 Then comment = 1 If t.find("rem") = 0 Then comment = 2 If t.find("endrem") = 0 Then comment = 0 If comment = False If trace If t.Find("import") = 0 Or t.Find("include") = 0 Local a:Int = t.find("~q") Local b:Int = t.find("~q",a+1) If b>a ScanSource(ExtractDir(m)+"/"+t[a+1..b]) EndIf EndIf EndIf EndIf If comment = 1 Then comment = 0 Wend CloseStream s Else Print "Couldn't open: "+m EndIf EndFunction Function GenerateBMXInvoker(bcsPath_$, invokerPath_$) Print "Generating invoker!" Local invCount% = BVM_CountInvokerGenerators() For Local i:Int = 0 Until invCount Local extCount% = BVM_GetInvokerGeneratorFileExtCount(i) For Local j:Int = 0 Until extCount If BVM_GetInvokerGeneratorFileExt(i, j).ToLower() = "bmx" Then Local hCmdSet% = BVM_LoadCommandSet(bcsPath_) If hCmdSet = BVM_INVALID_CMD_SET Then RuntimeError(BVM_GetLastErrorMsg()) EndIf If Not BVM_GenerateInvoker(hCmdSet, invokerPath_, i) Then RuntimeError(BVM_GetLastErrorMsg()) EndIf Return EndIf Next Next RuntimeError("Invoker Generator not found") End Function
Remember to copy bvmtools.dll and briskvm.dll to the same folder as the source code, otherwise it won't run...
BriskVM2 is superb!