Archive: Assembler for NSIS


Assembler for NSIS
  https://sourceforge.net/projects/nslassembler/files/

nsL is a high-level language for NSIS (http://nsis.sourceforge.net). The nsL assembler takes nsL code and translates it into NSIS script which can then be compiled into an NSIS installation wizard. nsL has a uniform syntax that is similar to familiar programming languages such as C and Java. Complex expressions can be written freely while being assembled into basic NSIS instructions. Functions are defined and called much like they are in C and Java with the additional syntax for multiple return values. nsL introduces assemble time scope checking of variables as well as automatic declaration and support for global variables declaration and initialization. nsL also provides more powerful pre-processor directives such as macros which can have multiple inputs and outputs, just like run-time functions.
This is still work in progress but everything is there that allows one to write and build NSIS installers using the new language. Included is the source code, some example scripts and a first draft reference document. I am very interested in getting some feedback such as suggestions for changes, feature requests and bug reports.

This project is part of my University degree but it's time for me to move on to other University related work before my exams in May/June. That does not mean I will be stopping work on nsL. I plan on adding support for arrays with the help of a small plug-in (among other things) but that will be done at a later stage. My demonstration for this project is on Tuesday (29th) so I would be grateful to get feedback tomorrow or Monday! I apologise for posting so close to the demonstration date but there was so many features that I wanted to add I got a little carried away.

Anyway, run the executable file from the SourceForge page and then you will have a "Compile nsL Script" right-click option on ".nsl" files. You'll find some example scripts in NSIS\Examples\NSL.

Edit: Attached an example script.

Stu

It is very interesting, I like its style very much. :up:


(All of my comments are based on just reading the .pdf)

"Before a variable can be used, it must
be assigned to" I don't really like this, I'm used to variables defaulting to "" if you never set them (And they don't need an initial value if you are going to be pop'ing into them)

Using \ as escape is a bit painful in a installer since it usually contains a lot of paths, maybe you could add @"this\is\not\escaped" like C#? Or use ^ or something like that?

Real functions (with overloading even) looks great!

I'm not really a fan of the section syntax, what if we add another flag? Named arguments would also be better so you don't have to remember the order. What about something like
section MySection("hello world",/ReadOnly,"/newflag=space string",/Bold,1,2,...N), also, "optional" is not a good word for /o, IMHO you should call it unselected or unchecked. (I'm assuming /o is supposed to simulate [O] vs [X] )

Did you forget about the /ENABLECANCEL flag for custom pages?

Is there a way to tell how many parameters have been passed to a #macro? getmacroargcount() or something like that?

There is an old bug in the nsis parser, MessageBox mb_ok "$${foo}" this should display "${foo}" and not "$" + the content of ${foo}, maybe you can either add a working escape for \$ ($\$ in nsis, but does not exist) or work around it in other ways in your string handling?

Are functions merged? aka can you have more than one .onInit() assuming they have the same number of parameters? (You don't want this for normal functions, but it would be nice to have for the nsis callbacks)

I assume the .docx is the same as the .pdf? I think .rtf has table support, all I know is, I can't (and will not try to) read .docx

Not a big fan of java, but hey, the author gets to choose the language =)


This looks totally awesome!

Pluses:
I am very happy about C like syntax and case sensitivity.
Making own functions is fantastic, variable scope (finally!), arithmetic operators, code blocks, inlining NSIS code these all are great!
Using hash for defines is a little strange, but it reminds me a old-good C/C++ :)

Minuses:
I am a little disappointed from function calls:
e.g

CopyFiles("source", "dest", true, true, 99);
CopyFiles /SILENT /FILESONLY "source" "dest" 99

WTF is that true, true, 99 ?
Althought I am skilled NSIS user on first signt I didn't have any idea what it means. I suggest to use enums for parameters [flags] - is this possible?
Maybe these flags should be ORed someone??
CopyFiles("from", "to", CF_SILENT|CF_FILESONLY) 
Also sending some parameters as string is not good idea e.g
MessageBox("MB_OK|MB_ICONEXCLAMATION", "NSIS is not installed on this machine. Setup will now exit.");

MB_OK|MB_ICONEXCLAMATION would fit perfectly for enums
enum MessageBox

>{
MB_OK,
MB_YES,
...
}
I tried your .nsl with MUI2 and it does not work (as I assumed) :( so everything should be rewritten into .nsl which is enormus work.
I noticed that generated .nsi file requires a little of brushing.

Anyway: nsL looks very promising and you made a really good job on it!
Thanks!!!

Edit:
In this state I suggest using nsL in this style:
Create .nsl file where you create all logic, functions, etc because in nsL it is easier than in .nsi
and then generate .nsi file which you later include in your installer, you brush it a little and generate final installer.

Thanks for the feedback guys. Keep it coming! I will make note of everything.

Did you forget about the /ENABLECANCEL flag for custom pages?
It is there; the last parameter after page callbacks can be a Boolean.

"Before a variable can be used, it must
be assigned to" I don't really like this, I'm used to variables defaulting to "" if you never set them (And they don't need an initial value if you are going to be pop'ing into them)
If you are popping into them then you are assigning to them, i.e. $0 = Pop();. You don't need to set them to an empty string. The point of having to assign to them before referring to variables is to avoid the problem of clobbering values. If you want to make a variable global, just stick an assignment to it outside functions and sections. I will add an optimisation that $R0 = ""; in global scope doesn't assemble anything (it will already be empty).

getmacroargcount() is a good idea. There are probably plenty more that I could add really such as macrodef(name) and perhaps date() etc.

Are functions merged?
That's a nice idea. I could allow this for all functions by adding a partial keyword (C#) or just allow it for callbacks?

The docx was included in the source code. The pdf is the Docs copy. The original plan was to write it in C++ but using Java of course allowed me to write code and debug much faster.

Yes the \\ in strings is a real pain. I will add support for the C# @ prefix.

MB_OK|MB_ICONEXCLAMATION would fit perfectly for enums
I agree. This was something I wanted to change/add but again because of time constraints I had to leave as strings. If you want enums, would you prefer C style or C#. For example with C# you'd need "MessageBox." in front of each value; however I could have the assembler look for an enum with the same name as the current function and match those :). Either way you can use enums now (no constructor mind) as the | operator exists and you can define constants as numbers.

As for MUI, I should include an example. It's actually very simple. Just add #nsis ... #nsisend sections with the MUI code in it. Maybe not very pretty but that's the best we can do probably. I need to add an #nsisdef or something similar to !define constants to nsL values (i.e. import values from nsL into NSIS) but maybe there is a nicer way. Any thoughts? (Defining all nsL constants as NSIS ones... no).

Edit: New build uploaded which has the @ string prefix added. Also included a simple Modern UI 2 example script.

Stu

I can't stand C# enums, and you should try to keep the amount of extra typing to a minimum and emulate the nsis constant names when possible...


Yeh I agree. I will keep it simple and predefine MB_* as constants (among others). Something else I need to add is to assemble MessageBox (and other jump instructions) specially in switch statements. Currently you can use them, sure, but it will first StrCpy IDOK for example to a register and use that register for the switch. This is not the case when used in if statements or while loops - e.g. the MessageBox or IfSilent go-to label arguments will be used instead, but you are limited to a true or false (i.e. IDOK or not).

Stu


1.0.2 released.

1.0.2 - 28th March 2011
* Global assignments of "" to registers are no longer assembled
(registers are intialised to an empty string by NSIS).
* Fixed < and > operators using incorrect jump labels.
* Jump instructions when used in switch statements now receive similar
optimisations to their use in if statements. For example, MessageBox
can be used with cases "IDYES", "IDNO", "IDCANCEL" and so on. IfSilent
can be used with cases true or false. The go-to labels for each case
will be used directly on the jump instruction (i.e. IfSilent
label_case_true label_case_false) as is also done with if statements.
* Switch cases must have literal string, Boolean or integer values.
* Added missing 'default:' case for switch statements.
* Fixed Boolean values or instructions not being accepted as operands
for a Boolean operator.
* Fixed MessageBox being accepted as a Boolean value.
* Fixed MessageBox using 3 goto jumps on the end when only 2 are
allowed.
* Fixed If statements accepting a non-boolean expression.
* Fixed Boolean logic for || operator with left and right operands as
relative/equality comparisons.
* Added error on literal division by zero.
* More example scripts!
Stu

Installation Issue
  I'm using a PortableApps version of NSIS so the install "Claims" that NSIS is not installed. I took a look at the SVN source and find that the installer get the install path from the registry, if the registry key is missing then kaboom. Install.nsl --> Line 18

For a simple workaround, just add the portable apps path to the registry.. here is a VBScript that dose the trick:


'## VBScript to provide a work around for installing nsL-Assembler




Dim NSISPath

Set fso = CreateObject("Scripting.FileSystemObject")
Set objDialog = CreateObject("UserAccounts.CommonDialog")
Set WshShell = CreateObject("Wscript.Shell")

'## Get the Current NSIS path if it exists in the registry
NSISPath = GetRegValue()
IfNot fso.FolderExists(NSISPath) Then NSISPath = WScript.Path

>'## Define the "Open File" Dialog
'## Prompt user to locate the makensis.exe file
objDialog.Filter = "makensis.exe|makensis.exe|All Files|*.*"
objDialog.FilterIndex = 1
objDialog
.InitialDir = NSISPath
intResult= objDialog.ShowOpen

>If intResult = 0 Then
If GetRegValue() <> "" Then
If MsgBox("Do you want to delete the existing registry key?",36) = 6 Then
On Error Resume Next
WshShell.RegDelete("HKLM\SOFTWARE\NSIS")
On Error Goto 0
ElseIf MsgBox("Do you want to delete the existing registry value?",36) = 6 Then
On Error Resume Next
WshShell.RegDelete("HKLM\SOFTWARE\NSIS\")
On Error Goto 0
End If
Else
MsgBox "ABORT: Configuration Aborted by user."
End If
Wscript.Quit
ElseIf fso.FileExists(objDialog.FileName) Then
'## Found it.. Setting the registry to match
NSISPath = fso.GetFile(objDialog.FileName).ParentFolder.Path
Wshshell.RegWrite "HKLMSOFTWARENSIS", NSISPath

'## Validate
If GetRegValue() = NSISPath Then
MsgBox "Success: Registry Path was set to ***91;" & NSISPath & "***93;"
Else
MsgBox "FAILED: Unable to set registry setting. You might not have administrative access to edit the registry."
End If
Else
Wscript.Quit
MsgBox "ERROR: File was not found!"
End If

Function GetRegValue()
Dim Value
Value = ""
On Error Resume Next
Value = WshShell.RegRead("HKLMSOFTWARENSIS")
On Error Goto 0
GetRegValue = Value
End Function
>
↓ Your Welcome :D ↓

Ah thanks. I may just remove that code as people can still use the assembler without NSIS installed anyway.

Stu


If anyone else would like to play around with the language and post some more feedback I would be grateful.

Stu