Skip to content

Commit

Permalink
Extend elvis operator (#195)
Browse files Browse the repository at this point in the history
* Adjust grammar

* Extend elvis operator

* Add test
  • Loading branch information
marcauberer committed Aug 28, 2022
1 parent d4b0554 commit 0b4d63f
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 7 deletions.
16 changes: 15 additions & 1 deletion media/test-project/os-test.spice
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,23 @@ f<int> main() {
printf("Hello %s!", p1.getSecond());
}*/

import "std/net/http" as http;
/*import "std/net/http" as http;

f<int> main() {
http::HttpServer server = http::HttpServer();
server.serve("/test", "Hello World!");
}*/

f<bool> f1() {
printf("F1 called.\n");
return false;
}

f<bool> f2() {
printf("F2 called.\n");
return false;
}

f<int> main() {
printf("Result: %d", f1() ?: f2());
}
2 changes: 1 addition & 1 deletion src/Spice.g4
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ joinCall: JOIN LPAREN assignExpr (COMMA assignExpr)* RPAREN;

// Expression loop
assignExpr: prefixUnaryExpr assignOp assignExpr | ternaryExpr | threadDef;
ternaryExpr: logicalOrExpr (QUESTION_MARK logicalOrExpr COLON logicalOrExpr)?;
ternaryExpr: logicalOrExpr (QUESTION_MARK logicalOrExpr? COLON logicalOrExpr)?;
logicalOrExpr: logicalAndExpr (LOGICAL_OR logicalAndExpr)*;
logicalAndExpr: bitwiseOrExpr (LOGICAL_AND bitwiseOrExpr)*;
bitwiseOrExpr: bitwiseXorExpr (BITWISE_OR bitwiseXorExpr)*;
Expand Down
13 changes: 10 additions & 3 deletions src/analyzer/AnalyzerVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1299,10 +1299,17 @@ std::any AnalyzerVisitor::visitAssignExpr(AssignExprNode *node) {
std::any AnalyzerVisitor::visitTernaryExpr(TernaryExprNode *node) {
// Check if there is a ternary operator applied
if (node->children.size() > 1) {
auto condition = node->operands()[0];
LogicalOrExprNode *condition = node->operands()[0];
auto conditionType = any_cast<SymbolType>(visit(condition));
auto trueType = any_cast<SymbolType>(visit(node->operands()[1]));
auto falseType = any_cast<SymbolType>(visit(node->operands()[2]));
SymbolType trueType;
SymbolType falseType;
if (node->isShortened) {
trueType = conditionType;
falseType = any_cast<SymbolType>(visit(node->operands()[1]));
} else {
trueType = any_cast<SymbolType>(visit(node->operands()[1]));
falseType = any_cast<SymbolType>(visit(node->operands()[2]));
}
// Check if the condition evaluates to boolean
if (!conditionType.is(TY_BOOL))
throw err->get(condition->codeLoc, OPERATOR_WRONG_DATA_TYPE, "Condition operand in ternary must be a bool");
Expand Down
2 changes: 2 additions & 0 deletions src/ast/AstNodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,8 @@ class TernaryExprNode : public AstNode {

// Public get methods
[[nodiscard]] std::vector<LogicalOrExprNode *> operands() const { return getChildren<LogicalOrExprNode>(); }

bool isShortened = false;
};

// ===================================================== LogicalOrExprNode =======================================================
Expand Down
11 changes: 9 additions & 2 deletions src/generator/GeneratorVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1696,8 +1696,15 @@ std::any GeneratorVisitor::visitTernaryExpr(TernaryExprNode *node) {

if (node->operands().size() > 1) {
llvm::Value *conditionPtr = resolveAddress(node->operands()[0]);
llvm::Value *trueValuePtr = resolveAddress(node->operands()[1]);
llvm::Value *falseValuePtr = resolveAddress(node->operands()[2]);
llvm::Value *trueValuePtr;
llvm::Value *falseValuePtr;
if (node->isShortened) {
trueValuePtr = conditionPtr;
falseValuePtr = resolveAddress(node->operands()[1]);
} else {
trueValuePtr = resolveAddress(node->operands()[1]);
falseValuePtr = resolveAddress(node->operands()[2]);
}

llvm::Type *conditionType = node->operands().front()->getEvaluatedSymbolType().toLLVMType(*context, currentScope);
llvm::Value *condition = builder->CreateLoad(conditionType, conditionPtr);
Expand Down
3 changes: 3 additions & 0 deletions src/parser/AstBuilderVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,9 @@ std::any AstBuilderVisitor::visitAssignExpr(SpiceParser::AssignExprContext *ctx)
std::any AstBuilderVisitor::visitTernaryExpr(SpiceParser::TernaryExprContext *ctx) {
auto ternaryExprNode = dynamic_cast<TernaryExprNode *>(currentNode);

// Check if is shortened
ternaryExprNode->isShortened = ctx->logicalOrExpr().size() == 2;

for (const auto &subTree : ctx->children) {
antlr4::ParserRuleContext *rule;
if (rule = dynamic_cast<SpiceParser::LogicalOrExprContext *>(subTree); rule != nullptr) // LogicalOrExpr
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
F1 called.
F2 called.
Result: 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
; ModuleID = 'source.spice'
source_filename = "source.spice"
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-w64-windows-gnu"

@0 = private unnamed_addr constant [12 x i8] c"F1 called.\0A\00", align 1
@1 = private unnamed_addr constant [12 x i8] c"F2 called.\0A\00", align 1
@2 = private unnamed_addr constant [11 x i8] c"Result: %d\00", align 1

define internal i1 @_f__void__f1() {
entry.l1:
%result = alloca i1, align 1
%0 = call i32 (ptr, ...) @printf(ptr @0)
%1 = alloca i1, align 1
store i1 false, ptr %1, align 1
%2 = load i1, ptr %1, align 1
ret i1 %2
}

declare i32 @printf(ptr, ...)

define internal i1 @_f__void__f2() {
entry.l6:
%result = alloca i1, align 1
%0 = call i32 (ptr, ...) @printf(ptr @1)
%1 = alloca i1, align 1
store i1 true, ptr %1, align 1
%2 = load i1, ptr %1, align 1
ret i1 %2
}

define i32 @main() {
entry.l11:
%result = alloca i32, align 4
store i32 0, ptr %result, align 4
%0 = call i1 @_f__void__f1()
%1 = alloca i1, align 1
store i1 %0, ptr %1, align 1
%2 = call i1 @_f__void__f2()
%3 = alloca i1, align 1
store i1 %2, ptr %3, align 1
%4 = load i1, ptr %1, align 1
%5 = select i1 %4, ptr %1, ptr %3
%6 = load i1, ptr %5, align 1
%7 = zext i1 %6 to i32
%8 = call i32 (ptr, ...) @printf(ptr @2, i32 %7)
%9 = load i32, ptr %result, align 4
ret i32 %9
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
f<bool> f1() {
printf("F1 called.\n");
return false;
}

f<bool> f2() {
printf("F2 called.\n");
return true;
}

f<int> main() {
printf("Result: %d", f1() ?: f2());
}

0 comments on commit 0b4d63f

Please sign in to comment.