17abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao(*===---------------------------------------------------------------------===
27abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao * Parser
37abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao *===---------------------------------------------------------------------===*)
47abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao
57abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao(* binop_precedence - This holds the precedence for each binary operator that is
67abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao * defined *)
77abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liaolet binop_precedence:(char, int) Hashtbl.t = Hashtbl.create 10
87abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao
97abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao(* precedence - Get the precedence of the pending binary operator token. *)
107abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liaolet precedence c = try Hashtbl.find binop_precedence c with Not_found -> -1
117abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao
127abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao(* primary
137abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao *   ::= identifier
147abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao *   ::= numberexpr
157abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao *   ::= parenexpr
167abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao *   ::= ifexpr
177abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao *   ::= forexpr
187abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao *   ::= varexpr *)
197abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liaolet rec parse_primary = parser
207abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  (* numberexpr ::= number *)
217abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  | [< 'Token.Number n >] -> Ast.Number n
227abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao
237abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  (* parenexpr ::= '(' expression ')' *)
247abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  | [< 'Token.Kwd '('; e=parse_expr; 'Token.Kwd ')' ?? "expected ')'" >] -> e
257abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao
267abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  (* identifierexpr
277abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao   *   ::= identifier
287abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao   *   ::= identifier '(' argumentexpr ')' *)
297abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  | [< 'Token.Ident id; stream >] ->
307abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao      let rec parse_args accumulator = parser
317abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao        | [< e=parse_expr; stream >] ->
327abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao            begin parser
337abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao              | [< 'Token.Kwd ','; e=parse_args (e :: accumulator) >] -> e
347abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao              | [< >] -> e :: accumulator
357abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao            end stream
367abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao        | [< >] -> accumulator
377abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao      in
387abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao      let rec parse_ident id = parser
397abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao        (* Call. *)
407abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao        | [< 'Token.Kwd '(';
417abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao             args=parse_args [];
427abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao             'Token.Kwd ')' ?? "expected ')'">] ->
437abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao            Ast.Call (id, Array.of_list (List.rev args))
447abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao
457abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao        (* Simple variable ref. *)
467abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao        | [< >] -> Ast.Variable id
477abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao      in
487abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao      parse_ident id stream
497abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao
507abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  (* ifexpr ::= 'if' expr 'then' expr 'else' expr *)
517abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  | [< 'Token.If; c=parse_expr;
527abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao       'Token.Then ?? "expected 'then'"; t=parse_expr;
537abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao       'Token.Else ?? "expected 'else'"; e=parse_expr >] ->
547abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao      Ast.If (c, t, e)
557abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao
567abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  (* forexpr
577abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao        ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression *)
587abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  | [< 'Token.For;
597abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao       'Token.Ident id ?? "expected identifier after for";
607abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao       'Token.Kwd '=' ?? "expected '=' after for";
617abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao       stream >] ->
627abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao      begin parser
637abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao        | [<
647abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao             start=parse_expr;
657abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao             'Token.Kwd ',' ?? "expected ',' after for";
667abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao             end_=parse_expr;
677abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao             stream >] ->
687abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao            let step =
697abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao              begin parser
707abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao              | [< 'Token.Kwd ','; step=parse_expr >] -> Some step
717abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao              | [< >] -> None
727abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao              end stream
737abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao            in
747abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao            begin parser
757abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao            | [< 'Token.In; body=parse_expr >] ->
767abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao                Ast.For (id, start, end_, step, body)
777abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao            | [< >] ->
787abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao                raise (Stream.Error "expected 'in' after for")
797abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao            end stream
807abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao        | [< >] ->
817abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao            raise (Stream.Error "expected '=' after for")
827abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao      end stream
837abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao
847abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  (* varexpr
857abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao   *   ::= 'var' identifier ('=' expression?
867abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao   *             (',' identifier ('=' expression)?)* 'in' expression *)
877abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  | [< 'Token.Var;
887abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao       (* At least one variable name is required. *)
897abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao       'Token.Ident id ?? "expected identifier after var";
907abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao       init=parse_var_init;
917abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao       var_names=parse_var_names [(id, init)];
927abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao       (* At this point, we have to have 'in'. *)
937abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao       'Token.In ?? "expected 'in' keyword after 'var'";
947abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao       body=parse_expr >] ->
957abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao      Ast.Var (Array.of_list (List.rev var_names), body)
967abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao
977abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  | [< >] -> raise (Stream.Error "unknown token when expecting an expression.")
987abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao
997abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao(* unary
1007abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao *   ::= primary
1017abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao *   ::= '!' unary *)
1027abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liaoand parse_unary = parser
1037abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  (* If this is a unary operator, read it. *)
1047abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  | [< 'Token.Kwd op when op != '(' && op != ')'; operand=parse_expr >] ->
1057abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao      Ast.Unary (op, operand)
1067abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao
1077abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  (* If the current token is not an operator, it must be a primary expr. *)
1087abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  | [< stream >] -> parse_primary stream
1097abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao
1107abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao(* binoprhs
1117abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao *   ::= ('+' primary)* *)
1127abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liaoand parse_bin_rhs expr_prec lhs stream =
1137abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  match Stream.peek stream with
1147abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  (* If this is a binop, find its precedence. *)
1157abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  | Some (Token.Kwd c) when Hashtbl.mem binop_precedence c ->
1167abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao      let token_prec = precedence c in
1177abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao
1187abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao      (* If this is a binop that binds at least as tightly as the current binop,
1197abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao       * consume it, otherwise we are done. *)
1207abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao      if token_prec < expr_prec then lhs else begin
1217abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao        (* Eat the binop. *)
1227abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao        Stream.junk stream;
1237abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao
1247abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao        (* Parse the primary expression after the binary operator. *)
1257abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao        let rhs = parse_unary stream in
1267abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao
1277abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao        (* Okay, we know this is a binop. *)
1287abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao        let rhs =
1297abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao          match Stream.peek stream with
1307abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao          | Some (Token.Kwd c2) ->
1317abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao              (* If BinOp binds less tightly with rhs than the operator after
1327abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao               * rhs, let the pending operator take rhs as its lhs. *)
1337abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao              let next_prec = precedence c2 in
1347abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao              if token_prec < next_prec
1357abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao              then parse_bin_rhs (token_prec + 1) rhs stream
1367abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao              else rhs
1377abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao          | _ -> rhs
1387abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao        in
1397abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao
1407abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao        (* Merge lhs/rhs. *)
1417abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao        let lhs = Ast.Binary (c, lhs, rhs) in
1427abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao        parse_bin_rhs expr_prec lhs stream
1437abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao      end
1447abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  | _ -> lhs
1457abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao
1467abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liaoand parse_var_init = parser
1477abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  (* read in the optional initializer. *)
1487abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  | [< 'Token.Kwd '='; e=parse_expr >] -> Some e
1497abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  | [< >] -> None
1507abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao
1517abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liaoand parse_var_names accumulator = parser
1527abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  | [< 'Token.Kwd ',';
1537abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao       'Token.Ident id ?? "expected identifier list after var";
1547abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao       init=parse_var_init;
1557abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao       e=parse_var_names ((id, init) :: accumulator) >] -> e
1567abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  | [< >] -> accumulator
1577abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao
1587abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao(* expression
1597abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao *   ::= primary binoprhs *)
1607abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liaoand parse_expr = parser
1617abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  | [< lhs=parse_unary; stream >] -> parse_bin_rhs 0 lhs stream
1627abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao
1637abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao(* prototype
1647abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao *   ::= id '(' id* ')'
1657abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao *   ::= binary LETTER number? (id, id)
1667abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao *   ::= unary LETTER number? (id) *)
1677abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liaolet parse_prototype =
1687abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  let rec parse_args accumulator = parser
1697abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao    | [< 'Token.Ident id; e=parse_args (id::accumulator) >] -> e
1707abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao    | [< >] -> accumulator
1717abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  in
1727abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  let parse_operator = parser
1737abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao    | [< 'Token.Unary >] -> "unary", 1
1747abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao    | [< 'Token.Binary >] -> "binary", 2
1757abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  in
1767abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  let parse_binary_precedence = parser
1777abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao    | [< 'Token.Number n >] -> int_of_float n
1787abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao    | [< >] -> 30
1797abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  in
1807abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  parser
1817abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  | [< 'Token.Ident id;
1827abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao       'Token.Kwd '(' ?? "expected '(' in prototype";
1837abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao       args=parse_args [];
1847abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao       'Token.Kwd ')' ?? "expected ')' in prototype" >] ->
1857abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao      (* success. *)
1867abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao      Ast.Prototype (id, Array.of_list (List.rev args))
1877abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  | [< (prefix, kind)=parse_operator;
1887abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao       'Token.Kwd op ?? "expected an operator";
1897abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao       (* Read the precedence if present. *)
1907abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao       binary_precedence=parse_binary_precedence;
1917abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao       'Token.Kwd '(' ?? "expected '(' in prototype";
1927abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao        args=parse_args [];
1937abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao       'Token.Kwd ')' ?? "expected ')' in prototype" >] ->
1947abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao      let name = prefix ^ (String.make 1 op) in
1957abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao      let args = Array.of_list (List.rev args) in
1967abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao
1977abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao      (* Verify right number of arguments for operator. *)
1987abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao      if Array.length args != kind
1997abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao      then raise (Stream.Error "invalid number of operands for operator")
2007abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao      else
2017abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao        if kind == 1 then
2027abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao          Ast.Prototype (name, args)
2037abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao        else
2047abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao          Ast.BinOpPrototype (name, args, binary_precedence)
2057abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  | [< >] ->
2067abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao      raise (Stream.Error "expected function name in prototype")
2077abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao
2087abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao(* definition ::= 'def' prototype expression *)
2097abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liaolet parse_definition = parser
2107abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  | [< 'Token.Def; p=parse_prototype; e=parse_expr >] ->
2117abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao      Ast.Function (p, e)
2127abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao
2137abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao(* toplevelexpr ::= expression *)
2147abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liaolet parse_toplevel = parser
2157abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  | [< e=parse_expr >] ->
2167abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao      (* Make an anonymous proto. *)
2177abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao      Ast.Function (Ast.Prototype ("", [||]), e)
2187abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao
2197abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao(*  external ::= 'extern' prototype *)
2207abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liaolet parse_extern = parser
2217abe37e4aee38cc79d91dd069a37d7e91d5bef53Shih-wei Liao  | [< 'Token.Extern; e=parse_prototype >] -> e
222