Source generator
Generate C# source with raw strings and interpolation side by side.
module recordIndexerGenerator
-- Generate C# source for a string indexer over the properties of a record.
-- Raw single-quoted strings keep C# braces literal, and a doubled brace in a
-- double-quoted string is a literal brace next to interpolation.
type Property = (
name: string
type: string
isGettable: bool
isSettable: bool
)
type PartialRecord = (
identifier: string
declaration: string
namespace?: string
properties: list(Property)
)
def getterCases: list(Property) -> string = { properties ->
properties
\filter { .isGettable }
\map { p -> '"' ++ p.name ++ '" => ' ++ p.name ++ "," }
\String.join("\n ")
}
def setterCases: list(Property) -> string = { properties ->
properties
\filter { .isSettable }
\map { p -> 'case "' ++ p.name ++ '": ' ++ p.name ++ " = ({p.type}) value; break;" }
\String.join("\n ")
}
def indexer: PartialRecord -> string = { record ->
[
"public object this[string name]"
'{'
" get => name switch"
' {'
" {getterCases(record.properties)}"
" _ => throw new IndexOutOfRangeException(name)"
' };'
" set"
' {'
" switch (name)"
' {'
" {setterCases(record.properties)}"
" default: throw new IndexOutOfRangeException(name);"
' }'
' }'
'}'
] \String.join("\n")
}
export def generateSource: PartialRecord -> string = { record ->
def body = "partial {record.declaration}\n{{\n{indexer(record)}\n}}"
match record.namespace
| #some(ns) -> "using System;\n\nnamespace {ns}\n{{\n{body}\n}}"
| #none -> "using System;\n\n{body}"
}
@entry
def main = {
def person = PartialRecord(
identifier = "Person"
declaration = "record Person"
namespace = #some("Demo")
properties = [
Property(name = "Name", type = "string", isGettable = true, isSettable = true)
Property(name = "Age", type = "int", isGettable = true, isSettable = false)
]
)
println(generateSource(person))
}
This program lives in the repository as examples/source-generator.nyx.