open System type Expr = | StringVal of string | NumVal of int | SeqOp of Expr*Expr | PrintOp of Expr | PlusOp of Expr*Expr | Variable of string | AssignOp of string*Expr type Value = | ValueString of string | ValueNum of int type Context = Map let parse s = SeqOp( AssignOp("x", NumVal(1)), SeqOp( PrintOp( StringVal("Hello ") ), SeqOp( PrintOp( StringVal("every ") ), SeqOp( PrintOp( PlusOp( NumVal(0), Variable("x") ) ), PrintOp( StringVal("\n") ) ) ) ) ) let valueprint v = match v with | ValueString s -> s | ValueNum n -> n.ToString() let rec prettyprint e : string = match e with | StringVal s -> "\"" + s + "\"" | NumVal n -> n.ToString() | Variable v -> v | SeqOp(e1, e2) -> prettyprint e1 + ";\n" + prettyprint e2 | PrintOp e' -> "print(" + prettyprint e' + ")" | PlusOp(e1, e2) -> prettyprint e1 + " + " + prettyprint e2 | AssignOp(s, e') -> s + " := " + prettyprint e' let rec eval e ctx : Expr*Context = match e with | StringVal s -> e, ctx | NumVal n -> e, ctx | Variable v -> match ctx.[v] with | ValueString s -> StringVal s, ctx | ValueNum n -> NumVal n, ctx | SeqOp(e1, e2) -> let (e1', ctx1) = eval e1 ctx let (e2', ctx2) = eval e2 ctx1 e2', ctx2 | PrintOp e' -> let (e'', ctx1) = eval e' ctx match e'' with | StringVal s -> printf "%s" s | NumVal n -> printf "%d" n | Variable v -> let value = ctx.[v] printf "%s" (valueprint value) | _ -> failwith "Not printable!" e'', ctx1 | PlusOp(e1, e2) -> let (e1', ctx1) = eval e1 ctx let (e2', ctx2) = eval e2 ctx1 match e1', e2' with | NumVal n1, NumVal n2 -> NumVal(n1 + n2), ctx2 | _ -> failwith "Not a number!" | AssignOp(s, e') -> let (e'', ctx1) = eval e' ctx match e'' with | NumVal n -> let ctx1 = Map.add s (ValueNum n) ctx e'', ctx1 | StringVal sv -> let ctx1 = Map.add s (ValueString sv) ctx e'', ctx1 | _ -> failwith "Not assignable!" [] let main argv = if Array.length argv <> 1 then printfn "Usage: dotnet run " exit 1 let ast = parse argv.[0] printfn "Program:\n%s" (prettyprint ast) printfn "\nOutput:" eval ast Map.empty |> ignore 0