blob: b948d46bf7dcbd5b8c6c5ab38b3b83189ff6faa4 [file] [log] [blame]
Zack Williams28f1e492019-02-01 10:02:56 -07001from __future__ import absolute_import
2from __future__ import print_function
Sapan Bhatia64c72512017-06-23 02:32:45 -07003__author__ = "Sapan Bhatia"
4
5__copyright__ = "Copyright (C) 2017 Open Networking Lab"
6__version__ = "1.0"
7
Scott Baker20997cf2019-04-04 10:10:06 -07008import sys
Zack Williams28f1e492019-02-01 10:02:56 -07009from .helpers import LexHelper
Sapan Bhatia64c72512017-06-23 02:32:45 -070010
Sapan Bhatia64c72512017-06-23 02:32:45 -070011
Sapan Bhatia9c579722018-01-12 13:45:09 -050012class FOLParsingError(Exception):
Zack Williamsbe7f36d2018-02-02 11:37:11 -070013
Sapan Bhatia9c579722018-01-12 13:45:09 -050014 def __init__(self, message, error_range):
15 super(FOLParsingError, self).__init__(message)
16 self.error_range = error_range
17
Zack Williamsbe7f36d2018-02-02 11:37:11 -070018
Sapan Bhatia64c72512017-06-23 02:32:45 -070019class FOLLexer(object):
Sapan Bhatiacee04022017-07-20 02:12:43 -040020 keywords = ('forall', 'exists', 'True', 'False', 'not', 'in')
Sapan Bhatia64c72512017-06-23 02:32:45 -070021
Zack Williamsbe7f36d2018-02-02 11:37:11 -070022 tokens = ['STRING_LITERAL',
23 'NUM',
24 'ESCAPE',
25 'COLON',
26 'IMPLIES',
27 'OR',
28 'AND',
29 'LPAREN',
30 'RPAREN',
31 'EQUALS',
32 'SYMBOL',
33 'LT',
34 'RT',
35 'STAR'] + [k.upper() for k in keywords]
Sapan Bhatia64c72512017-06-23 02:32:45 -070036 # literals = '()+-*/=?:,.^|&~!=[]{};<>@%'
37
38 t_ignore_LINE_COMMENT = '//.*'
39 t_COLON = '\\:'
40 t_IMPLIES = '\\-\\>'
41 t_OR = '\\|'
Sapan Bhatia99669732017-07-25 19:19:14 -040042 t_STAR = '\\*'
Sapan Bhatia64c72512017-06-23 02:32:45 -070043 t_LT = '\\<'
44 t_RT = '\\>'
45 t_AND = '\\&'
46 t_LPAREN = '\\('
47 t_RPAREN = '\\)'
Sapan Bhatiafc1278c2017-07-17 12:57:13 -040048 t_NUM = r'[+-]?\d+(\.\d+)?'
49 t_STRING_LITERAL = r'\"([^\\\n]|(\\.))*?\"'
Sapan Bhatia64c72512017-06-23 02:32:45 -070050
51 t_EQUALS = '\\='
52
53 literals = '()+-*/=?:,.^|&~!=[]{};<>@%'
54
55 t_ignore = ' \t\f'
56
57 def t_newline(self, t):
58 r'\n+'
59 t.lexer.lineno += len(t.value)
60
61 def t_newline2(self, t):
62 r'(\r\n)+'
63 t.lexer.lineno += len(t.value) / 2
64
Sapan Bhatia9c579722018-01-12 13:45:09 -050065 def t_ESCAPE(self, t):
66 r'{{ (.|\n)*? }}'
67 t.lexer.lineno += t.value.count('\n')
68 return t
Sapan Bhatia64c72512017-06-23 02:32:45 -070069
70 def t_BLOCK_COMMENT(self, t):
71 r'/\*(.|\n)*?\*/'
72 t.lexer.lineno += t.value.count('\n')
73
74 def t_SYMBOL(self, t):
Zack Williams28f1e492019-02-01 10:02:56 -070075 r'[A-Za-z_$][\.A-Za-z0-9_+$]*(\(\))?'
Sapan Bhatia64c72512017-06-23 02:32:45 -070076 if t.value in FOLLexer.keywords:
77 t.type = t.value.upper()
78 return t
79
80 def t_error(self, t):
Zack Williams28f1e492019-02-01 10:02:56 -070081 print(("Illegal character '{}' ({}) in line {}".format(
Scott Baker20997cf2019-04-04 10:10:06 -070082 t.value[0], hex(ord(t.value[0])), t.lexer.lineno)),
83 file=sys.stderr)
Sapan Bhatia64c72512017-06-23 02:32:45 -070084 t.lexer.skip(1)
Zack Williamsbe7f36d2018-02-02 11:37:11 -070085
86
Sapan Bhatia64c72512017-06-23 02:32:45 -070087class FOLParser(object):
88 tokens = FOLLexer.tokens
89 offset = 0
90 lh = LexHelper()
91
92 def setOffset(self, of):
93 self.offset = of
94 self.lh.offset = of
95
Sapan Bhatiafc1278c2017-07-17 12:57:13 -040096 def p_term_numeric_constant(self, p):
97 '''term : NUM'''
98 p[0] = p[1]
99
100 def p_term_string_constant(self, p):
101 '''term : STRING_LITERAL'''
102 p[0] = p[1]
103
104 def p_term_boolean_constant(self, p):
Sapan Bhatia64c72512017-06-23 02:32:45 -0700105 '''term : FALSE
106 | TRUE'''
107 p[0] = p[1]
108
Sapan Bhatia99669732017-07-25 19:19:14 -0400109 def p_term_policy_function(self, p):
110 '''term : STAR SYMBOL LPAREN SYMBOL RPAREN'''
111 p[0] = {'policy': [p[2], p[4]]}
112
Sapan Bhatia64c72512017-06-23 02:32:45 -0700113 def p_fole_not(self, p):
114 '''fole : NOT fole'''
115 p[0] = {p[1]: p[2]}
116
117 def p_fole_term(self, p):
118 '''fole : term'''
119 p[0] = p[1]
120
121 def p_term_symbol(self, p):
122 '''term : SYMBOL'''
123 p[0] = p[1]
124
125 def p_term_python(self, p):
Sapan Bhatiab934f722017-07-15 08:42:19 -0400126 '''term : ESCAPE'''
Sapan Bhatiabc6268c2017-07-16 02:43:45 -0400127 p[0] = {'python': p[1].lstrip('{ ').rstrip(' }')}
Sapan Bhatia64c72512017-06-23 02:32:45 -0700128
129 def p_fole_group(self, p):
130 "fole : LPAREN fole RPAREN"
131 p[0] = p[2]
132
Sapan Bhatiacee04022017-07-20 02:12:43 -0400133 def p_fole_in(self, p):
134 "fole : term IN term"
135 p[0] = {'in': (p[1], p[3])}
136
Sapan Bhatia64c72512017-06-23 02:32:45 -0700137 def p_fole_equals(self, p):
138 "fole : term EQUALS term"
139 p[0] = {'=': (p[1], p[3])}
140
141 def p_fole_binary(self, p):
142 '''fole : fole AND fole
143 | fole OR fole
144 | fole IMPLIES fole'''
145 p[0] = {p[2]: [p[1], p[3]]}
146
147 def p_fole_quant(self, p):
148 '''fole : FORALL SYMBOL COLON fole
149 | EXISTS SYMBOL COLON fole'''
150 p[0] = {p[1]: [p[2], p[4]]}
151
Sapan Bhatia64c72512017-06-23 02:32:45 -0700152 def p_goal(self, p):
153 '''goal : LT fole RT'''
154 p[0] = p[2]
155
156 def p_error(self, p):
Sapan Bhatia9c579722018-01-12 13:45:09 -0500157 error = 'error: {}'.format(p)
Zack Williamsbe7f36d2018-02-02 11:37:11 -0700158 raise FOLParsingError(error, (p.lineno, p.lexpos, len(p.value)))
Sapan Bhatia64c72512017-06-23 02:32:45 -0700159
Sapan Bhatia9c579722018-01-12 13:45:09 -0500160 precedence = (
Zack Williamsbe7f36d2018-02-02 11:37:11 -0700161 ("right", "IMPLIES"),
162 ("left", "OR"),
163 ("left", "AND"),
164 ("right", "COLON"),
165 ("right", "NOT"),
166 ("right", "STAR"),
167 ("right", "ESCAPE"),
168 ("nonassoc", "EQUALS", "IN"))