Skip to content

Commit 3c2b8ac

Browse files
Made a difference between variable declaration and assignment
1 parent 9c91b21 commit 3c2b8ac

File tree

10 files changed

+146
-30
lines changed

10 files changed

+146
-30
lines changed

BarkScript.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
#include "interpreter/interpreter.h"
99
#include "context/context.h"
1010

11-
const std::string bsversion = "0.1.3";
11+
const std::string bsversion = "0.1.4";
1212

1313
int main() {
1414
std::cout << "BarkScript version " << bsversion << std::endl;

ast/ast.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ namespace nodetypes {
1111
using namespace std;
1212

1313
const string Number = "NUMBER";
14+
const string VariableDeclaration = "VARDEC";
1415
const string VariableAssignment = "VARASS";
1516
const string VariableRetrievement = "VARRET";
1617
const string BinaryOperator = "BINOP";
@@ -70,6 +71,24 @@ struct NumberNode : Node {
7071
}
7172
};
7273

74+
struct VariableDeclarationNode : Node {
75+
VariableDeclarationNode(Token token, spNode valueNode) {
76+
this->nodeType = nodetypes::VariableDeclaration;
77+
this->token = token;
78+
this->valueNode = valueNode;
79+
this->positionStart = token.positionStart;
80+
this->positionEnd = valueNode->positionEnd;
81+
}
82+
83+
std::string to_string() override {
84+
return "(LET, identifier:\"" + token.value + "\", EQUAL, " + valueNode->to_string() + ")";
85+
}
86+
87+
operator spNode() override {
88+
return makeSharedNode(*this);
89+
}
90+
};
91+
7392
struct VariableAssignmentNode : Node {
7493
VariableAssignmentNode(Token token, spNode valueNode) {
7594
this->nodeType = nodetypes::VariableAssignment;
@@ -80,7 +99,7 @@ struct VariableAssignmentNode : Node {
8099
}
81100

82101
std::string to_string() override {
83-
return token.value + " = " + valueNode->to_string();
102+
return "(identifier:\"" + token.value + "\", EQUAL, " + valueNode->to_string() + ")";
84103
}
85104

86105
operator spNode() override {

error/error.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ struct Error {
4545

4646
std::string virtual to_string() {
4747
std::string output = type + ": " + details + '\n';
48-
output += "File " + positionStart.filename + ", line " + std::to_string(positionStart.lineNumber + 1);
48+
output += "File \"" + positionStart.filename + "\", line " + std::to_string(positionStart.lineNumber + 1);
4949
output += "\n\n";
5050
output += strings_with_arrows(positionStart.filetext, positionStart, positionEnd);
5151
return output;

interpreter/Interpreter.cpp

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#include "interpreter.h"
22
#include <iostream>
33
#include <string>
4-
#include <stdexcept>
54
#include "../ast/ast.h"
65
#include "../object/object.h"
76

@@ -33,6 +32,8 @@ RuntimeResult Interpreter::visit(spNode node, spContext context) {
3332

3433
if (type == nodetypes::Number) {
3534
return visitNumberNode(node, context);
35+
} else if (type == nodetypes::VariableDeclaration) {
36+
return visitVariableDeclarationNode(node, context);
3637
} else if (type == nodetypes::VariableAssignment) {
3738
return visitVariableAssignmentNode(node, context);
3839
} else if (type == nodetypes::VariableRetrievement) {
@@ -53,17 +54,36 @@ RuntimeResult Interpreter::visitNumberNode(spNode node, spContext context) {
5354
return RuntimeResult().success(number);
5455
}
5556

57+
RuntimeResult Interpreter::visitVariableDeclarationNode(spNode node, spContext context) {
58+
RuntimeResult rt;
59+
std::string variableName = node->token.value;
60+
if (context->symbolTable->exists(variableName, false)) {
61+
return rt.failure(RuntimeError(node->positionStart, node->positionEnd, "Variable " + variableName + " is already declared in the current scope!", context));
62+
}
63+
spObject value;
64+
value = rt.registerRT(visit(node->valueNode, context));
65+
if (rt.hasError()) return rt;
66+
SymbolTableSetReturnCode success = context->symbolTable->set(variableName, value, true);
67+
switch (success) {
68+
case SymbolTableSetReturnCode::perfect: { return rt.success(value); }
69+
case SymbolTableSetReturnCode::errorGlobalConstantVariable: { return rt.failure(RuntimeError(node->token.positionStart, node->positionEnd, "You cannot modify a global constant variable!", context)); }
70+
case SymbolTableSetReturnCode::errorUserDefinedConstantVariable: { return rt.failure(RuntimeError(node->token.positionStart, node->positionEnd, "You cannot modify a constant variable!", context)); }
71+
case SymbolTableSetReturnCode::errorNotInScope: { return rt.failure(RuntimeError(node->token.positionStart, node->positionEnd, "Variable \"" + variableName + "\" does not exist in the current scope!", context)); }
72+
default: { return rt.failure(RuntimeError(node->token.positionStart, node->positionEnd, "Unknown return value when setting: " + std::to_string((int) success), context)); }
73+
}
74+
}
75+
5676
RuntimeResult Interpreter::visitVariableAssignmentNode(spNode node, spContext context) {
5777
RuntimeResult rt;
5878
std::string variableName = node->token.value;
5979
spObject value = rt.registerRT(visit(node->valueNode, context));
6080
if (rt.hasError()) return rt;
61-
SymbolTableSetReturnCode success = context->symbolTable->set(variableName, value, true);
81+
SymbolTableSetReturnCode success = context->symbolTable->set(variableName, value, false);
6282
switch (success) {
6383
case SymbolTableSetReturnCode::perfect: { return rt.success(value); }
6484
case SymbolTableSetReturnCode::errorGlobalConstantVariable: { return rt.failure(RuntimeError(node->token.positionStart, node->positionEnd, "You cannot modify a global constant variable!", context)); }
6585
case SymbolTableSetReturnCode::errorUserDefinedConstantVariable: { return rt.failure(RuntimeError(node->token.positionStart, node->positionEnd, "You cannot modify a constant variable!", context)); }
66-
case SymbolTableSetReturnCode::errorNotInScope: { return rt.failure(RuntimeError(node->token.positionStart, node->positionEnd, "Variable " + variableName + " does not exist in the current scope!", context)); }
86+
case SymbolTableSetReturnCode::errorNotInScope: { return rt.failure(RuntimeError(node->token.positionStart, node->positionEnd, "Variable \"" + variableName + "\" does not exist in the current scope!", context)); }
6787
default: { return rt.failure(RuntimeError(node->token.positionStart, node->positionEnd, "Unknown return value when setting: " + std::to_string((int) success), context)); }
6888
}
6989
}

interpreter/interpreter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ struct Interpreter {
2525
RuntimeResult visit(spNode node, spContext context);
2626

2727
RuntimeResult visitNumberNode(spNode node, spContext context);
28+
RuntimeResult visitVariableDeclarationNode(spNode node, spContext context);
2829
RuntimeResult visitVariableAssignmentNode(spNode node, spContext context);
2930
RuntimeResult visitVariableRetrievementNode(spNode node, spContext context);
3031
RuntimeResult visitBinaryOperatorNode(spNode node, spContext context);

parser/Parser.cpp

Lines changed: 72 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ Token Parser::nextToken() {
2626
return currentToken;
2727
}
2828

29+
Token Parser::peekToken(unsigned int num) {
30+
if (tokenIndex + num + 1 >= tokens.size()) {
31+
return Token();
32+
} else {
33+
return tokens[tokenIndex + num + 1];
34+
}
35+
}
36+
2937
ParseResult Parser::atom() {
3038
ParseResult pr;
3139
Token token = currentToken;
@@ -40,12 +48,12 @@ ParseResult Parser::atom() {
4048
} else if (token.type == tokens::OPEN_PAREN) {
4149
nextToken();
4250
pr.registerAdvancement();
43-
spNode exprRes = pr.registerPR(expr());
51+
spNode value = pr.registerPR(expr());
4452
if (pr.hasError()) return pr;
4553
if (currentToken.type == tokens::CLOSE_PAREN) {
4654
nextToken();
4755
pr.registerAdvancement();
48-
return pr.success(exprRes);
56+
return pr.success(value);
4957
}
5058
return pr.failure(InvalidSyntaxError(currentToken.positionStart, currentToken.positionEnd, "Expected a ')'"));
5159
} else {
@@ -77,39 +85,77 @@ ParseResult Parser::term() {
7785
return binaryOperation(rule, { tokens::ASTERISK, tokens::F_SLASH, tokens::DOUBLE_F_SLASH });
7886
}
7987

80-
ParseResult Parser::expr() {
88+
ParseResult Parser::assignment() {
8189
ParseResult pr;
82-
if (currentToken.matches(tokens::KEYWORD, reservedWords::LET)) {
83-
nextToken();
84-
pr.registerAdvancement();
85-
if (!currentToken.matches(tokens::IDENTIFIER))
86-
return pr.failure(InvalidSyntaxError(currentToken.positionStart, currentToken.positionEnd, "Expected an identifier"));
87-
Token variableNameToken = currentToken;
88-
nextToken();
89-
pr.registerAdvancement();
90-
if (!currentToken.matches(tokens::EQUAL))
91-
return pr.failure(InvalidSyntaxError(currentToken.positionStart, currentToken.positionEnd, "Expected an '='"));
90+
if (!currentToken.matches(tokens::IDENTIFIER))
91+
return pr.failure(InvalidSyntaxError(currentToken.positionStart, currentToken.positionEnd, "Expected an identifier"));
92+
Token variableNameToken = currentToken;
93+
nextToken();
94+
pr.registerAdvancement();
95+
if (!currentToken.matches(tokens::EQUAL))
96+
return pr.failure(InvalidSyntaxError(currentToken.positionStart, currentToken.positionEnd, "Expected an '='"));
97+
nextToken();
98+
pr.registerAdvancement();
99+
spNode value = pr.registerPR(expr());
100+
if (pr.hasError()) return pr;
101+
return pr.success(VariableAssignmentNode(variableNameToken, value));
102+
}
103+
104+
ParseResult Parser::declaration() {
105+
ParseResult pr;
106+
nextToken();
107+
pr.registerAdvancement();
108+
Token variableNameToken = currentToken;
109+
if (variableNameToken.type != tokens::IDENTIFIER)
110+
return pr.failure(InvalidSyntaxError(variableNameToken.positionStart, variableNameToken.positionEnd, "Expected an identifier"));
111+
spNode value = nullptr;
112+
nextToken();
113+
pr.registerAdvancement();
114+
if (currentToken.matches(tokens::EQUAL)) {
92115
nextToken();
93116
pr.registerAdvancement();
94-
spNode exprRes = pr.registerPR(expr());
95-
if (pr.hasError()) return pr;
96-
return pr.success(VariableAssignmentNode(variableNameToken, exprRes));
117+
value = pr.registerPR(expr());
118+
} else {
119+
Position posEnd = variableNameToken.positionEnd.copy();
120+
posEnd.columnNumber--; // The Token constructor automatically calls `advance()`
121+
value = VariableRetrievementNode(Token(tokens::IDENTIFIER, "null", variableNameToken.positionStart, posEnd));
122+
}
123+
if (pr.hasError())
124+
return pr;
125+
return pr.success(VariableDeclarationNode(variableNameToken, value));
126+
}
127+
128+
ParseResult Parser::expr() {
129+
ParseResult pr;
130+
if (nextIsAssignment()) {
131+
return assignment();
97132
} else {
98133
std::function<ParseResult()> rule = [this]() { return term(); };
99134
spNode termRes = pr.registerPR(binaryOperation(rule, { tokens::PLUS, tokens::MINUS }));
100135
if (pr.hasError()) {
101-
return pr.failure(InvalidSyntaxError(currentToken.positionStart, currentToken.positionEnd, "Expected a 'let', number, identifier, '+', '-', or a '('"));
136+
return pr.failure(InvalidSyntaxError(currentToken.positionStart, currentToken.positionEnd, "Expected a number, identifier, '+', '-', or a '('"));
102137
}
103138
return pr.success(termRes);
104139
}
105140
}
106141

107-
ParseResult Parser::parse() {
108-
ParseResult pr = expr();
109-
if (!pr.hasError() && currentToken.type != tokens::EEOF) {
110-
return pr.failure(InvalidSyntaxError(currentToken.positionStart, currentToken.positionEnd, "Expected a '+', '-', '*', '/', '**', '//', or a '('"));
142+
ParseResult Parser::statement() {
143+
if (currentToken.matches(tokens::KEYWORD, reservedWords::LET)) {
144+
return declaration();
145+
} else {
146+
ParseResult pr = expr();
147+
if (pr.hasError()) {
148+
return pr.failure(InvalidSyntaxError(currentToken.positionStart, currentToken.positionEnd, "Expected a 'let', number, identifier, '+', '-', or a '('"));
149+
}
150+
if (!pr.hasError() && currentToken.type != tokens::EEOF) {
151+
return pr.failure(InvalidSyntaxError(currentToken.positionStart, currentToken.positionEnd, "Expected a '+', '-', '*', '/', '**', '//', or a '('"));
152+
}
153+
return pr;
111154
}
112-
return pr;
155+
}
156+
157+
ParseResult Parser::parse() {
158+
return statement();
113159
}
114160

115161
ParseResult Parser::binaryOperation(std::function<ParseResult()> rule, std::vector<std::string> allowedTokens) {
@@ -132,3 +178,7 @@ ParseResult Parser::binaryOperation(std::function<ParseResult()> rule1, std::vec
132178

133179
return pr.success(left);
134180
}
181+
182+
bool Parser::nextIsAssignment() {
183+
return peekToken(0).matches(tokens::EQUAL);
184+
}

parser/parser.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,22 @@ struct Parser {
4747
int tokenIndex;
4848

4949
Token nextToken();
50+
Token peekToken(unsigned int index = 0U);
5051

5152
ParseResult atom();
5253
ParseResult exponent();
5354
ParseResult factor();
5455
ParseResult term();
56+
ParseResult assignment();
57+
ParseResult declaration();
5558
ParseResult expr();
59+
ParseResult statement();
5660
ParseResult parse();
5761

5862
ParseResult binaryOperation(std::function<ParseResult()> rule, std::vector<std::string> allowedTokens);
5963
ParseResult binaryOperation(std::function<ParseResult()> rule1, std::vector<std::string> allowedTokens, std::function<ParseResult()> rule2);
64+
65+
bool nextIsAssignment();
6066
};
6167

6268
#endif // !PARSER_H

symboltable/SymbolTable.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,13 @@ SymbolTableSetReturnCode SymbolTable::set(std::string key, spObject value, bool
5252
}
5353
}
5454
}
55+
56+
bool SymbolTable::exists(std::string key, bool deepSearch) {
57+
if (symbols.find(key) != symbols.end()) {
58+
return true;
59+
} else if (deepSearch && parent != nullptr) {
60+
return parent->exists(key, deepSearch);
61+
} else {
62+
return false;
63+
}
64+
}

symboltable/symboltable.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ struct SymbolTable {
3030

3131
spObject get(std::string key);
3232
SymbolTableSetReturnCode set(std::string key, spObject value, bool currentContext = false);
33+
34+
bool exists(std::string key, bool deepSearch = true);
3335
};
3436

3537

syntax.txt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
1-
expr : KEYWORD:LET IDENTIFIER EQUAL expr
1+
statement : declaration
2+
: expr
3+
4+
declaration : KEYWORD:LET IDENTIFIER EQUAL expr
5+
: KEYWORD:LET IDENTIFIER
6+
7+
expr : assignment
28
: term ((PLUS|MINUS) term)*
39

10+
assignment : IDENTIFIER EQUAL expr
11+
412
term : factor ((ASTERISK|F_SLASH|DOUBLE_F_SLASH) factor)*
513

614
factor : (PLUS|MINUS) factor
715
: exponent
816

9-
exponent : atom (DOUBLE_ASTERISK factor)*
17+
exponent : atom (DOUBLE_ASTERISK factor)
1018

1119
atom : NUMBER
1220
: IDENTIFIER

0 commit comments

Comments
 (0)