F# Parse command line arguments, expected incomplete structured construct at or before this point ; or ;; - f#

I have a basic F# CLI that mimics F# touch command , my program takes a file name , creates the file if it exists or updates access time if it doesn't.
Core functionality is done, but it is supposed to mimic Linux' command Touch in terms of syntax. The syntax should be 'touch file1.text' for file creation or 'touch --version' for a message I want to print when option is given.
My core problems are:-
1. Having my code follow Linux' syntax -
Current - >>>Test.text = File created.
Expected - >>> touch test.txt or
touch --version = File created or touch command information printed.
Taking --version and --help or similar valid input and printed the corresponding information.
Current result
test.txt // File created
0 //
Expected
touch test.text //file created
0 //
or
Expected
touch --version / touch --help
/* Touch information
Touch information
Touch information
Touch information*/
Tried using the Argu library but seems out of my current scope, currently attempting with argument parser module.
// Learn more about F# at http://fsharp.org
open System
open System.IO
open System.Text
type filename = String
let touch path =
//Console.ReadLine()
if File.Exists path
then File.SetLastWriteTime(path, DateTime.Now)
else
if not(File.Exists path)
then File.WriteAllText(path, " ")
Console.ReadKey()|>ignore
[<EntryPoint>]
let main argv =
printfn "Touch Command - Built using F#"
printfn "Please enter the file you want to touch"
if argv |> Array.contains "Help " then
printfn "Display help here"
exit(0)
printfn "Version information"
exit(0)
for filename in argv do
touch(filename)
0
// return an integer exit code
```
Current result
> test.txt // File created
> 0 // internal
Expected
>touch test.text //file created
>0 //internal
or
Expected
>touch --version / touch --help
>/* Touch information
Touch information
Touch information
Touch information*/
No current errors
When argu library attempted, to many errors to bring to solution board.

argv is an array of strings, so the simplest way to tell if --help or --version is in that array is to use the Array.contains function:
[<EntryPoint>]
let main argv =
printfn "Argv: %A" argv // Helpful in debugging, remove in final version
if argv |> Array.contains "--help" then
printfn "Display help here"
exit(0)
if argv |> Array.contains "--version" then
printfn "Version information"
exit(0)
for filename in argv do
touch(filename)
Note that this example is assuming that you rewrite your touch function to take a filename parameter instead of reading the filename from the console via Console.ReadLine.
Also note that after an attribute like [<EntryPoint>], there's no need to add a second level of indentation. The attribute should be indented at the same level as the let declaration that it's modifying. So you should write your let main argv = line at the top level of your module (i.e., with zero indentation).

Related

dxl CreateProcess failed for system cmd instruction

I want to call run a file called csvplot.vbs (from this site) to turn a .csv file I have written using dxl (has 5 columns, each with a heading and then just numerical data) into a graph (stored as .png).
I have run the following instruction directly through cmd with success:
#echo off
cscript //nologo C:\Users\Administrator\csvplot.vbs C:\PROGRA~1\IBM\Rational\DOORS\9.6\lib\dxl\addins\Verification\Statistics\statGenTest_Top_Level.csv C:\PROGRA~1\IBM\Rational\DOORS\9.6\lib\dxl\addins\Verification\Statistics\statGenTest_Top_Level.png 800 600 1 3 1 4 1 5
pause
This produces the desired .png file.
What I want, however, is to be able to execute this through DOORS, so that whenever the script that generates the raw data is run, it also produces a graph.
What I have is this as my test case:
string echostr = "#echo off"
string commands = "cscript //nologo C:\\Users\\Administrator\\csvplot.vbs C:\\PROGRA~1\\IBM\\Rational\\DOORS\\9.6\\lib\\dxl\\addins\\Verification\\Statistics\\statGenTest_Top_Level.csv C:\\PROGRA~1\\IBM\\Rational\\DOORS\\9.6\\lib\\dxl\\addins\\Verification\\Statistics\\statGenTest_Top_Level.png 800 600 1 3 1 4 1 5"
system("cmd /c start #echo off") // doesn't recognise echo command
system("cmd /c start " commands "")
I get an error:
"Windows cannot find '#echo'. Make sure you typed the name correctly,
and then try again."
I am at a loss on how to get the script to run though cmd from dxl, and I would appreciate any help. I've only had one previous foray into system() prompts through dxl, and it was only to open a .pdf. In the meantime I will keep trying to work this out. Please let me know if I can provide any further information.
Edit: Further Information
#echo: I removed the # to see how it operates, it brings up a blank
cmd window and performs no further action. In order to even run the things in the points below, I left the # off.
I deleted "/c start" from the second system() line: this opens one command line with the usual white text at the top, and a second over the top that is completely blank.
I changed the first line as follows, and commented out the second:
system("cmd /c start echo off" "\n" commands "")
--- this got a similar result to the second dot-point, but only with one cmd window, the black (no text one)
If I don't include the "\n" marker then I get a cmd window with text of "off" commands (where commands is the defined string above).
If I only have the system("cmd /c start " commands "") line, and not the echo line, then a cmd window briefly flashes and disappears and no further results demonstrating the success of the script appear.
So my issue is this: I know this script works when run directly through command line, the problem I have is that I cannot now run it through dxl.
I have developed a solid work-around that does exactly what I need.
The issue was that the input I had dxl writing was not going through command line correctly.
Knowing that the script ran from cmd correctly and, in turn, that the script executed from a batch file correctly, and that I could run the batch file from dxl, my solution was as follows:
Define the paths in dxl using the format C:\PROGRA~1\PATHNAME\
Using the Stream write() command to write the instructions directly
to a .bat file
Then using the system() command to run the .bat file
I have included some of my code, so that maybe it might help someone attempting to do the same thing. (I'll gladly take any advice on better programming conventions.)
// functions used: genFileName(), assume if a variable is not declared here, it was declared under my globals
// genFileName() returns a string of the file name, replacing any " " with "_" so cmd doesn't cry when I run it
string basename = genFileName()
string fcsv = basename ".csv"
string csvPath = "blahblahthefilepath" fcsv
if(fileExists_(csvPath)) isFile = true
Stream fOut = append(csvPath)
// === if file does not exist, create, give column names
if( !isFile){
fOut << "Date and Time,count1,count2,count3,count4" "\n"
}
else ack ("File name exists, append stats to file?" // may not be necessary
// === print to file ===
fOut << datetime "," ctot "," ctc "," cti "," ctnc "\n"
// ===== Create Batch file to run grapher ===
string columnsToPlot = "1 3 1 4 1 5" // ==> may develop this to allow user to choose
string graphDim = "800 600" // ==> px dim, may develop for user choice
string fbat = basename ".bat"
string batPath = "blahblahthefilepath"
Stream batOut = write(batPath fbat)
batOut << "#echo off" "\n"
batOut << "title Batch file to plot statistics for " fcsv "\n"
batOut << "cscript //nologo " batPath "csvplot.vbs " batPath fcsv " " batPath basename ".png " graphDim " " columnsToPlot ""
system("cmd /c start " batPath fbat "")
// some infoBox feedback DB to tell the user that the files were created
Good luck to anyone else who is attempting something similar, and I hope this is of use to someone.
Does running the dxl script without the # in front of the echo command work?

Hello world won't compile with "The value or constructor is not defined"

let prefix prefixString baseString =
prefixString + " " + baseString
prefix "Hello" "World"
With the code above I'm getting the error Stuff.fs(34,1): error FS0039: The value or constructor 'prefix' is not defined.
I'm not entirely sure why this is happening, as I'm watching a video series on F# in which literally the same code is being compiled and ran successfully. Is there something wrong with my environment?
In the comment, you mentioned that you are running the snippet using "run selection" command. This command runs the selected piece of code in F# Interactive which initially contains no definitions. So, if you select and run just the last line, you will get:
> prefix "Hello" "World";;
stdin(1,1): error FS0039: The value or constructor 'prefix' is not defined
This is because F# Interactive does not know what the definition of prefix is - it does not look for it automatically in your file. You can fix this by selecting everything and running all code in a single interaction, or you can first run the definition and then the last line, i.e.:
> let prefix prefixString baseString =
prefixString + " " + baseString;;
val prefix : prefixString:string -> baseString:string -> string
> prefix "Hello" "World";;
val it : string = "Hello World"
Note that when you run the first command, F# Interactive will print the type of the defined functions, so you can see what has just been defined.
The fact that F# Interactive has its own separate "state of the world" is quite important, as it also means that you need to re-run functions after you change them so that subsequent commands use the new definition.

referencing com interface in fsi F# interactive

I'm trying to rewrite this matlab .Net example in F# interactive.
In the example a COM-interface reference is used.
How do I reference a COM-interface from within the fsi?
EDIT
I refence the as described
From the Project menu, select Add Reference. Select the COM tab in the Add Reference dialog box. Select the MATLAB application.
This reference I can not send with right click to the interactive. There is no path in the properties and the dll cited in the description MLApp.dll I can not find in my matlab directory. This F# programm works:
[<EntryPoint>]
let main argv =
let matlab = new MLApp.MLAppClass()
matlab.Execute "x=1+1" |> printfn "%A"
matlab.GetVariable("x","base") |> printfn "%A"
0
But I want to use it from FSI.

Is it possible to trace the current line in an F# script with FSI library

We are using FSharp compiler service FSI evaluation session to execute a DSL. To be precise we are using F# code to simulate G-Code for a CNC machine. As each line of the FSI script moves the machine to a different location our users would like to see the current line of the script that is executing synced to the position of the machine.
Is it possible to get a callback from the FSI evaluation session indicating the current line being executed?
Use the LINE directive
let x = "this is on line " + __LINE__
result
val x : string = "this is on line 42"

Why doesn't Console.Readline work but Console.Readline() does?

How do you use Console.Readline in F#? Unlike Console.Writeline, it isn't being honored when I call it.
If you use
let s = Console.ReadLine
you are only building a delegate that points to the ReadLine function. You need to say
let s = Console.ReadLine()
to actually execute the function. This is just like C# syntax, except type inference means you don't get a compiler warning.
What do you mean by "it isn't being honored"? Here's a small console app I've just written in VS2010b1, and it works fine:
open System
let line = Console.ReadLine()
Console.WriteLine("You wrote {0}", line)
// Just to make it pause
let unused = Console.ReadLine()
Are you trying to run the code from F# Interactive within Visual Studio? If so, that may be the issue, as Brian's post explains.
However, I haven't seen the same problem when using F# Interactive from the command line. Here's a complete transcript of a session:
Microsoft F# Interactive, (c) Microsoft Corporation, All Rights Reserved
F# Version 1.9.6.16, compiling for .NET Framework Version v4.0.20506
Please send bug reports to fsbugs#microsoft.com
For help type #help;;
> open System;;
> let line = Console.ReadLine();;
Hello world
val line : string = "Hello world"
Running Brian's looping code from F# Interactive didn't show the same problem.
Bottom line: It seems like this is broken in F# Interactive in Visual Studio, but not when running interactively from the command line or in a full console app.
I don't have a Beta1 box handy, but I know that in the past we've had a bug where ReadLine() would see the background commands that communicate between the interactive UI and the background process that runs your F# code. It may be interesting to investigate what
let Foo max =
let rec Loop i =
if i < max then
let line = System.Console.ReadLine()
printfn "line = %s" line
Loop (i+1)
Loop 1
Foo 12
prints when you highlight it and 'Send to Interactive'. I think possibly you'll see a few unexpected interesting lines, followed by lines you type into the window.
// is the right way if you're not wanting to use a return of anything typed into readline
Console.ReadLine() |> ignore

Resources