package p4pp

  1. Overview
  2. Docs

Source file eval.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
open Core_kernel
open Ast

type env =
  { file : string;
    defines : (string * Int64.t) list }
let empty file =
   { file; defines = [] }
let is_defined env m =
  not (Option.is_none (List.Assoc.find ~equal:String.equal env.defines m))
let define env m =
  if is_defined env m then env
  else { env with defines = List.Assoc.add ~equal:String.equal env.defines m Int64.zero }
let undefine env m =
  { env with
    defines = List.Assoc.remove ~equal:String.equal env.defines m }
let get_file env = env.file
let set_file env file = { env with file }

let rec find includes file =
  match includes with
  | [] ->
     failwith ("Error: " ^ file ^ " could not be found")
  | h::t ->
     let path = Filename.concat h file in
     if Sys.file_exists path then path
     else find t file

let eval_binop (bop:bop) =
  let open Int64 in
  match bop with
  | Add -> ( + )
  | Sub -> ( - )
  | Mult -> ( * )
  | Div -> ( / )
  | Eq -> (fun n1 n2 -> if n1 = n2 then one else zero)
  | Neq -> (fun n1 n2 -> if n1 <> n2 then one else zero)
  | Lt -> (fun n1 n2 -> if n1 < n2 then one else zero)
  | Gt -> (fun n1 n2 -> if n1 > n2 then one else zero)
  | Le -> (fun n1 n2 -> if n1 <= n2 then one else zero)
  | Ge -> (fun n1 n2 -> if n1 >= n2 then one else zero)
  | BAnd -> bit_and
  | BOr -> bit_or
  | BXor -> bit_xor
  | BShl -> (fun n1 n2 -> shift_left n1 (Int64.to_int_exn n2))
  | BShr -> (fun n1 n2 -> shift_right n1 (Int64.to_int_exn n2))
  | And -> (fun n1 n2 -> if n1 <> zero && n2 <> zero then one else zero)
  | Or -> (fun n1 n2 -> if n1 <> zero || n2 <> zero then one else zero)

let eval_uop (uop:uop) =
  let open Int64 in
  match uop with
  | BNot -> bit_not
  | Not -> (fun n -> if n = zero then one else zero)

let rec eval_test (env:env) (test:test) : Int64.t =
  match test with
  | Int(n) -> n
  | Defined(m) ->
     if is_defined env m then Int64.zero
     else Int64.one
  | Ident(m) ->
     Int64.zero
  | BinOp(test1,bop,test2) ->
     eval_binop bop (eval_test env test1) (eval_test env test2)
  | UnOp(uop,test1) ->
     eval_uop uop (eval_test env test1)

let rec eval (includes:string list) (env:env) (buf:Buffer.t) (term:term) (file_io:bool): env =
  let current = get_file env in
  match term with
  | String(s) ->
     Buffer.add_string buf (Printf.sprintf "\"%s\"" s);
     env
  | Text(s) ->
     Buffer.add_string buf s;
     env
  | Include(line,search,file) ->
     let env =
      if file_io then begin
        let path = find includes file in
        let env = set_file env path in
        let env = preprocess_file includes env buf path in
        set_file env current
      end
      else begin
        let path = file in
        let env = set_file env path in
        let contents =
          if String.equal file "core.p4" then Bake.core_p4_str
          else if String.equal file "v1model.p4" then Bake.core_v1_model_str
          else failwith ("Error: " ^ file ^ " could not be found in bake") in
          preprocess_string includes env buf file contents
      end in
     let env = set_file env current in
     Buffer.add_string buf "\n";
     Buffer.add_string buf (Printf.sprintf "#line %d \"%s\" %d\n" line current 2);
    env
  | Define(m) ->
     let env = define env m in
     Buffer.add_string buf "\n";
     env
  | Undef(m) ->
     let env = undefine env m in
     Buffer.add_string buf "\n";
     env
  | IfDef(macro,line_tru,tru,line_fls,fls,line_end) ->
     let b = is_defined env macro in
     cond includes env buf b line_tru tru line_fls fls line_end file_io
  | IfNDef(macro,line_tru,tru,line_fls,fls,line_end) ->
     let b = not(is_defined env macro) in
     cond includes env buf b line_tru tru line_fls fls line_end file_io
  | If(test,line_tru, tru, line_fls, fls, line_end) ->
     let b = Int64.(zero = eval_test env test) in
     cond includes env buf b line_tru tru line_fls fls line_end file_io

and cond includes env buf b line_tru tru line_fls fls line_end file_io =
  let current = get_file env in
  let env =
    if b then
      begin
        Buffer.add_string buf (Printf.sprintf "#line %d \"%s\"\n" line_tru current);
        List.fold_left ~init:env ~f:(fun env term -> eval includes env buf term file_io) tru
      end
    else
      begin
        Buffer.add_string buf (Printf.sprintf "#line %d \"%s\"\n" line_fls current);              List.fold_left ~init:env ~f:(fun env term -> eval includes env buf term file_io) fls
      end in
  Buffer.add_string buf (Printf.sprintf "#line %d \"%s\"\n" line_end current);
  env

and preprocess_string (includes:string list) (env:env) (buf:Buffer.t) (file:string) (file_contents:string) : env =
  let () = Buffer.add_string buf (Printf.sprintf "#line %d \"%s\" %d\n" 1 file 1) in
  let lexbuf = Lexing.from_string file_contents in
  let () = Prelexer.reset file in
  let string = Prelexer.lex lexbuf in
  let lexbuf = Lexing.from_string string in
  let terms =
    try Parser.program Lexer.token lexbuf
    with _ -> failwith ("Error parsing " ^ "typed input" ^ " : " ^ string_of_int (!Lexer.current_line)) in
  List.fold_left ~init:env ~f:(fun env term -> eval includes env buf term false) terms

and preprocess_file (includes:string list) (env:env) (buf:Buffer.t) (file:string) : env =
  let () = Buffer.add_string buf (Printf.sprintf "#line %d \"%s\" %d\n" 1 file 1) in
  let channel = In_channel.create file in
  let lexbuf = Lexing.from_channel channel in
  let () = Prelexer.reset file in
  let string = Prelexer.lex lexbuf in
  let () = In_channel.close channel in
  let lexbuf = Lexing.from_string string in
  let terms =
    try Parser.program Lexer.token lexbuf
    with _ -> failwith ("Error parsing " ^ file ^ " : " ^ string_of_int (!Lexer.current_line)) in
  List.fold_left ~init:env ~f:(fun env term -> eval includes env buf term true) terms
OCaml

Innovation. Community. Security.