Add parser combinators
This commit is contained in:
		
							parent
							
								
									6444f413ca
								
							
						
					
					
						commit
						1fd0b30b41
					
				
					 1 changed files with 41 additions and 28 deletions
				
			
		
							
								
								
									
										69
									
								
								parser.ml
									
										
									
									
									
								
							
							
						
						
									
										69
									
								
								parser.ml
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -35,6 +35,39 @@ let token_to_op = function
 | 
			
		|||
  | Slash -> Div
 | 
			
		||||
  | _ -> failwith "Parser.token_to_op"
 | 
			
		||||
 | 
			
		||||
(* common parsers *)
 | 
			
		||||
 | 
			
		||||
let idents set seq =
 | 
			
		||||
  match seq () with
 | 
			
		||||
  | Seq.Nil ->
 | 
			
		||||
    let msg = "ident " ^ (S.elements set |> String.concat " or ") in
 | 
			
		||||
    expected msg
 | 
			
		||||
  | Seq.Cons (x, seq) -> begin
 | 
			
		||||
      match x with
 | 
			
		||||
      | Token.Ident id when S.mem id set -> id, seq
 | 
			
		||||
      | _ -> unexpected_token x
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
let ident str seq =
 | 
			
		||||
  idents (S.singleton str) seq
 | 
			
		||||
 | 
			
		||||
let operator seq =
 | 
			
		||||
  match seq () with
 | 
			
		||||
  | Seq.Nil -> expected "operator"
 | 
			
		||||
  | Seq.Cons (x, seq) ->
 | 
			
		||||
    try token_to_op x, seq with
 | 
			
		||||
    | _ -> expected "operator"
 | 
			
		||||
 | 
			
		||||
(* parser combinators *)
 | 
			
		||||
 | 
			
		||||
let either f g seq =
 | 
			
		||||
  try f seq with _ -> g seq
 | 
			
		||||
 | 
			
		||||
let (@>) f g seq =
 | 
			
		||||
  let a, seq = f seq in
 | 
			
		||||
  g a seq
 | 
			
		||||
 | 
			
		||||
(* parse tokens *)
 | 
			
		||||
let parse ts =
 | 
			
		||||
  (* value := int | ( expr ) *)
 | 
			
		||||
  let rec value seq =
 | 
			
		||||
| 
						 | 
				
			
			@ -64,41 +97,21 @@ let parse ts =
 | 
			
		|||
        | _ -> unexpected_token x
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
  and ident set seq =
 | 
			
		||||
    match seq () with
 | 
			
		||||
    | Seq.Nil ->
 | 
			
		||||
      let msg = "ident " ^ (S.elements set |> String.concat " or ") in
 | 
			
		||||
      expected msg
 | 
			
		||||
    | Seq.Cons (x, seq) -> begin match x with
 | 
			
		||||
        | Token.Ident id when S.mem id set -> id, seq
 | 
			
		||||
        | _ -> unexpected_token x
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
  and operator seq =
 | 
			
		||||
    match seq () with
 | 
			
		||||
    | Seq.Nil -> expected "operator"
 | 
			
		||||
    | Seq.Cons (x, seq) ->
 | 
			
		||||
      try token_to_op x, seq with
 | 
			
		||||
      | _ -> expected "operator"
 | 
			
		||||
 | 
			
		||||
  and level seq =
 | 
			
		||||
    let id, seq = ident (S.of_list ["get"; "set"]) seq in
 | 
			
		||||
  and level _ seq =
 | 
			
		||||
    let id, seq = idents (S.of_list ["get"; "set"]) seq in
 | 
			
		||||
    let op, seq = operator seq in
 | 
			
		||||
    if id = "get" then
 | 
			
		||||
      Get_binop_pre op, seq
 | 
			
		||||
    else
 | 
			
		||||
    else if id = "set" then
 | 
			
		||||
      let v, seq = value seq in
 | 
			
		||||
      Set_binop_pre (op, v), seq
 | 
			
		||||
    else
 | 
			
		||||
      failwith "Parser.level"
 | 
			
		||||
 | 
			
		||||
  and expr seq =
 | 
			
		||||
    match seq () with
 | 
			
		||||
    | Seq.Nil -> Value Unit, Seq.empty (* nop *)
 | 
			
		||||
    | Seq.Cons (x, s) -> begin match x with
 | 
			
		||||
        | Ident "level" -> level s
 | 
			
		||||
        | _ ->
 | 
			
		||||
          let left, seq = value seq in
 | 
			
		||||
          binop ~-1 left seq
 | 
			
		||||
      end
 | 
			
		||||
    seq |> either
 | 
			
		||||
      (ident "level" @> level)
 | 
			
		||||
      (value @> binop ~-1)
 | 
			
		||||
  in
 | 
			
		||||
  let ast, rest = expr ts in
 | 
			
		||||
  if rest () <> Seq.Nil then failwith "Parser.parse";
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue