Skip to content

Commit

Permalink
Distinguish between member and scope access operators (#189)
Browse files Browse the repository at this point in the history
* Adjust grammar

* Add to parser

* Add tests and adapt the existing ones

* Update docs
  • Loading branch information
marcauberer authored Aug 23, 2022
1 parent 529c03a commit e471cb9
Show file tree
Hide file tree
Showing 30 changed files with 90 additions and 24 deletions.
1 change: 1 addition & 0 deletions docs/docs/language/operator-precedence.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The following table shows how Spice prioritizes the supported operators. The lis
| ---------- | -------- | ------------------------------------ | ------------- | --------- |
| 1 | `a()` | Function/procedure call | left to right | no |
| 1 | `.` | Member access operator | left to right | no |
| 1 | `::` | Scope access operator | left to right | no |
| 1 | `a[]` | Subscript operator | left to right | no |
| 1 | `a++` | Postfix increment operator | left to right | yes |
| 1 | `a--` | Postfix decrement operator | left to right | yes |
Expand Down
10 changes: 9 additions & 1 deletion media/test-project/os-test.spice
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ f<int> main() {
printf("Hello %s!", p1.getSecond());
}*/

import "std/type/int" as integer;
/*import "std/type/int" as integer;

const int vertexCount = 9;

Expand Down Expand Up @@ -78,4 +78,12 @@ f<int> main() {
printf("Computing shortest paths with Dijkstra's algorithm ...\n");
dijkstra(graph, 0);
printf("Done.\n");
}*/

import "std/data/pair" as pair;

f<int> main() {
pair::Pair<string, int> stringIntPair = pair::Pair<string, int>("Test", 1234);
printf("First: %s\n", stringIntPair.getFirst());
printf("Second: %d\n", stringIntPair.getSecond());
}
7 changes: 4 additions & 3 deletions src/Spice.g4
Original file line number Diff line number Diff line change
Expand Up @@ -61,19 +61,19 @@ additiveExpr: multiplicativeExpr ((PLUS | MINUS) multiplicativeExpr)*;
multiplicativeExpr: castExpr ((MUL | DIV | REM) castExpr)*;
castExpr: prefixUnaryExpr | LPAREN dataType RPAREN prefixUnaryExpr;
prefixUnaryExpr: prefixUnaryOp* postfixUnaryExpr;
postfixUnaryExpr: atomicExpr (LBRACKET assignExpr RBRACKET | DOT postfixUnaryExpr | PLUS_PLUS | MINUS_MINUS)*;
postfixUnaryExpr: atomicExpr (LBRACKET assignExpr RBRACKET | DOT postfixUnaryExpr | SCOPE_ACCESS postfixUnaryExpr | PLUS_PLUS | MINUS_MINUS)*;
atomicExpr: value | IDENTIFIER | builtinCall | LPAREN assignExpr RPAREN;

// Values and types
value: primitiveValue | functionCall | arrayInitialization | structInstantiation | NIL LESS dataType GREATER;
primitiveValue: DOUBLE_LIT | INT_LIT | SHORT_LIT | LONG_LIT | CHAR_LIT | STRING_LIT | TRUE | FALSE;
functionCall: IDENTIFIER (DOT IDENTIFIER)* (LESS typeLst GREATER)? LPAREN argLst? RPAREN;
arrayInitialization: LBRACE argLst? RBRACE;
structInstantiation: IDENTIFIER (DOT IDENTIFIER)* (LESS typeLst GREATER)? LBRACE argLst? RBRACE;
structInstantiation: IDENTIFIER (SCOPE_ACCESS IDENTIFIER)* (LESS typeLst GREATER)? LBRACE argLst? RBRACE;

dataType: baseDataType (MUL | LBRACKET (INT_LIT | assignExpr)? RBRACKET)*;
baseDataType: TYPE_DOUBLE | TYPE_INT | TYPE_SHORT | TYPE_LONG | TYPE_BYTE | TYPE_CHAR | TYPE_STRING | TYPE_BOOL | TYPE_DYN | customDataType;
customDataType: IDENTIFIER (DOT IDENTIFIER)* (LESS typeLst GREATER)?;
customDataType: IDENTIFIER (SCOPE_ACCESS IDENTIFIER)* (LESS typeLst GREATER)?;

// Shorthands
assignOp: ASSIGN | PLUS_EQUAL | MINUS_EQUAL | MUL_EQUAL | DIV_EQUAL | REM_EQUAL | SHL_EQUAL | SHR_EQUAL | AND_EQUAL | OR_EQUAL | XOR_EQUAL;
Expand Down Expand Up @@ -167,6 +167,7 @@ SEMICOLON: ';';
COLON: ':';
COMMA: ',';
DOT: '.';
SCOPE_ACCESS: '::';
ELLIPSIS: '...';

// Regex tokens
Expand Down
13 changes: 13 additions & 0 deletions src/analyzer/AnalyzerVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1629,6 +1629,19 @@ std::any AnalyzerVisitor::visitPostfixUnaryExpr(PostfixUnaryExprNode *node) {
break;
}
case PostfixUnaryExprNode::OP_MEMBER_ACCESS: {
// Check if lhs is struct
if (!lhs.isBaseType(TY_STRUCT))
throw err->get(node->codeLoc, MEMBER_ACCESS_ONLY_STRUCTS, "Cannot apply member access operator on " + lhs.getName());

PostfixUnaryExprNode *rhs = node->postfixUnaryExpr()[memberAccessCounter++];
lhs = any_cast<SymbolType>(visit(rhs)); // Visit rhs
break;
}
case PostfixUnaryExprNode::OP_SCOPE_ACCESS: {
// Check if lhs is import
if (!lhs.is(TY_IMPORT))
throw err->get(node->codeLoc, SCOPE_ACCESS_ONLY_IMPORTS, "Cannot apply scope access operator on " + lhs.getName());

PostfixUnaryExprNode *rhs = node->postfixUnaryExpr()[memberAccessCounter++];
lhs = any_cast<SymbolType>(visit(rhs)); // Visit rhs
break;
Expand Down
2 changes: 1 addition & 1 deletion src/ast/AstNodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -996,7 +996,7 @@ class PrefixUnaryExprNode : public AstNode {
class PostfixUnaryExprNode : public AstNode {
public:
// Enums
enum PostfixUnaryOp { OP_SUBSCRIPT, OP_MEMBER_ACCESS, OP_PLUS_PLUS, OP_MINUS_MINUS };
enum PostfixUnaryOp { OP_SUBSCRIPT, OP_MEMBER_ACCESS, OP_PLUS_PLUS, OP_MINUS_MINUS, OP_SCOPE_ACCESS };

// Constructors
using AstNode::AstNode;
Expand Down
4 changes: 4 additions & 0 deletions src/exception/SemanticError.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ std::string SemanticError::getMessagePrefix(SemanticErrorType type) {
return "Imported source file not existing";
case CIRCULAR_DEPENDENCY:
return "Circular import detected";
case MEMBER_ACCESS_ONLY_STRUCTS:
return "Member access is only allowed on structs";
case SCOPE_ACCESS_ONLY_IMPORTS:
return "Scope access is only allowed on imports";
case UNKNOWN_DATATYPE:
return "Unknown datatype";
case NUMBER_OF_FIELDS_NOT_MATCHING:
Expand Down
2 changes: 2 additions & 0 deletions src/exception/SemanticError.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ enum SemanticErrorType {
DUPLICATE_IMPORT_NAME,
IMPORTED_FILE_NOT_EXISTING,
CIRCULAR_DEPENDENCY,
MEMBER_ACCESS_ONLY_STRUCTS,
SCOPE_ACCESS_ONLY_IMPORTS,
UNKNOWN_DATATYPE,
NUMBER_OF_FIELDS_NOT_MATCHING,
FIELD_TYPE_NOT_MATCHING,
Expand Down
8 changes: 8 additions & 0 deletions src/generator/GeneratorVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2236,6 +2236,14 @@ std::any GeneratorVisitor::visitPostfixUnaryExpr(PostfixUnaryExprNode *node) {
lhs = nullptr;
break;
}
case PostfixUnaryExprNode::OP_SCOPE_ACCESS: {
// Visit identifier after the double colon
PostfixUnaryExprNode *rhs = node->postfixUnaryExpr()[memberAccessCounter++];
lhsPtr = resolveAddress(rhs);

lhs = nullptr;
break;
}
case PostfixUnaryExprNode::OP_PLUS_PLUS: {
if (!lhs)
lhs = builder->CreateLoad(lhsTy, lhsPtr);
Expand Down
2 changes: 2 additions & 0 deletions src/parser/AstBuilderVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1131,6 +1131,8 @@ std::any AstBuilderVisitor::visitPostfixUnaryExpr(SpiceParser::PostfixUnaryExprC
postfixUnaryExprNode->opQueue.emplace(PostfixUnaryExprNode::OP_PLUS_PLUS, SymbolType(TY_INVALID));
else if (auto t = dynamic_cast<antlr4::tree::TerminalNode *>(subTree); t->getSymbol()->getType() == SpiceParser::MINUS_MINUS)
postfixUnaryExprNode->opQueue.emplace(PostfixUnaryExprNode::OP_MINUS_MINUS, SymbolType(TY_INVALID));
else if (auto t = dynamic_cast<antlr4::tree::TerminalNode *>(subTree); t->getSymbol()->getType() == SpiceParser::SCOPE_ACCESS)
postfixUnaryExprNode->opQueue.emplace(PostfixUnaryExprNode::OP_SCOPE_ACCESS, SymbolType(TY_INVALID));
else
assert(dynamic_cast<antlr4::tree::TerminalNode *>(subTree)); // Fail if we did not get a terminal

Expand Down
2 changes: 1 addition & 1 deletion std/builtin/builtin.spice
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* @param condition Condition to check
* @param message Message to print if the condition evaluates to false
*/
public p assert(bool condition, string message = "<no-message>") {
public p assertCondition(bool condition, string message = "<no-message>") {
if (!condition) {

}
Expand Down
12 changes: 12 additions & 0 deletions std/type/int.spice
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ public const int SIZE = 32;
public const int MIN_VALUE = -2147483648;
public const int MAX_VALUE = 2147483647;

const int nSmall = 100;
const string smallsString10 = "0123456789";
const string smallsString100 = "00010203040506070809101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899";

// Converts an int to a double
public f<double> toDouble(int input) {
// ToDo: Implement
Expand Down Expand Up @@ -37,4 +41,12 @@ public f<string> toString(int input) {
// Converts an int to a boolean
public f<bool> toBool(int input) {
return input >= 1;
}

// Helper function: returns the string of a small number
f<string> small(int i) {
if i < 10 {
return smallsString10.substring(i, i+1);
}
return smallsString100.substring(i*2, i*2+2);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import "source1" as s1;

f<int> main() {
dyn v = s1.Vector<int>{};
dyn v = s1::Vector<int>{};
v.setData(12);
printf("Data: %d\n", v.data);
v.setData(1.5);
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Semantic error in ./test-files/analyzer/imports/error-insufficient-global-var-visibility/source.spice:4:33: Insufficient symbol visibility: Cannot access 'globalTestVar' due to its private visibility
Semantic error in ./test-files/analyzer/imports/error-insufficient-global-var-visibility/source.spice:4:34: Insufficient symbol visibility: Cannot access 'globalTestVar' due to its private visibility
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import "source1" as src1;

f<int> main() {
printf("Result: %d\n", src1.globalTestVar);
printf("Result: %d\n", src1::globalTestVar);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import "source1" as s1;

f<int> main() {
dyn s = s1.Vector{1};
dyn s = s1::Vector{1};
printf("Result: %d\n", s.i);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Semantic error in ./test-files/analyzer/operators/error-member-access-only-struct/source.spice:3:5: Member access is only allowed on structs: Cannot apply member access operator on double
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
f<int> main() {
double doubleVar = 1.34;
doubleVar.test = 1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Semantic error in ./test-files/analyzer/operators/error-scope-access-only-import/source.spice:8:5: Scope access is only allowed on imports: Cannot apply scope access operator on TestStruct
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
type TestStruct struct {
int t1
double* t2
}

f<int> main() {
dyn ts = TestStruct{};
ts::t1 = 2;
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import "source1" as socket;

f<int> main() {
socket.Socket s = socket.openServerSocket(8080s);
socket.NestedSocket n = s.nested;
socket::Socket s = socket.openServerSocket(8080s);
socket::NestedSocket n = s.nested;
printf("Test string: %s\n", n.testString);
printf("Socket: %d\n", s.sock);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import "source1" as s1;

f<int> main() {
dyn v = s1.Vec{11, false};
dyn v = s1::Vec{11, false};
v.print();
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import "source1" as s1;

f<int> main() {
printf("Global var: %s\n", s1.GLOBAL);
printf("Global var: %s\n", s1::GLOBAL);
}
6 changes: 3 additions & 3 deletions test/test-files/std/data/combined-test-1/source.spice
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import "std/data/vector" as vec;
import "std/data/pair" as pair;

f<int> main() {
vec.Vector<pair.Pair<int, string>> pairVector = vec.Vector<pair.Pair<int, string>>();
pairVector.pushBack(pair.Pair<int, string>(0, "Hello"));
pairVector.pushBack(pair.Pair<int, string>(1, "World"));
vec::Vector<pair::Pair<int, string>> pairVector = vec::Vector<pair::Pair<int, string>>();
pairVector.pushBack(pair::Pair<int, string>(0, "Hello"));
pairVector.pushBack(pair::Pair<int, string>(1, "World"));
}
2 changes: 1 addition & 1 deletion test/test-files/std/data/pair-normal-usecase/source.spice
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import "std/data/pair" as pair;

f<int> main() {
pair.Pair<string, int> stringIntPair = pair.Pair<string, int>("Test", 1234);
pair::Pair<string, int> stringIntPair = pair::Pair<string, int>("Test", 1234);
printf("First: %s\n", stringIntPair.getFirst());
printf("Second: %d\n", stringIntPair.getSecond());
}
2 changes: 1 addition & 1 deletion test/test-files/std/data/queue-normal-usecase/source.spice
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import "std/data/queue" as que;

f<int> main() {
dyn q1 = que.Queue<char>();
dyn q1 = que::Queue<char>();
q1.push('H');
q1.push('e');
q1.push('l');
Expand Down
2 changes: 1 addition & 1 deletion test/test-files/std/data/stack-normal-usecase/source.spice
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import "std/data/stack" as stc;

f<int> main() {
stc.Stack<int> s1 = stc.Stack<int>{};
stc::Stack<int> s1 = stc::Stack<int>{};
s1.ctor();
s1.push(123);
s1.push(456);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import "std/data/triple" as triple;

f<int> main() {
triple.Triple<string, int, bool> stringIntBoolTriple = triple.Triple<string, int, bool>("Test", 1234, true);
triple::Triple<string, int, bool> stringIntBoolTriple = triple::Triple<string, int, bool>("Test", 1234, true);
printf("First: %s\n", stringIntBoolTriple.getFirst());
printf("Second: %d\n", stringIntBoolTriple.getSecond());
printf("Third: %d\n", stringIntBoolTriple.getThird());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import "std/data/vector" as vec;

f<int> main() {
vec.Vector<double> v1 = vec.Vector<double>(3);
vec::Vector<double> v1 = vec::Vector<double>(3);
v1.pushBack(1.2);
v1.pushBack(7.4964598);
v1.pushBack(5.3);
Expand Down
2 changes: 1 addition & 1 deletion test/test-files/std/io/mkdir-rmdir-direxists/source.spice
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import "std/io/dir" as dir;

f<int> main() {
printf("Existing before create: %d\n", dir.dirExists("./test"));
dyn mkReturnCode = dir.mkDir("./test", dir.MODE_ALL_RWX);
dyn mkReturnCode = dir.mkDir("./test", dir::MODE_ALL_RWX);
printf("mkDir return code: %d\n", mkReturnCode);
printf("Existing after create: %d\n", dir.dirExists("./test"));
dyn rmReturnCode = dir.rmDir("./test");
Expand Down
2 changes: 1 addition & 1 deletion test/test-files/std/os/os-name/source.spice
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import "std/os/os" as os;

f<int> main() {
printf("OS name: %s", os.OS_NAME);
printf("OS name: %s", os::OS_NAME);
}

0 comments on commit e471cb9

Please sign in to comment.