Last active
February 22, 2020 18:17
-
-
Save jakewitcher/8e1f14314580c514279501133f063322 to your computer and use it in GitHub Desktop.
Using FParsec to parse local variable declarations in a Sanscript script and then only returning the array local variables.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Below is an example of the Sanscript code that serves as the target for this parser. | |
//(Sanscript is an old scripting language from the 90s) | |
//There would be additional code in the file as well, the parser ignores everything before and after the local variables are declared | |
//and then only returns the array variables. | |
//-------------------------------------------------------------------------------------------------------------------- | |
//local decimal retail_price,sale_price[12],cost[12],sum,local_taxes[12],federal_taxes[12],state_taxes[12], | |
// mileage[52],fuel_cost[52],capacity; | |
//local string customer_name,customer_id, order_ids[24]; | |
//local 'Custom Type' delivery_dates[12], order_dates[24]; | |
//-------------------------------------------------------------------------------------------------------------------- | |
open FParsec | |
type LocalArray = | |
{ Type: string | |
Name: string | |
ArraySize: int } | |
type UserState = unit | |
type Parser<'t> = Parser<'t, UserState> | |
module Option = | |
let apply ma mf = | |
match mf, ma with | |
| Some f, Some a -> Some (f a) | |
| _ -> None | |
let isType c = isLetter c | |
let isCustomType c = isLetter c || isDigit c || isAnyOf " /_-" c | |
let isIdentifier c = isLetter c || isDigit c || c = '_' | |
let ws = spaces | |
let plocal: Parser<_> = pstring "local" .>> ws | |
let pcustomType: Parser<_> = | |
between (pchar '\'') | |
(pchar '\'') | |
(many1Satisfy isCustomType) | |
let ptype: Parser<_> = | |
many1Satisfy isType | |
<|> pcustomType | |
.>> ws | |
let pname: Parser<_> = many1Satisfy isIdentifier | |
let parrsize: Parser<_> = | |
between (pchar '[') | |
(pchar ']') | |
pint32 | |
let toLocalArrayVars (varType, variables) = | |
let go state ele = | |
match snd ele with | |
| Some arrSize -> | |
{ Type = varType; Name = fst ele; ArraySize = arrSize } :: state | |
| None -> | |
state | |
variables | |
|> List.fold go [] | |
let plocalvar = | |
tuple2 (plocal >>. ptype) | |
(sepBy (pname .>>. opt parrsize) (pchar ',' .>> ws) .>> pchar ';' .>> ws) | |
|>> toLocalArrayVars | |
let plocalvars = | |
skipCharsTillString "local" false 10000 | |
>>. many plocalvar | |
|>> List.concat | |
let runParser p str = | |
match run p str with | |
| Success(result, _, _) -> Some result | |
| _ -> None | |
let localArrayVarsMap arrayVars = | |
arrayVars | |
|> List.map (fun arrayVar -> | |
arrayVar.Name, arrayVar) | |
|> Map.ofList | |
let findLocalArrayVars script = | |
script | |
|> runParser plocalvars | |
|> Option.map localArrayVarsMap | |
|> Option.defaultValue Map.empty |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment