type
Env* = ref object
parent: Env # --------------- Smart pointer to the environment that contains this one
freeVars: seq[Atom] # --------- Free variables, without binding
boundVars: Table[string, Atom] # Bound variables, have names given to them by statements
proc newEnv*(): Env =
# Create a new, empty environment
new(result)
result.parent = nil
result.freeVars = @[]
result.boundVars = initTable[string, Atom]()
type
F_Type = enum # https://nim-by-example.github.io/types/enums/
# This micro-language has the following types, all packaged into the every Atom
... # Other variant names here
FUNC, # Function
Atom = ref object
# The most basic and interchangeable unit of this LISP, Atom variants defined here
case kind: F_Type # the `kind` field is the discriminator
... # Other variant definitions here
of FUNC:
name: string # --------------------- Function name
args: OrderedTable[string, F_Type] # Input arguments and types
rtns: OrderedTable[string, F_Type] # Output returns and types
sorc: Atom # ----------------------- Actual code of the function
proc make_function*( fName: string, fArgs: OrderedTable[string, F_Type], fReturnVals: OrderedTable[string, F_Type], source: Atom ): Atom =
# Allocate and return a function
return Atom( kind: FUNC, name: fName, args: fArgs, rtns: fReturnVals, sorc: source )
proc empty_function*( funcName: string ): Atom =
# Return a Function in Name Only
new(result)
result = make_function( # Attempting to assign to fields as in Example 1 results in "Assigned to discriminator" error
funcName,
initOrderedTable[string, F_Type](),
initOrderedTable[string, F_Type](),
empty_atom()
)
Why can I not assign to the fields of the new(return) in empty_function in the same manner I did newEnv?
If I understood your question correctly, it's because you can't change the discriminant (branch) of an object variant at runtime. If you have something like:
new(result)
result.kind = FUNC
It'll try to change the kind at runtime, and fail, because this behaviour is not supported.
The correct way would be to assign a whole new object to the result:
new(result)
result[] = Atom(kind: FUNC, name: funcName, etc...)
proc empty_function*( funcName: string ): Atom =
# Return a Function in Name Only
new(result)
result = Atom( kind: FUNC )
result.name = funcName
proc empty_function*( funcName: string ): Atom =
# Return a Function in Name Only
result = Atom( kind: FUNC )
result.name = funcName