Skip to content

Instantly share code, notes, and snippets.

@kevmal
Last active April 17, 2023 16:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kevmal/5140c30fd6018eb4dfc006e19e5b98a6 to your computer and use it in GitHub Desktop.
Save kevmal/5140c30fd6018eb4dfc006e19e5b98a6 to your computer and use it in GitHub Desktop.
Code gen ops
open System
open System.Runtime.InteropServices
open System.Runtime.CompilerServices
type CallerInfo =
{
Inherited : bool
MemberName : string
Path : string
LineNumber : int
}
type Str = Str with
static member (?)(Str,str) = str
let mutable lineSep = "\r\n"
let mutable indentString = " "
type CodeGenElement =
| Block of indent : int * CodeGenElement list * srcInfo : CallerInfo
| Line of indent : int * line : string * srcInfo : CallerInfo
member x.Indent(n) =
match x with
| Line(i,l,info) -> Line(i + n, l,info)
| Block(i,xs,info) -> Block(i+1,xs,info)
member x.Indent() = x.Indent(1)
override x.ToString() =
match x with
| Line(i,str,info) -> (String.replicate i indentString) + str
| Block(i,xs,info) ->
if i <> 0 then
xs
|> Seq.map (fun x -> string (x.Indent(i)))
|> String.concat lineSep
else
xs |> Seq.map string |> String.concat lineSep
member x.MakeString(f) =
match x with
| Line(i,str,info) -> f i str info
| Block(i,xs,info) ->
if i <> 0 then
xs
|> Seq.map (fun x -> x.Indent(i).MakeString(f))
|> String.concat lineSep
else
xs |> Seq.map (fun x -> x.MakeString(f)) |> String.concat lineSep
member x.MakeString() = x.MakeString(fun i str info -> (String.replicate i indentString) + str)
member x.MakeStringDebug(?codeWidth,?includePath) =
let codeWidth = defaultArg codeWidth 120
let includePath = defaultArg includePath true
let f i str (info : CallerInfo) =
let str = ((String.replicate i indentString) + str).PadRight(codeWidth,' ')
if includePath then
str + sprintf " // %-5d %-20s %s" info.LineNumber info.MemberName (IO.Path.GetFileName(info.Path))
else
str + sprintf " // %-5d %-20s" info.LineNumber info.MemberName
x.MakeString(f)
let stringToLine info (x : string) =
let rec loop i (s : string) =
if s.StartsWith(indentString) then
loop (i + 1) (s.Substring(4))
else
Line(i,s,info)
loop 0 x
let stringToBlock indent info (x : string) =
let info2 = {info with Inherited = true}
x.Split '\n'
|> Array.map (fun x -> x.Trim('\r'))
|> Array.map (stringToLine info2)
|> Array.toList
|> (fun i -> Block(indent,i,info))
let indent i (x:CodeGenElement) = x.Indent(i)
let injectInto (filename : string) (markerStart : string) (markerEnd : string) injectTxt =
let injectTxt = markerStart + injectTxt
let txt = IO.File.ReadAllText(filename)
let startIndex = txt.IndexOf(markerStart)
let endIndex = txt.IndexOf(markerEnd)
if startIndex > 0 && endIndex > startIndex then
let newTxt = txt.Substring(0,startIndex) + injectTxt + txt.Substring(endIndex)
IO.File.WriteAllText(filename, newTxt)
let rec typeStr (t : Type) =
if t.IsGenericType then
let targs = t.GetGenericArguments() |> Array.map typeStr
let name =
let name = t.FullName
let i = name.IndexOf "`"
name.Substring(0,i)
sprintf "%s<%s>" name (targs |> String.concat ", ")
else
t.FullName
type Operators() =
static member C(str, [<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string, [<CallerFilePath; Optional; DefaultParameterValue("")>] path: string, [<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int) = Line(0, str, { MemberName = memberName; Path = path; LineNumber = line; Inherited = false})
static member C_(str, [<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string, [<CallerFilePath; Optional; DefaultParameterValue("")>] path: string, [<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int) = Line(1, str, { MemberName = memberName; Path = path; LineNumber = line; Inherited = false})
static member C__(str, [<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string, [<CallerFilePath; Optional; DefaultParameterValue("")>] path: string, [<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int) = Line(2, str, { MemberName = memberName; Path = path; LineNumber = line; Inherited = false})
static member C___(str, [<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string, [<CallerFilePath; Optional; DefaultParameterValue("")>] path: string, [<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int) = Line(3, str, { MemberName = memberName; Path = path; LineNumber = line; Inherited = false})
static member C____(str, [<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string, [<CallerFilePath; Optional; DefaultParameterValue("")>] path: string, [<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int) = Line(4, str, { MemberName = memberName; Path = path; LineNumber = line; Inherited = false})
static member C_____(str, [<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string, [<CallerFilePath; Optional; DefaultParameterValue("")>] path: string, [<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int) = Line(5, str, { MemberName = memberName; Path = path; LineNumber = line; Inherited = false})
static member C______(str, [<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string, [<CallerFilePath; Optional; DefaultParameterValue("")>] path: string, [<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int) = Line(6, str, { MemberName = memberName; Path = path; LineNumber = line; Inherited = false})
static member C_______(str, [<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string, [<CallerFilePath; Optional; DefaultParameterValue("")>] path: string, [<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int) = Line(7, str, { MemberName = memberName; Path = path; LineNumber = line; Inherited = false})
static member C________(str, [<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string, [<CallerFilePath; Optional; DefaultParameterValue("")>] path: string, [<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int) = Line(8, str, { MemberName = memberName; Path = path; LineNumber = line; Inherited = false})
static member B(l, [<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string, [<CallerFilePath; Optional; DefaultParameterValue("")>] path: string, [<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int) = Block(0, l, { MemberName = memberName; Path = path; LineNumber = line; Inherited = false})
static member B_(l, [<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string, [<CallerFilePath; Optional; DefaultParameterValue("")>] path: string, [<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int) = Block(1, l, { MemberName = memberName; Path = path; LineNumber = line; Inherited = false})
static member B__(l, [<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string, [<CallerFilePath; Optional; DefaultParameterValue("")>] path: string, [<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int) = Block(2, l, { MemberName = memberName; Path = path; LineNumber = line; Inherited = false})
static member B___(l, [<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string, [<CallerFilePath; Optional; DefaultParameterValue("")>] path: string, [<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int) = Block(3, l, { MemberName = memberName; Path = path; LineNumber = line; Inherited = false})
static member B____(l, [<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string, [<CallerFilePath; Optional; DefaultParameterValue("")>] path: string, [<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int) = Block(4, l, { MemberName = memberName; Path = path; LineNumber = line; Inherited = false})
static member B_____(l, [<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string, [<CallerFilePath; Optional; DefaultParameterValue("")>] path: string, [<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int) = Block(5, l, { MemberName = memberName; Path = path; LineNumber = line; Inherited = false})
static member B______(l, [<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string, [<CallerFilePath; Optional; DefaultParameterValue("")>] path: string, [<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int) = Block(6, l, { MemberName = memberName; Path = path; LineNumber = line; Inherited = false})
static member B_______(l, [<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string, [<CallerFilePath; Optional; DefaultParameterValue("")>] path: string, [<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int) = Block(7, l, { MemberName = memberName; Path = path; LineNumber = line; Inherited = false})
static member B________(l, [<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string, [<CallerFilePath; Optional; DefaultParameterValue("")>] path: string, [<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int) = Block(8, l, { MemberName = memberName; Path = path; LineNumber = line; Inherited = false})
static member P(str, [<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string, [<CallerFilePath; Optional; DefaultParameterValue("")>] path: string, [<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int) = stringToBlock 0 { MemberName = memberName; Path = path; LineNumber = line; Inherited = false} str
static member P_(str, [<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string, [<CallerFilePath; Optional; DefaultParameterValue("")>] path: string, [<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int) = stringToBlock 1 { MemberName = memberName; Path = path; LineNumber = line; Inherited = false} str
static member P__(str, [<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string, [<CallerFilePath; Optional; DefaultParameterValue("")>] path: string, [<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int) = stringToBlock 2 { MemberName = memberName; Path = path; LineNumber = line; Inherited = false} str
static member P___(str, [<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string, [<CallerFilePath; Optional; DefaultParameterValue("")>] path: string, [<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int) = stringToBlock 3 { MemberName = memberName; Path = path; LineNumber = line; Inherited = false} str
static member P____(str, [<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string, [<CallerFilePath; Optional; DefaultParameterValue("")>] path: string, [<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int) = stringToBlock 4 { MemberName = memberName; Path = path; LineNumber = line; Inherited = false} str
static member P_____(str, [<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string, [<CallerFilePath; Optional; DefaultParameterValue("")>] path: string, [<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int) = stringToBlock 5 { MemberName = memberName; Path = path; LineNumber = line; Inherited = false} str
static member P______(str, [<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string, [<CallerFilePath; Optional; DefaultParameterValue("")>] path: string, [<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int) = stringToBlock 6 { MemberName = memberName; Path = path; LineNumber = line; Inherited = false} str
open type Operators
let fieldList =
[
"A"
"B"
"C"
]
let record name fieldList =
B [
C$"type {name} ="
C_"{"
for name in fieldList do
C__$"{name} : string"
C_"}"
]
let codeBlock = record "MyRecord" fieldList
codeBlock.MakeStringDebug()
//Result:
type MyRecord = // 141 record CodeGen.fsx
{ // 142 record CodeGen.fsx
A : string // 144 record CodeGen.fsx
B : string // 144 record CodeGen.fsx
C : string // 144 record CodeGen.fsx
}
///////
let myRecords =
B [
record "Record1" ["Cat"; "Dog"]
record "Record2" ["Mouse"; "Lamma"]
]
let myModule =
B [
C "module MyModule ="
B_ [myRecords]
]
myModule.MakeStringDebug()
//Result:
module MyModule = // 168 myModule CodeGen.fsx
type Record1 = // 141 record CodeGen.fsx
{ // 142 record CodeGen.fsx
Cat : string // 144 record CodeGen.fsx
Dog : string // 144 record CodeGen.fsx
} // 145 record CodeGen.fsx
type Record2 = // 141 record CodeGen.fsx
{ // 142 record CodeGen.fsx
Mouse : string // 144 record CodeGen.fsx
Lamma : string // 144 record CodeGen.fsx
} // 145 record CodeGen.fsx
///////
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment