Ast: Rename ECallTactic to ETacticConstructor.
[goals.git] / src / parser.mly
index add72bb..347c072 100644 (file)
  *)
 
 %{
+open Utils
 open Printf
+
+(* This is initialized with Lexer.read once the program
+ * starts.  Doing this avoids a circular dependency caused
+ * by include files.
+ *)
+let lexer_read = ref None
+
+let find_on_include_path filename =
+  if not (Filename.is_implicit filename) then filename
+  else (
+    let rec loop = function
+      | [] -> filename
+      | inc :: incs ->
+         let path = inc // filename in
+         if Sys.file_exists path then path else loop incs
+    in
+    loop Cmdline.includes
+  )
+
+let do_include env loc filename optflag file =
+  let filename = Ast.substitute env loc filename in
+  let filename = find_on_include_path filename in
+  if optflag && not (Sys.file_exists filename) then env
+  else (
+    let fp = open_in filename in
+    let lexbuf = Lexing.from_channel fp in
+    lexbuf.lex_curr_p <- { lexbuf.lex_curr_p with pos_fname = filename };
+    let reader =
+      match !lexer_read with None -> assert false | Some r -> r in
+    let env' = file reader lexbuf in
+    close_in fp;
+    Ast.Env.merge env env'
+  )
 %}
 
 (* Tokens. *)
 %token <Ast.substs> CODE
 %token COLON
 %token COMMA
-%token <string> ID
 %token EQUALS
 %token EOF
 %token GOAL
+%token <string> ID
+%token INCLUDE
 %token LEFT_ARRAY
 %token LEFT_PAREN
 %token LET
+%token OPTINCLUDE
 %token RIGHT_ARRAY
 %token RIGHT_PAREN
 %token <Ast.substs> STRING
-
-%type <Ast.stmt> stmt
+%token <string> TACTIC
+%token TACTIC_KEYWORD
 
 (* Start nonterminals. *)
-%start <Ast.file> file
+%start <Ast.expr Ast.Env.t> file
 %start <Ast.expr> expr
 %%
 
@@ -48,41 +84,51 @@ file:
     ;
 
 stmts:
-    | list(stmt) { $1 }
+    | (* none *) { Ast.Env.empty }
+    | stmts INCLUDE STRING
+    { do_include $1 $loc $3 false file }
+    | stmts OPTINCLUDE STRING
+    { do_include $1 $loc $3 true file }
+    | stmts stmt  { let name, expr = $2 in Ast.Env.add name expr $1 }
     ;
+
 stmt:
     | option(goal_stmt) patterns COLON barelist option(CODE)
     { let name, params =
         match $1 with
         | None ->
-           let pos = $startpos in
-           sprintf "_goal@%d" pos.pos_lnum, []
+           sprintf "_goal@%d" $startpos.pos_lnum, []
         | Some x -> x in
-      Ast.Goal (name, params, $2, $4, $5)
+      name, Ast.EGoalDefn ($loc, (params, $2, $4, $5))
     }
     | goal_stmt CODE
     {
       let name, params = $1 in
-      Ast.Goal (name, params, [], [], Some $2)
+      name, Ast.EGoalDefn ($loc, (params, [], [], Some $2))
+    }
+    | TACTIC_KEYWORD TACTIC params_decl EQUALS CODE
+    {
+      $2, Ast.ETacticDefn ($loc, ($3, $5))
     }
-    | LET ID EQUALS expr { Ast.Let ($2, $4) }
+    | LET ID EQUALS expr { $2, $4 }
     ;
 
 goal_stmt:
-    | GOAL ID option(param_decl) EQUALS
+    | GOAL ID option(params_decl) EQUALS
     { $2, match $3 with None -> [] | Some ps -> ps }
     ;
-param_decl:
-    | LEFT_PAREN separated_list(COMMA, ID) RIGHT_PAREN { $2 }
+params_decl:
+    | LEFT_PAREN separated_list(COMMA, param_decl) RIGHT_PAREN { $2 }
     ;
+param_decl:
+    | ID         { $1 }
 
 patterns:
     | separated_list(COMMA, pattern) { $1 }
     ;
 pattern:
-    | STRING     { Ast.PTactic ("file", [$1]) }
-    | ID pattern_params { Ast.PTactic ($1, $2) }
-    | ID         { Ast.PVarSubst $1 }
+    | STRING     { Ast.PTactic ($loc, "*file", [$1]) }
+    | ID pattern_params { Ast.PTactic ($loc, $1, $2) }
     ;
 pattern_params:
     | LEFT_PAREN separated_list(COMMA, pattern_param) RIGHT_PAREN { $2 }
@@ -92,10 +138,11 @@ pattern_param:
     ;
 
 expr:
-    | ID params  { Ast.ECall ($1, $2) }
-    | ID         { Ast.EVar $1 (* This might be replaced with ECall later. *) }
-    | STRING     { Ast.EString $1 }
-    | LEFT_ARRAY barelist RIGHT_ARRAY { Ast.EList $2 }
+    | ID params  { Ast.ECallGoal ($loc, $1, $2) }
+    | ID         { Ast.EVar ($loc, $1) }
+    | TACTIC params { Ast.ETacticConstructor ($loc, $1, $2) }
+    | STRING     { Ast.ESubsts ($loc, $1) }
+    | LEFT_ARRAY barelist RIGHT_ARRAY { Ast.EList ($loc, $2) }
     ;
 barelist:
     | separated_list(COMMA, expr) { $1 }