Module Qcert.Translation.Lang.JavaScriptAsttoJavaScript
Require Import List.
Require Import String.
Require Import StringAdd.
Require Import Peano_dec.
Require Import EquivDec.
Require Import Utils.
Require Import JavaScriptAstRuntime.
Require Import JavaScriptRuntime.
Require Import JsAst.JsNumber.
Local Open Scope string_scope.
Section ToString.
Section Util.
Definition eol:
string :=
String (
Ascii.ascii_of_nat 10)
EmptyString.
Definition quotel:
string := """".
Fixpoint indent (
i :
nat) :
string :=
match i with
| 0 => ""
|
S j => " " ++ (
indent j)
end.
Definition comma_list l :=
concat ", "
l.
Definition js_quote_char (
a:
ascii) :
string :=
match a with
| "008"%
char => "\
b"
| "009"%
char => "\
t"
| "010"%
char => "\
n"
| "013"%
char => "\
r"
| """"%
char => "\"""
| "\"%
char => "\\"
|
_ =>
String a EmptyString
end.
Definition js_quote_string (
s:
string) :
string :=
flat_map_string js_quote_char s.
Definition js_quote_number (
n:
number) :
string :=
if (
float_eq n float_infinity)
then "
Infinity"
else if (
float_eq n float_neg_infinity)
then "-
Infinity"
else if (
float_eq n float_nan)
then "
NaN"
else to_string n.
End Util.
Definition string_of_literal (
c:
literal) :
string :=
match c with
|
literal_null => "
null"
|
literal_bool true => "
true"
|
literal_bool false => "
false"
|
literal_number n =>
js_quote_number n
|
literal_string s =>
quotel ++
js_quote_string s ++
quotel
|
literal_bigint z =>
Z_to_string10 z ++ "
n"
end.
Definition string_of_propname (
name:
propname) :
string :=
match name with
|
propname_identifier n =>
n
|
propname_string s =>
quotel ++
s ++
quotel
|
propname_number n =>
to_string n
end.
Fixpoint string_of_expr
(
e:
expr)
(
i:
nat)
{
struct e }
:
string :=
match e with
|
expr_this => "
this"
|
expr_identifier x =>
x
|
expr_literal c =>
string_of_literal c
|
expr_object o =>
let props :=
List.map
(
fun (
prop: (
propname *
propbody)) =>
let (
name,
body) :=
prop in
eol ++ (
indent (
i+1)) ++
match body with
|
propbody_val e =>
quotel ++
string_of_propname name ++
quotel
++ ": " ++ "(" ++
string_of_expr e (
i+1) ++ ")"
|
propbody_get funcbody =>
"
get " ++
quotel ++
string_of_propname name ++
quotel
++ "() {" ++ (
string_of_funcbody funcbody (
i+1)) ++ "}"
|
propbody_set args funcbody =>
"
set " ++
quotel ++
string_of_propname name ++
quotel
++ "(" ++
comma_list args ++ ") {"
++
string_of_funcbody funcbody (
i+1) ++ "}"
end)
o
in
"{" ++
comma_list props ++
eol ++
indent i ++ "}"
|
expr_array a =>
let l :=
List.map
(
fun eopt =>
match eopt with
|
Some e =>
string_of_expr e (
i+1)
|
None => "
null"
end)
a
in
"[ " ++
comma_list l ++ " ]"
|
expr_function fopt args body =>
let name :=
match fopt with
|
Some f =>
f
|
None => ""
end
in
"(
function " ++
name ++ "(" ++
comma_list args ++ ") {" ++
eol ++
indent (
i+1) ++
string_of_funcbody body (
i+1) ++
eol ++
indent i ++ "})"
|
expr_access e1 e2 =>
string_of_expr e1 i ++ "[" ++
string_of_expr e2 (
i+1) ++ "]"
|
expr_member e s =>
string_of_expr e i ++ "[" ++
quotel ++
s ++
quotel ++ "]"
|
expr_new e args =>
let args :=
List.map (
fun e =>
string_of_expr e (
i+1))
args in
"
new " ++
string_of_expr e i ++ "(" ++
comma_list args ++ ")"
|
expr_call f args =>
let args :=
List.map (
fun e =>
string_of_expr e (
i+1))
args in
string_of_expr f i ++ "(" ++
comma_list args ++ ")"
|
expr_unary_op op e =>
let e :=
string_of_expr e (
i+1)
in
match op with
|
unary_op_delete => "(
delete " ++
e ++ ")"
|
unary_op_void => "(
void " ++
e ++ ")"
|
unary_op_typeof => "(
typeof " ++
e ++ ")"
|
unary_op_post_incr => "(" ++
e ++ "++)"
|
unary_op_post_decr => "(" ++
e ++ "--)"
|
unary_op_pre_incr => "(++" ++
e ++ ")"
|
unary_op_pre_decr => "(--" ++
e ++ ")"
|
unary_op_add => "(+" ++
e ++ ")"
|
unary_op_neg => "(-" ++
e ++ ")"
|
unary_op_bitwise_not => "(~" ++
e ++ ")"
|
unary_op_not => "(!" ++
e ++ ")"
end
|
expr_binary_op e1 op e2 =>
let e1 :=
string_of_expr e1 (
i+1)
in
let e2 :=
string_of_expr e2 (
i+1)
in
match op with
|
binary_op_mult => "(" ++
e1 ++ " * " ++
e2 ++ ")"
|
binary_op_div => "(" ++
e1 ++ " / " ++
e2 ++ ")"
|
binary_op_mod => "(" ++
e1 ++ " % " ++
e2 ++ ")"
|
binary_op_add => "(" ++
e1 ++ " + " ++
e2 ++ ")"
|
binary_op_sub => "(" ++
e1 ++ " - " ++
e2 ++ ")"
|
binary_op_left_shift => "(" ++
e1 ++ " << " ++
e2 ++ ")"
|
binary_op_right_shift => "(" ++
e1 ++ " >> " ++
e2 ++ ")"
|
binary_op_unsigned_right_shift => "(" ++
e1 ++ " >>> " ++
e2 ++ ")"
|
binary_op_lt => "(" ++
e1 ++ " < " ++
e2 ++ ")"
|
binary_op_gt => "(" ++
e1 ++ " > " ++
e2 ++ ")"
|
binary_op_le => "(" ++
e1 ++ " <= " ++
e2 ++ ")"
|
binary_op_ge => "(" ++
e1 ++ " >= " ++
e2 ++ ")"
|
binary_op_instanceof => "(" ++
e1 ++ "
instanceof " ++
e2 ++ ")"
|
binary_op_in => "(" ++
e1 ++ "
in " ++
e2 ++ ")"
|
binary_op_equal => "(" ++
e1 ++ " == " ++
e2 ++ ")"
|
binary_op_disequal => "(" ++
e1 ++ " != " ++
e2 ++ ")"
|
binary_op_strict_equal => "(" ++
e1 ++ " === " ++
e2 ++ ")"
|
binary_op_strict_disequal => "(" ++
e1 ++ " !== " ++
e2 ++ ")"
|
binary_op_bitwise_and => "(" ++
e1 ++ " & " ++
e2 ++ ")"
|
binary_op_bitwise_or => "(" ++
e1 ++ " | " ++
e2 ++ ")"
|
binary_op_bitwise_xor => "(" ++
e1 ++ " ^ " ++
e2 ++ ")"
|
binary_op_and => "(" ++
e1 ++ " && " ++
e2 ++ ")"
|
binary_op_or => "(" ++
e1 ++ " || " ++
e2 ++ ")"
|
binary_op_coma => "(" ++
e1 ++ ", " ++
e2 ++ ")"
end
|
expr_conditional e1 e2 e3 =>
let e1 :=
string_of_expr e1 (
i+1)
in
let e2 :=
string_of_expr e2 (
i+1)
in
let e3 :=
string_of_expr e3 (
i+1)
in
"(" ++
e1 ++ " ? " ++
e2 ++ " : " ++
e3 ++ ")"
|
expr_assign e1 None e2 =>
let e1 :=
string_of_expr e1 (
i+1)
in
let e2 :=
string_of_expr e2 (
i+1)
in
e1 ++ " = " ++
e2
|
_ => "
XXX TODO XXX"
end
with string_of_stat
(
s:
stat)
(
i:
nat)
{
struct s }
:
string :=
indent i ++
match s with
|
stat_expr e =>
string_of_expr e i ++ ";"
|
stat_label lbl s =>
lbl ++ ":" ++
string_of_stat s i
|
stat_block l =>
let seq :=
List.map (
fun s =>
string_of_stat s (
i+1))
l
in
"{" ++
eol ++
concat (";" ++
eol)
seq ++
eol ++
indent i ++ "}"
|
stat_var_decl l =>
let decls :=
List.map
(
fun (
x_e_opt:
string *
option expr) =>
let (
x,
e_opt) :=
x_e_opt in
"
var " ++
x ++
match e_opt with
|
Some e =>
" = " ++
string_of_expr e (
i+1)
|
None => ""
end
)
l
in
concat (";" ++
eol)
decls
|
stat_let_decl l =>
let decls :=
List.map
(
fun (
x_e_opt:
string *
option expr) =>
let (
x,
e_opt) :=
x_e_opt in
"
let " ++
x ++
match e_opt with
|
Some e =>
" = " ++
string_of_expr e (
i+1)
|
None => ""
end
)
l
in
concat (";" ++
eol)
decls
|
stat_if e s1 s2_opt =>
"
if (" ++
string_of_expr e (
i+1) ++ ") {" ++
eol ++
string_of_stat s1 (
i+1) ++
eol ++
indent i ++ "}
else {" ++
eol ++
match s2_opt with
|
Some s2 =>
string_of_stat s2 (
i+1) ++
eol
|
None => ""
end ++
indent i ++ "}"
|
stat_return None =>
"
return ;"
|
stat_return (
Some e) =>
"
return " ++ (
string_of_expr e (
i+1)) ++ ";"
|
stat_for_var lbl vars e2_opt e3_opt s =>
let decls :=
List.map
(
fun (
decl: (
string *
option expr)) =>
let (
x,
e1_opt) :=
decl in
x ++
match e1_opt with
|
None => ""
|
Some e1 => " = " ++
string_of_expr e1 (
i+1)
end)
vars
in
"
for (" ++
"
var " ++
comma_list decls ++ "; " ++
match e2_opt with
|
Some e2 =>
string_of_expr e2 (
i+1)
|
None => ""
end ++ "; " ++
match e3_opt with
|
Some e3 =>
string_of_expr e3 (
i+1)
|
None => ""
end ++ ") {" ++
eol ++
string_of_stat s (
i+1) ++
eol ++
indent i ++ "}" ++
eol
|
stat_for_let lbl vars e2_opt e3_opt s =>
let decls :=
List.map
(
fun (
decl: (
string *
option expr)) =>
let (
x,
e1_opt) :=
decl in
x ++
match e1_opt with
|
None => ""
|
Some e1 => " = " ++
string_of_expr e1 (
i+1)
end)
vars
in
"
for (" ++
"
let " ++
comma_list decls ++ "; " ++
match e2_opt with
|
Some e2 =>
string_of_expr e2 (
i+1)
|
None => ""
end ++ "; " ++
match e3_opt with
|
Some e3 =>
string_of_expr e3 (
i+1)
|
None => ""
end ++ ") {" ++
eol ++
string_of_stat s (
i+1) ++
eol ++
indent i ++ "}" ++
eol
|
stat_for_in_var lbl x e1_opt e2 s =>
"
for (
var " ++
x ++
match e1_opt with
|
Some e => " = " ++
string_of_expr e (
i+1)
|
None => ""
end ++
"
in " ++
string_of_expr e2 (
i+1) ++ ") {" ++
eol ++
string_of_stat s (
i+1) ++
eol ++
indent i ++ "}" ++
eol
|
stat_for_in_let lbl x e1_opt e2 s =>
"
for (
let " ++
x ++
match e1_opt with
|
Some e => " = " ++
string_of_expr e (
i+1)
|
None => ""
end ++
"
in " ++
string_of_expr e2 (
i+1) ++ ") {" ++
eol ++
string_of_stat s (
i+1) ++
eol ++
indent i ++ "}" ++
eol
|
_ => "
XXX TODO XXX"
end
with string_of_element
(
e:
element)
(
i:
nat)
{
struct e }
:
string :=
match e with
|
element_stat s =>
string_of_stat s i
|
element_func_decl f params body =>
eol ++
indent i
++ "
function " ++
f ++ "(" ++ (
comma_list params) ++ ") {" ++
eol
++
string_of_funcbody body (
i+1) ++
eol ++
indent i ++ "}"
end
with string_of_prog
(
p:
prog)
(
i:
nat)
{
struct p }
:
string :=
match p with
|
prog_intro _ elems =>
let elems' :=
List.map (
fun e =>
string_of_element e i)
elems in
concat eol elems'
end
with string_of_funcbody
(
body:
funcbody)
(
i:
nat)
{
struct body }
:
string :=
match body with
|
funcbody_intro p _ =>
string_of_prog p i
end.
Definition string_of_funcdecl
(
f:
funcdecl)
(
i:
nat)
:
string :=
eol ++
indent i
++ "
function " ++ (
f.(
funcdecl_name)) ++ "(" ++ (
comma_list f.(
funcdecl_parameters)) ++ ") {" ++
eol
++
string_of_funcbody f.(
funcdecl_body) (
i+1) ++
eol ++
indent i ++ "}"
.
Definition string_of_method
(
f:
funcdecl)
(
i:
nat)
:
string :=
eol ++
indent i ++ "
static " ++
f.(
funcdecl_name) ++ "(" ++ (
comma_list f.(
funcdecl_parameters)) ++ ") {" ++
eol
++
string_of_funcbody f.(
funcdecl_body) (
i+1) ++
eol ++
indent i ++ "}"
.
Definition string_of_decl(
d:
topdecl)
:
string :=
match d with
|
strictmode =>
eol ++ "'
use strict';"
|
comment c =>
eol ++ "/*" ++
c ++ "*/"
|
elementdecl fd =>
string_of_element fd 0
|
classdecl cn cd =>
eol ++ "
class " ++
cn ++ "{"
++
List.fold_left (
fun acc q =>
append acc (
string_of_method q 1))
cd (""%
string) ++
eol
++ "}"
|
constdecl x e =>
eol ++ "
const " ++
x ++ "=" ++
string_of_expr e 0
end.
End ToString.
Section JavaScriptAsttoJavaScript.
Definition js_ast_to_js_top (
ja:
js_ast) :
javascript :=
List.fold_left (
fun acc f =>
append acc (
string_of_decl f))
ja (""%
string).
End JavaScriptAsttoJavaScript.