blob: ae8444e730bc19d13c45dc5d62510c1cd470cd02 [file] [log] [blame]
Sapan Bhatia64c72512017-06-23 02:32:45 -07001__author__ = "Sapan Bhatia"
2
3__copyright__ = "Copyright (C) 2017 Open Networking Lab"
4__version__ = "1.0"
5
Zack Williamsbe7f36d2018-02-02 11:37:11 -07006from helpers import LexHelper
Sapan Bhatia64c72512017-06-23 02:32:45 -07007
Sapan Bhatia64c72512017-06-23 02:32:45 -07008
Sapan Bhatia9c579722018-01-12 13:45:09 -05009class FOLParsingError(Exception):
Zack Williamsbe7f36d2018-02-02 11:37:11 -070010
Sapan Bhatia9c579722018-01-12 13:45:09 -050011 def __init__(self, message, error_range):
12 super(FOLParsingError, self).__init__(message)
13 self.error_range = error_range
14
Zack Williamsbe7f36d2018-02-02 11:37:11 -070015
Sapan Bhatia64c72512017-06-23 02:32:45 -070016class FOLLexer(object):
Sapan Bhatiacee04022017-07-20 02:12:43 -040017 keywords = ('forall', 'exists', 'True', 'False', 'not', 'in')
Sapan Bhatia64c72512017-06-23 02:32:45 -070018
Zack Williamsbe7f36d2018-02-02 11:37:11 -070019 tokens = ['STRING_LITERAL',
20 'NUM',
21 'ESCAPE',
22 'COLON',
23 'IMPLIES',
24 'OR',
25 'AND',
26 'LPAREN',
27 'RPAREN',
28 'EQUALS',
29 'SYMBOL',
30 'LT',
31 'RT',
32 'STAR'] + [k.upper() for k in keywords]
Sapan Bhatia64c72512017-06-23 02:32:45 -070033 # literals = '()+-*/=?:,.^|&~!=[]{};<>@%'
34
35 t_ignore_LINE_COMMENT = '//.*'
36 t_COLON = '\\:'
37 t_IMPLIES = '\\-\\>'
38 t_OR = '\\|'
Sapan Bhatia99669732017-07-25 19:19:14 -040039 t_STAR = '\\*'
Sapan Bhatia64c72512017-06-23 02:32:45 -070040 t_LT = '\\<'
41 t_RT = '\\>'
42 t_AND = '\\&'
43 t_LPAREN = '\\('
44 t_RPAREN = '\\)'
Sapan Bhatiafc1278c2017-07-17 12:57:13 -040045 t_NUM = r'[+-]?\d+(\.\d+)?'
46 t_STRING_LITERAL = r'\"([^\\\n]|(\\.))*?\"'
Sapan Bhatia64c72512017-06-23 02:32:45 -070047
48 t_EQUALS = '\\='
49
50 literals = '()+-*/=?:,.^|&~!=[]{};<>@%'
51
52 t_ignore = ' \t\f'
53
54 def t_newline(self, t):
55 r'\n+'
56 t.lexer.lineno += len(t.value)
57
58 def t_newline2(self, t):
59 r'(\r\n)+'
60 t.lexer.lineno += len(t.value) / 2
61
Sapan Bhatia9c579722018-01-12 13:45:09 -050062 def t_ESCAPE(self, t):
63 r'{{ (.|\n)*? }}'
64 t.lexer.lineno += t.value.count('\n')
65 return t
Sapan Bhatia64c72512017-06-23 02:32:45 -070066
67 def t_BLOCK_COMMENT(self, t):
68 r'/\*(.|\n)*?\*/'
69 t.lexer.lineno += t.value.count('\n')
70
71 def t_SYMBOL(self, t):
Sapan Bhatia99669732017-07-25 19:19:14 -040072 '[A-Za-z_$][\.A-Za-z0-9_+$]*(\(\))?'
Sapan Bhatia64c72512017-06-23 02:32:45 -070073 if t.value in FOLLexer.keywords:
74 t.type = t.value.upper()
75 return t
76
77 def t_error(self, t):
Zack Williamsbe7f36d2018-02-02 11:37:11 -070078 print("Illegal character '{}' ({}) in line {}".format(
79 t.value[0], hex(ord(t.value[0])), t.lexer.lineno))
Sapan Bhatia64c72512017-06-23 02:32:45 -070080 t.lexer.skip(1)
Zack Williamsbe7f36d2018-02-02 11:37:11 -070081
82
Sapan Bhatia64c72512017-06-23 02:32:45 -070083class FOLParser(object):
84 tokens = FOLLexer.tokens
85 offset = 0
86 lh = LexHelper()
87
88 def setOffset(self, of):
89 self.offset = of
90 self.lh.offset = of
91
Sapan Bhatiafc1278c2017-07-17 12:57:13 -040092 def p_term_numeric_constant(self, p):
93 '''term : NUM'''
94 p[0] = p[1]
95
96 def p_term_string_constant(self, p):
97 '''term : STRING_LITERAL'''
98 p[0] = p[1]
99
100 def p_term_boolean_constant(self, p):
Sapan Bhatia64c72512017-06-23 02:32:45 -0700101 '''term : FALSE
102 | TRUE'''
103 p[0] = p[1]
104
Sapan Bhatia99669732017-07-25 19:19:14 -0400105 def p_term_policy_function(self, p):
106 '''term : STAR SYMBOL LPAREN SYMBOL RPAREN'''
107 p[0] = {'policy': [p[2], p[4]]}
108
Sapan Bhatia64c72512017-06-23 02:32:45 -0700109 def p_fole_not(self, p):
110 '''fole : NOT fole'''
111 p[0] = {p[1]: p[2]}
112
113 def p_fole_term(self, p):
114 '''fole : term'''
115 p[0] = p[1]
116
117 def p_term_symbol(self, p):
118 '''term : SYMBOL'''
119 p[0] = p[1]
120
121 def p_term_python(self, p):
Sapan Bhatiab934f722017-07-15 08:42:19 -0400122 '''term : ESCAPE'''
Sapan Bhatiabc6268c2017-07-16 02:43:45 -0400123 p[0] = {'python': p[1].lstrip('{ ').rstrip(' }')}
Sapan Bhatia64c72512017-06-23 02:32:45 -0700124
125 def p_fole_group(self, p):
126 "fole : LPAREN fole RPAREN"
127 p[0] = p[2]
128
Sapan Bhatiacee04022017-07-20 02:12:43 -0400129 def p_fole_in(self, p):
130 "fole : term IN term"
131 p[0] = {'in': (p[1], p[3])}
132
Sapan Bhatia64c72512017-06-23 02:32:45 -0700133 def p_fole_equals(self, p):
134 "fole : term EQUALS term"
135 p[0] = {'=': (p[1], p[3])}
136
137 def p_fole_binary(self, p):
138 '''fole : fole AND fole
139 | fole OR fole
140 | fole IMPLIES fole'''
141 p[0] = {p[2]: [p[1], p[3]]}
142
143 def p_fole_quant(self, p):
144 '''fole : FORALL SYMBOL COLON fole
145 | EXISTS SYMBOL COLON fole'''
146 p[0] = {p[1]: [p[2], p[4]]}
147
Sapan Bhatia64c72512017-06-23 02:32:45 -0700148 def p_goal(self, p):
149 '''goal : LT fole RT'''
150 p[0] = p[2]
151
152 def p_error(self, p):
Sapan Bhatia9c579722018-01-12 13:45:09 -0500153 error = 'error: {}'.format(p)
Zack Williamsbe7f36d2018-02-02 11:37:11 -0700154 raise FOLParsingError(error, (p.lineno, p.lexpos, len(p.value)))
Sapan Bhatia64c72512017-06-23 02:32:45 -0700155
Sapan Bhatia9c579722018-01-12 13:45:09 -0500156 precedence = (
Zack Williamsbe7f36d2018-02-02 11:37:11 -0700157 ("right", "IMPLIES"),
158 ("left", "OR"),
159 ("left", "AND"),
160 ("right", "COLON"),
161 ("right", "NOT"),
162 ("right", "STAR"),
163 ("right", "ESCAPE"),
164 ("nonassoc", "EQUALS", "IN"))