Guest User

Untitled

a guest
Dec 6th, 2018
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
F# 6.06 KB | None | 0 0
  1. open System
  2. open System.Numerics
  3.  
  4. //// Tokenizer
  5.  
  6. type Token =
  7.     | Open | Close
  8.     | Number of string
  9.     | String of string
  10.     | Symbol of string
  11.  
  12. let tokenize source =
  13.     let rec token acc = function
  14.         | ')' :: _ as t -> acc, t                           // closing paren terminates
  15.         | w :: t when Char.IsWhiteSpace(w) -> acc, t        // whitespace terminates
  16.         | [] -> acc, []                                     // end of list terminates
  17.         | c :: t -> token (acc + (c.ToString())) t          // otherwise accumulate chars
  18.  
  19.     let rec stringToken acc = function
  20.         | '"' :: t -> acc, t                                // closing quote terminates
  21.         | c   :: t -> stringToken (acc + c.ToString()) t    // otherwise accumulate characters
  22.         | _ -> failwith "Malformed string."
  23.  
  24.     let rec tokenize2 acc = function
  25.         | w :: t when Char.IsWhiteSpace(w) -> tokenize2 acc t   // skip whitespace
  26.  
  27.         | '(' :: t -> tokenize2 (Open :: acc) t
  28.         | ')' :: t -> tokenize2 (Close :: acc) t
  29.  
  30.         | '"' :: t ->                                       // start of string
  31.             let s, t2 = stringToken "" t
  32.             tokenize2 (Token.String(s) :: acc) t2
  33.  
  34.         | '-' :: d :: t when Char.IsDigit(d) ->             // start of negative number
  35.             let n, t2 = token ("-" + d.ToString()) t
  36.             tokenize2 (Token.Number(n) :: acc) t2
  37.  
  38.         | '+' :: d :: t | d :: t when Char.IsDigit(d) ->    // start of positive number
  39.             let n, t2 = token (d.ToString()) t
  40.             tokenize2 (Token.Number(n) :: acc) t2
  41.  
  42.         | s :: t ->                                         // otherwise start of symbol
  43.             let s, t2 = token (s.ToString()) t
  44.             tokenize2 (Token.Symbol(s) :: acc) t2
  45.  
  46.         | [] -> List.rev acc                                // end of list terminates
  47.  
  48.     tokenize2 [] source
  49.  
  50.  
  51. //// Parser
  52.  
  53. type Expression =
  54.     | Number of BigInteger
  55.     | String of string
  56.     | Symbol of string
  57.     | List of Expression list
  58.     | Function of (Expression list -> Expression)
  59.     | Special of (Expression list -> Expression)
  60.  
  61. let parse source =
  62.     let map = function
  63.         | Token.Number(n) -> Expression.Number(BigInteger.Parse(n))
  64.         | Token.String(s) -> Expression.String(s)
  65.         | Token.Symbol(s) -> Expression.Symbol(s)
  66.         | _ -> failwith "Syntax error."
  67.  
  68.     let rec parse2 acc = function
  69.         | Open :: t ->
  70.             let e, t2 = parse2 [] t
  71.             parse2 (List(e) :: acc) t2
  72.         | Close :: t -> (List.rev acc), t
  73.         | h :: t -> parse2 ((map h) :: acc) t
  74.         | [] -> (List.rev acc), []
  75.  
  76.     let result, _ = parse2 [] (tokenize source)
  77.     result
  78.  
  79.  
  80. //// Printer
  81.  
  82. let rec print = function
  83.     | List(list) -> "(" + String.Join(" ", (List.map print list)) + ")"
  84.     | String(s) ->
  85.         let escape = String.collect (function '"' -> "\\\"" | c -> c.ToString()) // escape quotes
  86.         "\"" + (escape s) + "\""
  87.     | Symbol(s) -> s
  88.     | Number(n) -> n.ToString()
  89.     | Function(_) | Special(_) -> "Function"
  90.  
  91.  
  92. //// Primitives, Eval/Apply
  93.  
  94. let Multiply args =
  95.     let prod a = function
  96.         | Number(b) -> a * b
  97.         | _ -> failwith "Malformed multiplication argument."
  98.     Number(List.fold prod 1I args)
  99.  
  100. let Sum args =
  101.     let add a = function
  102.         | Number(b) -> a + b
  103.         | _ -> failwith "Malformed addition argument."
  104.     Number(List.fold add 0I args)
  105.  
  106. let Subtract = function
  107.     | [Number(n)] -> Number(-n) // (- a) == –a
  108.     | Number(n) :: ns ->        // (- a b c) == a - b – c,  we can't fold because the first needs to be positive
  109.         let sub a = function Number(b) -> a - b | _ -> failwith "Malformed subtraction argument."
  110.         Number(List.fold sub n ns)
  111.     | _ -> failwith "Malformed subtraction."
  112.  
  113. let rec If = function
  114.     | [condition; t; f] ->
  115.         match eval condition with
  116.         | List([]) | String("") -> eval f // empty list or empty string is false
  117.         | Number(n) when n = 0I -> eval f // zero is false
  118.         | _ -> eval t // everything else is true
  119.     | _ -> failwith "Malformed 'if'."
  120.  
  121. and environment =
  122.     Map.ofList [
  123.         "*", Function(Multiply)
  124.         "+", Function(Sum)
  125.         "-", Function(Subtract)
  126.         "if", Special(If)]
  127.  
  128. and eval expression =
  129.     match expression with
  130.     | Number(_) as lit -> lit
  131.     | String(_) as lit -> lit
  132.     | Symbol(s) -> environment.[s]
  133.     | List([]) -> List([])
  134.     | List(h :: t) ->
  135.         match eval h with
  136.         | Function(f) -> apply f t
  137.         | Special(f) -> f t
  138.         | _ -> failwith "Malformed expression."
  139.     | _ -> failwith "Malformed expression."
  140.  
  141. and apply fn args = fn (List.map eval args)
  142.  
  143.  
  144. //// REPL
  145.  
  146. let rep = List.ofSeq >> parse >> List.head >> eval >> print
  147.  
  148. let rec repl output =
  149.     printf "%s\n> " output
  150.     try Console.ReadLine() |> rep |> repl
  151.     with ex -> repl ex.Message
  152.  
  153.  
  154. //// Test
  155.  
  156. let case source expected =
  157.     try
  158.         let output = rep source
  159.         if output = expected then
  160.             printf "TEST PASSED\n"
  161.         else
  162.             printf "TEST FAILED: %s (Expected: %s, Actual: %s)\n" source expected output
  163.     with _ -> printf "TEST CRASHED: %s\n" source
  164.  
  165. case "1" "1"                        // numbers
  166. case "+1" "1"                       // explicit positive numbers
  167. case "-1" "-1"                      // negative numbers
  168. case "\"hello\"" "\"hello\""        // strings
  169. case "(*)" "1"                      // multiplication
  170. case "(* 2 3)" "6"                  // multiplication
  171. case "(* 2 3 4)" "24"               // multiplication
  172. case "(-)" "0"                      // strange subtraction case
  173. case "(- 10)" "-10"                 // negation
  174. case "(- 10 2)" "8"                 // subtraction
  175. case "(- 10 2 3)" "5"               // subtraction
  176. case "(if (* 0 1) 10 20)" "20"      // if true
  177. case "(if (* 1 1) 10 20)" "10"      // if false
  178. case "(if (* 1 1) 10 bomb)" "10"    // if (special form)
  179. case "(* 1234567890987654321 1234567890987654321)" "1524157877457704723228166437789971041" // bigint math
  180.  
  181. repl ""
Add Comment
Please, Sign In to add comment