Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
67 lines (58 sloc) 2.75 KB
// mtscheme
// Copyright (c) 2010 Martin Trojer <martin.trojer@gmail.com>
//
// inspired by
// http://blogs.msdn.com/b/ashleyf/archive/2010/09/24/fscheme-0-0-0.aspx
namespace mtscheme
module parser =
open System
open mtscheme.interpreter
type Token =
| TOpen | TClose
| TNumber of string
| TString of string
| TSymbol of string
let tokenize source =
let rec string acc = function
| '\\' :: '"' :: t -> string (acc + "\"") t // escaped quote becomes quote
| '"' :: t -> acc, t // closing quote terminates
| c :: t -> string (acc + (c.ToString())) t // otherwise accumulate chars
| _ -> failwith "malformed string"
let rec token acc = function
| (')' :: _) as t -> acc, t // closing paren terminates
| w :: t when Char.IsWhiteSpace(w) -> acc, t // whitespace terminates
| [] -> acc, [] // end of list terminates
| c :: t -> token (acc + (c.ToString())) t // otherwise accumulate chars
let rec tokenize' acc = function
| w :: t when Char.IsWhiteSpace(w) -> tokenize' acc t // skip whitespace
| '(' :: t -> tokenize' (TOpen :: acc) t
| ')' :: t -> tokenize' (TClose :: acc) t
| '"' :: t -> // start of string
let s, t' = string "" t
tokenize' (TString(s) :: acc) t'
| '-' :: d :: t when Char.IsDigit(d) -> // start of negative number
let n, t' = token ("-" + d.ToString()) t
tokenize' (TNumber(n) :: acc) t'
| '+' :: d :: t | d :: t when Char.IsDigit(d) -> // start of positive number
let n, t' = token (d.ToString()) t
tokenize' (TNumber(n) :: acc) t'
| s :: t -> // otherwise start of symbol
let s, t' = token (s.ToString()) t
tokenize' (TSymbol(s) :: acc) t'
| [] -> List.rev acc // end of list terminates
tokenize' [] source
let parse source =
let map = function
| TNumber(n) -> Value(Number(Double.Parse(n)))
| TString(s) -> Value(Name(s))
| TSymbol(s) -> Symbol(s)
| _ -> failwith "syntax error"
let rec parse' acc = function
| TOpen :: t ->
let e, t' = parse' [] t
parse' (Combination(e) :: acc) t'
| TClose :: t -> (List.rev acc), t
| h :: t -> parse' ((map h) :: acc) t
| [] -> (List.rev acc), []
let result, _ = parse' [] (tokenize (List.ofSeq source))
result