open Combinator
type Color =
| Red
| Green
| Blue
| Purple
type Expr =
| Line of Color
| Repeat of int * Expr
type Line = Color
type Exprs = Expr list
let CANVAS_HEIGHT = 400
let CANVAS_WIDTH = 400
let SVG_PREFIX = "\n"
(*
* ::=
* | repeat
* |
* ::= line
* ::= +
* ::= 0 | 1 | 2 | … | 9
* ::= red | green | blue | purple
*)
let pad p = pbetween pws0 p pws0
let color =
(pstr "red" |>> fun _ -> Red) <|>
(pstr "green" |>> fun _ -> Green) <|>
(pstr "blue" |>> fun _ -> Blue) <|>
(pstr "purple" |>> fun _ -> Purple)
let line = pleft (pad color) (pad (pstr "line")) |>> Line
let n = pmany1 pdigit |>> stringify |>> int
let repeat = pright (pad (pstr "repeat")) (pseq n line Repeat)
let expr = pmany0 (line <|> repeat)
let grammar = pleft expr peof
let parse (i: string) : Exprs option =
let input = prepare i
match grammar input with
| Success (ast, _) -> Some ast
| Failure _ -> None
let evalColor (c: Color) : string =
match c with
| Red -> "rgb(255,0,0)"
| Green -> "rgb(0,255,0)"
| Blue -> "rgb(0,0,255)"
| Purple -> "rgb(128,8,165)"
let rec evalExpr (e: Expr) : string =
match e with
| Line c ->
// draw a random line
let r = new System.Random()
let start_x = r.Next CANVAS_WIDTH
let start_y = r.Next CANVAS_HEIGHT
let end_x = r.Next CANVAS_WIDTH
let end_y = r.Next CANVAS_HEIGHT
// get the color
let rgb = evalColor c
// generate SVG
$""
| Repeat (n, x) ->
let svg_list = [0..n-1] |> List.map (fun _ -> evalExpr x)
System.String.Join("\n", svg_list)
let rec eval (es: Exprs) : string =
let ls_svgs = es |> List.map evalExpr
let inner_svg = System.String.Join("\n", ls_svgs)
SVG_PREFIX + inner_svg + SVG_SUFFIX
let usage() =
printfn "Usage: dotnet run "
exit 1
[]
let main args =
if Array.length args <> 1 then
printfn "ERROR: Must provide an input line program."
usage()
let filename = args[0]
if not (System.IO.File.Exists filename) then
printfn $"ERROR: Cannot find '{filename}'."
usage()
let input = System.IO.File.ReadAllText filename
let ast_maybe = parse input
match ast_maybe with
| Some ast -> printfn "%s" (eval ast)
| None -> printfn "Invalid linelang"
0