forked from solstice/solstice
Start work on static type checking
This commit is contained in:
4
Makefile
4
Makefile
@@ -5,7 +5,7 @@ LDFLAGS = -lgroundvm
|
||||
BUILD_DIR = build
|
||||
SRC_DIR = src
|
||||
|
||||
SRCS = $(SRC_DIR)/main.cpp $(SRC_DIR)/argparser.cpp $(SRC_DIR)/lexer.cpp $(SRC_DIR)/parser.cpp
|
||||
SRCS = $(SRC_DIR)/main.cpp $(SRC_DIR)/argparser.cpp $(SRC_DIR)/lexer.cpp $(SRC_DIR)/parser.cpp $(SRC_DIR)/error.cpp
|
||||
OBJS = $(patsubst $(SRC_DIR)/%.cpp, $(BUILD_DIR)/%.o, $(SRCS))
|
||||
TARGET = solstice
|
||||
|
||||
@@ -23,4 +23,4 @@ $(BUILD_DIR):
|
||||
clean:
|
||||
rm -rf $(BUILD_DIR) $(TARGET)
|
||||
|
||||
.PHONY: all clean
|
||||
.PHONY: all clean
|
||||
|
||||
18
src/error.cpp
Normal file
18
src/error.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "error.h"
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
namespace Solstice {
|
||||
namespace Error {
|
||||
[[noreturn]] void syntaxError(std::string what) {
|
||||
std::cout << "\033[31mSyntax error\n";
|
||||
std::cout << "What: " << what << "\n";
|
||||
exit(1);
|
||||
}
|
||||
[[noreturn]] void typingError(std::string what) {
|
||||
std::cout << "\033[31mTyping error\n";
|
||||
std::cout << "What: " << what << "\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
8
src/error.h
Normal file
8
src/error.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#include <string>
|
||||
|
||||
namespace Solstice {
|
||||
namespace Error {
|
||||
[[noreturn]] void syntaxError(std::string what);
|
||||
[[noreturn]] void typingError(std::string what);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "parser.h"
|
||||
#include "error.h"
|
||||
#include <groundvm.h>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
#define parseOneToken(token) Parser({token.value()}).parse().children[0]
|
||||
|
||||
@@ -13,6 +13,56 @@ namespace Solstice {
|
||||
return id.rfind("tmp_", 0) == 0;
|
||||
}
|
||||
|
||||
std::map<std::string, SolDataType> variables;
|
||||
|
||||
SolDataType checkNodeReturnType(SolNode i) {
|
||||
switch (i.nodeType) {
|
||||
case SolNodeType::Identifier: {
|
||||
if (variables.find(i.outputId) != variables.end()) {
|
||||
return variables[i.outputId];
|
||||
} else {
|
||||
Error::syntaxError("Unknown variable");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SolNodeType::Equal:
|
||||
case SolNodeType::Inequal:
|
||||
case SolNodeType::Greater:
|
||||
case SolNodeType::Lesser:
|
||||
case SolNodeType::EqGreater:
|
||||
case SolNodeType::EqLesser:
|
||||
return SolDataType::Bool;
|
||||
break;
|
||||
case SolNodeType::Add:
|
||||
{
|
||||
if (checkNodeReturnType(i.children[0]) == SolDataType::String && checkNodeReturnType(i.children[1]) == SolDataType::String) {
|
||||
return SolDataType::String;
|
||||
}
|
||||
}
|
||||
case SolNodeType::Subtract:
|
||||
case SolNodeType::Multiply:
|
||||
case SolNodeType::Divide:
|
||||
{
|
||||
if (checkNodeReturnType(i.children[0]) == SolDataType::Double) {
|
||||
return SolDataType::Double;
|
||||
}
|
||||
if (checkNodeReturnType(i.children[1]) == SolDataType::Double) {
|
||||
return SolDataType::Double;
|
||||
}
|
||||
return SolDataType::Int;
|
||||
break;
|
||||
}
|
||||
case SolNodeType::Puts:
|
||||
case SolNodeType::If:
|
||||
case SolNodeType::While:
|
||||
case SolNodeType::CodeBlock:
|
||||
default:
|
||||
return SolDataType::None;
|
||||
break;
|
||||
}
|
||||
return SolDataType::None;
|
||||
}
|
||||
|
||||
// SolData Implementation
|
||||
SolData::SolData(int64_t in) : data(in), type(SolDataType::Int) {}
|
||||
SolData::SolData(double in) : data(in), type(SolDataType::Double) {}
|
||||
@@ -359,6 +409,7 @@ namespace Solstice {
|
||||
break;
|
||||
}
|
||||
case SolNodeType::If: {
|
||||
ensure(children[0], SolDataType::Bool);
|
||||
auto conditionCode = children[0].generateCode();
|
||||
code.insert(code.end(), conditionCode.begin(), conditionCode.end());
|
||||
outputId = "tmp_" + std::to_string(tmpIdIterator++);
|
||||
@@ -390,6 +441,7 @@ namespace Solstice {
|
||||
break;
|
||||
}
|
||||
case SolNodeType::While: {
|
||||
ensure(children[0], SolDataType::Bool);
|
||||
SolGroundCodeBlock startLabelBlock;
|
||||
std::string startLabelIdString = "whilestart_" + std::to_string(labelIterator++);
|
||||
std::string endLabelIdString = "whileend_" + std::to_string(labelIterator);
|
||||
@@ -439,6 +491,11 @@ namespace Solstice {
|
||||
break;
|
||||
}
|
||||
case SolNodeType::Set: {
|
||||
if (variables.find(children[0].outputId) != variables.end()) {
|
||||
if (variables[children[0].outputId] != checkNodeReturnType(children[1])) {
|
||||
Error::typingError("Cannot change type of this variable");
|
||||
}
|
||||
}
|
||||
SolGroundCodeBlock codeBlock;
|
||||
GroundInstruction setInstruction = groundCreateInstruction(SET);
|
||||
groundAddReferenceToInstruction(&setInstruction, groundCreateReference(DIRREF, children[0].outputId.data()));
|
||||
@@ -446,6 +503,8 @@ namespace Solstice {
|
||||
codeBlock.code.push_back(setInstruction);
|
||||
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
|
||||
code.push_back(codeBlock);
|
||||
// Make sure we know what the variable type is
|
||||
variables[children[0].outputId] = children[1].data.type;
|
||||
break;
|
||||
}
|
||||
case SolNodeType::FunctionCall: {
|
||||
|
||||
17
src/parser.h
17
src/parser.h
@@ -2,11 +2,22 @@
|
||||
#define PARSER_H
|
||||
|
||||
#include <groundvm.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
#define ensure(node, datatype) \
|
||||
if (checkNodeReturnType(node) != datatype) { \
|
||||
Error::typingError("Expected " #datatype); \
|
||||
}
|
||||
|
||||
#define ensure2(node, datatype1, datatype2) \
|
||||
if (checkNodeReturnType(node) != datatype1 && checkNodeReturnType(node) != datatype2) { \
|
||||
Error::typingError("Expected either " #datatype1 " or " #datatype2); \
|
||||
}
|
||||
|
||||
namespace Solstice {
|
||||
|
||||
// External variables referenced in parser logic
|
||||
@@ -15,14 +26,17 @@ namespace Solstice {
|
||||
|
||||
namespace Parser {
|
||||
|
||||
|
||||
enum class SolNodeType {
|
||||
Add, Subtract, Equal, Inequal, Greater, Lesser, EqGreater, EqLesser, Set, While, If, Value, Identifier, None, Root, CodeBlock, CodeBlockStart, CodeBlockEnd, FunctionCall, Expression, BracketStart, BracketEnd, Puts
|
||||
Add, Subtract, Multiply, Divide, Equal, Inequal, Greater, Lesser, EqGreater, EqLesser, Set, While, If, Value, Identifier, None, Root, CodeBlock, CodeBlockStart, CodeBlockEnd, FunctionCall, Expression, BracketStart, BracketEnd, Puts
|
||||
};
|
||||
|
||||
enum class SolDataType {
|
||||
Int, String, Double, Bool, Char, None
|
||||
};
|
||||
|
||||
extern std::map<std::string, SolDataType> variables;
|
||||
|
||||
class SolNode;
|
||||
|
||||
class SolGroundCodeBlock {
|
||||
@@ -85,6 +99,7 @@ namespace Solstice {
|
||||
};
|
||||
|
||||
GroundProgram assembleProgram(SolNode& rootNode);
|
||||
SolDataType checkNodeReturnType(SolNode in);
|
||||
|
||||
} // namespace Parser
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user