fparsec hands on - f#unctional londoners 2014

30
FPARSEC HANDS ON Phillip Trelford F#unctional Londoners, 2014

Upload: phillip-trelford

Post on 27-Nov-2014

2.668 views

Category:

Software


0 download

DESCRIPTION

Accompanying presentation to FParsec Hands On Session at F#unctional Londoners meetup held at Skills Matter 2014.

TRANSCRIPT

Page 1: FParsec Hands On -  F#unctional Londoners 2014

FPARSEC HANDS ONPhillip TrelfordF#unctional Londoners, 2014

Page 2: FParsec Hands On -  F#unctional Londoners 2014
Page 3: FParsec Hands On -  F#unctional Londoners 2014

INTERNAL DSLS - EXAMPLES

Fake

#r "tools/FAKE/tools/FakeLib.dll" open Fake

Target "Test" (fun _ -> trace "Testing stuff..." )

Target "Deploy" (fun _ -> trace "Heavy deploy action" )

"Test" // define the dependencies ==> "Deploy"

Run "Deploy"

Canopy

"starting a game of 2048" &&& fun _ ->

start firefox

url "http://gabrielecirulli.github.io/2048/"

let score = element ".score-container" printfn "Score %s" score.Text

while not(lost()) && not (won()) do press up press right press left press up

Page 4: FParsec Hands On -  F#unctional Londoners 2014

EXTERNAL DSLS IN ACTION

1. Domain-specific syntax

2. Proprietary encodings

3. Custom execution environments

Page 5: FParsec Hands On -  F#unctional Londoners 2014

BUILDING EXTERNAL DSLS

Abstract Syntax Tree (AST)

Parse

Execute

Page 6: FParsec Hands On -  F#unctional Londoners 2014

PARSING OPTIONS

Hand rolled

• Regex• Active

Patterns

FParsec

• Combinators

• Monadic

FsLex, FsYacc

• Lexer• Parser

Page 7: FParsec Hands On -  F#unctional Londoners 2014

FPARSECFParsec Hands OnF#unctional Londoners 2014

Page 8: FParsec Hands On -  F#unctional Londoners 2014

THINGS YOU SHOULD NEVER DO Custom Operators

Funny picture

Page 9: FParsec Hands On -  F#unctional Londoners 2014

FUNSCRIPT’S TYPESCRIPT PARSERFParsec

let interfaceDeclaration =

str_ws "interface" >>. identifier .>>. typeParams

.>>. interfaceExtendsClause .>>. objectType

|>> fun (((id, tps), ex), t) ->

InterfaceDeclaration(id, tps, ex, t)

TypeScript Definition

interface JQueryKeyEventObject

extends JQueryInputEventObject {

char: any;

charCode: number;

key: any;

keyCode: number;

}

Page 10: FParsec Hands On -  F#unctional Londoners 2014

FPARSEC TUTORIAL

open FParsec

let test p str = match run p str with | Success(result, _, _) -> printfn "Success: %A" result | Failure(errorMsg, _, _) -> printfn "Failure: %s" errorMsg

test pfloat "1.25"test pfloat "1.25E 2"

let str s = pstring slet floatBetweenBrackets = str "[" >>. pfloat .>> str "]"

test floatBetweenBrackets "[1.0]"test floatBetweenBrackets "[]"test floatBetweenBrackets "[1.0]"

Page 11: FParsec Hands On -  F#unctional Londoners 2014

PARSING OPERATORS

// we set up an operator precedence parser for parsing the arithmetic expressions

let opp = new OperatorPrecedenceParser<float,unit,unit>()

let expr = opp.ExpressionParser

opp.TermParser <- number <|> between (str_ws "(") (str_ws ")") expr

// operator definitions follow the schema

// operator type, string, trailing whitespace parser, precedence, associativity, function to apply

opp.AddOperator(InfixOperator("+", ws, 1, Associativity.Left, (+)))

opp.AddOperator(InfixOperator("-", ws, 1, Associativity.Left, (-)))

opp.AddOperator(InfixOperator("*", ws, 2, Associativity.Left, (*)))

opp.AddOperator(InfixOperator("/", ws, 2, Associativity.Left, (/)))

opp.AddOperator(InfixOperator("^", ws, 3, Associativity.Right, fun x y -> System.Math.Pow(x, y)))

opp.AddOperator(PrefixOperator("-", ws, 4, true, fun x -> -x))

Page 12: FParsec Hands On -  F#unctional Londoners 2014

TURTLES ALL THE WAY DOWN

FParsec Hands OnF#unctional Londoners 2014

Page 13: FParsec Hands On -  F#unctional Londoners 2014

TURTLE LANGUAGE

repeat 10

[right 36 repeat 5

[forward 54 right 72]]

Page 14: FParsec Hands On -  F#unctional Londoners 2014

TURTLE AST

module AST

type arg = int

type command =

| Forward of arg

| Turn of arg

| Repeat of arg * command list

Page 15: FParsec Hands On -  F#unctional Londoners 2014

TURTLE PARSER: FORWARD AND TURN open AST

open FParsec

let pforward =

pstring "forward" >>. spaces1 >>. pfloat

|>> fun x -> Forward(int x)

let pleft =

pstring "left" >>. spaces1 >>. pfloat

|>> fun x -> Turn(int -x)

let pright =

pstring "right" >>. spaces1 >>. pfloat

|>> fun x -> Turn(int x)

Page 16: FParsec Hands On -  F#unctional Londoners 2014

TURTLE PARSER: REPEAT COMMANDlet pcommand = pforward <|> pleft <|> pright

let block = between (pstring "[") (pstring "]") (many1 (pcommand .>> spaces))

let prepeat =

pstring "repeat" >>. spaces1 >>. pfloat .>> spaces .>>. block

|>> fun (n,commands) -> Repeat(int n, commands)

Page 17: FParsec Hands On -  F#unctional Londoners 2014

TURTLE PARSER: FORWARD REPEATlet prepeat, prepeatimpl = createParserForwardedToRef ()

let pcommand = pforward <|> pleft <|> pright <|> prepeat

let block = between (pstring "[") (pstring "]") (many1 (pcommand .>> spaces))

prepeatimpl :=

pstring "repeat" >>. spaces1 >>. pfloat .>> spaces .>>. block

|>> fun (n,commands) -> Repeat(int n, commands)

Page 18: FParsec Hands On -  F#unctional Londoners 2014

TURTLE INTERPRETER: PATTERN MATCHINGlet rec perform turtle = function | Forward n -> let r = float turtle.A * Math.PI / 180.0 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' } | Turn n -> { turtle with A = turtle.A + n } | Repeat (n, commands) -> let rec repeat turtle = function | 0 -> turtle | n -> repeat (performAll turtle commands) (n-1) repeat turtle n and performAll = List.fold perform

Page 19: FParsec Hands On -  F#unctional Londoners 2014

TURTLE: PROCEDURES

to square

repeat 4 [forward 50 right 90]

end

to flower

repeat 36 [right 10 square]

end

to garden

repeat 25 [set-random-position flower]

end

garden

Page 20: FParsec Hands On -  F#unctional Londoners 2014

SMALL BASIC COMPILER

FParsec Hands OnF#unctional Londoners 2014

Page 21: FParsec Hands On -  F#unctional Londoners 2014

SMALL BASIC IDEFParsec Hands OnF#unctional Londoners 2014

Page 22: FParsec Hands On -  F#unctional Londoners 2014

SMALL BASIC SAMPLE

Sub Init

gw = 598

gh = 428

GraphicsWindow.BackgroundColor = "DodgerBlue"

GraphicsWindow.Width = gw

GraphicsWindow.Height = gh

color = "1=Orange;2=Cyan;3=Lime;"

size = "1=20;2=16;3=12;"

passed = 0

cd = "False" ' collision detected

EndSub

Page 23: FParsec Hands On -  F#unctional Londoners 2014

SMALL BASIC AST

/// Small Basic expressiontype expr = | Literal of value | Identifier of identifier | GetAt of location | Func of invoke | Neg of expr | Arithmetic of expr * arithmetic * expr | Comparison of expr * comparison * expr | Logical of expr * logical * expr

/// Small Basic instruction type instruction = | Assign of assign | SetAt of location * expr | PropertySet of string * string * expr

| Action of invoke | For of assign * expr * expr | EndFor | If of expr | ElseIf of expr | Else | EndIf | While of expr | EndWhile | Sub of identifier * string list | EndSub | Label of label | Goto of label

Page 24: FParsec Hands On -  F#unctional Londoners 2014

SMALL BASIC PARSER

/// > For i = 1 To 100 Step 2

let pfor =

let pfrom = str_ws1 "For" >>. pset

let pto = str_ws1 "To" >>. pexpr

let pstep = str_ws1 "Step" >>. pexpr

let toStep = function None -> Literal(Int(1)) | Some s -> s

pipe3 pfrom pto (opt pstep) (fun f t s -> For(f, t, toStep s))

let pendfor = str_ws "EndFor" |>> (fun _ -> EndFor)

Page 25: FParsec Hands On -  F#unctional Londoners 2014

SMALL BASIC COMPILER: GOTO| Goto(name) ->

let label = obtainLabel il name

il.Emit(OpCodes.Br, label)

| Label(name) ->

let label = obtainLabel il name

il.MarkLabel(label)

Page 26: FParsec Hands On -  F#unctional Londoners 2014

RESOURCESFParsec Hands OnF#unctional Londoners 2014

Page 27: FParsec Hands On -  F#unctional Londoners 2014

F# KOANS

[<Koan>]let SquareEvenNumbersWithPipelineOperator() =(* In F#, you can use the pipeline operator to get the benefit of the parens style with the readability of the statement style. *)

let result = [0..5] |> List.filter isEven |> List.map square AssertEquality result __

Page 28: FParsec Hands On -  F#unctional Londoners 2014

TRYFSHARP.ORG

Page 29: FParsec Hands On -  F#unctional Londoners 2014

F# BOOKS