The Autofac programming language is a new .NET based language (really an interpreter) that uses only Autofac constructor injection. Every command, literal, expression, etc is a type defined by constructor parameters. Program execution is defined by the order that the constructor values are resolved in. Inversion of control has never been so accessible!
Values are the core data types in AFPL. A value is always retrieved from an IValueProvider
. To create a new value (including a new literal), simply create a new class that implements IValueProvider
and implement string Provide()
. This is modular and good separation of concerns - hardcoded literals inhibit testing, and now you can inject anything you want where previously you'd have to say Console.WriteLine("Hello World!")
.
Built-in values:
NewLineValueProvider
: provides a newline (specificallyEnvironment.NewLine
)ConcatValueProvider<TValueProvider1, TValueProvider2>
: provides the concatenation ofTValueProvider1
andTValueProvider2
StackValueProvider
: provides the top value from the program stack (without removing it)SecondStackValueProvider
: provides the second-from-the-top value from the program stack (without removing it or the top value)RandomValueProvider
: provides a random GUID
Commands tell the runtime what to do. You execute commands by placing them in order in the constructor of a type that is then resolved. If your program (the constructor signature) gets too long, you can easily break it apart by creating new types to inject.
Built-in commands:
NoOp
: does nothingPrintValue<TValueProvider>
: prints the value returned fromTValueProvider
PrintValueNewLine<TValueProvider>
: prints the value returned fromTValueProvider
followed by a newlinePushValue<TValueProvider>
: pushes the value returned fromTValueProvider
onto the program stackPopValue
: pops the top value from the program stackPrintStackValue
: prints the top value from the program stack without popping itReadLine
: reads a line from console input and places it onto the program stackIf<TCondition, TSuccess, TElse>
: if the conditional provided byTConditon
evaluates totrue
, then it resolves (executes)TSuccess
- otherwise it resolves (executes)TElse
While<TCondition, TBody>
: resolves (executes)TBody
as long asTCondition
evaluates totrue
Conditionals implement ICondition
. They have one must-implement method: bool Evaluate()
. A conditional is true
if Evaluate()
returns true
.
AFPL has the following built-in conditionals:
Equals<TLeftValueProvider, TRightValueProvider>
:true
if the value provided byTLeftValueProvider
equals the value provided byTRightValueProvider
Equals<TLeftValueProvider>
:true
if the value provided byTLeftValueProvider
is equal to the top value of the program stackStackEquals
:true
if the top value of the program stack is equal to the second-to-top value of the program stackNotEquals<TLeftValueProvider, TRightValueProvider>
:true
if the value provided byTLeftValueProvider
does not equal the value provided byTRightValueProvider
NotEquals<TLeftValueProvider>
:true
if the value provided byTLeftValueProvider
is not equal to the top value of the program stackStackNotEquals
:true
if the top value of the program stack is not equal to the second-to-top value of the program stackGreaterThan<TLeftValueProvider, TRightValueProvider>
:true
if the value provided byTLeftValueProvider
is greater than the value provided byTRightValueProvider
GreaterThan<TLeftValueProvider>
:true
if the value provided byTLeftValueProvider
is greater than to the top value of the program stackStackGreaterThan
:true
if the top value of the program stack is greater than the second-to-top value of the program stackLessThan<TLeftValueProvider, TRightValueProvider>
:true
if the value provided byTLeftValueProvider
is less than the value provided byTRightValueProvider
LessThan<TLeftValueProvider>
:true
if the value provided byTLeftValueProvider
is less than to the top value of the program stackStackLessThan
:true
if the top value of the program stack is less than the second-to-top value of the program stack
See IsAndrewProgram.cs for an example of a program, or OverUnderProgram for a full-fledged number guessing game.
Why not?