Skip to content

Commit

Permalink
enh(directx): Add do-while loop support to DirectX backend (#206)
Browse files Browse the repository at this point in the history
* enh(DirectX): Add do-while parser support for DirectX backend

Implementation details:

- Added "DO" token in lexer.
- Implemented DoWhileNode in DirectxAst.py to create do-while node in the AST
- Added logic to parse do-while statement when "DO" token is read
- Implemented do-while code generation from CrossGL

Test details:

- Added parser test for do-while
- Added code generation test for do-while

Signed-off-by: Maharshi Basu <[email protected]>

* enh(DirectX): Add line break after while in do-while codegen

Signed-off-by: Maharshi Basu <[email protected]>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Signed-off-by: Maharshi Basu <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
MashyBasker and pre-commit-ci[bot] authored Oct 21, 2024
1 parent 6ee42fb commit 676f901
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 0 deletions.
9 changes: 9 additions & 0 deletions crosstl/src/backend/DirectX/DirectxAst.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,15 @@ def __repr__(self):
return f"WhileNode(condition={self.condition}, body={self.body})"


class DoWhileNode(ASTNode):
def __init__(self, condition, body):
self.condition = condition
self.body = body

def __repr__(self):
return f"DoWhileNode(condition={self.condition}, body={self.body})"


class ReturnNode(ASTNode):
def __init__(self, value):
self.value = value
Expand Down
11 changes: 11 additions & 0 deletions crosstl/src/backend/DirectX/DirectxCrossGLCodeGen.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ def generate_function_body(self, body, indent=0, is_main=False):
code += self.generate_for_loop(stmt, indent, is_main)
elif isinstance(stmt, WhileNode):
code += self.generate_while_loop(stmt, indent, is_main)
elif isinstance(stmt, DoWhileNode):
code += self.generate_do_while_loop(stmt, indent, is_main)
elif isinstance(stmt, IfNode):
code += self.generate_if_statement(stmt, indent, is_main)
return code
Expand All @@ -164,6 +166,15 @@ def generate_while_loop(self, node, indent, is_main):
code += " " * indent + "}\n"
return code

def generate_do_while_loop(self, node, indent, is_main):
condition = self.generate_expression(node.condition, is_main)

code = "do {\n"
code += self.generate_function_body(node.body, indent + 1, is_main)
code += " " * indent + "} "
code += f"while ({condition});\n"
return code

def generate_if_statement(self, node, indent, is_main):
condition = self.generate_expression(node.condition, is_main)

Expand Down
2 changes: 2 additions & 0 deletions crosstl/src/backend/DirectX/DirectxLexer.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
("ELSE", r"\belse\b"),
("FOR", r"\bfor\b"),
("WHILE", r"\b\while\b"),
("DO", r"\b\do\b"),
("REGISTER", r"\bregister\b"),
("IDENTIFIER", r"[a-zA-Z_][a-zA-Z0-9_]*"),
("NUMBER", r"\d+(\.\d+)?"),
Expand Down Expand Up @@ -75,6 +76,7 @@
"else": "ELSE",
"for": "FOR",
"while": "WHILE",
"do": "DO",
"register": "REGISTER",
}

Expand Down
19 changes: 19 additions & 0 deletions crosstl/src/backend/DirectX/DirectxParser.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
BinaryOpNode,
ForNode,
WhileNode,
DoWhileNode,
FunctionCallNode,
FunctionNode,
IfNode,
Expand Down Expand Up @@ -198,6 +199,8 @@ def parse_statement(self):
return self.parse_return_statement()
elif self.current_token[0] == "WHILE":
return self.parse_while_statement()
elif self.current_token[0] == "DO":
return self.parse_do_while_statement()
else:
return self.parse_expression_statement()

Expand Down Expand Up @@ -359,6 +362,22 @@ def parse_while_statement(self):

return WhileNode(condition, body)

def parse_do_while_statement(self):
# do token
self.eat("DO")

# parse do block
body = self.parse_block()

# parse while condition
self.eat("WHILE")
self.eat("LPAREN")
condition = self.parse_expression()
self.eat("RPAREN")
self.eat("SEMICOLON")

return DoWhileNode(condition, body)

def parse_return_statement(self):
self.eat("RETURN")
value = self.parse_expression()
Expand Down
45 changes: 45 additions & 0 deletions tests/test_backend/test_directx/test_codegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,51 @@ def test_while_codegen():
pytest.fail("While loop parsing or code generation not implemented.")


def test_do_while_codegen():
code = """
struct VSInput {
float4 position : POSITION;
float4 color : TEXCOORD0;
};
struct VSOutput {
float4 out_position : TEXCOORD0;
};
VSOutput VSMain(VSInput input) {
VSOutput output;
output.out_position = input.position;
int i = 0;
do {
output.out_position = input.color;
i = i + 1; // Increment the loop variable
} while (i < 10);
return output;
}
struct PSInput {
float4 in_position : TEXCOORD0;
};
struct PSOutput {
float4 out_color : SV_TARGET0;
};
PSOutput PSMain(PSInput input) {
PSOutput output;
output.out_color = input.in_position;
int i = 0;
do {
output.out_color = float4(1.0, 1.0, 1.0, 1.0);
i = i + 1; // Increment the loop variable
} while (i < 10);
return output;
}
"""
try:
tokens = tokenize_code(code)
ast = parse_code(tokens)
generated_code = generate_code(ast)
print(generated_code)
except SyntaxError:
pytest.fail("While loop parsing or code generation not implemented.")


def test_else_codegen():
code = """
struct VSInput {
Expand Down
19 changes: 19 additions & 0 deletions tests/test_backend/test_directx/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,25 @@ def test_while_parsing():
pytest.fail("while parsing not implemented")


def test_do_while_parsing():
code = """
VSOutput VSMain(VSInput input) {
VSOutput output;
int i = 0;
do {
output.out_position = input.position;
i = i + 1;
} while (i < 10);
return output;
}
"""
try:
tokens = tokenize_code(code)
parse_code(tokens)
except SyntaxError:
pytest.fail("do while parsing not implemented")


def test_else_parsing():
code = """
PSOutput PSMain(PSInput input) {
Expand Down

0 comments on commit 676f901

Please sign in to comment.