Dark Mode

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 2ae0a5c

Browse files
committed
Add: elif & else cases
1 parent 6587247 commit 2ae0a5c

File tree

11 files changed

+160
-18
lines changed
  • config
    • parser.json
    • transpiler.json
  • docs
    • TODO.md
  • fastpy_build
    • bin
      • main.exe
    • src
      • main.cpp
  • fastpy
    • lexer
      • detectors.py
    • parser
      • node_parsers.py
      • nodes.py
    • transpiler
      • node_transpilers.py
      • transpilers.py
  • main.fpy

11 files changed

+160
-18
lines changed

config/parser.json

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,37 @@
269269
}
270270
]
271271
},
272+
"ElseNode": {
273+
"parser_class": "fastpy.parser.node_parsers.UniversalNodeParser",
274+
"node_class": "fastpy.parser.nodes.ElseNode",
275+
"cases": [
276+
{
277+
"validate_data": {
278+
"methods": {
279+
"check_token_names": {
280+
"names": [
281+
"else"
282+
]
283+
},
284+
"check_token_name": {
285+
"exception": {
286+
"message": "SyntaxError: body start operator expected"
287+
},
288+
"token_index": -1,
289+
"possible_names": [
290+
"body_start"
291+
]
292+
},
293+
"check_fixed_tokens_length": {
294+
"length": 2
295+
}
296+
}
297+
},
298+
"parse_data": {
299+
}
300+
}
301+
]
302+
},
272303
"IfNode": {
273304
"parser_class": "fastpy.parser.node_parsers.UniversalNodeParser",
274305
"node_class": "fastpy.parser.nodes.IfNode",
@@ -307,6 +338,44 @@
307338
}
308339
}
309340
}
341+
},
342+
{
343+
"validate_data": {
344+
"methods": {
345+
"check_token_names": {
346+
"names": [
347+
"elif"
348+
]
349+
},
350+
"check_token_name": {
351+
"exception": {
352+
"message": "SyntaxError: body start operator expected"
353+
},
354+
"token_index": -1,
355+
"possible_names": [
356+
"body_start"
357+
]
358+
},
359+
"check_min_tokens_length": {
360+
"min_length": 3
361+
}
362+
}
363+
},
364+
"parse_data": {
365+
"condition": {
366+
"parser_class": "fastpy.parser.node_parsers.ConditionParser",
367+
"possible_node_classes": [
368+
"fastpy.parser.nodes.LogicOpNode",
369+
"fastpy.parser.nodes.BinOpNode"
370+
],
371+
"tokens_slice": {
372+
"start_index": 1
373+
}
374+
},
375+
"is_elif": {
376+
"value": true
377+
}
378+
}
310379
}
311380
]
312381
},

config/transpiler.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"fastpy.parser.nodes.FuncNode": "fastpy.transpiler.node_transpilers.FuncNodeTranspiler",
1212
"fastpy.parser.nodes.CallNode": "fastpy.transpiler.node_transpilers.CallNodeTranspiler",
1313
"fastpy.parser.nodes.IfNode": "fastpy.transpiler.node_transpilers.IfNodeTranspiler",
14-
"fastpy.parser.nodes.LogicOpNode": "fastpy.transpiler.node_transpilers.OperationsNodeTranspiler"
14+
"fastpy.parser.nodes.LogicOpNode": "fastpy.transpiler.node_transpilers.OperationsNodeTranspiler",
15+
"fastpy.parser.nodes.ElseNode": "fastpy.transpiler.node_transpilers.ElseNodeTranspiler"
1516
}
1617
}

docs/TODO.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44

55
- [x] Variables & base types
66
- [x] Functions
7-
- [x] Modules
8-
- [ ] Conditions
7+
- [ ] Modules
8+
- [x] Importing
9+
- [ ] Namespaces
10+
- [x] Conditions
911
- [x] if
10-
- [ ] elif
11-
- [ ] else
12-
- [ ] Namespaces
12+
- [x] elif
13+
- [x] else

fastpy/lexer/detectors.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,11 @@ def detect(self,
5353

5454
for op, name in OPERATORS.items():
5555
if start == op[0]:
56-
if op[0] in string.ascii_letters:
56+
if op[0] in string.ascii_letters and name != 'else':
5757
if re.match(op + ' ', cut_string):
5858
overlaps.append(op)
5959
else:
60+
6061
if re.match(re.escape(op), cut_string):
6162
overlaps.append(op)
6263

fastpy/parser/node_parsers.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ class UniversalNodeParser(BaseNodeParser):
3131
CallNode,
3232
ValueNode,
3333
VariableNode,
34-
IfNode
34+
IfNode,
35+
ElseNode
3536
)
3637

3738
@staticmethod
@@ -59,6 +60,7 @@ def validate(self,
5960
):
6061
if exception:
6162
self._raise_exception(tokens=tokens, exception_data=exception)
63+
6264
return False
6365

6466
return True
@@ -68,6 +70,10 @@ def _parse_value(tokens: list[BaseToken], parse_node: callable, **value_data):
6870
index = value_data.get('index')
6971
parser_class_path = value_data.get('parser_class')
7072
nullable = value_data.get('nullable', True)
73+
value = value_data.get('value')
74+
if value:
75+
return value
76+
7177
value = None
7278

7379
if index is not None:
@@ -82,6 +88,7 @@ def _parse_value(tokens: list[BaseToken], parse_node: callable, **value_data):
8288
)
8389
tokens_slice_data = value_data.get('tokens_slice')
8490
slice_start = tokens_slice_data.get('start_index')
91+
8592
if slice_start:
8693
value = parse_node(
8794
tokens=tokens[slice_start::],
@@ -151,10 +158,24 @@ def _check_operand_fields(operand: BinOpNode) -> bool:
151158

152159
@staticmethod
153160
def _create_op_node(left_operand: BaseNode, operator: BaseToken, right_operand: BaseNode):
161+
if not operator:
162+
return LogicOpNode(
163+
left_operand=left_operand,
164+
operator=operator,
165+
right_operand=right_operand
166+
)
154167
if operator.name in ['and', 'or']:
155-
return LogicOpNode(left_operand=left_operand, operator=operator, right_operand=right_operand)
168+
return LogicOpNode(
169+
left_operand=left_operand,
170+
operator=operator,
171+
right_operand=right_operand
172+
)
156173
else:
157-
return BinOpNode(left_operand=left_operand, operator=operator, right_operand=right_operand)
174+
return BinOpNode(
175+
left_operand=left_operand,
176+
operator=operator,
177+
right_operand=right_operand
178+
)
158179

159180
def parse(self,
160181
tokens: list[BaseToken],

fastpy/parser/nodes.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,16 +110,29 @@ def line(self) -> int:
110110
return self.left_operand.line
111111

112112

113+
class ElseNode(NodeWithBody, PrintableNode):
114+
def __init__(self, body: list[BaseNode] = None, ):
115+
self.body = body or []
116+
117+
@property
118+
def line(self) -> int:
119+
if len(self.body) > 0:
120+
return self.body[0].line
121+
return -1
122+
123+
113124
class IfNode(NodeWithBody, PrintableNode):
114125
def __init__(self,
115126
condition: LogicOpNode = None,
116127
body: list[BaseNode] = None,
117128
elif_cases: list = None,
118-
else_body: list[BaseNode] = None):
129+
else_case: ElseNode = None,
130+
is_elif: bool = False):
119131
self.condition = condition
120132
self.body = body or []
121133
self.elif_cases: list[IfNode.__init__] = elif_cases
122-
self.else_body = else_body
134+
self.else_case = else_case
135+
self.is_elif = is_elif
123136

124137
@property
125138
def line(self) -> int:

fastpy/transpiler/node_transpilers.py

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,6 @@ def transpile(self,
173173

174174
@singleton
175175
class IfNodeTranspiler(BaseNodeTranspiler):
176-
177176
@staticmethod
178177
def _transpile_condition(node: LogicOpNode, transpile_node_clb) -> str:
179178
return transpile_node_clb(node, endl=False, auto_semicolon=False).internal
@@ -197,5 +196,37 @@ def transpile(self,
197196
condition = self._transpile_condition(node.condition, transpile_node_clb)
198197
body = self._transpile_body(node.body, transpile_node_clb)
199198

200-
code.push_internal(f'if ({condition}) {{\n{body}\n}}', auto_semicolon=False, endl=True)
199+
code.push_internal(
200+
f'{"else if" if node.is_elif else "if"} ({condition}) {{\n{body}\n}}',
201+
auto_semicolon=False,
202+
endl=True
203+
)
204+
return code
205+
206+
207+
class ElseNodeTranspiler(BaseNodeTranspiler):
208+
209+
@staticmethod
210+
def _transpile_body(body: list[BaseNode], transpile_node_clb) -> str:
211+
code = Code()
212+
213+
for i, node in enumerate(body):
214+
code.push_internal(
215+
transpile_node_clb(node=node, endl=False, auto_semicolon=False).internal,
216+
)
217+
218+
return code.internal
219+
220+
def transpile(self,
221+
node: ElseNode,
222+
transpile_node_clb: callable,
223+
**kwargs) -> BaseCode:
224+
code = Code()
225+
body = self._transpile_body(node.body, transpile_node_clb)
226+
227+
code.push_internal(
228+
f'else {{\n{body}\n}}',
229+
auto_semicolon=False,
230+
endl=True
231+
)
201232
return code

fastpy/transpiler/transpilers.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from ..log import Logger
77
from .node_transpilers import *
88
from jinja2 import Environment, FileSystemLoader, Template
9+
from ..exceptions import *
910

1011

1112
class BaseTranspiler(ABC):
@@ -53,6 +54,10 @@ def _load_template(self):
5354
def _transpile_node(self, node: BaseNode, **kwargs) -> BaseCode:
5455
Logger.log_info(f'Transpiling: {node.line}: {node}')
5556
transpiler: BaseNodeTranspiler = self._transpilers.get(node.__class__)
57+
if not transpiler:
58+
raise TranspilingError(f'You need to specify the node transpiler for "{node.__class__.__name__}"'
59+
f' in "transpiler.json" config file')
60+
5661
return transpiler.transpile(
5762
node=node,
5863
transpile_node_clb=self._transpile_node,

fastpy_build/bin/main.exe

0 Bytes
Binary file not shown.

fastpy_build/src/main.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@ log_info(name, true);
2525

2626
}
2727

28-
if (age > 15 && age < 18) {
28+
else if (age > 15) {
2929
log_warning(name, true);
3030

3131
}
3232

33-
if (age < 16) {
33+
else {
3434
log_error(name, true);
3535

3636
}

0 commit comments

Comments
(0)