8 people like it.
Like the snippet!
Turtle procedures
Minimal Logo implementation using FParsec with support for procedures.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
|
module AST =
type name = string
type param = string
type arg = Number of int | Arg of param
type command =
| Forward of arg
| Left of arg
| Right of arg
| SetRandomPosition
| Repeat of arg * command list
| Call of name * arg list
| Proc of name * param list * command list
Windows Forms references
module Interpreter =
open AST
open System
open System.Drawing
open System.Windows.Forms
type Turtle = { X:float; Y:float; A:int }
let execute commands =
let procs = ref Map.empty
let width, height = 640, 480
let form = new Form (Text="Turtle", Width=width, Height=height)
let image = new Bitmap(width, height)
let picture = new PictureBox(Dock=DockStyle.Fill, Image=image)
do form.Controls.Add(picture)
let turtle = { X=float width/2.0; Y=float height/2.0; A = -90 }
use pen = new Pen(Color.Red)
let rand = let r = Random() in fun n -> r.Next(n) |> float
let drawLine (x1,y1) (x2,y2) =
use graphics = Graphics.FromImage(image)
graphics.DrawLine(pen,int x1,int y1,int x2, int y2)
let rec perform env turtle = function
| Forward arg ->
let r = float turtle.A * Math.PI / 180.0
let n = getValue env arg
let dx, dy = float n * cos r, float n * sin r
let x, y = turtle.X, turtle.Y
let x',y' = x + dx, y + dy
drawLine (x,y) (x',y')
{ turtle with X = x'; Y = y' }
| Left arg -> { turtle with A=turtle.A - getValue env arg }
| Right arg -> { turtle with A=turtle.A + getValue env arg }
| SetRandomPosition -> { turtle with X=rand width; Y=rand height }
| Repeat(arg,commands) ->
let n = getValue env arg
let rec repeat turtle = function
| 0 -> turtle
| n -> repeat (performAll env turtle commands) (n-1)
repeat turtle n
| Proc(name, ps, commands) -> procs := Map.add name (ps,commands) !procs; turtle
| Call(name,args) ->
let ps, commands = (!procs).[name]
if ps.Length <> args.Length then raise (ArgumentException("Parameter count mismatch"))
let xs = List.zip ps args
let env = xs |> List.fold (fun e (name,value) -> Map.add name value env) env
commands |> performAll env turtle
and performAll env turtle commands = commands |> List.fold (perform env) turtle
and getValue env = function
| Number n -> n
| Arg name -> getValue env (Map.tryFind name env).Value
performAll Map.empty turtle commands |> ignore
form.ShowDialog() |> ignore
FParsec references
module Parser =
open AST
open FParsec
let procs = ref []
let pidentifier =
let isIdentifierFirstChar c = isLetter c || c = '-'
let isIdentifierChar c = isLetter c || isDigit c || c = '-'
many1Satisfy2L isIdentifierFirstChar isIdentifierChar "identifier"
let pparam = pstring ":" >>. pidentifier
let pnumber = pfloat |>> fun n -> Number(int n)
let parg = pnumber <|> (pparam |>> fun a -> Arg(a))
let pforward =
(pstring "forward" <|> pstring "fd") >>. spaces1 >>. parg
|>> fun arg -> Forward(arg)
let pleft =
(pstring "left" <|> pstring "lt") >>. spaces1 >>. parg
|>> fun arg -> Left(arg)
let pright =
(pstring "right" <|> pstring "rt") >>. spaces1 >>. parg
|>> fun arg -> Right(arg)
let prandom =
pstring "set-random-position"
|>> fun _ -> SetRandomPosition
let prepeat, prepeatimpl = createParserForwardedToRef ()
let pcall, pcallimpl = createParserForwardedToRef ()
let pcommand = pforward <|> pleft <|> pright <|> prandom <|> prepeat <|> pcall
let updateCalls () =
pcallimpl :=
choice [
for (name,ps) in !procs ->
pstring name >>. spaces >>. (many parg .>> spaces)
|>> fun args -> Call(name,args)
]
updateCalls()
let block = between (pstring "[" .>> spaces) (pstring "]")
(sepEndBy pcommand spaces1)
prepeatimpl :=
pstring "repeat" >>. spaces1 >>. parg .>> spaces .>>. block
|>> fun (arg,commands) -> Repeat(arg, commands)
let pparams = many (pparam .>> spaces)
let pheader = pstring "to" >>. spaces1 >>. pidentifier .>> spaces1 .>>. pparams
let pbody = many (pcommand .>> spaces1)
let pfooter = pstring "end"
let pproc =
pheader .>>. pbody .>> pfooter
|>> fun ((name,ps),body) ->
procs := (name,ps)::!procs; updateCalls()
Proc(name, ps, body)
let parser =
spaces >>. (sepEndBy (pcommand <|> pproc) spaces1)
let parse code =
match run parser code with
| Success(result,_,_) -> result
| Failure(msg,_,_) -> failwith msg
let code = "
to square
repeat 4 [forward 50 right 90]
end
to flower
repeat 36 [right 10 square]
end
to garden :count
repeat :count [set-random-position flower]
end
garden 25
"
let program = Parser.parse code
Interpreter.execute program
|
type name = string
Full name: Script.AST.name
Multiple items
val string : value:'T -> string
Full name: Microsoft.FSharp.Core.Operators.string
--------------------
type string = System.String
Full name: Microsoft.FSharp.Core.string
type param = string
Full name: Script.AST.param
type arg =
| Number of int
| Arg of param
Full name: Script.AST.arg
union case arg.Number: int -> arg
Multiple items
val int : value:'T -> int (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.int
--------------------
type int = int32
Full name: Microsoft.FSharp.Core.int
--------------------
type int<'Measure> = int
Full name: Microsoft.FSharp.Core.int<_>
union case arg.Arg: param -> arg
type command =
| Forward of arg
| Left of arg
| Right of arg
| SetRandomPosition
| Repeat of arg * command list
| Call of name * arg list
| Proc of name * param list * command list
Full name: Script.AST.command
union case command.Forward: arg -> command
union case command.Left: arg -> command
union case command.Right: arg -> command
union case command.SetRandomPosition: command
union case command.Repeat: arg * command list -> command
type 'T list = List<'T>
Full name: Microsoft.FSharp.Collections.list<_>
union case command.Call: name * arg list -> command
union case command.Proc: name * param list * command list -> command
#if INTERACTIVE
#r "System.Drawing.dll"
#r "System.Windows.Forms.dll"
#endif
module AST
from Script
namespace System
namespace System.Drawing
namespace System.Windows
namespace System.Windows.Forms
type Turtle =
{X: float;
Y: float;
A: int;}
Full name: Script.Interpreter.Turtle
Turtle.X: float
Multiple items
val float : value:'T -> float (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.float
--------------------
type float = Double
Full name: Microsoft.FSharp.Core.float
--------------------
type float<'Measure> = float
Full name: Microsoft.FSharp.Core.float<_>
Turtle.Y: float
Turtle.A: int
val execute : commands:command list -> unit
Full name: Script.Interpreter.execute
val commands : command list
val procs : Map<name,(param list * command list)> ref
Multiple items
val ref : value:'T -> 'T ref
Full name: Microsoft.FSharp.Core.Operators.ref
--------------------
type 'T ref = Ref<'T>
Full name: Microsoft.FSharp.Core.ref<_>
Multiple items
module Map
from Microsoft.FSharp.Collections
--------------------
type Map<'Key,'Value (requires comparison)> =
interface IEnumerable
interface IComparable
interface IEnumerable<KeyValuePair<'Key,'Value>>
interface ICollection<KeyValuePair<'Key,'Value>>
interface IDictionary<'Key,'Value>
new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>
member Add : key:'Key * value:'Value -> Map<'Key,'Value>
member ContainsKey : key:'Key -> bool
override Equals : obj -> bool
member Remove : key:'Key -> Map<'Key,'Value>
...
Full name: Microsoft.FSharp.Collections.Map<_,_>
--------------------
new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>
val empty<'Key,'T (requires comparison)> : Map<'Key,'T> (requires comparison)
Full name: Microsoft.FSharp.Collections.Map.empty
val width : int
val height : int
val form : Form
Multiple items
type Form =
inherit ContainerControl
new : unit -> Form
member AcceptButton : IButtonControl with get, set
member Activate : unit -> unit
member ActiveMdiChild : Form
member AddOwnedForm : ownedForm:Form -> unit
member AllowTransparency : bool with get, set
member AutoScale : bool with get, set
member AutoScaleBaseSize : Size with get, set
member AutoScroll : bool with get, set
member AutoSize : bool with get, set
...
nested type ControlCollection
Full name: System.Windows.Forms.Form
--------------------
Form() : unit
Multiple items
namespace System.Drawing.Text
--------------------
namespace System.Text
val image : Bitmap
Multiple items
type Bitmap =
inherit Image
new : filename:string -> Bitmap + 11 overloads
member Clone : rect:Rectangle * format:PixelFormat -> Bitmap + 1 overload
member GetHbitmap : unit -> nativeint + 1 overload
member GetHicon : unit -> nativeint
member GetPixel : x:int * y:int -> Color
member LockBits : rect:Rectangle * flags:ImageLockMode * format:PixelFormat -> BitmapData + 1 overload
member MakeTransparent : unit -> unit + 1 overload
member SetPixel : x:int * y:int * color:Color -> unit
member SetResolution : xDpi:float32 * yDpi:float32 -> unit
member UnlockBits : bitmapdata:BitmapData -> unit
...
Full name: System.Drawing.Bitmap
--------------------
Bitmap(filename: string) : unit
(+0 other overloads)
Bitmap(stream: IO.Stream) : unit
(+0 other overloads)
Bitmap(original: Image) : unit
(+0 other overloads)
Bitmap(filename: string, useIcm: bool) : unit
(+0 other overloads)
Bitmap(type: Type, resource: string) : unit
(+0 other overloads)
Bitmap(stream: IO.Stream, useIcm: bool) : unit
(+0 other overloads)
Bitmap(width: int, height: int) : unit
(+0 other overloads)
Bitmap(original: Image, newSize: Size) : unit
(+0 other overloads)
Bitmap(width: int, height: int, format: Imaging.PixelFormat) : unit
(+0 other overloads)
Bitmap(width: int, height: int, g: Graphics) : unit
(+0 other overloads)
val picture : PictureBox
Multiple items
type PictureBox =
inherit Control
new : unit -> PictureBox
member AllowDrop : bool with get, set
member BorderStyle : BorderStyle with get, set
member CancelAsync : unit -> unit
member CausesValidation : bool with get, set
member ErrorImage : Image with get, set
member Font : Font with get, set
member ForeColor : Color with get, set
member Image : Image with get, set
member ImageLocation : string with get, set
...
Full name: System.Windows.Forms.PictureBox
--------------------
PictureBox() : unit
type DockStyle =
| None = 0
| Top = 1
| Bottom = 2
| Left = 3
| Right = 4
| Fill = 5
Full name: System.Windows.Forms.DockStyle
field DockStyle.Fill = 5
type Image =
inherit MarshalByRefObject
member Clone : unit -> obj
member Dispose : unit -> unit
member Flags : int
member FrameDimensionsList : Guid[]
member GetBounds : pageUnit:GraphicsUnit -> RectangleF
member GetEncoderParameterList : encoder:Guid -> EncoderParameters
member GetFrameCount : dimension:FrameDimension -> int
member GetPropertyItem : propid:int -> PropertyItem
member GetThumbnailImage : thumbWidth:int * thumbHeight:int * callback:GetThumbnailImageAbort * callbackData:nativeint -> Image
member Height : int
...
nested type GetThumbnailImageAbort
Full name: System.Drawing.Image
property Control.Controls: Control.ControlCollection
Control.ControlCollection.Add(value: Control) : unit
val turtle : Turtle
val pen : Pen
Multiple items
type Pen =
inherit MarshalByRefObject
new : color:Color -> Pen + 3 overloads
member Alignment : PenAlignment with get, set
member Brush : Brush with get, set
member Clone : unit -> obj
member Color : Color with get, set
member CompoundArray : float32[] with get, set
member CustomEndCap : CustomLineCap with get, set
member CustomStartCap : CustomLineCap with get, set
member DashCap : DashCap with get, set
member DashOffset : float32 with get, set
...
Full name: System.Drawing.Pen
--------------------
Pen(color: Color) : unit
Pen(brush: Brush) : unit
Pen(color: Color, width: float32) : unit
Pen(brush: Brush, width: float32) : unit
type Color =
struct
member A : byte
member B : byte
member Equals : obj:obj -> bool
member G : byte
member GetBrightness : unit -> float32
member GetHashCode : unit -> int
member GetHue : unit -> float32
member GetSaturation : unit -> float32
member IsEmpty : bool
member IsKnownColor : bool
...
end
Full name: System.Drawing.Color
property Color.Red: Color
val rand : (int -> float)
val r : Random
Multiple items
type Random =
new : unit -> Random + 1 overload
member Next : unit -> int + 2 overloads
member NextBytes : buffer:byte[] -> unit
member NextDouble : unit -> float
Full name: System.Random
--------------------
Random() : unit
Random(Seed: int) : unit
val n : int
Random.Next() : int
Random.Next(maxValue: int) : int
Random.Next(minValue: int, maxValue: int) : int
val drawLine : (float * float -> float * float -> unit)
val x1 : float
val y1 : float
val x2 : float
val y2 : float
val graphics : Graphics
type Graphics =
inherit MarshalByRefObject
member AddMetafileComment : data:byte[] -> unit
member BeginContainer : unit -> GraphicsContainer + 2 overloads
member Clear : color:Color -> unit
member Clip : Region with get, set
member ClipBounds : RectangleF
member CompositingMode : CompositingMode with get, set
member CompositingQuality : CompositingQuality with get, set
member CopyFromScreen : upperLeftSource:Point * upperLeftDestination:Point * blockRegionSize:Size -> unit + 3 overloads
member Dispose : unit -> unit
member DpiX : float32
...
nested type DrawImageAbort
nested type EnumerateMetafileProc
Full name: System.Drawing.Graphics
Graphics.FromImage(image: Image) : Graphics
Graphics.DrawLine(pen: Pen, pt1: Point, pt2: Point) : unit
Graphics.DrawLine(pen: Pen, pt1: PointF, pt2: PointF) : unit
Graphics.DrawLine(pen: Pen, x1: int, y1: int, x2: int, y2: int) : unit
Graphics.DrawLine(pen: Pen, x1: float32, y1: float32, x2: float32, y2: float32) : unit
val perform : (Map<param,arg> -> Turtle -> command -> Turtle)
val env : Map<param,arg>
Multiple items
val arg : arg
--------------------
type arg =
| Number of int
| Arg of param
Full name: Script.AST.arg
val r : float
type Math =
static val PI : float
static val E : float
static member Abs : value:sbyte -> sbyte + 6 overloads
static member Acos : d:float -> float
static member Asin : d:float -> float
static member Atan : d:float -> float
static member Atan2 : y:float * x:float -> float
static member BigMul : a:int * b:int -> int64
static member Ceiling : d:decimal -> decimal + 1 overload
static member Cos : d:float -> float
...
Full name: System.Math
field Math.PI = 3.14159265359
val getValue : (Map<param,arg> -> arg -> int)
val dx : float
val dy : float
val cos : value:'T -> 'T (requires member Cos)
Full name: Microsoft.FSharp.Core.Operators.cos
val sin : value:'T -> 'T (requires member Sin)
Full name: Microsoft.FSharp.Core.Operators.sin
val x : float
val y : float
val x' : float
val y' : float
val repeat : (Turtle -> int -> Turtle)
val performAll : (Map<param,arg> -> Turtle -> command list -> Turtle)
Multiple items
val name : name
--------------------
type name = string
Full name: Script.AST.name
val ps : param list
val add : key:'Key -> value:'T -> table:Map<'Key,'T> -> Map<'Key,'T> (requires comparison)
Full name: Microsoft.FSharp.Collections.Map.add
val args : arg list
property List.Length: int
val raise : exn:Exception -> 'T
Full name: Microsoft.FSharp.Core.Operators.raise
Multiple items
type ArgumentException =
inherit SystemException
new : unit -> ArgumentException + 4 overloads
member GetObjectData : info:SerializationInfo * context:StreamingContext -> unit
member Message : string
member ParamName : string
Full name: System.ArgumentException
--------------------
ArgumentException() : unit
ArgumentException(message: string) : unit
ArgumentException(message: string, innerException: exn) : unit
ArgumentException(message: string, paramName: string) : unit
ArgumentException(message: string, paramName: string, innerException: exn) : unit
val xs : (param * arg) list
Multiple items
module List
from Microsoft.FSharp.Collections
--------------------
type List<'T> =
| ( [] )
| ( :: ) of Head: 'T * Tail: 'T list
interface IEnumerable
interface IEnumerable<'T>
member Head : 'T
member IsEmpty : bool
member Item : index:int -> 'T with get
member Length : int
member Tail : 'T list
static member Cons : head:'T * tail:'T list -> 'T list
static member Empty : 'T list
Full name: Microsoft.FSharp.Collections.List<_>
val zip : list1:'T1 list -> list2:'T2 list -> ('T1 * 'T2) list
Full name: Microsoft.FSharp.Collections.List.zip
val fold : folder:('State -> 'T -> 'State) -> state:'State -> list:'T list -> 'State
Full name: Microsoft.FSharp.Collections.List.fold
val e : Map<param,arg>
Multiple items
val name : param
--------------------
type name = string
Full name: Script.AST.name
val value : arg
val tryFind : key:'Key -> table:Map<'Key,'T> -> 'T option (requires comparison)
Full name: Microsoft.FSharp.Collections.Map.tryFind
val ignore : value:'T -> unit
Full name: Microsoft.FSharp.Core.Operators.ignore
Form.ShowDialog() : DialogResult
Form.ShowDialog(owner: IWin32Window) : DialogResult
#if INTERACTIVE
#r @"..\..\packages\FParsec.1.0.1\lib\net40-client\FParsecCS.dll"
#r @"..\..\packages\FParsec.1.0.1\lib\net40-client\FParsec.dll"
#endif
namespace FParsec
val procs : (string * string list) list ref
Full name: Script.Parser.procs
val pidentifier : Parser<string,unit>
Full name: Script.Parser.pidentifier
val isIdentifierFirstChar : (char -> bool)
val c : char
val isLetter : char -> bool
Full name: FParsec.CharParsers.isLetter
val isIdentifierChar : (char -> bool)
val isDigit : char -> bool
Full name: FParsec.CharParsers.isDigit
val many1Satisfy2L : (char -> bool) -> (char -> bool) -> string -> Parser<string,'u>
Full name: FParsec.CharParsers.many1Satisfy2L
val pparam : Parser<string,unit>
Full name: Script.Parser.pparam
val pstring : string -> Parser<string,'u>
Full name: FParsec.CharParsers.pstring
val pnumber : Parser<arg,unit>
Full name: Script.Parser.pnumber
val pfloat : Parser<float,'u>
Full name: FParsec.CharParsers.pfloat
val n : float
val parg : Parser<arg,unit>
Full name: Script.Parser.parg
val a : string
val pforward : Parser<command,unit>
Full name: Script.Parser.pforward
val spaces1 : Parser<unit,'u>
Full name: FParsec.CharParsers.spaces1
val pleft : Parser<command,unit>
Full name: Script.Parser.pleft
val pright : Parser<command,unit>
Full name: Script.Parser.pright
val prandom : Parser<command,unit>
Full name: Script.Parser.prandom
val prepeat : Parser<command,unit>
Full name: Script.Parser.prepeat
val prepeatimpl : Parser<command,unit> ref
Full name: Script.Parser.prepeatimpl
val createParserForwardedToRef : unit -> Parser<'a,'u> * Parser<'a,'u> ref
Full name: FParsec.Primitives.createParserForwardedToRef
val pcall : Parser<command,unit>
Full name: Script.Parser.pcall
val pcallimpl : Parser<command,unit> ref
Full name: Script.Parser.pcallimpl
val pcommand : Parser<command,unit>
Full name: Script.Parser.pcommand
val updateCalls : unit -> unit
Full name: Script.Parser.updateCalls
val choice : seq<Parser<'a,'u>> -> Parser<'a,'u>
Full name: FParsec.Primitives.choice
Multiple items
val name : string
--------------------
type name = string
Full name: Script.AST.name
val ps : string list
val spaces : Parser<unit,'u>
Full name: FParsec.CharParsers.spaces
val many : Parser<'a,'u> -> Parser<'a list,'u>
Full name: FParsec.Primitives.many
val block : Parser<command list,unit>
Full name: Script.Parser.block
val between : Parser<'a,'u> -> Parser<'b,'u> -> Parser<'c,'u> -> Parser<'c,'u>
Full name: FParsec.Primitives.between
val sepEndBy : Parser<'a,'u> -> Parser<'b,'u> -> Parser<'a list,'u>
Full name: FParsec.Primitives.sepEndBy
val pparams : Parser<string list,unit>
Full name: Script.Parser.pparams
val pheader : Parser<(string * string list),unit>
Full name: Script.Parser.pheader
val pbody : Parser<command list,unit>
Full name: Script.Parser.pbody
val pfooter : Parser<string,unit>
Full name: Script.Parser.pfooter
val pproc : Parser<command,unit>
Full name: Script.Parser.pproc
val body : command list
val parser : Parser<command list,unit>
Full name: Script.Parser.parser
val parse : code:string -> command list
Full name: Script.Parser.parse
val code : string
val run : Parser<'Result,unit> -> string -> ParserResult<'Result,unit>
Full name: FParsec.CharParsers.run
union case ParserResult.Success: 'Result * 'UserState * Position -> ParserResult<'Result,'UserState>
val result : command list
union case ParserResult.Failure: string * ParserError * 'UserState -> ParserResult<'Result,'UserState>
val msg : string
val failwith : message:string -> 'T
Full name: Microsoft.FSharp.Core.Operators.failwith
val code : string
Full name: Script.code
val program : AST.command list
Full name: Script.program
module Parser
from Script
val parse : code:string -> AST.command list
Full name: Script.Parser.parse
module Interpreter
from Script
val execute : commands:AST.command list -> unit
Full name: Script.Interpreter.execute
More information