Skip to content

Instantly share code, notes, and snippets.

@JasonGross
Last active September 19, 2017 22:32
Show Gist options
  • Save JasonGross/2c792768f8ca895351152b388f167440 to your computer and use it in GitHub Desktop.
Save JasonGross/2c792768f8ca895351152b388f167440 to your computer and use it in GitHub Desktop.
Notations for compcert clight
Require Import Clightdefs.
Delimit Scope None_scope with None.
Delimit Scope C_scope with C.
Delimit Scope Z_scope with Z.
Delimit Scope camlfloat_of_coqfloat_scope with camlfloat_of_coqfloat.
Delimit Scope camlfloat_of_coqfloat32_scope with camlfloat_of_coqfloat32.
Delimit Scope camlint64_of_coqint_scope with camlint64_of_coqint.
Delimit Scope camlint_of_coqint_scope with camlint_of_coqint.
Delimit Scope expr_scope with expr.
Delimit Scope extern_atom_scope with extern_atom.
Delimit Scope name_of_external_scope with name_of_external.
Delimit Scope name_type_scope with name_type.
Delimit Scope positive_scope with positive.
Delimit Scope print_case_label_scope with print_case_label.
Delimit Scope print_cases_scope with print_cases.
Delimit Scope print_expr_list_true_scope with print_expr_list_true.
Delimit Scope print_stmt_for_scope with print_stmt_for.
Notation "x" := (Int.repr x%Z) (only printing, at level 10) : expr_scope.
Notation "({ s_val })" := s_val%C (only printing, left associativity, at level 26, format "({ s_val })") : print_stmt_for_scope.
Notation "id = 'builtin' ef ( el );" := (Sbuiltin (Some id%positive) ef%name_of_external _ el%print_expr_list_true) (only printing, ef at level 26, el at level 26, left associativity, at level 26, format "'[hv ' id = '/' 'builtin' ef '/' ( el ); ']'") : print_stmt_for_scope.
Notation "'builtin' ef ( el );" := (Sbuiltin None ef%name_of_external _ el%print_expr_list_true) (only printing, ef at level 26, el at level 26, left associativity, at level 26, format "'[hv ' 'builtin' ef '/' ( el ); ']'") : print_stmt_for_scope.
Notation "id = e1 ( el )" := (Scall (Some id%positive) e1%expr el%print_expr_list_true) (only printing, e1 at level 26, el at level 26, left associativity, at level 26, format "'[hv ' id = '/' e1 '/' ( el ) ']'") : print_stmt_for_scope.
Notation "e1 ( el )" := (Scall None e1%expr el%print_expr_list_true) (only printing, el at level 26, left associativity, at level 26, format "'[hv ' e1 '/' ( el ) ']'") : print_stmt_for_scope.
Notation "s1 , s2" := (Ssequence s1%print_stmt_for s2%print_stmt_for) (only printing, s2 at level 26, left associativity, at level 26, format "s1 , s2") : print_stmt_for_scope.
Notation "id = e2" := (Sset id%positive e2%expr) (only printing, format "id = e2", at level 70) : print_stmt_for_scope.
Notation "e1 = e2" := (Sassign e1%expr e2%expr) (only printing, format "e1 = e2", at level 70) : print_stmt_for_scope.
Notation "/*nothing*/" := Sskip (only printing, format "/*nothing*/", at level 10) : print_stmt_for_scope.
Notation "'goto' lbl ;" := (Sgoto lbl%extern_atom) (only printing, lbl at level 26, left associativity, at level 26, format "'goto' lbl ;") : C_scope.
Notation "lbl : s1" := (Slabel lbl%extern_atom s1%C) (only printing, s1 at level 26, left associativity, at level 26, format "lbl : '/' s1") : C_scope.
Notation "'return' e_val ;" := (Sreturn (Some e_val%expr)) (only printing, left associativity, at level 26, format "'return' e_val ;") : C_scope.
Notation "return;" := (Sreturn None) (only printing, format "return;", at level 10) : C_scope.
Notation "'switch' ( e_val ) { cases }" := (Sswitch e_val%expr cases%print_cases) (only printing, cases at level 26, left associativity, at level 26, format "'[v' 'switch' ( e_val ) { '/ ' cases '/' } ']'") : C_scope.
Notation "continue;" := Scontinue (only printing, format "continue;", at level 10) : C_scope.
Notation "break;" := Sbreak (only printing, format "break;", at level 10) : C_scope.
Notation "'for' ( ; 1; s2 ) { s1 }" := (Sloop s1%C s2%print_stmt_for) (only printing, s2 at level 26, s1 at level 26, left associativity, at level 26, format "'[v' 'for' ( ; '/' 1; '/' s2 ) { '/ ' s1 '/' } ']'") : C_scope.
Notation "'while' (1) { s1 }" := (Sloop s1%C Sskip) (only printing, s1 at level 26, left associativity, at level 26, format "'[v' 'while' (1) { '/ ' s1 '/' } ']'") : C_scope.
Notation "'if' ( e_val ) { s1 } 'else' { s2 }" := (Sifthenelse e_val%expr s1%C s2%C) (only printing, s1 at level 26, s2 at level 26, left associativity, at level 26, format "'[v' 'if' ( e_val ) { '/ ' s1 '/' } 'else' { '/ ' s2 '/' } ']'") : C_scope.
Notation "'if' (! e_val ) { s2 }" := (Sifthenelse e_val%expr Sskip s2%C) (only printing, s2 at level 26, left associativity, at level 26, format "'[v' 'if' (! e_val ) { '/ ' s2 '/' } ']'") : C_scope.
Notation "'if' ( e_val ) { s1 }" := (Sifthenelse e_val%expr s1%C Sskip) (only printing, s1 at level 26, left associativity, at level 26, format "'[v' 'if' ( e_val ) { '/ ' s1 '/' } ']'") : C_scope.
Notation "s1 s2" := (Ssequence s1%C s2%C) (only printing, s2 at level 26, left associativity, at level 26, format "s1 '//' s2") : C_scope.
Notation "s1" := (Ssequence s1%C Sskip) (only printing, format "s1", at level 10) : C_scope.
Notation "s2" := (Ssequence Sskip s2%C) (only printing, format "s2", at level 10) : C_scope.
Notation "id = 'builtin' ef ( el );" := (Sbuiltin (Some id%positive) ef%name_of_external _ el%print_expr_list_true) (only printing, ef at level 26, el at level 26, left associativity, at level 26, format "'[hv ' id = '/' 'builtin' ef '/' ( el ); ']'") : C_scope.
Notation "'builtin' ef ( el );" := (Sbuiltin None ef%name_of_external _ el%print_expr_list_true) (only printing, ef at level 26, el at level 26, left associativity, at level 26, format "'[hv ' 'builtin' ef '/' ( el ); ']'") : C_scope.
Notation "id = e1 ( el );" := (Scall (Some id%positive) e1%expr el%print_expr_list_true) (only printing, e1 at level 26, el at level 26, left associativity, at level 26, format "'[hv ' id = '/' e1 '/' ( el ); ']'") : C_scope.
Notation "e1 ( el );" := (Scall None e1%expr el%print_expr_list_true) (only printing, el at level 26, left associativity, at level 26, format "'[hv ' e1 '/' ( el ); ']'") : C_scope.
Notation "id = e2 ;" := (Sset id%positive e2%expr) (only printing, e2 at level 26, left associativity, at level 26, format "'[hv ' id = '/' e2 ; ']'") : C_scope.
Notation "e1 = e2 ;" := (Sassign e1%expr e2%expr) (only printing, e2 at level 26, left associativity, at level 26, format "'[hv ' e1 = '/' e2 ; ']'") : C_scope.
Notation "/*skip*/;" := Sskip (only printing, format "/*skip*/;", at level 10) : C_scope.
Notation "'__alignof__(' ty )" := (Ealignof ty%name_type _) (only printing, ty at level 11, right associativity (* XXX Is RtoL the same as right associativity in Coq? *), at level 11, format "'[hv ' '__alignof__(' ty ) ']'") : expr_scope.
Notation "'sizeof(' ty )" := (Esizeof ty%name_type _) (only printing, ty at level 11, right associativity (* XXX Is RtoL the same as right associativity in Coq? *), at level 11, format "'[hv ' 'sizeof(' ty ) ']'") : expr_scope.
Notation "( ty ) a1" := (Ecast a1%expr ty%name_type) (only printing, ty at level 12, a1 at level 12, right associativity (* XXX Is RtoL the same as right associativity in Coq? *), at level 12, format "'[hv ' ( ty ) a1 ']'") : expr_scope.
Notation "a1 < a2" := (Ebinop Olt a1%expr a2%expr _) (only printing, format "'[hv ' a1 '/' < a2 ']'", at level 70) : expr_scope.
Notation "a1 > a2" := (Ebinop Ogt a1%expr a2%expr _) (only printing, format "'[hv ' a1 '/' > a2 ']'", at level 70) : expr_scope.
Notation "a1 >= a2" := (Ebinop Oge a1%expr a2%expr _) (only printing, format "'[hv ' a1 '/' >= a2 ']'", at level 70) : expr_scope.
Notation "a1 % a2" := (Ebinop Omod a1%expr a2%expr _) (only printing, a2 at level 12, left associativity (* XXX Is LtoR the same as left associativity in Coq? *), at level 13, format "'[hv ' a1 '/' % a2 ']'") : expr_scope.
Notation "a1 ^ a2" := (Ebinop Oxor a1%expr a2%expr _) (only printing, format "'[hv ' a1 '/' ^ a2 ']'", at level 30, right associativity) : expr_scope.
Notation "a1 - a2" := (Ebinop Osub a1%expr a2%expr _) (only printing, format "'[hv ' a1 '/' - a2 ']'", at level 50, left associativity) : expr_scope.
Notation "a1 >> a2" := (Ebinop Oshr a1%expr a2%expr _) (only printing, a2 at level 14, left associativity (* XXX Is LtoR the same as left associativity in Coq? *), at level 15, format "'[hv ' a1 '/' >> a2 ']'") : expr_scope.
Notation "a1 <= a2" := (Ebinop Ole a1%expr a2%expr _) (only printing, format "'[hv ' a1 '/' <= a2 ']'", at level 70) : expr_scope.
Notation "a1 | a2" := (Ebinop Oor a1%expr a2%expr _) (only printing, a2 at level 19, left associativity (* XXX Is LtoR the same as left associativity in Coq? *), at level 20, format "'[hv ' a1 '/' | a2 ']'") : expr_scope.
Notation "a1 / a2" := (Ebinop Odiv a1%expr a2%expr _) (only printing, format "'[hv ' a1 '/' / a2 ']'", at level 40, left associativity) : expr_scope.
Notation "a1 << a2" := (Ebinop Oshl a1%expr a2%expr _) (only printing, a2 at level 14, left associativity (* XXX Is LtoR the same as left associativity in Coq? *), at level 15, format "'[hv ' a1 '/' << a2 ']'") : expr_scope.
Notation "a1 & a2" := (Ebinop Oand a1%expr a2%expr _) (only printing, a2 at level 17, left associativity (* XXX Is LtoR the same as left associativity in Coq? *), at level 18, format "'[hv ' a1 '/' & a2 ']'") : expr_scope.
Notation "a1 != a2" := (Ebinop Cop.One a1%expr a2%expr _) (only printing, a2 at level 16, left associativity (* XXX Is LtoR the same as left associativity in Coq? *), at level 17, format "'[hv ' a1 '/' != a2 ']'") : expr_scope.
Notation "a1 * a2" := (Ebinop Omul a1%expr a2%expr _) (only printing, format "'[hv ' a1 '/' * a2 ']'", at level 40, left associativity) : expr_scope.
Notation "a1 == a2" := (Ebinop Oeq a1%expr a2%expr _) (only printing, a2 at level 16, left associativity (* XXX Is LtoR the same as left associativity in Coq? *), at level 17, format "'[hv ' a1 '/' == a2 ']'") : expr_scope.
Notation "a1 + a2" := (Ebinop Oadd a1%expr a2%expr _) (only printing, format "'[hv ' a1 '/' + a2 ']'", at level 50, left associativity) : expr_scope.
Notation "& a1" := (Eaddrof a1%expr _) (only printing, a1 at level 11, right associativity (* XXX Is RtoL the same as right associativity in Coq? *), at level 11, format "'[hv ' & a1 ']'") : expr_scope.
Notation "'__builtin_fabs' a1" := (Eunop Oabsfloat a1%expr _) (only printing, a1 at level 11, right associativity (* XXX Is RtoL the same as right associativity in Coq? *), at level 11, format "'[hv ' '__builtin_fabs' a1 ']'") : expr_scope.
Notation "~ a1" := (Eunop Onotint a1%expr _) (only printing, format "'[hv ' ~ a1 ']'", at level 75, right associativity) : expr_scope.
Notation "! a1" := (Eunop Onotbool a1%expr _) (only printing, format "'[hv ' ! a1 ']'", at level 30, right associativity) : expr_scope.
Notation "- a1" := (Eunop Oneg a1%expr _) (only printing, format "'[hv ' - a1 ']'", at level 35, right associativity) : expr_scope.
Notation "'__builtin_fabs(' a1 )" := (Eunop Oabsfloat a1%expr _) (only printing, a1 at level 24, right associativity (* XXX Is RtoL the same as right associativity in Coq? *), at level 11, format "'[hv ' '__builtin_fabs(' a1 ) ']'") : expr_scope.
Notation "n_val 'LL'" := (Econst_long n_val%camlint64_of_coqint _) (only printing, no associativity, at level 10, format "'[hv ' n_val 'LL' ']'") : expr_scope.
Notation "n_val 'LLU'" := (Econst_long n_val%camlint64_of_coqint (Tlong Unsigned _)) (only printing, no associativity, at level 10, format "'[hv ' n_val 'LLU' ']'") : expr_scope.
Notation "f_val 'f'" := (Econst_single f_val%camlfloat_of_coqfloat32 _) (only printing, no associativity, at level 10, format "'[hv ' f_val 'f' ']'") : expr_scope.
Notation "f_val" := (Econst_float f_val%camlfloat_of_coqfloat _) (only printing, format "'[hv ' f_val ']'", at level 10) : expr_scope.
Notation "n_val" := (Econst_int n_val%camlint_of_coqint _) (only printing, format "'[hv ' n_val ']'", at level 10) : expr_scope.
Notation "n_val 'U'" := (Econst_int n_val%camlint_of_coqint (Tint I32 Unsigned _)) (only printing, no associativity, at level 10, format "'[hv ' n_val 'U' ']'") : expr_scope.
Notation "a1 . f_val" := (Efield a1%expr f_val%extern_atom _) (only printing, left associativity (* XXX Is LtoR the same as left associativity in Coq? *), at level 10, format "'[hv ' a1 . f_val ']'") : expr_scope.
Notation "* a1" := (Ederef a1%expr _) (only printing, a1 at level 11, right associativity (* XXX Is RtoL the same as right associativity in Coq? *), at level 11, format "'[hv ' * a1 ']'") : expr_scope.
Notation "id" := (Etempvar id%positive _) (only printing, format "'[hv ' id ']'", at level 10) : expr_scope.
Notation "id" := (Evar id%extern_atom _) (only printing, format "'[hv ' id ']'", at level 10) : expr_scope.
Notation "lbl : s_val rem" := (LScons lbl%print_case_label s_val%C rem%print_cases) (only printing, rem at level 26, left associativity, at level 26, format "'[v ' lbl : '/' s_val ']' '/' rem") : print_cases_scope.
Notation "lbl : rem" := (LScons lbl%print_case_label Sskip rem%print_cases) (only printing, rem at level 26, left associativity, at level 26, format "lbl : '/' rem") : print_cases_scope.
Notation "" := LSnil (only printing, left associativity, at level 26, format "") : print_cases_scope.
Notation "'case' lbl" := (Some lbl%Z) (only printing, lbl at level 26, left associativity, at level 26, format "'case' lbl") : print_case_label_scope.
Notation "'default'" := None (only printing, format "'default'", at level 10) : print_case_label_scope.
Notation "p_val -> f_val" := (Efield (Ederef p_val%expr _) f_val%extern_atom _) (only printing, right associativity, at level 99, f_val at level 200, format "p_val -> f_val") : expr_scope.
Notation "p_val [ i_val ]" := (Ederef (Ebinop Oadd p_val%expr i_val%expr _) _) (only printing, left associativity, at level 26, format "p_val [ i_val ]") : expr_scope.
Notation "x , .. , y" := (@cons expr x%expr .. (@cons expr y%expr (@nil expr)) .. ) (only printing, at level 26, x at level 24, y at level 24) : print_expr_list_true_scope.
Notation "'while' ( e_val ) { s1 }" := (Swhile e_val%expr s1%C) (only printing, s1 at level 26, left associativity, at level 26, format "'[v' 'while' ( e_val ) { '/ ' s1 '/' } ']'") : C_scope.
Global Open Scope expr_scope.
Global Open Scope C_scope.
#!/usr/bin/env python
from __future__ import with_statement
import sys, re, os
KNOWN_FUNCTIONS = {}
KNOWN_RUNNABLE_FUNCTIONS = {}
FUNCTIONS_AS_SCOPES = ('name_of_external', 'extern_atom', 'camlint_of_coqint', 'camlfloat_of_coqfloat', 'camlfloat_of_coqfloat32', 'camlint64_of_coqint', 'name_type')
FUNCTION_WITH_STREAM_AND_ONE_ARG_AS_SCOPES = ('print_stmt', )
FUNCTIONS_WITH_PRECEDENCE = ('expr', )
FOR_COQ_8_6 = True
SCOPE_MAP = {'print_expr':'expr', 'print_stmt':'C'}
TEMP_NAME_REPLACEMENT = (r'"$" ^ ', '')
EVERY_STATEMENT_ON_A_NEW_LINE = True
var_replacements = dict((ch, ch + '_val') for ch in 'abcdefghijklmnopqrstuvwxyz')
def ocaml_to_coq_precedence(prec):
# PrintClight.ml parenthesizes things whenever a smaller precedence
# falls inside a larger one; Coq parenthesizes things the other
# way around, so we need to flip the sense of precedences. Note
# that the .ml file has 16 as it's max precedence, and we probably
# don't want anything below 10 (the level of Coq function
# application
return 26 - prec
def get_new_function_name(line, cur_function):
words = line.split(' ')
if words[0] in ('let', 'and') and len(words) > 1:
if words[0] == 'let' and words[1] == 'rec' and len(words) > 2:
return True, words[2], ' '.join(words[3:])
else:
return True, words[1], ' '.join(words[2:])
else:
return False, cur_function, None
def normalize(line):
line = line.strip()
if line[:2] == '(*' and line[-2:] == '*)' and '(*' not in line[2:-2]:
return ''
return line
def lines_to_functions(lines):
cur_function = None
is_match = False
ret = []
for line in lines:
changed, cur_function, extra = get_new_function_name(line, cur_function)
if changed:
parts = extra.split('=')
ret.append((cur_function, parts[0].strip(), [normalize('='.join(parts[1:]))]))
elif len(ret) > 0:
ret[-1][-1].append(normalize(line))
return tuple((name, args, tuple(line for line in body if len(line) > 0))
for name, args, body in ret)
def lex_string(body, delim='"'):
assert(len(delim) > 0)
assert(body[:len(delim)] == delim)
assert(delim in body[len(delim):])
body = body[len(delim):]
idx = body.index(delim) + len(delim)
return body[idx:], delim + body[:idx]
TOKENS = tuple(reversed(sorted(
list(r'~!@#$%^&*()+`-={}|[]\:;<>?,./') +
['->', '<-', ':=', '()', '[]', '::']
)))
def lex_token(body):
body = body.strip(' \n\t')
if len(body) == 0: return body, None
if body[0] in "'\"": return lex_string(body, body[0])
if body[0].isalpha() or body[0] == '_' or (body[0] == "'" and (body[1].isalpha() or body[1] == '_')):
if body[0] == "'":
body, ident = lex_token(body[1:])
return body, "'" + ident
match = re.match(r"^([A-Za-z_][A-Za-z0-9_'\.]*)", body)
ident = match.groups()[0]
body = body[len(ident):]
if ident in var_replacements.keys():
# this is a kludge to get around the fact that we can't
# use a variable called 'f' after reserving 'f' as a
# keyword
ident = var_replacements[ident]
return body, ident
if body[0].isdigit() or (body[0] in '+-' and len(body) > 1 and
(body[1].isdigit() or (body[1] == '.' and len(body) > 2 and
body[2].isdigit()))):
match = re.match(r'^([+-]?[0-9][0-9\.]*[L]?)', body)
ident = match.groups()[0]
return body[len(ident):], ident
else:
for tok in TOKENS:
if body[:len(tok)] == tok:
return body[len(tok):], tok
raw_input('ERROR: Unknown token: %s' % repr(body[20:]))
DEFAULT_INVALID_TOKS = ('let', 'in', 'if', 'then', 'else', 'rec', 'begin', 'match', 'with', 'end', 'function')
def parse_sexpr_gen(body, cur_sep=None, extra_toks=tuple(), inside_parens=False, max_app=None, top_invalid_toks=tuple(), invalid_toks=DEFAULT_INVALID_TOKS):
body = body.strip(' \n\t')
if len(body) == 0: return body, None, None
orig_body = body
def parse_again(body, tok):
if max_app is None:
new_max_app = None
else:
new_max_app = max_app - 1
if max_app == 0:
rest_idents, ty = None, None
else:
body, rest_idents, ty = parse_sexpr_gen(body, cur_sep=' ', extra_toks=extra_toks, inside_parens=inside_parens, max_app=new_max_app, top_invalid_toks=top_invalid_toks, invalid_toks=invalid_toks)
my_idents = [tok]
if ty == 'atom': my_idents.append(rest_idents)
elif ty is None: pass
elif ty == 'app': my_idents += rest_idents
else: assert(False)
if cur_sep == ' ':
return body, my_idents, 'app'
elif cur_sep == ',':
if len(my_idents) > 1:
ident = ('app', tuple(my_idents))
else:
ident = my_idents[0]
if max_app is not None:
return body, ident, 'atom'
body, rest_elements, ty2 = parse_sexpr_gen(body, cur_sep=',', extra_toks=extra_toks, inside_parens=inside_parens, max_app=None, top_invalid_toks=top_invalid_toks, invalid_toks=invalid_toks)
if ty2 is None:
return body, [ident], 'tuple'
elif ty2 == 'tuple':
return body, [ident] + rest_elements, 'tuple'
elif ty2 == 'atom':
return body, [ident, rest_elements], 'tuple'
else:
assert(False)
else:
assert(False)
body, tok = lex_token(body)
if cur_sep is None:
body, subexpr, ty = parse_sexpr_gen(orig_body, cur_sep=',', extra_toks=extra_toks, inside_parens=inside_parens, max_app=max_app, top_invalid_toks=top_invalid_toks, invalid_toks=invalid_toks)
if ty == 'atom' or ty is None:
return body, subexpr, ty
elif ty == 'tuple':
if len(subexpr) > 1:
return body, ('tuple', tuple(subexpr)), 'atom'
else:
return body, subexpr[0], 'atom'
else:
print(ty)
assert(False)
elif tok == ')':
return orig_body, None, None
elif tok == '(':
body, subexpr, ty = parse_sexpr_gen(body, cur_sep=None, extra_toks=extra_toks, inside_parens=True, max_app=None, top_invalid_toks=tuple(), invalid_toks=invalid_toks)
body = body.strip(' \n\t')
assert(body[:1] == ')')
body = body[1:]
if subexpr is None:
subexpr, ty = '()', 'atom'
elif ty == 'atom':
pass
elif ty in ('app', 'tuple'):
if len(subexpr) > 1:
subexpr, ty = (ty, tuple(subexpr)), 'atom'
else:
subexpr, ty = subexpr[0], 'atom'
else:
assert(False)
assert(ty == 'atom')
return parse_again(body, subexpr)
elif tok == ',':
if cur_sep == ' ':
return orig_body, None, None
elif cur_sep == ',':
body, next_app_list, ty = parse_sexpr_gen(body, cur_sep=' ', extra_toks=extra_toks, inside_parens=inside_parens, max_app=max_app, top_invalid_toks=top_invalid_toks, invalid_toks=invalid_toks)
if ty == 'app':
if len(next_app_list) > 1:
next_app_list = (ty, tuple(next_app_list))
else:
next_app_list = next_app_list[0]
ty = 'atom'
else:
assert(ty == 'atom')
if max_app is not None:
return orig_body, next_app_list, 'atom'
body, rest_components, ty2 = parse_sexpr_gen(body, cur_sep=',', extra_toks=extra_toks, inside_parens=inside_parens, max_app=None, top_invalid_toks=top_invalid_toks, invalid_toks=invalid_toks)
if ty2 == 'tuple':
return body, [next_app_list] + rest_components, 'tuple'
elif ty2 == 'app':
return body, [next_app_list, (ty2, tuple(rest_components))], 'tuple'
elif ty2 == 'atom':
return body, [next_app_list, rest_components], 'tuple'
elif ty2 is None:
return body, [next_app_list], 'tuple'
else:
assert(False)
else:
assert(False)
elif tok in top_invalid_toks or tok in invalid_toks:
return orig_body, None, None
elif tok[0].isalnum() or tok[0] in "'_\"" or tok in extra_toks or (inside_parens and tok in '|+<>'):
return parse_again(body, tok)
else:
return orig_body, None, None
def parse_sexpr(body, extra_toks=tuple(), max_app=None, top_invalid_toks=tuple(), invalid_toks=DEFAULT_INVALID_TOKS):
body = body.strip(' \n\t')
orig_body = body
body, sexpr, ty = parse_sexpr_gen(body, extra_toks=extra_toks, max_app=None, top_invalid_toks=top_invalid_toks, invalid_toks=invalid_toks)
if ty is None:
return orig_body, None
assert(ty == 'atom')
body = body.strip(' \n\t')
return body, sexpr
def parse_begin_end(body):
body = body.strip(' \n\t')
expr = []
orig_body = body
new_body, tok = lex_token(body)
if tok != 'begin': return parse_sexpr(orig_body)
new_body, main = parse_body(new_body)
new_body, tok = lex_token(new_body)
#print(tok)
assert(tok == 'end')
return new_body, ('begin_end', main)
def parse_list_with_toks(body, tag, good_toks, end_toks, parse_next):
body = body.strip(' \n\t')
expr = []
orig_body = body
new_body = body
tok = ''
while len(new_body) > 0 and tok not in end_toks:
body = new_body
new_body, pexpr = parse_next(body)
if pexpr is not None:
expr.append(pexpr)
else:
new_body, tok = lex_token(body)
if tok in good_toks:
expr.append(tok)
elif tok not in end_toks:
raw_input((tok, body))
if tok not in end_toks: body = new_body
if len(expr) == 0: return orig_body, None
if len(expr) == 1: return body, expr[0]
if tag is not None: return body, (tag, tuple(expr))
return body, tuple(expr)
def parse_unit(body):
body = body.strip(' \n\t')
new_body, tok = lex_token(body)
if tok == '()': return new_body, ('()',)
return parse_begin_end(body)
def parse_strcat(body):
body, expr \
= parse_list_with_toks(body, 'strcat', tuple('^'), tuple(list('+=-*<>;|') + list(DEFAULT_INVALID_TOKS)), parse_unit)
if expr is None: return body, None
if expr[0] == 'strcat':
#print(expr)
expr = expr[1]
assert(all(expr[i] == '^' for i in range(len(expr)) if i % 2 == 1))
assert(len(expr) > 1)
return body, ('strcat', tuple(i for i in expr if i != '^'))
return body, expr
def parse_infix(body):
return parse_list_with_toks(body, 'infix', tuple('+=-*<>'), tuple(list(';|') + list(DEFAULT_INVALID_TOKS)), parse_strcat)
def parse_if_then_else(body):
body = body.strip(' \n\t')
expr = []
orig_body = body
new_body, tok = lex_token(body)
if tok != 'if': return parse_infix(orig_body)
new_body, cond = parse_infix(new_body)
new_body, thens = lex_token(new_body)
if thens != 'then': return parse_seq(orig_body)
new_body, then_case = parse_infix(new_body)
body = new_body
new_body, elses = lex_token(new_body)
if elses != 'else':
return body, ('ifthenelse', {'test':cond, 'then':then_case, 'else':None})
new_body, else_case = parse_infix(new_body)
return new_body, ('ifthenelse', {'test':cond, 'then':then_case, 'else':else_case})
def parse_seq(body):
body, expr \
= parse_list_with_toks(body, 'seq', tuple(';'), tuple(list('|') + list(DEFAULT_INVALID_TOKS)), parse_if_then_else)
if expr is None: return body, None
if expr[0] == 'seq':
#print(expr)
expr = expr[1]
assert(len(expr) > 1)
return body, ('seq', tuple(i for i in expr if i != ';'))
return body, expr
def parse_let_in(body):
body = body.strip(' \n\t')
expr = []
orig_body = body
new_body, tok = lex_token(body)
if tok != 'let': return parse_seq(orig_body)
#print('let')
new_body, ident = parse_sexpr(new_body, max_app=1)
new_body, eqs = lex_token(new_body)
#print('=')
if eqs != '=': return parse_seq(orig_body)
new_body, val = parse_let_in(new_body)
new_body, instr = lex_token(new_body)
if instr != 'in': return parse_seq(orig_body)
#print('in')
new_body, rest = parse_let_in(new_body)
#print(rest)
#print(repr(new_body[:40]))
if len(new_body.strip(' \n\t')) != 0: return parse_seq(orig_body)
return new_body, ('letin', {'ident':ident,'val':val,'body':rest})
def parse_branch_cont(body):
return parse_list_with_toks(body, None, tuple(), tuple(list('|') + list(DEFAULT_INVALID_TOKS)), parse_let_in)
def parse_branch(body):
assert(body[0] == '|')
pats = []
while body[:1] == '|':
body, pat = parse_sexpr(body[1:], extra_toks=('::', '[]'))
pats.append(pat)
body, sep = lex_token(body)
assert(sep == '->')
body, expr = parse_branch_cont(body)
if isinstance(expr, str): expr = (expr,)
return body.strip(' \n\t'), {'patterns':tuple(pats), 'body': tuple(expr)}
def parse_match_branches(body):
body = body.strip(' \n\t')
ret = []
while True:
if body[:1] != '|': return body, ret
body, branch = parse_branch(body)
if branch is not None: ret.append(branch)
def parse_body(body):
body = body.strip(' \n\t')
if len(body) == 0: return '', []
orig_body = body
body, tok = lex_token(body)
if tok == 'match':
body, discriminee = parse_body(body)
if discriminee is None: return parse_let_in(orig_body)
body, tok = lex_token(body)
if tok != 'with': return parse_let_in(orig_body)
body, branches = parse_match_branches(body)
return body, [('match', {'discriminee':discriminee, 'branches':tuple(branches)})]
elif tok == 'function':
body, branches = parse_match_branches(body)
return body, [('function', {'branches':tuple(branches)})]
else:
return parse_let_in(orig_body)
def match_branch_body_to_notation(name, body, stream=None):
stmt = body
if len(stmt) == 1 and stmt[0] == '()': return '""', tuple()
if len(stmt) == 2 and stmt[0] == 'app':
funcall = stmt[1]
if funcall[0] == 'fprintf':
if stream is not None: assert(funcall[1] == stream)
format_string, args = funcall[2], funcall[3:]
args_types = re.findall('%(.)', format_string)
if len(args) == 0:
assert(len(args_types) == 0)
return format_string, tuple()
else:
arg_info = []
for ty in args_types:
if ty == 'a':
arg_info.append((args[1], args[0]))
args = args[2:]
else:
arg_info.append((args[0], None))
args = args[1:]
return format_string, tuple(arg_info)
elif funcall[0] in FUNCTION_WITH_STREAM_AND_ONE_ARG_AS_SCOPES:
assert(len(funcall) == 3)
if stream is not None: assert(funcall[1] == stream)
return '"%a"', ((funcall[2], funcall[0]), )
else:
raw_input(funcall)
elif len(stmt) == 2 and stmt[0] == 'seq':
stmt = stmt[1]
assert(len(stmt) == 2)
assert(stmt[0][0] == 'ifthenelse')
assert(stmt[0][1]['test'] == ('app', ('not', 'first')))
raw_input(stmt)
else:
raw_input(stmt)
def run_if_then_else(body, env):
if body[0] == 'ifthenelse':
test = run_if_then_else(body[1]['test'], env)
if test == True:
return run_if_then_else(body[1]['then'], env)
elif test == False:
return run_if_then_else(body[1]['else'], env)
else:
raw_input(test)
elif body[0] == 'infix':
body = body[1]
if len(body) == 3:
x1, x2 = run_if_then_else(body[0], env), run_if_then_else(body[2], env)
if body[1] == '=': return x1 == x2
raw_input(body)
else:
raw_input(body)
elif body[0] == 'app':
body = body[1]
if len(body) == 3:
x1, x2 = run_if_then_else(body[0], env), run_if_then_else(body[2], env)
if body[1] == '+': return int(x1) + int(x2)
raw_input(body)
else:
raw_input(body)
elif isinstance(body, str):
if body in env.keys(): return env[body]
elif body[0].isupper(): return body
elif body.isdigit(): return int(body)
raw_input(body)
elif body[0] == 'tuple':
return tuple(run_if_then_else(v, env) for v in body[1])
else:
raw_input(body)
def adjust_format_string(format_string, args, env, pattern):
special_toks = {
'@ ':(" '/'", None),
'%%':('%', '%'),
'@[':("'['", None),
'@]':("']'", None),
'@,':("'/'", None),
'@;':(" '/'", None),
'@.':("'//'", None)
}
ret = []
ret_format = []
args = list(args)
args_out = []
cur = None
def update_cur(cur):
if cur is not None:
if cur.strip() != '' and (cur[0].isalpha() or cur[0] in '_') and cur.replace('_', '').replace('(', '').isalnum():
#print('yes')
ret.append("'%s'" % cur)
ret_format.append("'%s'" % cur)
else:
#print('no')
ret.append(cur)
ret_format.append(cur)
return None
ocaml_assoc = None
associativity = 'left associativity'
precedence = None
if len(env) > 0:
for key, val in env.items():
if key == 'assoc' or key[0] == 'tuple' and 'assoc' in key[1]:
#print(val)
assert(val[0] == 'app')
assert(len(val) == 2)
val = val[1]
assert(val[0] in KNOWN_RUNNABLE_FUNCTIONS.keys())
comp_val = run_function_on_pattern(KNOWN_RUNNABLE_FUNCTIONS[val[0]], pattern)
#if not comp_val:
#raw_input((val[0], pattern))
if len(comp_val) == 1:
comp_val, mapping, comp_pat = comp_val[0]
extra_mapping = pattern_matches(key, comp_val)
assert('assoc' in extra_mapping.keys())
assoc = extra_mapping['assoc']
ocaml_assoc = assoc
assert("prec'" in extra_mapping.keys())
precedence = extra_mapping["prec'"]
if assoc == 'NA':
associativity = 'no associativity'
elif assoc == 'RtoL':
associativity = 'right associativity'
msg = 'XXX Is %s the same as %s in Coq?' % (assoc, associativity)
associativity = '%s (* %s *)' % (associativity, msg)
print(msg)
elif assoc == 'LtoR':
associativity = 'left associativity'
msg = 'XXX Is %s the same as %s in Coq?' % (assoc, associativity)
associativity = '%s (* %s *)' % (associativity, msg)
print(msg)
else:
pass
#raw_input(assoc)
else:
associativity = {}
precedence = {}
ocaml_assoc = {}
for comp_val, mapping, comp_pat in comp_val:
extra_mapping = pattern_matches(key, comp_val)
assert('assoc' in extra_mapping.keys())
assoc = extra_mapping['assoc']
assert("prec'" in extra_mapping.keys())
cur_precedence = extra_mapping["prec'"]
if assoc == 'NA':
cur_associativity = 'no associativity'
elif assoc == 'RtoL':
cur_associativity = 'right associativity'
msg = 'XXX Is %s the same as %s in Coq?' % (assoc, cur_associativity)
cur_associativity = '%s (* %s *)' % (cur_associativity, msg)
print(msg)
elif assoc == 'LtoR':
cur_associativity = 'left associativity'
msg = 'XXX Is %s the same as %s in Coq?' % (assoc, cur_associativity)
cur_associativity = '%s (* %s *)' % (cur_associativity, msg)
print(msg)
else:
raw_input(assoc)
for k, v in mapping.items():
if k not in associativity.keys(): associativity[k] = {}
if v not in associativity[k].keys(): associativity[k][v] = cur_associativity
if k not in ocaml_assoc.keys(): ocaml_assoc[k] = {}
if v not in ocaml_assoc[k].keys(): ocaml_assoc[k][v] = assoc
if k not in precedence.keys(): precedence[k] = {}
if v not in precedence[k].keys(): precedence[k][v] = cur_precedence
assert(ocaml_assoc[k][v] == assoc)
assert(associativity[k][v] == cur_associativity)
assert(precedence[k][v] == cur_precedence)
#print((repr(format_string), type(format_string)))
has_neg_break = (re.search(r'@;<[0-9]+\s+-[0-9]+>', format_string) is not None)
box_stack = []
while len(format_string) > 0:
cur_indent = (0 if len(box_stack) == 0 else box_stack[-1][1])
if format_string[:3] == '@[<':
match = re.match(r'^@\[<(hov|h|v|hv) ([0-9]+)>(.*)$', format_string, flags=re.DOTALL)
if not match:
print(format_string[:10])
box_type, count, format_string = match.groups()
cur = update_cur(cur)
coq_box_type = box_type.replace('hov', 'hv')
if has_neg_break:
box_stack.append((("'[%s'" % coq_box_type), int(count)))
else:
box_stack.append((("'[%s%s'" % (coq_box_type, ' ' * int(count))), int(count)))
if len(box_stack) == 1 or not FOR_COQ_8_6:
ret_format.append(box_stack[-1][0])
elif format_string[:3] == '@;<':
match = re.match(r'^@;<([0-9]+)\s+(-?[0-9]+)>(.*)$', format_string, flags=re.DOTALL)
if not match:
print(format_string[:10])
nspaces, offset, format_string = match.groups()
cur = update_cur(cur)
if has_neg_break:
ret_format.append("%s'/%s'" % (' ' * int(nspaces), ' ' * (cur_indent + int(offset))))
else:
ret_format.append("%s'/%s'" % (' ' * int(nspaces), ' ' * int(offset)))
elif format_string[:1] == ' ':
if cur is None:
cur = ''
elif cur.strip() == '':
cur += ' '
else:
cur = update_cur(cur)
cur = ''
format_string = format_string[1:]
elif format_string[:1] == '%':
if format_string[:2] in ('%a', '%s') or format_string[:3] in ('%lu', '%ld', '%Lu', '%Ld') or format_string[:5] in ('%.15F',):
(arg, printer), args = args[0], args[1:]
#print('cur %s' % cur)
cur = update_cur(cur)
if format_string[:2] in ('%a', '%s'): use_len = 2
elif format_string[:3] in ('%lu', '%ld', '%Lu', '%Ld'): use_len = 3
elif format_string[:5] in ('%.15F',): use_len = 5
info, format_string = format_string[:use_len], format_string[use_len:]
if isinstance(arg, str):
args_out.append((arg, printer, None, info))
if arg.strip() != '' and (arg[0].isalpha() or arg[0] in '_') and arg.replace('_', '').replace('(', '').isalnum():
ret.append("'%s'" % arg)
ret_format.append("'%s'" % arg)
else:
ret.append(arg)
ret_format.append(arg)
elif len(arg) == 2 and arg[0] == 'app':
notations = seq_to_notations(arg)
assert(len(notations) == 1)
upattern, uliteral_string, uformat_string, uargs_info \
= notations[0]
assert(upattern is None)
ret.extend(uliteral_string)
ret_format.extend(uformat_string)
args_out.extend(uargs_info)
elif len(arg) == 2 and arg[0] == 'tuple':
arg = arg[1]
#print((format_string, printer, arg))
assert(len(arg) == 2)
assert(isinstance(arg[1], str))
if arg[0] in ('true', 'false'):
args_out.append((arg[1], printer + '_' + arg[0], None, info))
ret.append(arg[1])
ret_format.append(arg[1])
elif printer in FUNCTIONS_WITH_PRECEDENCE:
#print((arg, printer))
#print(env)
if arg[0].isdigit():
args_out.append((arg[1], printer, int(arg[0]), info))
ret.append(arg[1])
ret_format.append(arg[1])
else:
found = False
for key, val in env.items():
if found: continue
if arg[0] == key or key[0] == 'tuple' and arg[0] in key[1]:
found = True
#print(val)
#print(format_string)
if val[0] == 'app':
assert(len(val) == 2)
val = val[1]
assert(val[0] in KNOWN_RUNNABLE_FUNCTIONS.keys())
comp_val = run_function_on_pattern(KNOWN_RUNNABLE_FUNCTIONS[val[0]], pattern)
assert(len(comp_val) == 1)
comp_val, mapping, comp_pat = comp_val[0]
extra_mapping = pattern_matches(key, comp_val)
assert(arg[0] in extra_mapping.keys())
prec = extra_mapping[arg[0]]
if prec.isdigit():
args_out.append((arg[1], printer, int(prec), info))
ret.append(arg[1])
ret_format.append(arg[1])
else:
raw_input(extra_mapping[arg[0]])
raw_input((key, comp_val))
raw_input((pattern, val))
elif val[0] == 'ifthenelse':
if isinstance(ocaml_assoc, str) and isinstance(precedence, str):
comp_val = run_if_then_else(val, {'assoc': ocaml_assoc, "prec'":int(precedence)})
extra_mapping = pattern_matches(key, ('tuple', tuple(str(i) for i in comp_val)))
assert(arg[0] in extra_mapping.keys())
prec = extra_mapping[arg[0]]
if prec.isdigit():
args_out.append((arg[1], printer, int(prec), info))
ret.append(arg[1])
ret_format.append(arg[1])
else:
raw_input(extra_mapping[arg[0]])
raw_input((key, comp_val))
raw_input((pattern, val))
raw_input((arg[0], extra_mapping))
else:
raw_input((ocaml_assoc, precedence))
else:
assert(False)
assert(found)
else:
assert(False)
else:
raw_input((arg, printer))
assert(False)
elif format_string[:2] in ('%@', '%%'):
if cur is None or cur.strip() == '':
cur = update_cur(cur)
cur = ''
cur += format_string[1]
format_string = format_string[2:]
else:
raw_input(format_string[:6])
else:
found = False
for tok, (rep_format, rep) in reversed(sorted(special_toks.items(),
key=(lambda (k,v): len(k)))):
if found: continue
if format_string[:len(tok)] == tok:
cur = update_cur(cur)
if rep is not None: ret.append(rep)
if has_neg_break and "'/'" in rep_format or "'//'" in rep_format:
rep_format = rep_format.replace("'/'", "'/%s'" % (' ' * cur_indent)).replace("'//'", "'//%s'" % (' ' * cur_indent))
if tok == '@[': box_stack.append((rep_format, 0))
if tok not in ('@[', '@]') or len(box_stack) == 1 or not FOR_COQ_8_6:
ret_format.append(rep_format)
if tok == '@]': box_stack.pop()
format_string = format_string[len(tok):]
found = True
if not found:
if format_string[0] not in '@%':
#print(cur)
if cur is None or cur.strip() == '':
cur = update_cur(cur)
cur = ''
cur += format_string[0]
format_string = format_string[1:]
else:
raw_input(format_string[:4])
cur = update_cur(cur)
#print((ret_format, args))
assert(len(args) == 0)
#print(ret)
if precedence is not None: precedence = int(precedence)
assert(precedence is None or isinstance(precedence, int))
assert(associativity is None or isinstance(associativity, str))
return (tuple(i.strip() for i in ret if i.strip() != ''),
tuple(ret_format),
tuple(args_out),
associativity,
precedence)
def strip_quotes(v):
if v[0] == '"' and v[-1] == '"': return v[1:-1]
return v
def multiply_args(pattern, args, env):
if len(args) == 0: return [(pattern, args)]
arg, args = args[0], args[1:]
if arg[0][0] != 'app':
#print('noapp')
return [(pattern, tuple([arg] + list(args)))
for pattern, args in multiply_args(pattern, args, env)]
arg_name = arg[0][1][0]
#print(('app', arg_name))
if arg_name in KNOWN_FUNCTIONS.keys():
#print('found')
body, mkmap = KNOWN_FUNCTIONS[arg_name]
#raw_input(expr[1:])
body = do_subst(body, mkmap(*arg[0][1][1:]))
if isinstance(body, dict):
assert(all(len(inner_expr) == 1
for k, v in body.items()
for pats, inner_expr in v.items()))
ret = [(new_pattern, new_args)
for pattern, args in [(do_subst(pattern, {k:pat}),
tuple([(strip_quotes(inner_expr[0]), arg[1])] + list(args)))
for k, v in body.items()
for pats, inner_expr in v.items()
for pat in pats]
for new_pattern, new_args in multiply_args(pattern, args, env)]
#raw_input(ret)
return ret
else:
return [(pattern, tuple([arg] + list(args)))
for pattern, args in multiply_args(pattern, args, env)]
return [(pattern, tuple([arg] + list(args)))
for pattern, args in multiply_args(pattern, args, env)]
def match_to_notations(branches, env, discriminee=None):
notations = []
for branch in branches:
format_string, args = match_branch_body_to_notation(name, branch['body'])
assert(format_string[0] == '"' and format_string[-1] == '"')
for pattern in branch['patterns']:
if pattern == '_' and discriminee is not None: pattern = discriminee
for new_pattern, new_args in multiply_args(pattern, args, env):
#print('here')
#print((new_args, env, new_pattern))
literal_string, new_format_string, arg_info, associativity, precedence \
= adjust_format_string(format_string[1:-1], new_args, env, new_pattern)
#if '__builtin_fabs' in ' '.join(literal_string):
#raw_input((literal_string, new_format_string, format_string, new_args, new_pattern, format_string))
notations.append((new_pattern, literal_string, new_format_string, arg_info, associativity, precedence))
#print(notations[-1])
#raw_input(notations[-1])
return list(reversed(notations))
def pattern_matches(loose_pattern, tight_pattern):
ret = {}
if loose_pattern == '_' or tight_pattern == '_': return ret
if isinstance(loose_pattern, str) and isinstance(tight_pattern, str):
if loose_pattern[0].isupper() and tight_pattern[0].isupper():
return ret if loose_pattern == tight_pattern else None
else:
ret[loose_pattern] = tight_pattern
return ret
if loose_pattern[0] == tight_pattern[0] and loose_pattern[0] in ('app', 'tuple'):
assert(len(loose_pattern) == 2)
assert(len(tight_pattern) == 2)
loose_pattern, tight_pattern = loose_pattern[1], tight_pattern[1]
assert(len(loose_pattern) == len(tight_pattern))
for lp, tp in zip(loose_pattern, tight_pattern):
matches = pattern_matches(lp, tp)
if matches is None: return None
ret.update(matches)
elif isinstance(loose_pattern, str) and tight_pattern[0] == 'app' and \
all(tight_pattern[1][2*i+1] == '|'
for i in range(len(tight_pattern[1]) / 2)):
for tp in tight_pattern[1]:
if tp == '|': continue
matches = pattern_matches(loose_pattern, tp)
if matches is not None:
ret.update(matches)
return ret
return None
else:
raw_input((loose_pattern, tight_pattern))
return ret
def run_function_on_pattern(body, pattern):
assert(len(body) == 1)
body = body[0]
assert(len(body) == 2)
assert(body[0] == 'function')
branches = body[1]['branches']
ret = []
for branch in branches:
for branch_pattern in branch['patterns']:
mapping = pattern_matches(pattern, branch_pattern)
#print(('mapping', mapping, pattern, branch_pattern))
if mapping is None: continue
ret.append((branch['body'], mapping, branch_pattern))
#print(ret[-1])
return ret
def do_subst(body, rep_dict):
if isinstance(body, str):
return rep_dict.get(body, body)
elif body[0] in ('strcat', 'seq', 'app', 'tuple'):
assert(len(body) == 2)
return (body[0],
tuple(do_subst(arg, rep_dict) for arg in body[1]))
elif len(body) == 1 and body[0][0] == 'function':
assert(isinstance(rep_dict, tuple))
assert(len(rep_dict) == 1)
body = body[0][1]
return {rep_dict[0]:dict((branch['patterns'], branch['body'])
for branch in body['branches'])}
raw_input((body, rep_dict))
def join_notations(notations_list):
def pattern_matches(p1, p2):
assert(p1 is None)
assert(p2 is None)
return True
ret_notations = []
for notations in notations_list:
assert(len(notations) == 1)
for pattern, literal_string, format_string, args_info, associativity, precedence in notations:
if not any(pattern_matches(pattern, upattern) for upattern, uliteral_string, uformat_string, uargs_info, uassociativity, uprecedence in ret_notations):
ret_notations.append([pattern, list(literal_string), list(format_string), list(args_info), associativity, precedence])
else:
for upattern, uliteral_string, uformat_string, uargs_info, uassociativity, uprecedence in ret_notations:
if pattern_matches(upattern, pattern):
assert(pattern is None)
uliteral_string.extend(literal_string)
uformat_string.extend(format_string)
uargs_info.extend(args_info)
assert(uassociativity == associativity)
assert(uprecedence == precedence)
assert(isinstance(associativity, str))
assert(isinstance(precedence, int))
return [(pattern, tuple(literal_string), tuple(format_string), tuple(args_info), associativity, precedence)
for pattern, literal_string, format_string, args_info, associativity, precedence in ret_notations]
def seq_to_notations(expr, env=None):
if env is None: env = {}
if isinstance(expr, str):
#print(expr)
assert(expr[0] == '"' and expr[-1] == '"')
expr = expr[1:-1]
return [(None, [expr], [expr], tuple())]
elif expr[0] in ('match', 'function'):
return match_to_notations(expr[1]['branches'], env, discriminee=expr[1].get('discriminee', None))
elif expr[0] == 'app':
assert(len(expr) == 2)
expr = expr[1]
if expr[0] in KNOWN_FUNCTIONS.keys():
body, mkmap = KNOWN_FUNCTIONS[expr[0]]
#raw_input(expr[1:])
body = do_subst(body, mkmap(*expr[1:]))
if isinstance(body, dict):
return dict((k,
dict((pat,
seq_to_notations(inner_expr))
for pat, inner_expr in v.items()))
for k, v in body.items())
else:
return seq_to_notations(body)
elif expr[0] == 'Z.to_string':
assert(len(expr) == 2)
expr = expr[1]
if expr[0] == 'app':
assert(len(expr) == 2)
expr = expr[1]
assert(expr[0] == 'Z.Zpos')
assert(len(expr) == 2)
ident = expr[1]
assert(isinstance(ident, str))
return [(None, [ident], [ident], ((ident, 'positive', None, None), ))]
elif isinstance(expr, str):
return [(None, [expr], [expr], ((expr, 'Z', None, None), ))]
else:
raw_input(expr)
elif expr[0] in FUNCTIONS_AS_SCOPES:
assert(isinstance(expr[1], str))
assert(len(expr) == 2)
scope, ident = expr
return [(None, [ident], [ident], ((ident, scope, None, None), ))]
else:
raw_input(expr)
elif expr[0] == 'strcat':
assert(len(expr) == 2)
expr = expr[1]
return join_notations(seq_to_notations(s) for s in expr)
elif len(expr) == 1 and isinstance(expr[0], str) and expr[0][0] == '"' and expr[0][-1] == '"':
ident = expr[0][1:-1]
return [(None, [ident], [ident], tuple())]
else:
raw_input(expr)
def function_to_notations(name, body, env=None):
notations = []
if len(body) == 1:
for line in body:
notations += seq_to_notations(line, env)
else:
if body[0] == 'letin':
assert(len(body) == 2)
body = body[1]
if env is None: env = {}
env = dict(env)
env[body['ident']] = body['val']
return function_to_notations(name, body['body'], env)
elif body[0] == 'seq':
assert(len(body) == 2)
body = body[1]
if len(body) == 3 and body[0][0] == 'ifthenelse' and body[-1][0] == 'ifthenelse':
if (body[0][1]['then'] == ('app', ('fprintf', var_replacements.get('p', 'p'), '"@[<hov 2>("')) and
body[0][1]['else'] == ('app', ('fprintf', var_replacements.get('p', 'p'), '"@[<hov 2>"')) and
body[-1][1]['then'] == ('app', ('fprintf', var_replacements.get('p', 'p'), '")@]"')) and
body[-1][1]['else'] == ('app', ('fprintf', var_replacements.get('p', 'p'), '"@]"'))):
body = body[1]
notations = function_to_notations(name, body, env)
notations = [(pattern,
literal_string,
tuple(["'[hv '"] + list(format_string) + ["']'"]),
args_info,
associativity,
precedence)
for pattern, literal_string, format_string, args_info, associativity, precedence in notations]
return notations
else:
raw_input(body)
else:
raw_input((len(body), body))
elif body[0] == 'begin_end':
assert(len(body) == 2)
body = body[1]
return function_to_notations(name, body, env)
elif body[0] == 'function':
assert(len(body) == 2)
body = body[1]
return match_to_notations(body['branches'], env)
else:
raw_input(body)
return notations
def sexpr_args_to_mkmap(sargs):
ret = []
if sargs[0] == 'app' and len(sargs) == 2:
sargs = sargs[1][1:]
for arg in sargs:
if isinstance(arg, str):
ret.append(arg)
elif arg[0] == 'app':
assert(len(arg) == 2)
arg = arg[1]
assert(len(arg) == 3)
assert(arg[1] == ':')
ret.append(arg[0])
else:
raw_input(arg)
arg_names = tuple(ret)
#print(arg_names)
def mkmap(*args):
assert(len(args) == len(arg_names))
return dict(zip(arg_names, args))
return mkmap
elif isinstance(sargs, str):
def mkmap(*args):
return args
return mkmap
else:
raw_input(sargs)
def print_term(term, scope_map, needs_parens=False, known_idents=tuple()):
if isinstance(term, str):
if term in scope_map.keys():
scope = scope_map[term]
return term + '%' + SCOPE_MAP.get(scope, scope)
elif term[0].isupper() or not term[0].isalpha():
return term
elif term in known_idents:
return term
else:
print('Replacing %s with _' % term)
return '_'
elif term[0] == 'app':
assert(len(term) == 2)
term = term[1]
if term[0][0].isupper() and len(term) == 2 and term[1][0] == 'tuple' and len(term[1]) == 2:
term = tuple([term[0]] + list(term[1][1]))
ret = ' '.join(print_term(arg, scope_map, needs_parens=True)
for arg in term)
if needs_parens: ret = '(%s)' % ret
return ret
else:
fmt = '%s' if not needs_parens and len(term) > 1 else '(%s)'
ret = ' '.join(print_term(arg, scope_map, needs_parens=True)
for arg in term)
return fmt % ret
raw_input(term)
DEFAULT_PRECEDENCE = 0
SINGLE_IDENT_PRECEDENCE = 10
def notations_to_coq(scope, notations, default_precedence=DEFAULT_PRECEDENCE, default_associativity='left associativity'):
ret = []
specifiers = ['only printing']
scopes = set([scope])
for pattern, literal_string, format_string, args, associativity, precedence in notations:
if associativity is None: associativity = default_associativity
if precedence is None: precedence = default_precedence
cur_specifiers = list(specifiers)
scope_map = {}
for arg, arg_scope, arg_precedence, fmt in args:
scope_map[arg] = arg_scope
if literal_string[0].strip("'") != arg.strip("'"):
if arg_precedence is None: arg_precedence = precedence
if arg.isalnum():
cur_specifiers.append('%s at level %d' % (arg, ocaml_to_coq_precedence(arg_precedence)))
else:
if arg_precedence is not None:
# ERROR if we run afoul of
# https://coq.inria.fr/bugs/show_bug.cgi?id=5739,
# It should be possible to change the level of
# the leftmost non-terminal for only printing
# notations
assert(precedence == arg_precedence)
#precedence = arg_precedence
scopes.add(arg_scope)
cur_specifiers.append(associativity)
cur_specifiers.append('at level %d' % ocaml_to_coq_precedence(precedence))
printed_term = print_term(pattern, scope_map)
for arg, arg_scope, arg_precedence, fmt in args:
if arg in printed_term:
qarg = "'%s'" % arg
if qarg in literal_string:
literal_string = [i.replace(qarg, arg) for i in literal_string]
if qarg in format_string:
format_string = [i.replace(qarg, arg) for i in format_string]
if len(literal_string) == 2 and len(args) == 2 and tuple(literal_string) == tuple(arg[0] for arg in args) and EVERY_STATEMENT_ON_A_NEW_LINE:
format_string = [i.replace("'/'", "'//'") for i in format_string]
cur_specifiers.append('format "%s"' % ' '.join(format_string))
ignore_level = False
forced_specifiers = []
forced_levels = {'<':70, '>':70, '>=':70, '^':30, '-':50, '<=':70, '/':40, '*':40, '+':50, '=':70}
forced_prefix_levels = {'-':35, '~':75, '!':30}
forced_assoc = {'^':'right associativity', '-':'left associativity', '/':'left associativity', '+':'left associativity', '*':'left associativity'}
forced_prefix_assoc = {'~':'right associativity', '-':'right associativity', '!':'right associativity'}
if len(literal_string) == 3 and literal_string[1] in forced_levels.keys():
ignore_level = True
forced_specifiers.append('at level %d'
% forced_levels[literal_string[1]])
if literal_string[1] in forced_assoc.keys():
forced_specifiers.append(forced_assoc[literal_string[1]])
elif len(literal_string) == 2 and literal_string[0] in forced_prefix_levels.keys():
ignore_level = True
forced_specifiers.append('at level %d'
% forced_prefix_levels[literal_string[0]])
if literal_string[0] in forced_prefix_assoc.keys():
forced_specifiers.append(forced_prefix_assoc[literal_string[0]])
elif len(literal_string) == 1:
ignore_level = True
forced_specifiers.append('at level %d' % SINGLE_IDENT_PRECEDENCE)
#if '__builtin_fabs' in ' '.join(literal_string):
#raw_input((literal_string))
ret.append('Notation "%s" := %s (%s) : %s_scope.'
% (' '.join(literal_string),
print_term(pattern, scope_map, needs_parens=True),
', '.join([i for i in cur_specifiers
if ('at level' not in i and 'associativity' not in i) or not ignore_level]
+ forced_specifiers),
SCOPE_MAP.get(scope, scope)))
#print(ret[-1])
return scopes, ret
def assemble_coq(scopes, notations):
ret = ['Require Import Clightdefs.', '']
for scope in sorted(set(SCOPE_MAP.get(scope, scope) for scope in scopes)):
ret.append('Delimit Scope %s_scope with %s.' % (scope, scope))
ret.append('')
ret.append('Notation "x" := (Int.repr x%%Z) (only printing, at level %d) : expr_scope.' % SINGLE_IDENT_PRECEDENCE)
ret.append('')
ret.extend(notations)
ret.append('')
ret.append('Notation "p_val -> f_val" := (Efield (Ederef p_val%expr _) f_val%extern_atom _) (only printing, right associativity, at level 99, f_val at level 200, format "p_val -> f_val") : expr_scope.')
ret.append('Notation "p_val [ i_val ]" := (Ederef (Ebinop Oadd p_val%%expr i_val%%expr _) _) (only printing, left associativity, at level %d, format "p_val [ i_val ]") : expr_scope.' % ocaml_to_coq_precedence(DEFAULT_PRECEDENCE))
ret.append('Notation "x , .. , y" := (@cons expr x%%expr .. (@cons expr y%%expr (@nil expr)) .. ) (only printing, at level %d, x at level %d, y at level %d) : print_expr_list_true_scope.' % (ocaml_to_coq_precedence(DEFAULT_PRECEDENCE), ocaml_to_coq_precedence(2), ocaml_to_coq_precedence(2))) # 2 comes from print_expr_list in PrintClight.ml
ret.append('''Notation "'while' ( e_val ) { s1 }" := (Swhile e_val%%expr s1%%C) (only printing, s1 at level %d, left associativity, at level %d, format "'[v' 'while' ( e_val ) { '/ ' s1 '/' } ']'") : C_scope.''' % (ocaml_to_coq_precedence(DEFAULT_PRECEDENCE), ocaml_to_coq_precedence(DEFAULT_PRECEDENCE)))
ret.append('')
for scope in ('expr', 'C'):
ret.append('Global Open Scope %s_scope.' % scope)
ret.append('')
return '\n'.join(ret)
if __name__ == '__main__':
if len(sys.argv) != 3 or '--help' in sys.argv or '-h' in sys.argv:
print('USAGE: %s COMPCERT_FOLDER OUTPUT' % sys.argv[0])
sys.exit(1)
dirpath = sys.argv[1]
fname = os.path.join(dirpath, 'cfrontend/PrintClight.ml')
#fname = '/home/jgross/Documents/repos/VST/compcert/cfrontend/PrintClight.ml'
fname2 = os.path.join(dirpath, 'cfrontend/PrintCsyntax.ml')
#fname2 = '/home/jgross/Documents/repos/VST/compcert/cfrontend/PrintCsyntax.ml'
with open(fname, 'r') as f:
lines = f.readlines()
with open(fname2, 'r') as f:
lines_syntax = f.readlines()
fns = dict((name, (args, body)) for name, args, body in lines_to_functions(lines_syntax))
fns.update(dict((name, (args, body)) for name, args, body in lines_to_functions(lines)))
for name in ('temp_name', 'name_unop', 'name_binop'):
(args, body) = fns[name]
if name == 'temp_name' and TEMP_NAME_REPLACEMENT is not None:
assert(TEMP_NAME_REPLACEMENT[0] in body[0])
body = tuple(b.replace(TEMP_NAME_REPLACEMENT[0], TEMP_NAME_REPLACEMENT[1]) for b in body)
body, parsed_body = parse_body('\n'.join(body))
assert(body == '')
extra, sargs = parse_sexpr(name + ' ' + args, extra_toks=(':',))
assert(extra == '')
mkmap = sexpr_args_to_mkmap(sargs)
KNOWN_FUNCTIONS[name] = (parsed_body, mkmap)
name, (args, body) = 'precedence', fns['precedence']
body, precedence = parse_body('\n'.join(body))
assert(body == '')
KNOWN_RUNNABLE_FUNCTIONS['precedence'] = precedence
notations, scopes = [], set()
for name in ('print_stmt_for', 'print_stmt', 'expr', 'print_cases', 'print_case_label'): # 'print_expr_list',
(args, body) = fns[name]
body, parsed_body = parse_body('\n'.join(body))
assert(body == '')
cur_notations = function_to_notations(name, parsed_body)
cur_scopes, cur_notations = notations_to_coq(name, cur_notations)
scopes.update(cur_scopes)
notations += cur_notations
coq = assemble_coq(scopes, notations)
with open(sys.argv[2], 'w') as f:
f.write(coq)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment