1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2021 Thomas Pointhuber <thomas.pointhuber@gmx.at>
5  * Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
23  */
24 
25 #include "altium_rule_transformer.h"
26 
27 #include <iostream>
28 #include <wx/wxcrt.h>   // for wxIsspace
29 
Next()30 const ALTIUM_RULE_TOKEN& ALTIUM_RULE_TOKENIZER::Next()
31 {
32     m_currentToken = m_nextToken;
33 
34     // skip whitespaces
35     for( ; m_it != m_expr.end() && wxIsspace( curChar() ); nextChar() )
36         ;
37 
38     // check for end of string
39     if( m_it == m_expr.end() )
40     {
41         m_nextToken = { ALTIUM_RULE_TOKEN_KIND::END_OF_EXPR, m_pos };
42         return m_currentToken;
43     }
44 
45     const size_t    startPos = m_pos;
46     const wxUniChar curCh = curChar();
47     wxUniChar       nextCh = nextChar();
48 
49     if( curCh == '(' )
50     {
51         m_nextToken = { ALTIUM_RULE_TOKEN_KIND::LPAR, startPos };
52         return m_currentToken;
53     }
54     else if( curCh == ')' )
55     {
56         m_nextToken = { ALTIUM_RULE_TOKEN_KIND::RPAR, startPos };
57         return m_currentToken;
58     }
59     else if( curCh == '*' )
60     {
61         m_nextToken = { ALTIUM_RULE_TOKEN_KIND::MUL, startPos };
62         return m_currentToken;
63     }
64     else if( curCh == '/' )
65     {
66         m_nextToken = { ALTIUM_RULE_TOKEN_KIND::DIV, startPos };
67         return m_currentToken;
68     }
69     else if( curCh == '=' )
70     {
71         m_nextToken = { ALTIUM_RULE_TOKEN_KIND::EQUAL, startPos };
72         return m_currentToken;
73     }
74     else if( curCh == '<' )
75     {
76         if( nextCh == '=' )
77         {
78             nextChar();
79             m_nextToken = { ALTIUM_RULE_TOKEN_KIND::LESS_EQUAL, startPos };
80         }
81         else if( nextCh == '>' )
82         {
83             nextChar();
84             m_nextToken = { ALTIUM_RULE_TOKEN_KIND::NOT_EQUAL, startPos };
85         }
86         else
87         {
88             m_nextToken = { ALTIUM_RULE_TOKEN_KIND::LESS, startPos };
89         }
90         return m_currentToken;
91     }
92     else if( curCh == '>' )
93     {
94         if( nextCh == '=' )
95         {
96             nextChar();
97             m_nextToken = { ALTIUM_RULE_TOKEN_KIND::GREATER_EQUAL, startPos };
98         }
99         else
100         {
101             m_nextToken = { ALTIUM_RULE_TOKEN_KIND::GREATER, startPos };
102         }
103         return m_currentToken;
104     }
105     else if( curCh == '&' && nextCh == '&' )
106     {
107         nextChar();
108         m_nextToken = { ALTIUM_RULE_TOKEN_KIND::LOW_AND, startPos };
109         return m_currentToken;
110     }
111     else if( curCh == '|' && nextCh == '|' )
112     {
113         nextChar();
114         m_nextToken = { ALTIUM_RULE_TOKEN_KIND::LOW_OR, startPos };
115         return m_currentToken;
116     }
117     else if( curCh == '\'' )
118     {
119         std::cout << "start const string" << std::endl;
120         wxString constString;
121         while( m_it != m_expr.end() && nextCh != '\'' )
122         {
123             constString += nextCh; // TODO: escaping?
124             nextCh = nextChar();
125         }
126         std::cout << "end const string: " << constString << std::endl;
127 
128         if( m_it != m_expr.end() )
129         {
130             nextChar(); // TODO: exception if EOF reached?
131         }
132 
133         m_nextToken = { ALTIUM_RULE_TOKEN_KIND::CONST_STRING, startPos, constString };
134         return m_currentToken;
135     }
136     else if( curCh == '+' && !wxIsdigit( nextCh ) )
137     {
138         m_nextToken = { ALTIUM_RULE_TOKEN_KIND::ADD, startPos };
139         return m_currentToken;
140     }
141     else if( curCh == '-' && !wxIsdigit( nextCh ) )
142     {
143         m_nextToken = { ALTIUM_RULE_TOKEN_KIND::SUB, startPos };
144         return m_currentToken;
145     }
146     else if( curCh == '+' || curCh == '-' || wxIsdigit( curCh ) )
147     {
148         wxString digitString = curCh;
149         while( wxIsdigit( nextCh ) )
150         {
151             digitString += nextCh;
152             nextCh = nextChar();
153         }
154 
155         long value;
156         digitString.ToLong( &value ); // TODO: check return value
157 
158         m_nextToken = { ALTIUM_RULE_TOKEN_KIND::CONST_INT, startPos, value };
159         return m_currentToken;
160     }
161     else
162     {
163         wxString identString = curCh;
164         while( wxIsalnum( nextCh ) )
165         {
166             identString += nextCh;
167             nextCh = nextChar();
168         }
169 
170         if( identString.IsSameAs( "True", false ) )
171         {
172             m_nextToken = { ALTIUM_RULE_TOKEN_KIND::CONST_TRUE, startPos };
173         }
174         else if( identString.IsSameAs( "False", false ) )
175         {
176             m_nextToken = { ALTIUM_RULE_TOKEN_KIND::CONST_FALSE, startPos };
177         }
178         else if( identString.IsSameAs( "Div", false ) )
179         {
180             m_nextToken = { ALTIUM_RULE_TOKEN_KIND::INTEGRAL_DIV, startPos };
181         }
182         else if( identString.IsSameAs( "Mod", false ) )
183         {
184             m_nextToken = { ALTIUM_RULE_TOKEN_KIND::MOD, startPos };
185         }
186         else if( identString.IsSameAs( "And", false ) )
187         {
188             m_nextToken = { ALTIUM_RULE_TOKEN_KIND::AND, startPos };
189         }
190         else if( identString.IsSameAs( "Or", false ) )
191         {
192             m_nextToken = { ALTIUM_RULE_TOKEN_KIND::OR, startPos };
193         }
194         else if( identString.IsSameAs( "Xor", false ) )
195         {
196             m_nextToken = { ALTIUM_RULE_TOKEN_KIND::XOR, startPos };
197         }
198         else if( identString.IsSameAs( "Not", false ) )
199         {
200             m_nextToken = { ALTIUM_RULE_TOKEN_KIND::NOT, startPos };
201         }
202         else if( identString.IsSameAs( "Between", false ) )
203         {
204             m_nextToken = { ALTIUM_RULE_TOKEN_KIND::BETWEEN, startPos };
205         }
206         else if( identString.IsSameAs( "Like", false ) )
207         {
208             m_nextToken = { ALTIUM_RULE_TOKEN_KIND::LIKE, startPos };
209         }
210         else
211         {
212             m_nextToken = { ALTIUM_RULE_TOKEN_KIND::IDENT, startPos, identString };
213         }
214 
215         return m_currentToken;
216     }
217 }
218 
Peek() const219 const ALTIUM_RULE_TOKEN& ALTIUM_RULE_TOKENIZER::Peek() const
220 {
221     return m_nextToken;
222 }