Add experimental support for type classes and many more enhancements
This commit is contained in:
parent
a7fdc59440
commit
db26fd3b18
23 changed files with 3176 additions and 2446 deletions
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
|
@ -9,7 +9,7 @@
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"name": "Debug",
|
"name": "Debug",
|
||||||
"program": "${workspaceFolder}/build/bolt",
|
"program": "${workspaceFolder}/build/bolt",
|
||||||
"args": ["test.bolt"],
|
"args": [ "test.bolt" ],
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
"preLaunchTask": "CMake: build"
|
"preLaunchTask": "CMake: build"
|
||||||
}
|
}
|
||||||
|
|
51
.vscode/settings.json
vendored
51
.vscode/settings.json
vendored
|
@ -27,6 +27,53 @@
|
||||||
"initializer_list": "cpp",
|
"initializer_list": "cpp",
|
||||||
"numeric": "cpp",
|
"numeric": "cpp",
|
||||||
"ostream": "cpp",
|
"ostream": "cpp",
|
||||||
"system_error": "cpp"
|
"system_error": "cpp",
|
||||||
}
|
"cctype": "cpp",
|
||||||
|
"clocale": "cpp",
|
||||||
|
"cstdarg": "cpp",
|
||||||
|
"cstddef": "cpp",
|
||||||
|
"cstdio": "cpp",
|
||||||
|
"cstring": "cpp",
|
||||||
|
"ctime": "cpp",
|
||||||
|
"cwchar": "cpp",
|
||||||
|
"cwctype": "cpp",
|
||||||
|
"any": "cpp",
|
||||||
|
"atomic": "cpp",
|
||||||
|
"strstream": "cpp",
|
||||||
|
"bit": "cpp",
|
||||||
|
"bitset": "cpp",
|
||||||
|
"cinttypes": "cpp",
|
||||||
|
"codecvt": "cpp",
|
||||||
|
"compare": "cpp",
|
||||||
|
"complex": "cpp",
|
||||||
|
"concepts": "cpp",
|
||||||
|
"condition_variable": "cpp",
|
||||||
|
"coroutine": "cpp",
|
||||||
|
"cstdint": "cpp",
|
||||||
|
"map": "cpp",
|
||||||
|
"set": "cpp",
|
||||||
|
"algorithm": "cpp",
|
||||||
|
"iterator": "cpp",
|
||||||
|
"memory_resource": "cpp",
|
||||||
|
"optional": "cpp",
|
||||||
|
"ratio": "cpp",
|
||||||
|
"tuple": "cpp",
|
||||||
|
"type_traits": "cpp",
|
||||||
|
"utility": "cpp",
|
||||||
|
"iomanip": "cpp",
|
||||||
|
"iostream": "cpp",
|
||||||
|
"mutex": "cpp",
|
||||||
|
"new": "cpp",
|
||||||
|
"numbers": "cpp",
|
||||||
|
"semaphore": "cpp",
|
||||||
|
"shared_mutex": "cpp",
|
||||||
|
"stdexcept": "cpp",
|
||||||
|
"stop_token": "cpp",
|
||||||
|
"thread": "cpp",
|
||||||
|
"cfenv": "cpp",
|
||||||
|
"typeindex": "cpp",
|
||||||
|
"variant": "cpp",
|
||||||
|
"__nullptr": "cpp"
|
||||||
|
},
|
||||||
|
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools"
|
||||||
}
|
}
|
5
.vscode/tasks.json
vendored
5
.vscode/tasks.json
vendored
|
@ -8,7 +8,10 @@
|
||||||
"targets": [
|
"targets": [
|
||||||
"all"
|
"all"
|
||||||
],
|
],
|
||||||
"group": "build",
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
},
|
||||||
"problemMatcher": [],
|
"problemMatcher": [],
|
||||||
"detail": "CMake template build task"
|
"detail": "CMake template build task"
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,11 +73,11 @@ if (BOLT_ENABLE_TESTS)
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
#add_custom_command(
|
# add_custom_command(
|
||||||
# OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/include/bolt/CST.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/CST.cc"
|
# OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/include/bolt/CST.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/CST.cc"
|
||||||
# COMMAND scripts/gennodes.py --name=CST ./bolt-cst-spec.txt -Iinclude/ --include-root=bolt --source-root=src/ --namespace=bolt
|
# COMMAND scripts/gennodes.py --name=CST ./bolt-cst-spec.txt -Iinclude/ --include-root=bolt --source-root=src/ --namespace=bolt
|
||||||
# DEPENDS scripts/gennodes.py
|
# DEPENDS scripts/gennodes.py
|
||||||
# MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/bolt-cst-spec.txt"
|
# MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/bolt-cst-spec.txt"
|
||||||
# WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
# WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
#)
|
# )
|
||||||
|
|
||||||
|
|
|
@ -1,167 +0,0 @@
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
#include "bolt/Text.hpp"
|
|
||||||
#include "bolt/Integer.hpp"
|
|
||||||
#include "bolt/ByteString.hpp"
|
|
||||||
|
|
||||||
external Integer;
|
|
||||||
external ByteString;
|
|
||||||
external TextRange;
|
|
||||||
|
|
||||||
// Tokens
|
|
||||||
|
|
||||||
node Token {
|
|
||||||
TextLoc start_loc;
|
|
||||||
}
|
|
||||||
|
|
||||||
node Equals : Token {}
|
|
||||||
node Colon : Token {}
|
|
||||||
node Dot : Token {}
|
|
||||||
node LParen : Token {}
|
|
||||||
node RParen : Token {}
|
|
||||||
node LBracket : Token {}
|
|
||||||
node RBracket : Token {}
|
|
||||||
node LBrace : Token {}
|
|
||||||
node RBrace : Token {}
|
|
||||||
|
|
||||||
node LetKeyword : Token {}
|
|
||||||
node MutKeyword : Token {}
|
|
||||||
node PubKeyword : Token {}
|
|
||||||
node TypeKeyword : Token {}
|
|
||||||
node ReturnKeyword : Token {}
|
|
||||||
node ModKeyword : Token {}
|
|
||||||
node StructKeyword : Token {}
|
|
||||||
|
|
||||||
node Invalid : Token {}
|
|
||||||
|
|
||||||
node EndOfFile : Token {}
|
|
||||||
node BlockStart : Token {}
|
|
||||||
node BlockEnd : Token {}
|
|
||||||
node LineFoldEnd : Token {}
|
|
||||||
|
|
||||||
node CustomOperator : Token {
|
|
||||||
ByteString text;
|
|
||||||
}
|
|
||||||
|
|
||||||
node Identifier : Token {
|
|
||||||
ByteString text;
|
|
||||||
}
|
|
||||||
|
|
||||||
node StringLiteral : Token {
|
|
||||||
ByteString text;
|
|
||||||
}
|
|
||||||
|
|
||||||
node IntegerLiteral : Token {
|
|
||||||
Integer value;
|
|
||||||
}
|
|
||||||
|
|
||||||
node QualifiedName {
|
|
||||||
List<Identifier> module_path;
|
|
||||||
Identifier name;
|
|
||||||
}
|
|
||||||
|
|
||||||
node SourceElement {}
|
|
||||||
|
|
||||||
node LetBodyElement {}
|
|
||||||
|
|
||||||
// Type expressions
|
|
||||||
|
|
||||||
node TypeExpression {}
|
|
||||||
|
|
||||||
node ReferenceTypeExpression : TypeExpression {
|
|
||||||
QualifiedName name;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Patterns
|
|
||||||
|
|
||||||
node Pattern {}
|
|
||||||
|
|
||||||
node BindPattern : Pattern {
|
|
||||||
Identifier name;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expresssions
|
|
||||||
|
|
||||||
node Expression {}
|
|
||||||
|
|
||||||
node ReferenceExpression : Expression {
|
|
||||||
Identifier name;
|
|
||||||
}
|
|
||||||
|
|
||||||
node ConstantExpression : Expression {
|
|
||||||
Variant<StringLiteral, IntegerLiteral> token;
|
|
||||||
}
|
|
||||||
|
|
||||||
node CallExpression : Expression {
|
|
||||||
Expression function;
|
|
||||||
List<Expression> args;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Statements
|
|
||||||
|
|
||||||
node Statement : LetBodyElement {}
|
|
||||||
|
|
||||||
node ExpressionStatement : Statement, SourceElement {
|
|
||||||
Expression expression;
|
|
||||||
}
|
|
||||||
|
|
||||||
node ReturnStatement : Statement {
|
|
||||||
ReturnKeyword return_keyword;
|
|
||||||
Expression expression;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Other nodes
|
|
||||||
|
|
||||||
node TypeAssert {
|
|
||||||
Colon colon;
|
|
||||||
TypeExpression type_expression;
|
|
||||||
}
|
|
||||||
|
|
||||||
node Param {
|
|
||||||
Pattern pattern;
|
|
||||||
TypeAssert type_assert;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Declarations
|
|
||||||
|
|
||||||
node LetBody {}
|
|
||||||
|
|
||||||
node LetBlockBody : LetBody {
|
|
||||||
BlockStart block_start;
|
|
||||||
List<LetBodyElement> elements;
|
|
||||||
}
|
|
||||||
|
|
||||||
node LetExprBody : LetBody {
|
|
||||||
Equals equals;
|
|
||||||
Expression expression;
|
|
||||||
}
|
|
||||||
|
|
||||||
node LetDeclaration : SourceElement, LetBodyElement {
|
|
||||||
Option<PubKeyword> pub_keyword;
|
|
||||||
LetKeyword let_keywod;
|
|
||||||
Option<MutKeyword> mut_keyword;
|
|
||||||
Pattern pattern;
|
|
||||||
List<Param> params;
|
|
||||||
Option<TypeAssert> type_assert;
|
|
||||||
Option<LetBody> body;
|
|
||||||
}
|
|
||||||
|
|
||||||
node StructDeclField {
|
|
||||||
Identifier name;
|
|
||||||
Colon colon;
|
|
||||||
TypeExpression type_expression;
|
|
||||||
}
|
|
||||||
|
|
||||||
node StructDecl : SourceElement {
|
|
||||||
StructKeyword struct_keyword;
|
|
||||||
Identifier name;
|
|
||||||
Dot dot;
|
|
||||||
List<StructDeclField> fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
node SourceFile {
|
|
||||||
List<SourceElement> elements;
|
|
||||||
}
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
951
include/bolt/CSTVisitor.hpp
Normal file
951
include/bolt/CSTVisitor.hpp
Normal file
|
@ -0,0 +1,951 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "bolt/CST.hpp"
|
||||||
|
|
||||||
|
namespace bolt {
|
||||||
|
|
||||||
|
template<typename D, typename R = void>
|
||||||
|
class CSTVisitor {
|
||||||
|
public:
|
||||||
|
|
||||||
|
void visit(Node* N) {
|
||||||
|
switch (N->getKind()) {
|
||||||
|
case NodeKind::Equals:
|
||||||
|
return static_cast<D*>(this)->visitEquals(static_cast<Equals*>(N));
|
||||||
|
case NodeKind::Colon:
|
||||||
|
return static_cast<D*>(this)->visitColon(static_cast<Colon*>(N));
|
||||||
|
case NodeKind::Comma:
|
||||||
|
return static_cast<D*>(this)->visitComma(static_cast<Comma*>(N));
|
||||||
|
case NodeKind::Dot:
|
||||||
|
return static_cast<D*>(this)->visitDot(static_cast<Dot*>(N));
|
||||||
|
case NodeKind::DotDot:
|
||||||
|
return static_cast<D*>(this)->visitDotDot(static_cast<DotDot*>(N));
|
||||||
|
case NodeKind::Tilde:
|
||||||
|
return static_cast<D*>(this)->visitTilde(static_cast<Tilde*>(N));
|
||||||
|
case NodeKind::LParen:
|
||||||
|
return static_cast<D*>(this)->visitLParen(static_cast<LParen*>(N));
|
||||||
|
case NodeKind::RParen:
|
||||||
|
return static_cast<D*>(this)->visitRParen(static_cast<RParen*>(N));
|
||||||
|
case NodeKind::LBracket:
|
||||||
|
return static_cast<D*>(this)->visitLBracket(static_cast<LBracket*>(N));
|
||||||
|
case NodeKind::RBracket:
|
||||||
|
return static_cast<D*>(this)->visitRBracket(static_cast<RBracket*>(N));
|
||||||
|
case NodeKind::LBrace:
|
||||||
|
return static_cast<D*>(this)->visitLBrace(static_cast<LBrace*>(N));
|
||||||
|
case NodeKind::RBrace:
|
||||||
|
return static_cast<D*>(this)->visitRBrace(static_cast<RBrace*>(N));
|
||||||
|
case NodeKind::RArrow:
|
||||||
|
return static_cast<D*>(this)->visitRArrow(static_cast<RArrow*>(N));
|
||||||
|
case NodeKind::RArrowAlt:
|
||||||
|
return static_cast<D*>(this)->visitRArrowAlt(static_cast<RArrowAlt*>(N));
|
||||||
|
case NodeKind::LetKeyword:
|
||||||
|
return static_cast<D*>(this)->visitLetKeyword(static_cast<LetKeyword*>(N));
|
||||||
|
case NodeKind::MutKeyword:
|
||||||
|
return static_cast<D*>(this)->visitMutKeyword(static_cast<MutKeyword*>(N));
|
||||||
|
case NodeKind::PubKeyword:
|
||||||
|
return static_cast<D*>(this)->visitPubKeyword(static_cast<PubKeyword*>(N));
|
||||||
|
case NodeKind::TypeKeyword:
|
||||||
|
return static_cast<D*>(this)->visitTypeKeyword(static_cast<TypeKeyword*>(N));
|
||||||
|
case NodeKind::ReturnKeyword:
|
||||||
|
return static_cast<D*>(this)->visitReturnKeyword(static_cast<ReturnKeyword*>(N));
|
||||||
|
case NodeKind::ModKeyword:
|
||||||
|
return static_cast<D*>(this)->visitModKeyword(static_cast<ModKeyword*>(N));
|
||||||
|
case NodeKind::StructKeyword:
|
||||||
|
return static_cast<D*>(this)->visitStructKeyword(static_cast<StructKeyword*>(N));
|
||||||
|
case NodeKind::ClassKeyword:
|
||||||
|
return static_cast<D*>(this)->visitClassKeyword(static_cast<ClassKeyword*>(N));
|
||||||
|
case NodeKind::InstanceKeyword:
|
||||||
|
return static_cast<D*>(this)->visitInstanceKeyword(static_cast<InstanceKeyword*>(N));
|
||||||
|
case NodeKind::ElifKeyword:
|
||||||
|
return static_cast<D*>(this)->visitElifKeyword(static_cast<ElifKeyword*>(N));
|
||||||
|
case NodeKind::IfKeyword:
|
||||||
|
return static_cast<D*>(this)->visitIfKeyword(static_cast<IfKeyword*>(N));
|
||||||
|
case NodeKind::ElseKeyword:
|
||||||
|
return static_cast<D*>(this)->visitElseKeyword(static_cast<ElseKeyword*>(N));
|
||||||
|
case NodeKind::Invalid:
|
||||||
|
return static_cast<D*>(this)->visitInvalid(static_cast<Invalid*>(N));
|
||||||
|
case NodeKind::EndOfFile:
|
||||||
|
return static_cast<D*>(this)->visitEndOfFile(static_cast<EndOfFile*>(N));
|
||||||
|
case NodeKind::BlockStart:
|
||||||
|
return static_cast<D*>(this)->visitBlockStart(static_cast<BlockStart*>(N));
|
||||||
|
case NodeKind::BlockEnd:
|
||||||
|
return static_cast<D*>(this)->visitBlockEnd(static_cast<BlockEnd*>(N));
|
||||||
|
case NodeKind::LineFoldEnd:
|
||||||
|
return static_cast<D*>(this)->visitLineFoldEnd(static_cast<LineFoldEnd*>(N));
|
||||||
|
case NodeKind::CustomOperator:
|
||||||
|
return static_cast<D*>(this)->visitCustomOperator(static_cast<CustomOperator*>(N));
|
||||||
|
case NodeKind::Assignment:
|
||||||
|
return static_cast<D*>(this)->visitAssignment(static_cast<Assignment*>(N));
|
||||||
|
case NodeKind::Identifier:
|
||||||
|
return static_cast<D*>(this)->visitIdentifier(static_cast<Identifier*>(N));
|
||||||
|
case NodeKind::StringLiteral:
|
||||||
|
return static_cast<D*>(this)->visitStringLiteral(static_cast<StringLiteral*>(N));
|
||||||
|
case NodeKind::IntegerLiteral:
|
||||||
|
return static_cast<D*>(this)->visitIntegerLiteral(static_cast<IntegerLiteral*>(N));
|
||||||
|
case NodeKind::QualifiedName:
|
||||||
|
return static_cast<D*>(this)->visitQualifiedName(static_cast<QualifiedName*>(N));
|
||||||
|
case NodeKind::TypeclassConstraintExpression:
|
||||||
|
return static_cast<D*>(this)->visitTypeclassConstraintExpression(static_cast<TypeclassConstraintExpression*>(N));
|
||||||
|
case NodeKind::EqualityConstraintExpression:
|
||||||
|
return static_cast<D*>(this)->visitEqualityConstraintExpression(static_cast<EqualityConstraintExpression*>(N));
|
||||||
|
case NodeKind::QualifiedTypeExpression:
|
||||||
|
return static_cast<D*>(this)->visitQualifiedTypeExpression(static_cast<QualifiedTypeExpression*>(N));
|
||||||
|
case NodeKind::ReferenceTypeExpression:
|
||||||
|
return static_cast<D*>(this)->visitReferenceTypeExpression(static_cast<ReferenceTypeExpression*>(N));
|
||||||
|
case NodeKind::ArrowTypeExpression:
|
||||||
|
return static_cast<D*>(this)->visitArrowTypeExpression(static_cast<ArrowTypeExpression*>(N));
|
||||||
|
case NodeKind::VarTypeExpression:
|
||||||
|
return static_cast<D*>(this)->visitVarTypeExpression(static_cast<VarTypeExpression*>(N));
|
||||||
|
case NodeKind::BindPattern:
|
||||||
|
return static_cast<D*>(this)->visitBindPattern(static_cast<BindPattern*>(N));
|
||||||
|
case NodeKind::ReferenceExpression:
|
||||||
|
return static_cast<D*>(this)->visitReferenceExpression(static_cast<ReferenceExpression*>(N));
|
||||||
|
case NodeKind::NestedExpression:
|
||||||
|
return static_cast<D*>(this)->visitNestedExpression(static_cast<NestedExpression*>(N));
|
||||||
|
case NodeKind::ConstantExpression:
|
||||||
|
return static_cast<D*>(this)->visitConstantExpression(static_cast<ConstantExpression*>(N));
|
||||||
|
case NodeKind::CallExpression:
|
||||||
|
return static_cast<D*>(this)->visitCallExpression(static_cast<CallExpression*>(N));
|
||||||
|
case NodeKind::InfixExpression:
|
||||||
|
return static_cast<D*>(this)->visitInfixExpression(static_cast<InfixExpression*>(N));
|
||||||
|
case NodeKind::PrefixExpression:
|
||||||
|
return static_cast<D*>(this)->visitPrefixExpression(static_cast<PrefixExpression*>(N));
|
||||||
|
case NodeKind::ExpressionStatement:
|
||||||
|
return static_cast<D*>(this)->visitExpressionStatement(static_cast<ExpressionStatement*>(N));
|
||||||
|
case NodeKind::ReturnStatement:
|
||||||
|
return static_cast<D*>(this)->visitReturnStatement(static_cast<ReturnStatement*>(N));
|
||||||
|
case NodeKind::IfStatement:
|
||||||
|
return static_cast<D*>(this)->visitIfStatement(static_cast<IfStatement*>(N));
|
||||||
|
case NodeKind::IfStatementPart:
|
||||||
|
return static_cast<D*>(this)->visitIfStatementPart(static_cast<IfStatementPart*>(N));
|
||||||
|
case NodeKind::TypeAssert:
|
||||||
|
return static_cast<D*>(this)->visitTypeAssert(static_cast<TypeAssert*>(N));
|
||||||
|
case NodeKind::Parameter:
|
||||||
|
return static_cast<D*>(this)->visitParameter(static_cast<Parameter*>(N));
|
||||||
|
case NodeKind::LetBlockBody:
|
||||||
|
return static_cast<D*>(this)->visitLetBlockBody(static_cast<LetBlockBody*>(N));
|
||||||
|
case NodeKind::LetExprBody:
|
||||||
|
return static_cast<D*>(this)->visitLetExprBody(static_cast<LetExprBody*>(N));
|
||||||
|
case NodeKind::LetDeclaration:
|
||||||
|
return static_cast<D*>(this)->visitLetDeclaration(static_cast<LetDeclaration*>(N));
|
||||||
|
case NodeKind::StructDeclarationField:
|
||||||
|
return static_cast<D*>(this)->visitStructDeclarationField(static_cast<StructDeclarationField*>(N));
|
||||||
|
case NodeKind::StructDeclaration:
|
||||||
|
return static_cast<D*>(this)->visitStructDeclaration(static_cast<StructDeclaration*>(N));
|
||||||
|
case NodeKind::ClassDeclaration:
|
||||||
|
return static_cast<D*>(this)->visitClassDeclaration(static_cast<ClassDeclaration*>(N));
|
||||||
|
case NodeKind::InstanceDeclaration:
|
||||||
|
return static_cast<D*>(this)->visitInstanceDeclaration(static_cast<InstanceDeclaration*>(N));
|
||||||
|
case NodeKind::SourceFile:
|
||||||
|
return static_cast<D*>(this)->visitSourceFile(static_cast<SourceFile*>(N));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void visitNode(Node* N) {
|
||||||
|
visitEachChild(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitToken(Token* N) {
|
||||||
|
visitNode(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEquals(Equals* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitColon(Colon* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitComma(Comma* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitDot(Dot* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitDotDot(DotDot* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitTilde(Tilde* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitLParen(LParen* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitRParen(RParen* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitLBracket(LBracket* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitRBracket(RBracket* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitLBrace(LBrace* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitRBrace(RBrace* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitRArrow(RArrow* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitRArrowAlt(RArrowAlt* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitLetKeyword(LetKeyword* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitMutKeyword(MutKeyword* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitPubKeyword(PubKeyword* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitTypeKeyword(TypeKeyword* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitReturnKeyword(ReturnKeyword* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitModKeyword(ModKeyword* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitStructKeyword(StructKeyword* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitClassKeyword(ClassKeyword* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitInstanceKeyword(InstanceKeyword* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitElifKeyword(ElifKeyword* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitIfKeyword(IfKeyword* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitElseKeyword(ElseKeyword* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitInvalid(Invalid* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEndOfFile(EndOfFile* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitBlockStart(BlockStart* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitBlockEnd(BlockEnd* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitLineFoldEnd(LineFoldEnd* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitCustomOperator(CustomOperator* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitAssignment(Assignment* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitIdentifier(Identifier* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitStringLiteral(StringLiteral* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitIntegerLiteral(IntegerLiteral* N) {
|
||||||
|
visitToken(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitQualifiedName(QualifiedName* N) {
|
||||||
|
visitNode(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitConstraintExpression(ConstraintExpression* N) {
|
||||||
|
visitNode(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitTypeclassConstraintExpression(TypeclassConstraintExpression* N) {
|
||||||
|
visitConstraintExpression(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEqualityConstraintExpression(EqualityConstraintExpression* N) {
|
||||||
|
visitConstraintExpression(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitTypeExpression(TypeExpression* N) {
|
||||||
|
visitNode(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitQualifiedTypeExpression(QualifiedTypeExpression* N) {
|
||||||
|
visitTypeExpression(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitReferenceTypeExpression(ReferenceTypeExpression* N) {
|
||||||
|
visitTypeExpression(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitArrowTypeExpression(ArrowTypeExpression* N) {
|
||||||
|
visitTypeExpression(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitVarTypeExpression(VarTypeExpression* N) {
|
||||||
|
visitTypeExpression(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitPattern(Pattern* N) {
|
||||||
|
visitNode(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitBindPattern(BindPattern* N) {
|
||||||
|
visitPattern(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitExpression(Expression* N) {
|
||||||
|
visitNode(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitReferenceExpression(ReferenceExpression* N) {
|
||||||
|
visitExpression(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitNestedExpression(NestedExpression* N) {
|
||||||
|
visitExpression(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitConstantExpression(ConstantExpression* N) {
|
||||||
|
visitExpression(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitCallExpression(CallExpression* N) {
|
||||||
|
visitExpression(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitInfixExpression(InfixExpression* N) {
|
||||||
|
visitExpression(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitPrefixExpression(PrefixExpression* N) {
|
||||||
|
visitExpression(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitStatement(Statement* N) {
|
||||||
|
visitNode(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitExpressionStatement(ExpressionStatement* N) {
|
||||||
|
visitStatement(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitReturnStatement(ReturnStatement* N) {
|
||||||
|
visitStatement(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitIfStatement(IfStatement* N) {
|
||||||
|
visitStatement(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitIfStatementPart(IfStatementPart* N) {
|
||||||
|
visitNode(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitTypeAssert(TypeAssert* N) {
|
||||||
|
visitNode(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitParameter(Parameter* N) {
|
||||||
|
visitNode(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitLetBody(LetBody* N) {
|
||||||
|
visitNode(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitLetBlockBody(LetBlockBody* N) {
|
||||||
|
visitLetBody(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitLetExprBody(LetExprBody* N) {
|
||||||
|
visitLetBody(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitLetDeclaration(LetDeclaration* N) {
|
||||||
|
visitNode(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitStructDeclarationField(StructDeclarationField* N) {
|
||||||
|
visitNode(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitStructDeclaration(StructDeclaration* N) {
|
||||||
|
visitNode(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitClassDeclaration(ClassDeclaration* N) {
|
||||||
|
visitNode(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitInstanceDeclaration(InstanceDeclaration* N) {
|
||||||
|
visitNode(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitSourceFile(SourceFile* N) {
|
||||||
|
visitNode(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void visitEachChild(Node* N) {
|
||||||
|
switch (N->getKind()) {
|
||||||
|
case NodeKind::Equals:
|
||||||
|
visitEachChild(static_cast<Equals*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::Colon:
|
||||||
|
visitEachChild(static_cast<Colon*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::Comma:
|
||||||
|
visitEachChild(static_cast<Comma*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::Dot:
|
||||||
|
visitEachChild(static_cast<Dot*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::DotDot:
|
||||||
|
visitEachChild(static_cast<DotDot*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::Tilde:
|
||||||
|
visitEachChild(static_cast<Tilde*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::LParen:
|
||||||
|
visitEachChild(static_cast<LParen*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::RParen:
|
||||||
|
visitEachChild(static_cast<RParen*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::LBracket:
|
||||||
|
visitEachChild(static_cast<LBracket*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::RBracket:
|
||||||
|
visitEachChild(static_cast<RBracket*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::LBrace:
|
||||||
|
visitEachChild(static_cast<LBrace*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::RBrace:
|
||||||
|
visitEachChild(static_cast<RBrace*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::RArrow:
|
||||||
|
visitEachChild(static_cast<RArrow*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::RArrowAlt:
|
||||||
|
visitEachChild(static_cast<RArrowAlt*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::LetKeyword:
|
||||||
|
visitEachChild(static_cast<LetKeyword*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::MutKeyword:
|
||||||
|
visitEachChild(static_cast<MutKeyword*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::PubKeyword:
|
||||||
|
visitEachChild(static_cast<PubKeyword*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::TypeKeyword:
|
||||||
|
visitEachChild(static_cast<TypeKeyword*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::ReturnKeyword:
|
||||||
|
visitEachChild(static_cast<ReturnKeyword*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::ModKeyword:
|
||||||
|
visitEachChild(static_cast<ModKeyword*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::StructKeyword:
|
||||||
|
visitEachChild(static_cast<StructKeyword*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::ClassKeyword:
|
||||||
|
visitEachChild(static_cast<ClassKeyword*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::InstanceKeyword:
|
||||||
|
visitEachChild(static_cast<InstanceKeyword*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::ElifKeyword:
|
||||||
|
visitEachChild(static_cast<ElifKeyword*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::IfKeyword:
|
||||||
|
visitEachChild(static_cast<IfKeyword*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::ElseKeyword:
|
||||||
|
visitEachChild(static_cast<ElseKeyword*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::Invalid:
|
||||||
|
visitEachChild(static_cast<Invalid*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::EndOfFile:
|
||||||
|
visitEachChild(static_cast<EndOfFile*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::BlockStart:
|
||||||
|
visitEachChild(static_cast<BlockStart*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::BlockEnd:
|
||||||
|
visitEachChild(static_cast<BlockEnd*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::LineFoldEnd:
|
||||||
|
visitEachChild(static_cast<LineFoldEnd*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::CustomOperator:
|
||||||
|
visitEachChild(static_cast<CustomOperator*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::Assignment:
|
||||||
|
visitEachChild(static_cast<Assignment*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::Identifier:
|
||||||
|
visitEachChild(static_cast<Identifier*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::StringLiteral:
|
||||||
|
visitEachChild(static_cast<StringLiteral*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::IntegerLiteral:
|
||||||
|
visitEachChild(static_cast<IntegerLiteral*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::QualifiedName:
|
||||||
|
visitEachChild(static_cast<QualifiedName*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::TypeclassConstraintExpression:
|
||||||
|
visitEachChild(static_cast<TypeclassConstraintExpression*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::EqualityConstraintExpression:
|
||||||
|
visitEachChild(static_cast<EqualityConstraintExpression*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::QualifiedTypeExpression:
|
||||||
|
visitEachChild(static_cast<QualifiedTypeExpression*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::ReferenceTypeExpression:
|
||||||
|
visitEachChild(static_cast<ReferenceTypeExpression*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::ArrowTypeExpression:
|
||||||
|
visitEachChild(static_cast<ArrowTypeExpression*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::VarTypeExpression:
|
||||||
|
visitEachChild(static_cast<VarTypeExpression*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::BindPattern:
|
||||||
|
visitEachChild(static_cast<BindPattern*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::ReferenceExpression:
|
||||||
|
visitEachChild(static_cast<ReferenceExpression*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::NestedExpression:
|
||||||
|
visitEachChild(static_cast<NestedExpression*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::ConstantExpression:
|
||||||
|
visitEachChild(static_cast<ConstantExpression*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::CallExpression:
|
||||||
|
visitEachChild(static_cast<CallExpression*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::InfixExpression:
|
||||||
|
visitEachChild(static_cast<InfixExpression*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::PrefixExpression:
|
||||||
|
visitEachChild(static_cast<PrefixExpression*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::ExpressionStatement:
|
||||||
|
visitEachChild(static_cast<ExpressionStatement*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::ReturnStatement:
|
||||||
|
visitEachChild(static_cast<ReturnStatement*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::IfStatement:
|
||||||
|
visitEachChild(static_cast<IfStatement*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::IfStatementPart:
|
||||||
|
visitEachChild(static_cast<IfStatementPart*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::TypeAssert:
|
||||||
|
visitEachChild(static_cast<TypeAssert*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::Parameter:
|
||||||
|
visitEachChild(static_cast<Parameter*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::LetBlockBody:
|
||||||
|
visitEachChild(static_cast<LetBlockBody*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::LetExprBody:
|
||||||
|
visitEachChild(static_cast<LetExprBody*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::LetDeclaration:
|
||||||
|
visitEachChild(static_cast<LetDeclaration*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::StructDeclaration:
|
||||||
|
visitEachChild(static_cast<StructDeclaration*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::StructDeclarationField:
|
||||||
|
visitEachChild(static_cast<StructDeclarationField*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::ClassDeclaration:
|
||||||
|
visitEachChild(static_cast<ClassDeclaration*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::InstanceDeclaration:
|
||||||
|
visitEachChild(static_cast<InstanceDeclaration*>(N));
|
||||||
|
break;
|
||||||
|
case NodeKind::SourceFile:
|
||||||
|
visitEachChild(static_cast<SourceFile*>(N));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ZEN_UNREACHABLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BOLT_VISIT(node) static_cast<D*>(this)->visit(node)
|
||||||
|
|
||||||
|
void visitEachChild(Equals* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(Colon* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(Comma* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(Dot* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(DotDot* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(Tilde* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(LParen* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(RParen* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(LBracket* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(RBracket* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(LBrace* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(RBrace* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(RArrow* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(RArrowAlt* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(LetKeyword* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(MutKeyword* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(PubKeyword* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(TypeKeyword* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(ReturnKeyword* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(ModKeyword* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(StructKeyword* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(ClassKeyword* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(InstanceKeyword* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(ElifKeyword* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(IfKeyword* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(ElseKeyword* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(Invalid* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(EndOfFile* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(BlockStart* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(BlockEnd* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(LineFoldEnd* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(CustomOperator* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(Assignment* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(Identifier* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(StringLiteral* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(IntegerLiteral* N) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(QualifiedName* N) {
|
||||||
|
for (auto Name: N->ModulePath) {
|
||||||
|
BOLT_VISIT(Name);
|
||||||
|
}
|
||||||
|
BOLT_VISIT(N->Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(TypeclassConstraintExpression* N) {
|
||||||
|
BOLT_VISIT(N->Name);
|
||||||
|
for (auto TE: N->TEs) {
|
||||||
|
BOLT_VISIT(TE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(EqualityConstraintExpression* N) {
|
||||||
|
BOLT_VISIT(N->Left);
|
||||||
|
BOLT_VISIT(N->Tilde);
|
||||||
|
BOLT_VISIT(N->Right);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(QualifiedTypeExpression* N) {
|
||||||
|
for (auto [CE, Comma]: N->Constraints) {
|
||||||
|
BOLT_VISIT(CE);
|
||||||
|
if (Comma) {
|
||||||
|
BOLT_VISIT(Comma);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BOLT_VISIT(N->RArrowAlt);
|
||||||
|
BOLT_VISIT(N->TE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(ReferenceTypeExpression* N) {
|
||||||
|
BOLT_VISIT(N->Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(ArrowTypeExpression* N) {
|
||||||
|
for (auto PT: N->ParamTypes) {
|
||||||
|
BOLT_VISIT(PT);
|
||||||
|
}
|
||||||
|
BOLT_VISIT(N->ReturnType);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(VarTypeExpression* N) {
|
||||||
|
BOLT_VISIT(N->Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(BindPattern* N) {
|
||||||
|
BOLT_VISIT(N->Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(ReferenceExpression* N) {
|
||||||
|
BOLT_VISIT(N->Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(NestedExpression* N) {
|
||||||
|
BOLT_VISIT(N->LParen);
|
||||||
|
BOLT_VISIT(N->Inner);
|
||||||
|
BOLT_VISIT(N->RParen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(ConstantExpression* N) {
|
||||||
|
BOLT_VISIT(N->Token);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(CallExpression* N) {
|
||||||
|
BOLT_VISIT(N->Function);
|
||||||
|
for (auto Arg: N->Args) {
|
||||||
|
BOLT_VISIT(Arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(InfixExpression* N) {
|
||||||
|
BOLT_VISIT(N->LHS);
|
||||||
|
BOLT_VISIT(N->Operator);
|
||||||
|
BOLT_VISIT(N->RHS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(PrefixExpression* N) {
|
||||||
|
BOLT_VISIT(N->Operator);
|
||||||
|
BOLT_VISIT(N->Argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(ExpressionStatement* N) {
|
||||||
|
BOLT_VISIT(N->Expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(ReturnStatement* N) {
|
||||||
|
BOLT_VISIT(N->ReturnKeyword);
|
||||||
|
BOLT_VISIT(N->Expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(IfStatement* N) {
|
||||||
|
for (auto Part: N->Parts) {
|
||||||
|
BOLT_VISIT(Part);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(IfStatementPart* N) {
|
||||||
|
BOLT_VISIT(N->Keyword);
|
||||||
|
if (N->Test != nullptr) {
|
||||||
|
BOLT_VISIT(N->Test);
|
||||||
|
}
|
||||||
|
BOLT_VISIT(N->BlockStart);
|
||||||
|
for (auto Element: N->Elements) {
|
||||||
|
BOLT_VISIT(Element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(TypeAssert* N) {
|
||||||
|
BOLT_VISIT(N->Colon);
|
||||||
|
BOLT_VISIT(N->TypeExpression);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(Parameter* N) {
|
||||||
|
BOLT_VISIT(N->Pattern);
|
||||||
|
if (N->TypeAssert != nullptr) {
|
||||||
|
BOLT_VISIT(N->TypeAssert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(LetBlockBody* N) {
|
||||||
|
BOLT_VISIT(N->BlockStart);
|
||||||
|
for (auto Element: N->Elements) {
|
||||||
|
BOLT_VISIT(Element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(LetExprBody* N) {
|
||||||
|
BOLT_VISIT(N->Equals);
|
||||||
|
BOLT_VISIT(N->Expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(LetDeclaration* N) {
|
||||||
|
if (N->PubKeyword) {
|
||||||
|
BOLT_VISIT(N->PubKeyword);
|
||||||
|
}
|
||||||
|
BOLT_VISIT(N->LetKeyword);
|
||||||
|
if (N->MutKeyword) {
|
||||||
|
BOLT_VISIT(N->MutKeyword);
|
||||||
|
}
|
||||||
|
BOLT_VISIT(N->Pattern);
|
||||||
|
for (auto Param: N->Params) {
|
||||||
|
BOLT_VISIT(Param);
|
||||||
|
}
|
||||||
|
if (N->TypeAssert) {
|
||||||
|
BOLT_VISIT(N->TypeAssert);
|
||||||
|
}
|
||||||
|
if (N->Body) {
|
||||||
|
BOLT_VISIT(N->Body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(StructDeclarationField* N) {
|
||||||
|
BOLT_VISIT(N->Name);
|
||||||
|
BOLT_VISIT(N->Colon);
|
||||||
|
BOLT_VISIT(N->TypeExpression);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(StructDeclaration* N) {
|
||||||
|
if (N->PubKeyword) {
|
||||||
|
BOLT_VISIT(N->PubKeyword);
|
||||||
|
}
|
||||||
|
BOLT_VISIT(N->StructKeyword);
|
||||||
|
BOLT_VISIT(N->Name);
|
||||||
|
BOLT_VISIT(N->StructKeyword);
|
||||||
|
for (auto Field: N->Fields) {
|
||||||
|
BOLT_VISIT(Field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(ClassDeclaration* N) {
|
||||||
|
if (N->PubKeyword) {
|
||||||
|
BOLT_VISIT(N->PubKeyword);
|
||||||
|
}
|
||||||
|
BOLT_VISIT(N->ClassKeyword);
|
||||||
|
BOLT_VISIT(N->Name);
|
||||||
|
for (auto Name: N->TypeVars) {
|
||||||
|
BOLT_VISIT(Name);
|
||||||
|
}
|
||||||
|
BOLT_VISIT(N->BlockStart);
|
||||||
|
for (auto Element: N->Elements) {
|
||||||
|
BOLT_VISIT(Element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(InstanceDeclaration* N) {
|
||||||
|
BOLT_VISIT(N->InstanceKeyword);
|
||||||
|
BOLT_VISIT(N->Name);
|
||||||
|
for (auto TE: N->TypeExps) {
|
||||||
|
BOLT_VISIT(TE);
|
||||||
|
}
|
||||||
|
BOLT_VISIT(N->BlockStart);
|
||||||
|
for (auto Element: N->Elements) {
|
||||||
|
BOLT_VISIT(Element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitEachChild(SourceFile* N) {
|
||||||
|
for (auto Element: N->Elements) {
|
||||||
|
BOLT_VISIT(Element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "bolt/ByteString.hpp"
|
#include "bolt/ByteString.hpp"
|
||||||
#include "bolt/CST.hpp"
|
#include "bolt/CST.hpp"
|
||||||
|
#include "bolt/Diagnostics.hpp"
|
||||||
|
|
||||||
#include <istream>
|
#include <istream>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
@ -14,6 +15,30 @@
|
||||||
|
|
||||||
namespace bolt {
|
namespace bolt {
|
||||||
|
|
||||||
|
class LanguageConfig {
|
||||||
|
|
||||||
|
enum ConfigFlags {
|
||||||
|
ConfigFlags_TypeVarsRequireForall = 1 << 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned Flags;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void setTypeVarsRequireForall(bool Enable) {
|
||||||
|
if (Enable) {
|
||||||
|
Flags |= ConfigFlags_TypeVarsRequireForall;
|
||||||
|
} else {
|
||||||
|
Flags |= ~ConfigFlags_TypeVarsRequireForall;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool typeVarsRequireForall() const noexcept {
|
||||||
|
return Flags & ConfigFlags_TypeVarsRequireForall;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
class DiagnosticEngine;
|
class DiagnosticEngine;
|
||||||
class Node;
|
class Node;
|
||||||
|
|
||||||
|
@ -23,11 +48,12 @@ namespace bolt {
|
||||||
using TVSub = std::unordered_map<TVar*, Type*>;
|
using TVSub = std::unordered_map<TVar*, Type*>;
|
||||||
using TVSet = std::unordered_set<TVar*>;
|
using TVSet = std::unordered_set<TVar*>;
|
||||||
|
|
||||||
|
using TypeclassContext = std::unordered_set<TypeclassId>;
|
||||||
|
|
||||||
enum class TypeKind : unsigned char {
|
enum class TypeKind : unsigned char {
|
||||||
Var,
|
Var,
|
||||||
Con,
|
Con,
|
||||||
Arrow,
|
Arrow,
|
||||||
Any,
|
|
||||||
Tuple,
|
Tuple,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -70,15 +96,45 @@ namespace bolt {
|
||||||
inline TCon(const size_t Id, std::vector<Type*> Args, ByteString DisplayName):
|
inline TCon(const size_t Id, std::vector<Type*> Args, ByteString DisplayName):
|
||||||
Type(TypeKind::Con), Id(Id), Args(Args), DisplayName(DisplayName) {}
|
Type(TypeKind::Con), Id(Id), Args(Args), DisplayName(DisplayName) {}
|
||||||
|
|
||||||
|
static bool classof(const Type* Ty) {
|
||||||
|
return Ty->getKind() == TypeKind::Con;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class VarKind {
|
||||||
|
Rigid,
|
||||||
|
Unification,
|
||||||
};
|
};
|
||||||
|
|
||||||
class TVar : public Type {
|
class TVar : public Type {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
const size_t Id;
|
const size_t Id;
|
||||||
|
VarKind VK;
|
||||||
|
|
||||||
inline TVar(size_t Id):
|
TypeclassContext Contexts;
|
||||||
Type(TypeKind::Var), Id(Id) {}
|
|
||||||
|
inline TVar(size_t Id, VarKind VK):
|
||||||
|
Type(TypeKind::Var), Id(Id), VK(VK) {}
|
||||||
|
|
||||||
|
inline VarKind getVarKind() const noexcept {
|
||||||
|
return VK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool classof(const Type* Ty) {
|
||||||
|
return Ty->getKind() == TypeKind::Var;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class TVarRigid : public TVar {
|
||||||
|
public:
|
||||||
|
|
||||||
|
ByteString Name;
|
||||||
|
|
||||||
|
inline TVarRigid(size_t Id, ByteString Name):
|
||||||
|
TVar(Id, VarKind::Rigid), Name(Name) {}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -95,6 +151,10 @@ namespace bolt {
|
||||||
ParamTypes(ParamTypes),
|
ParamTypes(ParamTypes),
|
||||||
ReturnType(ReturnType) {}
|
ReturnType(ReturnType) {}
|
||||||
|
|
||||||
|
static bool classof(const Type* Ty) {
|
||||||
|
return Ty->getKind() == TypeKind::Arrow;
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class TTuple : public Type {
|
class TTuple : public Type {
|
||||||
|
@ -105,13 +165,9 @@ namespace bolt {
|
||||||
inline TTuple(std::vector<Type*> ElementTypes):
|
inline TTuple(std::vector<Type*> ElementTypes):
|
||||||
Type(TypeKind::Tuple), ElementTypes(ElementTypes) {}
|
Type(TypeKind::Tuple), ElementTypes(ElementTypes) {}
|
||||||
|
|
||||||
};
|
static bool classof(const Type* Ty) {
|
||||||
|
return Ty->getKind() == TypeKind::Tuple;
|
||||||
class TAny : public Type {
|
}
|
||||||
public:
|
|
||||||
|
|
||||||
inline TAny():
|
|
||||||
Type(TypeKind::Any) {}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -126,26 +182,6 @@ namespace bolt {
|
||||||
|
|
||||||
using ConstraintSet = std::vector<Constraint*>;
|
using ConstraintSet = std::vector<Constraint*>;
|
||||||
|
|
||||||
class Forall {
|
|
||||||
public:
|
|
||||||
|
|
||||||
TVSet* TVs;
|
|
||||||
ConstraintSet* Constraints;
|
|
||||||
Type* Type;
|
|
||||||
|
|
||||||
inline Forall(class Type* Type):
|
|
||||||
TVs(new TVSet), Constraints(new ConstraintSet), Type(Type) {}
|
|
||||||
|
|
||||||
inline Forall(
|
|
||||||
TVSet& TVs,
|
|
||||||
ConstraintSet& Constraints,
|
|
||||||
class Type* Type
|
|
||||||
): TVs(&TVs),
|
|
||||||
Constraints(&Constraints),
|
|
||||||
Type(Type) {}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class SchemeKind : unsigned char {
|
enum class SchemeKind : unsigned char {
|
||||||
Forall,
|
Forall,
|
||||||
};
|
};
|
||||||
|
@ -154,61 +190,102 @@ namespace bolt {
|
||||||
|
|
||||||
const SchemeKind Kind;
|
const SchemeKind Kind;
|
||||||
|
|
||||||
union {
|
protected:
|
||||||
Forall F;
|
|
||||||
};
|
inline Scheme(SchemeKind Kind):
|
||||||
|
Kind(Kind) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
inline Scheme(Forall F):
|
|
||||||
Kind(SchemeKind::Forall), F(F) {}
|
|
||||||
|
|
||||||
inline Scheme(const Scheme& Other):
|
|
||||||
Kind(Other.Kind) {
|
|
||||||
switch (Kind) {
|
|
||||||
case SchemeKind::Forall:
|
|
||||||
F = Other.F;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline Scheme(Scheme&& Other):
|
|
||||||
Kind(std::move(Other.Kind)) {
|
|
||||||
switch (Kind) {
|
|
||||||
case SchemeKind::Forall:
|
|
||||||
F = std::move(Other.F);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
T& as();
|
|
||||||
|
|
||||||
template<>
|
|
||||||
Forall& as<Forall>() {
|
|
||||||
ZEN_ASSERT(Kind == SchemeKind::Forall);
|
|
||||||
return F;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline SchemeKind getKind() const noexcept {
|
inline SchemeKind getKind() const noexcept {
|
||||||
return Kind;
|
return Kind;
|
||||||
}
|
}
|
||||||
|
|
||||||
~Scheme() {
|
virtual ~Scheme() {}
|
||||||
switch (Kind) {
|
|
||||||
case SchemeKind::Forall:
|
};
|
||||||
F.~Forall();
|
|
||||||
break;
|
class Forall : public Scheme {
|
||||||
}
|
public:
|
||||||
|
|
||||||
|
TVSet* TVs;
|
||||||
|
ConstraintSet* Constraints;
|
||||||
|
class Type* Type;
|
||||||
|
|
||||||
|
inline Forall(class Type* Type):
|
||||||
|
Scheme(SchemeKind::Forall), TVs(new TVSet), Constraints(new ConstraintSet), Type(Type) {}
|
||||||
|
|
||||||
|
inline Forall(
|
||||||
|
TVSet* TVs,
|
||||||
|
ConstraintSet* Constraints,
|
||||||
|
class Type* Type
|
||||||
|
): Scheme(SchemeKind::Forall),
|
||||||
|
TVs(TVs),
|
||||||
|
Constraints(Constraints),
|
||||||
|
Type(Type) {}
|
||||||
|
|
||||||
|
static bool classof(const Scheme* Scm) {
|
||||||
|
return Scm->getKind() == SchemeKind::Forall;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
using TypeEnv = std::unordered_map<ByteString, Scheme>;
|
/* class Scheme { */
|
||||||
|
|
||||||
|
/* const SchemeKind Kind; */
|
||||||
|
|
||||||
|
/* public: */
|
||||||
|
|
||||||
|
/* inline Scheme(Forall F): */
|
||||||
|
/* Kind(SchemeKind::Forall), F(F) {} */
|
||||||
|
|
||||||
|
/* inline Scheme(const Scheme& Other): */
|
||||||
|
/* Kind(Other.Kind) { */
|
||||||
|
/* switch (Kind) { */
|
||||||
|
/* case SchemeKind::Forall: */
|
||||||
|
/* F = Other.F; */
|
||||||
|
/* break; */
|
||||||
|
/* } */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
|
||||||
|
/* inline Scheme(Scheme&& Other): */
|
||||||
|
/* Kind(std::move(Other.Kind)) { */
|
||||||
|
/* switch (Kind) { */
|
||||||
|
/* case SchemeKind::Forall: */
|
||||||
|
/* F = std::move(Other.F); */
|
||||||
|
/* break; */
|
||||||
|
/* } */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* inline SchemeKind getKind() const noexcept { */
|
||||||
|
/* return Kind; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* template<typename T> */
|
||||||
|
/* T& as(); */
|
||||||
|
|
||||||
|
/* template<> */
|
||||||
|
/* Forall& as<Forall>() { */
|
||||||
|
/* ZEN_ASSERT(Kind == SchemeKind::Forall); */
|
||||||
|
/* return F; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* ~Scheme() { */
|
||||||
|
/* switch (Kind) { */
|
||||||
|
/* case SchemeKind::Forall: */
|
||||||
|
/* F.~Forall(); */
|
||||||
|
/* break; */
|
||||||
|
/* } */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* }; */
|
||||||
|
|
||||||
|
using TypeEnv = std::unordered_map<ByteString, Scheme*>;
|
||||||
|
|
||||||
enum class ConstraintKind {
|
enum class ConstraintKind {
|
||||||
Equal,
|
Equal,
|
||||||
|
Class,
|
||||||
Many,
|
Many,
|
||||||
Empty,
|
Empty,
|
||||||
};
|
};
|
||||||
|
@ -249,8 +326,8 @@ namespace bolt {
|
||||||
|
|
||||||
ConstraintSet& Elements;
|
ConstraintSet& Elements;
|
||||||
|
|
||||||
inline CMany(ConstraintSet& Constraints):
|
inline CMany(ConstraintSet& Elements):
|
||||||
Constraint(ConstraintKind::Many), Elements(Constraints) {}
|
Constraint(ConstraintKind::Many), Elements(Elements) {}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -262,32 +339,76 @@ namespace bolt {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class InferContext {
|
class CClass : public Constraint {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
TVSet TVs;
|
ByteString Name;
|
||||||
ConstraintSet Constraints;
|
std::vector<Type*> Types;
|
||||||
TypeEnv Env;
|
|
||||||
Type* ReturnType;
|
|
||||||
|
|
||||||
InferContext* Parent;
|
inline CClass(ByteString Name, std::vector<Type*> Types):
|
||||||
|
Constraint(ConstraintKind::Class), Name(Name), Types(Types) {}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
/**
|
||||||
|
* Indicates that the typing environment of the current context will not
|
||||||
|
* hold on to any bindings.
|
||||||
|
*
|
||||||
|
* Concretely, bindings that are assigned fall through to the parent
|
||||||
|
* context, where this process is repeated until an environment is found
|
||||||
|
* that is not pervious.
|
||||||
|
*/
|
||||||
|
InferContextFlags_PerviousEnv = 1 << 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
using InferContextFlagsMask = unsigned;
|
||||||
|
|
||||||
|
class InferContext {
|
||||||
|
|
||||||
|
InferContextFlagsMask Flags = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A heap-allocated list of type variables that eventually will become part of a Forall scheme.
|
||||||
|
*/
|
||||||
|
TVSet* TVs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A heap-allocated list of constraints that eventually will become part of a Forall scheme.
|
||||||
|
*/
|
||||||
|
ConstraintSet* Constraints;
|
||||||
|
|
||||||
|
TypeEnv Env;
|
||||||
|
|
||||||
|
Type* ReturnType = nullptr;
|
||||||
|
std::vector<TypeclassSignature> Classes;
|
||||||
|
|
||||||
|
inline void setIsEnvPervious(bool Enable) noexcept {
|
||||||
|
if (Enable) {
|
||||||
|
Flags |= InferContextFlags_PerviousEnv;
|
||||||
|
} else {
|
||||||
|
Flags &= ~InferContextFlags_PerviousEnv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isEnvPervious() const noexcept {
|
||||||
|
return Flags & InferContextFlags_PerviousEnv;
|
||||||
|
}
|
||||||
|
|
||||||
//inline InferContext(InferContext* Parent, TVSet& TVs, ConstraintSet& Constraints, TypeEnv& Env, Type* ReturnType):
|
//inline InferContext(InferContext* Parent, TVSet& TVs, ConstraintSet& Constraints, TypeEnv& Env, Type* ReturnType):
|
||||||
// Parent(Parent), TVs(TVs), Constraints(Constraints), Env(Env), ReturnType(ReturnType) {}
|
// Parent(Parent), TVs(TVs), Constraints(Constraints), Env(Env), ReturnType(ReturnType) {}
|
||||||
|
|
||||||
inline InferContext(InferContext* Parent = nullptr):
|
|
||||||
Parent(Parent), ReturnType(nullptr) {}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Checker {
|
class Checker {
|
||||||
|
|
||||||
|
const LanguageConfig& Config;
|
||||||
DiagnosticEngine& DE;
|
DiagnosticEngine& DE;
|
||||||
|
|
||||||
size_t nextConTypeId = 0;
|
size_t NextConTypeId = 0;
|
||||||
size_t nextTypeVarId = 0;
|
size_t NextTypeVarId = 0;
|
||||||
|
|
||||||
std::unordered_map<Node*, Type*> Mapping;
|
|
||||||
|
|
||||||
std::unordered_map<Node*, InferContext*> CallGraph;
|
std::unordered_map<Node*, InferContext*> CallGraph;
|
||||||
|
|
||||||
|
@ -295,44 +416,83 @@ namespace bolt {
|
||||||
Type* IntType;
|
Type* IntType;
|
||||||
Type* StringType;
|
Type* StringType;
|
||||||
|
|
||||||
|
TVSub Solution;
|
||||||
|
|
||||||
std::vector<InferContext*> Contexts;
|
std::vector<InferContext*> Contexts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds the current inferred type class contexts in a given LetDeclaration body.
|
||||||
|
*/
|
||||||
|
// std::vector<TypeclassContext*> TCCs;
|
||||||
|
|
||||||
|
InferContext& getContext();
|
||||||
|
|
||||||
void addConstraint(Constraint* Constraint);
|
void addConstraint(Constraint* Constraint);
|
||||||
|
void addClass(TypeclassSignature Sig);
|
||||||
|
|
||||||
void forwardDeclare(Node* Node);
|
void forwardDeclare(Node* Node);
|
||||||
|
|
||||||
Type* inferExpression(Expression* Expression);
|
Type* inferExpression(Expression* Expression);
|
||||||
Type* inferTypeExpression(TypeExpression* TE);
|
Type* inferTypeExpression(TypeExpression* TE);
|
||||||
|
|
||||||
void inferBindings(Pattern* Pattern, Type* T, ConstraintSet& Constraints, TVSet& Tvs);
|
void inferBindings(Pattern* Pattern, Type* T, ConstraintSet* Constraints, TVSet* TVs);
|
||||||
|
void inferBindings(Pattern* Pattern, Type* T);
|
||||||
|
|
||||||
void infer(Node* node);
|
void infer(Node* node);
|
||||||
|
|
||||||
|
Constraint* convertToConstraint(ConstraintExpression* C);
|
||||||
|
|
||||||
TCon* createPrimConType();
|
TCon* createPrimConType();
|
||||||
|
|
||||||
TVar* createTypeVar();
|
TVar* createTypeVar();
|
||||||
|
TVarRigid* createRigidVar(ByteString Name);
|
||||||
|
InferContext* createInferContext();
|
||||||
|
|
||||||
void addBinding(ByteString Name, Scheme Scm);
|
void addBinding(ByteString Name, Scheme* Scm);
|
||||||
|
|
||||||
|
Scheme* lookup(ByteString Name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Looks up a type/variable and ensures that it is a monomorphic type.
|
||||||
|
*
|
||||||
|
* This method is mainly syntactic sugar to make it clear in the code when a
|
||||||
|
* monomorphic type is expected.
|
||||||
|
*
|
||||||
|
* Note that if the type is not monomorphic the program will abort with a
|
||||||
|
* stack trace. It wil **not** print a user-friendly error message.
|
||||||
|
*
|
||||||
|
* \returns If the type/variable could not be found `nullptr` is returned.
|
||||||
|
* Otherwise, a [Type] is returned.
|
||||||
|
*/
|
||||||
Type* lookupMono(ByteString Name);
|
Type* lookupMono(ByteString Name);
|
||||||
|
|
||||||
InferContext* lookupCall(Node* Source, SymbolPath Path);
|
InferContext* lookupCall(Node* Source, SymbolPath Path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the return type for the current context. If none could be found, the program will abort.
|
||||||
|
*/
|
||||||
Type* getReturnType();
|
Type* getReturnType();
|
||||||
|
|
||||||
Scheme* lookup(ByteString Name);
|
Type* instantiate(Scheme* S, Node* Source);
|
||||||
|
|
||||||
Type* instantiate(Scheme& S, Node* Source);
|
/* void addToTypeclassContexts(Node* N, std::vector<TypeclassContext>& Contexts); */
|
||||||
|
|
||||||
bool unify(Type* A, Type* B, TVSub& Solution);
|
std::unordered_map<ByteString, std::vector<InstanceDeclaration*>> InstanceMap;
|
||||||
|
std::vector<TypeclassContext> findInstanceContext(TCon* Ty, TypeclassId& Class, Node* Source);
|
||||||
|
void propagateClasses(TypeclassContext& Classes, Type* Ty, Node* Source);
|
||||||
|
void propagateClassTycon(TypeclassId& Class, TCon* Ty, Node* Source);
|
||||||
|
|
||||||
|
void checkTypeclassSigs(Node* N);
|
||||||
|
|
||||||
|
bool unify(Type* A, Type* B, Node* Source);
|
||||||
|
|
||||||
|
void solveCEqual(CEqual* C);
|
||||||
void solve(Constraint* Constraint, TVSub& Solution);
|
void solve(Constraint* Constraint, TVSub& Solution);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Checker(DiagnosticEngine& DE);
|
Checker(const LanguageConfig& Config, DiagnosticEngine& DE);
|
||||||
|
|
||||||
TVSub check(SourceFile* SF);
|
void check(SourceFile* SF);
|
||||||
|
|
||||||
inline Type* getBoolType() {
|
inline Type* getBoolType() {
|
||||||
return BoolType;
|
return BoolType;
|
||||||
|
@ -346,7 +506,7 @@ namespace bolt {
|
||||||
return IntType;
|
return IntType;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type* getType(Node* Node, const TVSub& Solution);
|
Type* getType(TypedNode* Node);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -13,12 +13,30 @@
|
||||||
namespace bolt {
|
namespace bolt {
|
||||||
|
|
||||||
class Type;
|
class Type;
|
||||||
|
class TCon;
|
||||||
|
class TVar;
|
||||||
|
|
||||||
|
using TypeclassId = ByteString;
|
||||||
|
|
||||||
|
struct TypeclassSignature {
|
||||||
|
|
||||||
|
using TypeclassId = ByteString;
|
||||||
|
TypeclassId Id;
|
||||||
|
std::vector<TVar*> Params;
|
||||||
|
|
||||||
|
bool operator<(const TypeclassSignature& Other) const;
|
||||||
|
bool operator==(const TypeclassSignature& Other) const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
enum class DiagnosticKind : unsigned char {
|
enum class DiagnosticKind : unsigned char {
|
||||||
UnexpectedToken,
|
UnexpectedToken,
|
||||||
UnexpectedString,
|
UnexpectedString,
|
||||||
BindingNotFound,
|
BindingNotFound,
|
||||||
UnificationError,
|
UnificationError,
|
||||||
|
TypeclassMissing,
|
||||||
|
InstanceNotFound,
|
||||||
|
ClassNotFound,
|
||||||
};
|
};
|
||||||
|
|
||||||
class Diagnostic : std::runtime_error {
|
class Diagnostic : std::runtime_error {
|
||||||
|
@ -31,7 +49,7 @@ namespace bolt {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DiagnosticKind getKind() const noexcept {
|
inline DiagnosticKind getKind() const noexcept {
|
||||||
return Kind;
|
return Kind;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,9 +60,9 @@ namespace bolt {
|
||||||
|
|
||||||
TextFile& File;
|
TextFile& File;
|
||||||
Token* Actual;
|
Token* Actual;
|
||||||
std::vector<NodeType> Expected;
|
std::vector<NodeKind> Expected;
|
||||||
|
|
||||||
inline UnexpectedTokenDiagnostic(TextFile& File, Token* Actual, std::vector<NodeType> Expected):
|
inline UnexpectedTokenDiagnostic(TextFile& File, Token* Actual, std::vector<NodeKind> Expected):
|
||||||
Diagnostic(DiagnosticKind::UnexpectedToken), File(File), Actual(Actual), Expected(Expected) {}
|
Diagnostic(DiagnosticKind::UnexpectedToken), File(File), Actual(Actual), Expected(Expected) {}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -84,6 +102,39 @@ namespace bolt {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TypeclassMissingDiagnostic : public Diagnostic {
|
||||||
|
public:
|
||||||
|
|
||||||
|
TypeclassSignature Sig;
|
||||||
|
LetDeclaration* Decl;
|
||||||
|
|
||||||
|
inline TypeclassMissingDiagnostic(TypeclassSignature Sig, LetDeclaration* Decl):
|
||||||
|
Diagnostic(DiagnosticKind::TypeclassMissing), Sig(Sig), Decl(Decl) {}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class InstanceNotFoundDiagnostic : public Diagnostic {
|
||||||
|
public:
|
||||||
|
|
||||||
|
ByteString TypeclassName;
|
||||||
|
TCon* Ty;
|
||||||
|
Node* Source;
|
||||||
|
|
||||||
|
inline InstanceNotFoundDiagnostic(ByteString TypeclassName, TCon* Ty, Node* Source):
|
||||||
|
Diagnostic(DiagnosticKind::InstanceNotFound), TypeclassName(TypeclassName), Ty(Ty), Source(Source) {}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class ClassNotFoundDiagnostic : public Diagnostic {
|
||||||
|
public:
|
||||||
|
|
||||||
|
ByteString Name;
|
||||||
|
|
||||||
|
inline ClassNotFoundDiagnostic(ByteString Name):
|
||||||
|
Diagnostic(DiagnosticKind::ClassNotFound), Name(Name) {}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
class DiagnosticEngine {
|
class DiagnosticEngine {
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include "bolt/CST.hpp"
|
#include "bolt/CST.hpp"
|
||||||
|
#include "bolt/Stream.hpp"
|
||||||
|
|
||||||
namespace bolt {
|
namespace bolt {
|
||||||
|
|
||||||
|
@ -68,14 +69,24 @@ namespace bolt {
|
||||||
|
|
||||||
Token* peekFirstTokenAfterModifiers();
|
Token* peekFirstTokenAfterModifiers();
|
||||||
|
|
||||||
Token* expectToken(NodeType Ty);
|
Token* expectToken(NodeKind Ty);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T* expectToken() {
|
||||||
|
return static_cast<T*>(expectToken(getNodeType<T>()));
|
||||||
|
}
|
||||||
|
|
||||||
Expression* parseInfixOperatorAfterExpression(Expression* LHS, int MinPrecedence);
|
Expression* parseInfixOperatorAfterExpression(Expression* LHS, int MinPrecedence);
|
||||||
|
|
||||||
TypeExpression* parsePrimitiveTypeExpression();
|
|
||||||
|
|
||||||
Expression* parsePrimitiveExpression();
|
Expression* parsePrimitiveExpression();
|
||||||
|
|
||||||
|
ConstraintExpression* parseConstraintExpression();
|
||||||
|
|
||||||
|
TypeExpression* parsePrimitiveTypeExpression();
|
||||||
|
TypeExpression* parseQualifiedTypeExpression();
|
||||||
|
TypeExpression* parseArrowTypeExpression();
|
||||||
|
VarTypeExpression* parseVarTypeExpression();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Parser(TextFile& File, Stream<Token*>& S);
|
Parser(TextFile& File, Stream<Token*>& S);
|
||||||
|
@ -86,7 +97,7 @@ namespace bolt {
|
||||||
|
|
||||||
Pattern* parsePattern();
|
Pattern* parsePattern();
|
||||||
|
|
||||||
Param* parseParam();
|
Parameter* parseParam();
|
||||||
|
|
||||||
ReferenceExpression* parseReferenceExpression();
|
ReferenceExpression* parseReferenceExpression();
|
||||||
|
|
||||||
|
@ -106,6 +117,12 @@ namespace bolt {
|
||||||
|
|
||||||
LetDeclaration* parseLetDeclaration();
|
LetDeclaration* parseLetDeclaration();
|
||||||
|
|
||||||
|
Node* parseClassElement();
|
||||||
|
|
||||||
|
ClassDeclaration* parseClassDeclaration();
|
||||||
|
|
||||||
|
InstanceDeclaration* parseInstanceDeclaration();
|
||||||
|
|
||||||
Node* parseSourceElement();
|
Node* parseSourceElement();
|
||||||
|
|
||||||
SourceFile* parseSourceFile();
|
SourceFile* parseSourceFile();
|
||||||
|
|
|
@ -8,78 +8,12 @@
|
||||||
|
|
||||||
#include "bolt/Text.hpp"
|
#include "bolt/Text.hpp"
|
||||||
#include "bolt/String.hpp"
|
#include "bolt/String.hpp"
|
||||||
|
#include "bolt/Stream.hpp"
|
||||||
|
|
||||||
namespace bolt {
|
namespace bolt {
|
||||||
|
|
||||||
class Token;
|
class Token;
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class Stream {
|
|
||||||
public:
|
|
||||||
|
|
||||||
virtual T get() = 0;
|
|
||||||
virtual T peek(std::size_t Offset = 0) = 0;
|
|
||||||
|
|
||||||
virtual ~Stream() {}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename ContainerT, typename T = typename ContainerT::value_type>
|
|
||||||
class VectorStream : public Stream<T> {
|
|
||||||
public:
|
|
||||||
|
|
||||||
using value_type = T;
|
|
||||||
|
|
||||||
ContainerT& Data;
|
|
||||||
value_type Sentry;
|
|
||||||
std::size_t Offset;
|
|
||||||
|
|
||||||
VectorStream(ContainerT& Data, value_type Sentry, std::size_t Offset = 0):
|
|
||||||
Data(Data), Sentry(Sentry), Offset(Offset) {}
|
|
||||||
|
|
||||||
value_type get() override {
|
|
||||||
return Offset < Data.size() ? Data[Offset++] : Sentry;
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type peek(std::size_t Offset2) override {
|
|
||||||
auto I = Offset + Offset2;
|
|
||||||
return I < Data.size() ? Data[I] : Sentry;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class BufferedStream : public Stream<T> {
|
|
||||||
|
|
||||||
std::deque<T> Buffer;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
virtual T read() = 0;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
using value_type = T;
|
|
||||||
|
|
||||||
value_type get() override {
|
|
||||||
if (Buffer.empty()) {
|
|
||||||
return read();
|
|
||||||
} else {
|
|
||||||
auto Keep = Buffer.front();
|
|
||||||
Buffer.pop_front();
|
|
||||||
return Keep;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type peek(std::size_t Offset = 0) override {
|
|
||||||
while (Buffer.size() <= Offset) {
|
|
||||||
Buffer.push_back(read());
|
|
||||||
}
|
|
||||||
return Buffer[Offset];
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class Scanner : public BufferedStream<Token*> {
|
class Scanner : public BufferedStream<Token*> {
|
||||||
|
|
||||||
TextFile& File;
|
TextFile& File;
|
||||||
|
|
|
@ -36,8 +36,7 @@ namespace bolt {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class TextRange {
|
struct TextRange {
|
||||||
public:
|
|
||||||
TextLoc Start;
|
TextLoc Start;
|
||||||
TextLoc End;
|
TextLoc End;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,66 +0,0 @@
|
||||||
{!
|
|
||||||
root_node_name = root_node.name
|
|
||||||
|
|
||||||
def gen_cpp_unref(expr, ty):
|
|
||||||
if isinstance(ty, NodeType):
|
|
||||||
return f'{expr}->unref();\n'
|
|
||||||
elif isinstance(ty, ListType):
|
|
||||||
dtor = gen_cpp_unref('Element', ty.element_type)
|
|
||||||
if dtor:
|
|
||||||
out = ''
|
|
||||||
out += f'for (auto& Element: {expr})'
|
|
||||||
out += '{\n'
|
|
||||||
out += dtor
|
|
||||||
out += '}\n'
|
|
||||||
return out
|
|
||||||
elif isinstance(ty, OptionalType):
|
|
||||||
if is_type_optional_by_default(ty.element_type):
|
|
||||||
element_expr = expr
|
|
||||||
else:
|
|
||||||
element_expr = f'(*{expr})'
|
|
||||||
dtor = gen_cpp_unref(element_expr, ty.element_type)
|
|
||||||
if dtor:
|
|
||||||
out = ''
|
|
||||||
out += 'if ('
|
|
||||||
out += expr
|
|
||||||
out += ') {\n'
|
|
||||||
out += dtor
|
|
||||||
out += '}\n'
|
|
||||||
return out
|
|
||||||
elif isinstance(ty, RawType):
|
|
||||||
pass # field should be destroyed by class
|
|
||||||
else:
|
|
||||||
raise RuntimeError(f'unexpected {ty}')
|
|
||||||
|
|
||||||
!}
|
|
||||||
#include "{{include_path}}/{{name}}.hpp"
|
|
||||||
|
|
||||||
{% for namespace in namespaces %}
|
|
||||||
namespace {{namespace}} { {! indent() !}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
{{root_node_name}}:~{{root_node_name}}() {}
|
|
||||||
|
|
||||||
SourceFile* {root_node.name}::getSourceFile() {
|
|
||||||
auto CurrNode = this;
|
|
||||||
for (;;) {
|
|
||||||
if (CurrNode->Type == NodeType::SourceFile) {
|
|
||||||
return static_cast<SourceFile*>(this);
|
|
||||||
}
|
|
||||||
CurrNode = CurrNode->Parent;
|
|
||||||
ZEN_ASSERT(CurrNode != nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{% for node in nodes %}
|
|
||||||
{{node.name}}::~{{node.name}}() {
|
|
||||||
{% for name, ty in node.fields %}
|
|
||||||
{{gen_cpp_unref(name, ty)}
|
|
||||||
{% endfor %}
|
|
||||||
}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
{% for namespace in namespaces %}
|
|
||||||
} {! dedent() !}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
|
@ -1,118 +0,0 @@
|
||||||
{!
|
|
||||||
macro_prefix = '_'.join(namespaces).upper() + '_'
|
|
||||||
variant_name = root_node_name + 'Type'
|
|
||||||
!}
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
{% for namespace in namespaces %}
|
|
||||||
namespace {{namespace}} { {! indent() !}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
class {{base_node.name}};
|
|
||||||
|
|
||||||
class {{root_node_name}} {
|
|
||||||
|
|
||||||
unsigned RefCount = 0;
|
|
||||||
|
|
||||||
{{root_node_name}}* Parent = nullptr;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
inline void ref() {
|
|
||||||
++RefCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void unref() {
|
|
||||||
--RefCount;
|
|
||||||
if (RefCount == 0) {
|
|
||||||
delete this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const {{variant_name}} Type;
|
|
||||||
|
|
||||||
inline {{root_node_name}}({{variant_name}}Type):
|
|
||||||
Type(Type) {}
|
|
||||||
|
|
||||||
{{base_node.name}}* get{{base_node.name}}();
|
|
||||||
|
|
||||||
virtual void setParents();
|
|
||||||
|
|
||||||
virtual ~Node();
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
{% for node in nodes %}
|
|
||||||
{!
|
|
||||||
|
|
||||||
def gen_cpp_ctor_params(out, node):
|
|
||||||
visited = set()
|
|
||||||
queue = deque([ node ])
|
|
||||||
is_leaf = not graph.has_children(node.name)
|
|
||||||
first = True
|
|
||||||
if not is_leaf:
|
|
||||||
out.write(f"{cpp_root_node_name}Type Type")
|
|
||||||
first = False
|
|
||||||
while queue:
|
|
||||||
node = queue.popleft()
|
|
||||||
if node.name in visited:
|
|
||||||
return
|
|
||||||
visited.add(node.name)
|
|
||||||
for member in node.members:
|
|
||||||
if first:
|
|
||||||
first = False
|
|
||||||
else:
|
|
||||||
out.write(', ')
|
|
||||||
out.write(gen_cpp_type_expr(member.type_expr.type))
|
|
||||||
out.write(' ')
|
|
||||||
out.write(camel_case(member.name))
|
|
||||||
for parent in node.parents:
|
|
||||||
queue.append(types[parent])
|
|
||||||
|
|
||||||
def gen_cpp_ctor_args(out, orig_node: NodeDecl):
|
|
||||||
first = True
|
|
||||||
is_leaf = not graph.has_children(orig_node.name)
|
|
||||||
if orig_node.parents:
|
|
||||||
for parent in orig_node.parents:
|
|
||||||
if first:
|
|
||||||
first = False
|
|
||||||
else:
|
|
||||||
out.write(', ')
|
|
||||||
node = types[parent]
|
|
||||||
refs = ''
|
|
||||||
if is_leaf:
|
|
||||||
refs += f"{cpp_root_node_name}Type::{orig_node.name}"
|
|
||||||
else:
|
|
||||||
refs += 'Type'
|
|
||||||
for member in node.members:
|
|
||||||
refs += f", {camel_case(member.name)}"
|
|
||||||
out.write(f"{prefix}{node.name}({refs})")
|
|
||||||
else:
|
|
||||||
if is_leaf:
|
|
||||||
out.write(f"{cpp_root_node_name}({cpp_root_node_name}Type::{orig_node.name})")
|
|
||||||
else:
|
|
||||||
out.write(f"{cpp_root_node_name}(Type)")
|
|
||||||
first = False
|
|
||||||
for member in orig_node.members:
|
|
||||||
if first:
|
|
||||||
first = False
|
|
||||||
else:
|
|
||||||
out.write(', ')
|
|
||||||
out.write(f"{camel_case(member.name)}({camel_case(member.name)})")
|
|
||||||
|
|
||||||
!}
|
|
||||||
class {{node.name}} : public {{node.parent.name}} {
|
|
||||||
|
|
||||||
{{node.name}}(
|
|
||||||
{{cpp_ctor_params}}
|
|
||||||
): {{node.parent.name}}({{variant_name}}::{{node.name}}{{cpp_ctor_args}} {}
|
|
||||||
|
|
||||||
~{{node.name}}();
|
|
||||||
};
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
{% for namespace in namespaces %}
|
|
||||||
} {! dedent() !}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
|
@ -1,848 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
from os import wait
|
|
||||||
import re
|
|
||||||
from collections import deque
|
|
||||||
from pathlib import Path
|
|
||||||
import argparse
|
|
||||||
from typing import List, Optional
|
|
||||||
from sweetener.record import Record
|
|
||||||
import templaty
|
|
||||||
|
|
||||||
here = Path(__file__).parent.resolve()
|
|
||||||
|
|
||||||
EOF = '\uFFFF'
|
|
||||||
|
|
||||||
END_OF_FILE = 0
|
|
||||||
IDENTIFIER = 1
|
|
||||||
SEMI = 2
|
|
||||||
EXTERNAL = 3
|
|
||||||
NODE = 4
|
|
||||||
LBRACE = 5
|
|
||||||
RBRACE = 6
|
|
||||||
LESSTHAN = 7
|
|
||||||
GREATERTHAN = 8
|
|
||||||
COLON = 9
|
|
||||||
LPAREN = 10
|
|
||||||
RPAREN = 11
|
|
||||||
VBAR = 12
|
|
||||||
COMMA = 13
|
|
||||||
HASH = 14
|
|
||||||
STRING = 15
|
|
||||||
|
|
||||||
RE_WHTITESPACE = re.compile(r"[\n\r\t ]")
|
|
||||||
RE_IDENT_START = re.compile(r"[a-zA-Z_]")
|
|
||||||
RE_IDENT_PART = re.compile(r"[a-zA-Z_0-9]")
|
|
||||||
|
|
||||||
KEYWORDS = {
|
|
||||||
'external': EXTERNAL,
|
|
||||||
'node': NODE,
|
|
||||||
}
|
|
||||||
|
|
||||||
def escape_char(ch):
|
|
||||||
code = ord(ch)
|
|
||||||
if code >= 32 and code < 126:
|
|
||||||
return ch
|
|
||||||
if code <= 127:
|
|
||||||
return f"\\x{code:02X}"
|
|
||||||
return f"\\u{code:04X}"
|
|
||||||
|
|
||||||
def camel_case(ident: str) -> str:
|
|
||||||
out = ident[0].upper()
|
|
||||||
i = 1
|
|
||||||
while i < len(ident):
|
|
||||||
ch = ident[i]
|
|
||||||
i += 1
|
|
||||||
if ch == '_':
|
|
||||||
c1 = ident[i]
|
|
||||||
i += 1
|
|
||||||
out += c1.upper()
|
|
||||||
else:
|
|
||||||
out += ch
|
|
||||||
return out
|
|
||||||
|
|
||||||
class ScanError(RuntimeError):
|
|
||||||
|
|
||||||
def __init__(self, file, position, actual):
|
|
||||||
super().__init__(f"{file.name}:{position.line}:{position.column}: unexpected character '{escape_char(actual)}'")
|
|
||||||
self.file = file
|
|
||||||
self.position = position
|
|
||||||
self.actual = actual
|
|
||||||
|
|
||||||
TOKEN_TYPE_TO_STRING = {
|
|
||||||
LPAREN: '(',
|
|
||||||
RPAREN: ')',
|
|
||||||
LBRACE: '{',
|
|
||||||
RBRACE: '}',
|
|
||||||
LESSTHAN: '<',
|
|
||||||
GREATERTHAN: '>',
|
|
||||||
NODE: 'node',
|
|
||||||
EXTERNAL: 'external',
|
|
||||||
SEMI: ';',
|
|
||||||
COLON: ':',
|
|
||||||
COMMA: ',',
|
|
||||||
VBAR: '|',
|
|
||||||
HASH: '#',
|
|
||||||
}
|
|
||||||
|
|
||||||
class Token:
|
|
||||||
|
|
||||||
def __init__(self, type, position=None, value=None):
|
|
||||||
self.type = type
|
|
||||||
self.start_pos = position
|
|
||||||
self.value = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def text(self):
|
|
||||||
if self.type in TOKEN_TYPE_TO_STRING:
|
|
||||||
return TOKEN_TYPE_TO_STRING[self.type]
|
|
||||||
if self.type == IDENTIFIER:
|
|
||||||
return self.value
|
|
||||||
if self.type == STRING:
|
|
||||||
return f'"{self.value}"'
|
|
||||||
if self.type == END_OF_FILE:
|
|
||||||
return ''
|
|
||||||
return '(unknown token)'
|
|
||||||
|
|
||||||
class TextFile:
|
|
||||||
|
|
||||||
def __init__(self, filename, text=None):
|
|
||||||
self.name = filename
|
|
||||||
self._cached_text = text
|
|
||||||
|
|
||||||
@property
|
|
||||||
def text(self):
|
|
||||||
if self._cached_text is None:
|
|
||||||
with open(self.name, 'r') as f:
|
|
||||||
self._cached_text = f.read()
|
|
||||||
return self._cached_text
|
|
||||||
|
|
||||||
class TextPos:
|
|
||||||
|
|
||||||
def __init__(self, line=1, column=1):
|
|
||||||
self.line = line
|
|
||||||
self.column = column
|
|
||||||
|
|
||||||
def clone(self):
|
|
||||||
return TextPos(self.line, self.column)
|
|
||||||
|
|
||||||
def advance(self, text):
|
|
||||||
for ch in text:
|
|
||||||
if ch == '\n':
|
|
||||||
self.line += 1
|
|
||||||
self.column = 1
|
|
||||||
else:
|
|
||||||
self.column += 1
|
|
||||||
|
|
||||||
class Scanner:
|
|
||||||
|
|
||||||
def __init__(self, text, text_offset=0, filename=None):
|
|
||||||
self._text = text
|
|
||||||
self._text_offset = text_offset
|
|
||||||
self.file = TextFile(filename, text)
|
|
||||||
self._curr_pos = TextPos()
|
|
||||||
|
|
||||||
def _peek_char(self, offset=1):
|
|
||||||
i = self._text_offset + offset - 1
|
|
||||||
return self._text[i] if i < len(self._text) else EOF
|
|
||||||
|
|
||||||
def _get_char(self):
|
|
||||||
if self._text_offset == len(self._text):
|
|
||||||
return EOF
|
|
||||||
i = self._text_offset
|
|
||||||
self._text_offset += 1
|
|
||||||
ch = self._text[i]
|
|
||||||
self._curr_pos.advance(ch)
|
|
||||||
return ch
|
|
||||||
|
|
||||||
def _take_while(self, pred):
|
|
||||||
out = ''
|
|
||||||
while True:
|
|
||||||
ch = self._peek_char()
|
|
||||||
if not pred(ch):
|
|
||||||
break
|
|
||||||
self._get_char()
|
|
||||||
out += ch
|
|
||||||
return out
|
|
||||||
|
|
||||||
def scan(self):
|
|
||||||
|
|
||||||
while True:
|
|
||||||
c0 = self._peek_char()
|
|
||||||
c1 = self._peek_char(2)
|
|
||||||
if c0 == '/' and c1 == '/':
|
|
||||||
self._get_char()
|
|
||||||
self._get_char()
|
|
||||||
while True:
|
|
||||||
c3 = self._get_char()
|
|
||||||
if c3 == '\n' or c3 == EOF:
|
|
||||||
break
|
|
||||||
continue
|
|
||||||
if RE_WHTITESPACE.match(c0):
|
|
||||||
self._get_char()
|
|
||||||
continue
|
|
||||||
break
|
|
||||||
|
|
||||||
if c0 == EOF:
|
|
||||||
return Token(END_OF_FILE, self._curr_pos.clone())
|
|
||||||
|
|
||||||
start_pos = self._curr_pos.clone()
|
|
||||||
self._get_char()
|
|
||||||
|
|
||||||
if c0 == ';': return Token(SEMI, start_pos)
|
|
||||||
if c0 == '{': return Token(LBRACE, start_pos)
|
|
||||||
if c0 == '}': return Token(RBRACE, start_pos)
|
|
||||||
if c0 == '(': return Token(LPAREN, start_pos)
|
|
||||||
if c0 == ')': return Token(RPAREN, start_pos)
|
|
||||||
if c0 == '<': return Token(LESSTHAN, start_pos)
|
|
||||||
if c0 == '>': return Token(GREATERTHAN, start_pos)
|
|
||||||
if c0 == ':': return Token(COLON, start_pos)
|
|
||||||
if c0 == '|': return Token(VBAR, start_pos)
|
|
||||||
if c0 == ',': return Token(COMMA, start_pos)
|
|
||||||
if c0 == '#': return Token(HASH, start_pos)
|
|
||||||
|
|
||||||
if c0 == '"':
|
|
||||||
text = ''
|
|
||||||
while True:
|
|
||||||
c1 = self._get_char()
|
|
||||||
if c1 == '"':
|
|
||||||
break
|
|
||||||
text += c1
|
|
||||||
return Token(STRING, start_pos, text)
|
|
||||||
|
|
||||||
if RE_IDENT_START.match(c0):
|
|
||||||
name = c0 + self._take_while(lambda ch: RE_IDENT_PART.match(ch))
|
|
||||||
return Token(KEYWORDS[name], start_pos) \
|
|
||||||
if name in KEYWORDS \
|
|
||||||
else Token(IDENTIFIER, start_pos, name)
|
|
||||||
|
|
||||||
raise ScanError(self.file, start_pos, c0)
|
|
||||||
|
|
||||||
class Type(Record):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class ListType(Type):
|
|
||||||
element_type: Type
|
|
||||||
|
|
||||||
class OptionalType(Type):
|
|
||||||
element_type: Type
|
|
||||||
|
|
||||||
class NodeType(Type):
|
|
||||||
name: str
|
|
||||||
|
|
||||||
class VariantType(Type):
|
|
||||||
types: List[Type]
|
|
||||||
|
|
||||||
class RawType(Type):
|
|
||||||
text: str
|
|
||||||
|
|
||||||
class AST(Record):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class Directive(AST):
|
|
||||||
pass
|
|
||||||
|
|
||||||
INCLUDEMODE_LOCAL = 0
|
|
||||||
INCLUDEMODE_SYSTEM = 1
|
|
||||||
|
|
||||||
class IncludeDiretive(Directive):
|
|
||||||
path: str
|
|
||||||
mode: int
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
if self.mode == INCLUDEMODE_LOCAL:
|
|
||||||
return f"#include \"{self.path}\"\n"
|
|
||||||
if self.mode == INCLUDEMODE_SYSTEM:
|
|
||||||
return f"#include <{self.path}>\n"
|
|
||||||
|
|
||||||
class TypeExpr(AST):
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
self.type = None
|
|
||||||
|
|
||||||
class RefTypeExpr(TypeExpr):
|
|
||||||
name: str
|
|
||||||
args: List[TypeExpr]
|
|
||||||
|
|
||||||
class UnionTypeExpr(TypeExpr):
|
|
||||||
types: List[TypeExpr]
|
|
||||||
|
|
||||||
class External(AST):
|
|
||||||
name: str
|
|
||||||
|
|
||||||
class NodeDeclField(AST):
|
|
||||||
name: str
|
|
||||||
type_expr: TypeExpr
|
|
||||||
|
|
||||||
class NodeDecl(AST):
|
|
||||||
name: str
|
|
||||||
parents: List[str]
|
|
||||||
members: List[NodeDeclField]
|
|
||||||
|
|
||||||
def pretty_token(token):
|
|
||||||
if token.type == END_OF_FILE:
|
|
||||||
return 'end-of-file'
|
|
||||||
return f"'{token.text}'"
|
|
||||||
|
|
||||||
def pretty_token_type(token_type):
|
|
||||||
if token_type in TOKEN_TYPE_TO_STRING:
|
|
||||||
return f"'{TOKEN_TYPE_TO_STRING[token_type]}'"
|
|
||||||
if token_type == IDENTIFIER:
|
|
||||||
return 'an identfier'
|
|
||||||
if token_type == STRING:
|
|
||||||
return 'a string literal'
|
|
||||||
if token_type == END_OF_FILE:
|
|
||||||
return 'end-of-file'
|
|
||||||
return f"(unknown token type {token_type})"
|
|
||||||
|
|
||||||
def pretty_alternatives(elements):
|
|
||||||
try:
|
|
||||||
out = next(elements)
|
|
||||||
except StopIteration:
|
|
||||||
return 'nothing'
|
|
||||||
try:
|
|
||||||
prev_element = next(elements)
|
|
||||||
except StopIteration:
|
|
||||||
return out
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
element = next(elements)
|
|
||||||
except StopIteration:
|
|
||||||
break
|
|
||||||
out += ', ' + prev_element
|
|
||||||
prev_element = element
|
|
||||||
return out + ' or ' + prev_element
|
|
||||||
|
|
||||||
class ParseError(RuntimeError):
|
|
||||||
|
|
||||||
def __init__(self, file, actual, expected):
|
|
||||||
super().__init__(f"{file.name}:{actual.start_pos.line}:{actual.start_pos.column}: got {pretty_token(actual)} but expected {pretty_alternatives(pretty_token_type(tt) for tt in expected)}")
|
|
||||||
self.actual = actual
|
|
||||||
self.expected = expected
|
|
||||||
|
|
||||||
class Parser:
|
|
||||||
|
|
||||||
def __init__(self, scanner):
|
|
||||||
self._scanner = scanner
|
|
||||||
self._token_buffer = deque()
|
|
||||||
|
|
||||||
def _peek_token(self, offset=1):
|
|
||||||
while len(self._token_buffer) < offset:
|
|
||||||
self._token_buffer.append(self._scanner.scan())
|
|
||||||
return self._token_buffer[offset-1]
|
|
||||||
|
|
||||||
def _get_token(self):
|
|
||||||
if self._token_buffer:
|
|
||||||
return self._token_buffer.popleft()
|
|
||||||
return self._scanner.scan()
|
|
||||||
|
|
||||||
def _expect_token(self, expected_token_type):
|
|
||||||
t0 = self._get_token()
|
|
||||||
if t0.type != expected_token_type:
|
|
||||||
raise ParseError(self._scanner.file, t0, [ expected_token_type ])
|
|
||||||
return t0
|
|
||||||
|
|
||||||
def _parse_prim_type_expr(self):
|
|
||||||
t0 = self._get_token()
|
|
||||||
if t0.type == LPAREN:
|
|
||||||
result = self.parse_type_expr()
|
|
||||||
self._expect_token(RPAREN)
|
|
||||||
return result
|
|
||||||
if t0.type == IDENTIFIER:
|
|
||||||
t1 = self._peek_token()
|
|
||||||
args = []
|
|
||||||
if t1.type == LESSTHAN:
|
|
||||||
self._get_token()
|
|
||||||
while True:
|
|
||||||
t2 = self._peek_token()
|
|
||||||
if t2.type == GREATERTHAN:
|
|
||||||
self._get_token()
|
|
||||||
break
|
|
||||||
args.append(self.parse_type_expr())
|
|
||||||
t3 = self._get_token()
|
|
||||||
if t3.type == GREATERTHAN:
|
|
||||||
break
|
|
||||||
if t3.type != COMMA:
|
|
||||||
raise ParseError(self._scanner.file, t3, [ COMMA, GREATERTHAN ])
|
|
||||||
return RefTypeExpr(t0.value, args)
|
|
||||||
raise ParseError(self._scanner.file, t0, [ LPAREN, IDENTIFIER ])
|
|
||||||
|
|
||||||
def parse_type_expr(self):
|
|
||||||
return self._parse_prim_type_expr()
|
|
||||||
|
|
||||||
def parse_member(self):
|
|
||||||
type_expr = self.parse_type_expr()
|
|
||||||
name = self._expect_token(IDENTIFIER)
|
|
||||||
self._expect_token(SEMI)
|
|
||||||
return NodeDeclField(name.value, type_expr)
|
|
||||||
|
|
||||||
def parse_toplevel(self):
|
|
||||||
t0 = self._get_token()
|
|
||||||
if t0.type == EXTERNAL:
|
|
||||||
name = self._expect_token(IDENTIFIER)
|
|
||||||
self._expect_token(SEMI)
|
|
||||||
return External(name.value)
|
|
||||||
if t0.type == NODE:
|
|
||||||
name = self._expect_token(IDENTIFIER).value
|
|
||||||
parents = []
|
|
||||||
t1 = self._peek_token()
|
|
||||||
if t1.type == COLON:
|
|
||||||
self._get_token()
|
|
||||||
while True:
|
|
||||||
parent = self._expect_token(IDENTIFIER).value
|
|
||||||
parents.append(parent)
|
|
||||||
t2 = self._peek_token()
|
|
||||||
if t2.type == COMMA:
|
|
||||||
self._get_token()
|
|
||||||
continue
|
|
||||||
if t2.type == LBRACE:
|
|
||||||
break
|
|
||||||
raise ParseError(self._scanner.file, t2, [ COMMA, LBRACE ])
|
|
||||||
self._expect_token(LBRACE)
|
|
||||||
members = []
|
|
||||||
while True:
|
|
||||||
t2 = self._peek_token()
|
|
||||||
if t2.type == RBRACE:
|
|
||||||
self._get_token()
|
|
||||||
break
|
|
||||||
member = self.parse_member()
|
|
||||||
members.append(member)
|
|
||||||
return NodeDecl(name, parents, members)
|
|
||||||
if t0.type == HASH:
|
|
||||||
name = self._expect_token(IDENTIFIER)
|
|
||||||
if name.value == 'include':
|
|
||||||
t1 = self._get_token()
|
|
||||||
if t1.type == LESSTHAN:
|
|
||||||
assert(not self._token_buffer)
|
|
||||||
path = self._scanner._take_while(lambda ch: ch != '>')
|
|
||||||
self._scanner._get_char()
|
|
||||||
mode = INCLUDEMODE_SYSTEM
|
|
||||||
elif t1.type == STRING:
|
|
||||||
mode = INCLUDEMODE_LOCAL
|
|
||||||
path = t1.value
|
|
||||||
else:
|
|
||||||
raise ParseError(self._scanner.file, t1, [ STRING, LESSTHAN ])
|
|
||||||
return IncludeDiretive(path, mode)
|
|
||||||
raise RuntimeError(f"invalid preprocessor directive '{name.value}'")
|
|
||||||
raise ParseError(self._scanner.file, t0, [ EXTERNAL, NODE, HASH ])
|
|
||||||
|
|
||||||
def parse_grammar(self):
|
|
||||||
elements = []
|
|
||||||
while True:
|
|
||||||
t0 = self._peek_token()
|
|
||||||
if t0.type == END_OF_FILE:
|
|
||||||
break
|
|
||||||
element = self.parse_toplevel()
|
|
||||||
elements.append(element)
|
|
||||||
return elements
|
|
||||||
|
|
||||||
class Writer:
|
|
||||||
|
|
||||||
def __init__(self, text='', path=None):
|
|
||||||
self.path = path
|
|
||||||
self.text = text
|
|
||||||
self._at_blank_line = True
|
|
||||||
self._indentation = ' '
|
|
||||||
self._indent_level = 0
|
|
||||||
|
|
||||||
def indent(self, count=1):
|
|
||||||
self._indent_level += count
|
|
||||||
|
|
||||||
def dedent(self, count=1):
|
|
||||||
self._indent_level -= count
|
|
||||||
|
|
||||||
def write(self, chunk):
|
|
||||||
for ch in chunk:
|
|
||||||
if ch == '}':
|
|
||||||
self.dedent()
|
|
||||||
if ch == '\n':
|
|
||||||
self._at_blank_line = True
|
|
||||||
elif self._at_blank_line and not RE_WHTITESPACE.match(ch):
|
|
||||||
self.text += self._indentation * self._indent_level
|
|
||||||
self._at_blank_line = False
|
|
||||||
self.text += ch
|
|
||||||
if ch == '{':
|
|
||||||
self.indent()
|
|
||||||
|
|
||||||
def save(self, dest_dir):
|
|
||||||
dest_path = dest_dir / self.path
|
|
||||||
print(f'Writing file {dest_path} ...')
|
|
||||||
with open(dest_path, 'w') as f:
|
|
||||||
f.write(self.text)
|
|
||||||
|
|
||||||
class DiGraph:
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self._out_edges = dict()
|
|
||||||
self._in_edges = dict()
|
|
||||||
|
|
||||||
def add_edge(self, a, b):
|
|
||||||
if a not in self._out_edges:
|
|
||||||
self._out_edges[a] = set()
|
|
||||||
self._out_edges[a].add(b)
|
|
||||||
if b not in self._in_edges:
|
|
||||||
self._in_edges[b] = set()
|
|
||||||
self._in_edges[b].add(a)
|
|
||||||
|
|
||||||
def get_children(self, node):
|
|
||||||
if node not in self._out_edges:
|
|
||||||
return
|
|
||||||
for child in self._out_edges[node]:
|
|
||||||
yield child
|
|
||||||
|
|
||||||
def has_children(self, node):
|
|
||||||
return node in self._out_edges
|
|
||||||
|
|
||||||
def is_child_of(self, a, b):
|
|
||||||
stack = [ b ]
|
|
||||||
visited = set()
|
|
||||||
while stack:
|
|
||||||
node = stack.pop()
|
|
||||||
if node in visited:
|
|
||||||
break
|
|
||||||
visited.add(node)
|
|
||||||
if node == a:
|
|
||||||
return True
|
|
||||||
for child in self.get_children(node):
|
|
||||||
stack.append(child)
|
|
||||||
return False
|
|
||||||
|
|
||||||
def get_ancestors(self, node):
|
|
||||||
if node not in self._in_edges:
|
|
||||||
return
|
|
||||||
for parent in self._in_edges[node]:
|
|
||||||
yield parent
|
|
||||||
|
|
||||||
def get_common_ancestor(self, nodes):
|
|
||||||
out = nodes[0]
|
|
||||||
parents = []
|
|
||||||
for node in nodes[1:]:
|
|
||||||
if not self.is_child_of(node, out):
|
|
||||||
for parent in self.get_ancestors(node):
|
|
||||||
parents.append(parent)
|
|
||||||
if not parents:
|
|
||||||
return out
|
|
||||||
parents.append(out)
|
|
||||||
return self.get_common_ancestor(parents)
|
|
||||||
|
|
||||||
def main():
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
|
|
||||||
parser.add_argument('file', nargs=1, help='The specification file to generate C++ code for')
|
|
||||||
parser.add_argument('--namespace', default='', help='What C++ namespace to put generated code under')
|
|
||||||
parser.add_argument('--name', default='AST', help='How to name the generated tree')
|
|
||||||
parser.add_argument('-I', default='.', help='What path will be used to include generated header files')
|
|
||||||
parser.add_argument('--include-root', default='.', help='Where the headers live inside the include directroy')
|
|
||||||
parser.add_argument('--enable-serde', action='store_true', help='Also write (de)serialization logic')
|
|
||||||
parser.add_argument('--source-root', default='.', help='Where to store generated souce files')
|
|
||||||
parser.add_argument('--node-name', default='Node', help='How the root node of the hierachy should be called')
|
|
||||||
parser.add_argument('--node-prefix', default='', help='String to prepend to the names of node types')
|
|
||||||
parser.add_argument('--out-dir', default='.', help='Place the endire folder structure inside this folder')
|
|
||||||
parser.add_argument('--dry-run', action='store_true', help='Do not write generated code to the file system')
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
filename = args.file[0]
|
|
||||||
prefix = args.node_prefix
|
|
||||||
cpp_root_node_name = prefix + args.node_name
|
|
||||||
include_dir = Path(args.I)
|
|
||||||
include_path = Path(args.include_root or '.')
|
|
||||||
full_include_path = include_dir / include_path
|
|
||||||
source_path = Path(args.source_root)
|
|
||||||
namespace = args.namespace.split('::')
|
|
||||||
out_dir = Path(args.out_dir)
|
|
||||||
out_name = args.name
|
|
||||||
write_serde = args.enable_serde
|
|
||||||
|
|
||||||
with open(filename, 'r') as f:
|
|
||||||
text = f.read()
|
|
||||||
|
|
||||||
scanner = Scanner(text, filename=filename)
|
|
||||||
parser = Parser(scanner)
|
|
||||||
elements = parser.parse_grammar()
|
|
||||||
|
|
||||||
types = dict()
|
|
||||||
nodes = list()
|
|
||||||
leaf_nodes = list()
|
|
||||||
graph = DiGraph()
|
|
||||||
parent_to_children = dict()
|
|
||||||
|
|
||||||
for element in elements:
|
|
||||||
if isinstance(element, External) \
|
|
||||||
or isinstance(element, NodeDecl):
|
|
||||||
types[element.name] = element
|
|
||||||
if isinstance(element, NodeDecl):
|
|
||||||
nodes.append(element)
|
|
||||||
for parent in element.parents:
|
|
||||||
graph.add_edge(parent, element.name)
|
|
||||||
if parent not in parent_to_children:
|
|
||||||
parent_to_children[parent] = set()
|
|
||||||
children = parent_to_children[parent]
|
|
||||||
children.add(element)
|
|
||||||
|
|
||||||
for node in nodes:
|
|
||||||
if node.name not in parent_to_children:
|
|
||||||
leaf_nodes.append(node)
|
|
||||||
|
|
||||||
def is_null_type_expr(type_expr):
|
|
||||||
return isinstance(type_expr, RefTypeExpr) and type_expr.name == 'null'
|
|
||||||
|
|
||||||
def is_node(name):
|
|
||||||
if name in types:
|
|
||||||
return isinstance(types[name], NodeDecl)
|
|
||||||
if name in parent_to_children:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def get_all_variant_elements(type_expr):
|
|
||||||
types = list()
|
|
||||||
def loop(ty):
|
|
||||||
if isinstance(ty, RefTypeExpr) and ty.name == 'Variant':
|
|
||||||
for arg in ty.args:
|
|
||||||
loop(arg)
|
|
||||||
else:
|
|
||||||
types.append(ty)
|
|
||||||
loop(type_expr)
|
|
||||||
return types
|
|
||||||
|
|
||||||
def infer_type(type_expr):
|
|
||||||
if isinstance(type_expr, RefTypeExpr):
|
|
||||||
if type_expr.name == 'Option':
|
|
||||||
assert(len(type_expr.args) == 1)
|
|
||||||
return OptionalType(infer_type(type_expr.args[0]))
|
|
||||||
if type_expr.name == 'List':
|
|
||||||
assert(len(type_expr.args) == 1)
|
|
||||||
return ListType(infer_type(type_expr.args[0]))
|
|
||||||
if type_expr.name == 'Variant':
|
|
||||||
types = get_all_variant_elements(type_expr)
|
|
||||||
has_null = False
|
|
||||||
if any(is_null_type_expr(ty) for ty in types):
|
|
||||||
has_null = True
|
|
||||||
types = list(ty for ty in types if not is_null_type_expr(ty))
|
|
||||||
if all(isinstance(ty, RefTypeExpr) and is_node(ty.name) for ty in types):
|
|
||||||
node_name = graph.get_common_ancestor(list(t.name for t in types))
|
|
||||||
return NodeType(node_name)
|
|
||||||
if len(types) == 1:
|
|
||||||
out = infer_type(types[0])
|
|
||||||
else:
|
|
||||||
out = VariantType(infer_type(ty) for ty in types)
|
|
||||||
return OptionalType(out) if has_null else out
|
|
||||||
if is_node(type_expr.name):
|
|
||||||
assert(len(type_expr.args) == 0)
|
|
||||||
return NodeType(type_expr.name)
|
|
||||||
assert(len(type_expr.args) == 0)
|
|
||||||
return RawType(type_expr.name)
|
|
||||||
raise RuntimeError(f"unhandled type expression {type_expr}")
|
|
||||||
|
|
||||||
for node in nodes:
|
|
||||||
for member in node.members:
|
|
||||||
member.type_expr.type = infer_type(member.type_expr)
|
|
||||||
|
|
||||||
def is_type_optional_by_default(ty):
|
|
||||||
return isinstance(ty, NodeType)
|
|
||||||
|
|
||||||
def gen_cpp_type_expr(ty):
|
|
||||||
if isinstance(ty, NodeType):
|
|
||||||
return prefix + ty.name + "*"
|
|
||||||
if isinstance(ty, ListType):
|
|
||||||
return f"std::vector<{gen_cpp_type_expr(ty.element_type)}>"
|
|
||||||
if isinstance(ty, NodeType):
|
|
||||||
return ty.name + '*'
|
|
||||||
if isinstance(ty, OptionalType):
|
|
||||||
cpp_expr = gen_cpp_type_expr(ty.element_type)
|
|
||||||
if is_type_optional_by_default(ty.element_type):
|
|
||||||
return cpp_expr
|
|
||||||
return f"std::optional<{cpp_expr}>"
|
|
||||||
if isinstance(ty, VariantType):
|
|
||||||
return f"std::variant<{','.join(gen_cpp_type_expr(t) for t in ty.element_types)}>"
|
|
||||||
if isinstance(ty, RawType):
|
|
||||||
return ty.text
|
|
||||||
raise RuntimeError(f"unhandled Type {ty}")
|
|
||||||
|
|
||||||
def gen_cpp_dtor(expr, ty):
|
|
||||||
if isinstance(ty, NodeType):
|
|
||||||
return f'{expr}->unref();\n'
|
|
||||||
elif isinstance(ty, ListType):
|
|
||||||
dtor = gen_cpp_dtor('Element', ty.element_type)
|
|
||||||
if dtor:
|
|
||||||
out = ''
|
|
||||||
out += f'for (auto& Element: {expr})'
|
|
||||||
out += '{\n'
|
|
||||||
out += dtor
|
|
||||||
out += '}\n'
|
|
||||||
return out
|
|
||||||
elif isinstance(ty, OptionalType):
|
|
||||||
if is_type_optional_by_default(ty.element_type):
|
|
||||||
element_expr = expr
|
|
||||||
else:
|
|
||||||
element_expr = f'(*{expr})'
|
|
||||||
dtor = gen_cpp_dtor(element_expr, ty.element_type)
|
|
||||||
if dtor:
|
|
||||||
out = ''
|
|
||||||
out += 'if ('
|
|
||||||
out += expr
|
|
||||||
out += ') {\n'
|
|
||||||
out += dtor
|
|
||||||
out += '}\n'
|
|
||||||
return out
|
|
||||||
elif isinstance(ty, RawType):
|
|
||||||
pass # field should be destroyed by class
|
|
||||||
else:
|
|
||||||
raise RuntimeError(f'unexpected {ty}')
|
|
||||||
|
|
||||||
def gen_cpp_ctor_params(out, node):
|
|
||||||
visited = set()
|
|
||||||
queue = deque([ node ])
|
|
||||||
is_leaf = not graph.has_children(node.name)
|
|
||||||
first = True
|
|
||||||
if not is_leaf:
|
|
||||||
out.write(f"{cpp_root_node_name}Type Type")
|
|
||||||
first = False
|
|
||||||
while queue:
|
|
||||||
node = queue.popleft()
|
|
||||||
if node.name in visited:
|
|
||||||
return
|
|
||||||
visited.add(node.name)
|
|
||||||
for member in node.members:
|
|
||||||
if first:
|
|
||||||
first = False
|
|
||||||
else:
|
|
||||||
out.write(', ')
|
|
||||||
out.write(gen_cpp_type_expr(member.type_expr.type))
|
|
||||||
out.write(' ')
|
|
||||||
out.write(camel_case(member.name))
|
|
||||||
for parent in node.parents:
|
|
||||||
queue.append(types[parent])
|
|
||||||
|
|
||||||
def gen_cpp_ctor_args(out, orig_node: NodeDecl):
|
|
||||||
first = True
|
|
||||||
is_leaf = not graph.has_children(orig_node.name)
|
|
||||||
if orig_node.parents:
|
|
||||||
for parent in orig_node.parents:
|
|
||||||
if first:
|
|
||||||
first = False
|
|
||||||
else:
|
|
||||||
out.write(', ')
|
|
||||||
node = types[parent]
|
|
||||||
refs = ''
|
|
||||||
if is_leaf:
|
|
||||||
refs += f"{cpp_root_node_name}Type::{orig_node.name}"
|
|
||||||
else:
|
|
||||||
refs += 'Type'
|
|
||||||
for member in node.members:
|
|
||||||
refs += f", {camel_case(member.name)}"
|
|
||||||
out.write(f"{prefix}{node.name}({refs})")
|
|
||||||
else:
|
|
||||||
if is_leaf:
|
|
||||||
out.write(f"{cpp_root_node_name}({cpp_root_node_name}Type::{orig_node.name})")
|
|
||||||
else:
|
|
||||||
out.write(f"{cpp_root_node_name}(Type)")
|
|
||||||
first = False
|
|
||||||
for member in orig_node.members:
|
|
||||||
if first:
|
|
||||||
first = False
|
|
||||||
else:
|
|
||||||
out.write(', ')
|
|
||||||
out.write(f"{camel_case(member.name)}({camel_case(member.name)})")
|
|
||||||
|
|
||||||
node_hdr = templaty.execute(here / 'CST.hpp.tply', ctx={
|
|
||||||
'namespaces': namespace,
|
|
||||||
'nodes': nodes,
|
|
||||||
'root_node_name': args.node_name
|
|
||||||
})
|
|
||||||
|
|
||||||
node_hdr = Writer(path=full_include_path / (out_name + '.hpp'))
|
|
||||||
node_src = Writer(path=source_path / (out_name + '.cc'))
|
|
||||||
|
|
||||||
# Generating the header file
|
|
||||||
|
|
||||||
if write_serde:
|
|
||||||
node_hdr.write('void encode(Encoder& encoder) const;\n\n')
|
|
||||||
node_hdr.write('virtual void encode_fields(Encoder& encoder) const = 0;\n');
|
|
||||||
#node_hdr.write('virtual void decode_fields(Decoder& decoder) = 0;\n\n');
|
|
||||||
|
|
||||||
for element in elements:
|
|
||||||
if isinstance(element, NodeDecl):
|
|
||||||
node = element
|
|
||||||
is_leaf = not list(graph.get_children(node.name))
|
|
||||||
cpp_node_name = prefix + node.name
|
|
||||||
node_hdr.write("class ")
|
|
||||||
node_hdr.write(cpp_node_name)
|
|
||||||
node_hdr.write(" : ")
|
|
||||||
if node.parents:
|
|
||||||
node_hdr.write(', '.join('public ' + prefix + parent for parent in node.parents))
|
|
||||||
else:
|
|
||||||
node_hdr.write('public ' + cpp_root_node_name)
|
|
||||||
node_hdr.write(" {\n\n")
|
|
||||||
node_hdr.write('public:\n\n')
|
|
||||||
|
|
||||||
node_hdr.write(cpp_node_name + '(')
|
|
||||||
gen_cpp_ctor_params(node_hdr, node)
|
|
||||||
node_hdr.write('): ')
|
|
||||||
gen_cpp_ctor_args(node_hdr, node)
|
|
||||||
node_hdr.write(' {}\n\n')
|
|
||||||
|
|
||||||
if node.members:
|
|
||||||
for member in node.members:
|
|
||||||
node_hdr.write(gen_cpp_type_expr(member.type_expr.type))
|
|
||||||
node_hdr.write(" ");
|
|
||||||
node_hdr.write(camel_case(member.name))
|
|
||||||
node_hdr.write(";\n");
|
|
||||||
node_hdr.write('\n')
|
|
||||||
if write_serde and is_leaf:
|
|
||||||
node_hdr.write('void encode_fields(Encoder& encoder) const override;\n');
|
|
||||||
#node_hdr.write('void decode_fields(Decoder& decoder) override;\n\n');
|
|
||||||
|
|
||||||
# Generating the source file
|
|
||||||
|
|
||||||
node_src.write(f"""#include "{include_path / (out_name + '.hpp')}"\n\n""")
|
|
||||||
|
|
||||||
for name in namespace:
|
|
||||||
node_src.write(f"namespace {name} {{\n\n")
|
|
||||||
|
|
||||||
node_src.write(f"""{cpp_root_node_name}::~{cpp_root_node_name}() {{ }}\n\n""")
|
|
||||||
|
|
||||||
if write_serde:
|
|
||||||
node_src.write(f"""
|
|
||||||
void {cpp_root_node_name}::encode(Encoder& encoder) const {{
|
|
||||||
encoder.start_encode_struct("{cpp_root_node_name}");
|
|
||||||
encode_fields(encoder);
|
|
||||||
encoder.end_encode_struct();
|
|
||||||
}}
|
|
||||||
|
|
||||||
""")
|
|
||||||
|
|
||||||
for node in nodes:
|
|
||||||
is_leaf = not list(graph.get_children(node.name))
|
|
||||||
cpp_node_name = prefix + node.name
|
|
||||||
|
|
||||||
if write_serde and is_leaf:
|
|
||||||
node_src.write(f'void {cpp_node_name}::encode_fields(Encoder& encoder) const {{\n')
|
|
||||||
for member in node.members:
|
|
||||||
node_src.write(f'encoder.encode_field("{member.name}", {member.name});\n')
|
|
||||||
node_src.write('}\n\n')
|
|
||||||
|
|
||||||
node_src.write(f'{cpp_node_name}::~{cpp_node_name}() {{\n')
|
|
||||||
for member in node.members:
|
|
||||||
dtor = gen_cpp_dtor(camel_case(member.name), member.type_expr.type)
|
|
||||||
if dtor:
|
|
||||||
node_src.write(dtor)
|
|
||||||
node_src.write('}\n\n')
|
|
||||||
|
|
||||||
for _ in namespace:
|
|
||||||
node_src.write("}\n\n")
|
|
||||||
|
|
||||||
if args.dry_run:
|
|
||||||
print('# ' + str(node_hdr.path))
|
|
||||||
print(node_hdr.text)
|
|
||||||
print('# ' + str(node_src.path))
|
|
||||||
print(node_src.text)
|
|
||||||
else:
|
|
||||||
out_dir.mkdir(exist_ok=True, parents=True)
|
|
||||||
node_hdr.save(out_dir)
|
|
||||||
node_src.save(out_dir)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
586
src/CST.cc
586
src/CST.cc
|
@ -2,6 +2,7 @@
|
||||||
#include "zen/config.hpp"
|
#include "zen/config.hpp"
|
||||||
|
|
||||||
#include "bolt/CST.hpp"
|
#include "bolt/CST.hpp"
|
||||||
|
#include "bolt/CSTVisitor.hpp"
|
||||||
|
|
||||||
namespace bolt {
|
namespace bolt {
|
||||||
|
|
||||||
|
@ -11,23 +12,34 @@ namespace bolt {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scope::scan(Node* X) {
|
void Scope::scan(Node* X) {
|
||||||
switch (X->Type) {
|
switch (X->getKind()) {
|
||||||
case NodeType::ExpressionStatement:
|
case NodeKind::ExpressionStatement:
|
||||||
case NodeType::ReturnStatement:
|
case NodeKind::ReturnStatement:
|
||||||
case NodeType::IfStatement:
|
case NodeKind::IfStatement:
|
||||||
break;
|
break;
|
||||||
case NodeType::SourceFile:
|
case NodeKind::SourceFile:
|
||||||
{
|
{
|
||||||
auto Y = static_cast<SourceFile*>(X);
|
auto File = static_cast<SourceFile*>(X);
|
||||||
for (auto Element: Y->Elements) {
|
for (auto Element: File->Elements) {
|
||||||
scan(Element);
|
scan(Element);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NodeType::LetDeclaration:
|
case NodeKind::ClassDeclaration:
|
||||||
{
|
{
|
||||||
auto Y = static_cast<LetDeclaration*>(X);
|
auto Decl = static_cast<ClassDeclaration*>(X);
|
||||||
addBindings(Y->Pattern, Y);
|
for (auto Element: Decl->Elements) {
|
||||||
|
scan(Element);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NodeKind::InstanceDeclaration:
|
||||||
|
// FIXME is this right?
|
||||||
|
break;
|
||||||
|
case NodeKind::LetDeclaration:
|
||||||
|
{
|
||||||
|
auto Decl = static_cast<LetDeclaration*>(X);
|
||||||
|
addBindings(Decl->Pattern, Decl);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -36,8 +48,8 @@ namespace bolt {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scope::addBindings(Pattern* X, Node* ToInsert) {
|
void Scope::addBindings(Pattern* X, Node* ToInsert) {
|
||||||
switch (X->Type) {
|
switch (X->getKind()) {
|
||||||
case NodeType::BindPattern:
|
case NodeKind::BindPattern:
|
||||||
{
|
{
|
||||||
auto Y = static_cast<BindPattern*>(X);
|
auto Y = static_cast<BindPattern*>(X);
|
||||||
Mapping.emplace(Y->Name->Text, ToInsert);
|
Mapping.emplace(Y->Name->Text, ToInsert);
|
||||||
|
@ -49,6 +61,7 @@ namespace bolt {
|
||||||
}
|
}
|
||||||
|
|
||||||
Node* Scope::lookup(SymbolPath Path) {
|
Node* Scope::lookup(SymbolPath Path) {
|
||||||
|
ZEN_ASSERT(Path.Modules.empty());
|
||||||
auto Curr = this;
|
auto Curr = this;
|
||||||
do {
|
do {
|
||||||
auto Match = Curr->Mapping.find(Path.Name);
|
auto Match = Curr->Mapping.find(Path.Name);
|
||||||
|
@ -70,7 +83,7 @@ namespace bolt {
|
||||||
SourceFile* Node::getSourceFile() {
|
SourceFile* Node::getSourceFile() {
|
||||||
auto CurrNode = this;
|
auto CurrNode = this;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (CurrNode->Type == NodeType::SourceFile) {
|
if (CurrNode->Kind == NodeKind::SourceFile) {
|
||||||
return static_cast<SourceFile*>(CurrNode);
|
return static_cast<SourceFile*>(CurrNode);
|
||||||
}
|
}
|
||||||
CurrNode = CurrNode->Parent;
|
CurrNode = CurrNode->Parent;
|
||||||
|
@ -95,435 +108,49 @@ namespace bolt {
|
||||||
return EndLoc;
|
return EndLoc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Token::setParents() {
|
void Node::setParents() {
|
||||||
}
|
|
||||||
|
|
||||||
void QualifiedName::setParents() {
|
struct SetParentsVisitor : public CSTVisitor<SetParentsVisitor> {
|
||||||
for (auto Name: ModulePath) {
|
|
||||||
Name->Parent = this;
|
|
||||||
}
|
|
||||||
Name->Parent = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReferenceTypeExpression::setParents() {
|
std::vector<Node*> Parents { nullptr };
|
||||||
Name->Parent = this;
|
|
||||||
Name->setParents();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ArrowTypeExpression::setParents() {
|
void visit(Node* N) {
|
||||||
for (auto ParamType: ParamTypes) {
|
N->Parent = Parents.back();
|
||||||
ParamType->Parent = this;
|
Parents.push_back(N);
|
||||||
ParamType->setParents();
|
visitEachChild(N);
|
||||||
}
|
Parents.pop_back();
|
||||||
ReturnType->Parent = this;
|
}
|
||||||
ReturnType->setParents();
|
|
||||||
}
|
|
||||||
|
|
||||||
void BindPattern::setParents() {
|
};
|
||||||
Name->Parent = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReferenceExpression::setParents() {
|
SetParentsVisitor V;
|
||||||
Name->Parent = this;
|
V.visit(this);
|
||||||
}
|
|
||||||
|
|
||||||
void NestedExpression::setParents() {
|
|
||||||
LParen->Parent = this;
|
|
||||||
Inner->Parent = this;
|
|
||||||
Inner->setParents();
|
|
||||||
RParen->Parent = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConstantExpression::setParents() {
|
|
||||||
Token->Parent = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CallExpression::setParents() {
|
|
||||||
Function->Parent = this;
|
|
||||||
Function->setParents();
|
|
||||||
for (auto Arg: Args) {
|
|
||||||
Arg->Parent = this;
|
|
||||||
Arg->setParents();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void InfixExpression::setParents() {
|
|
||||||
LHS->Parent = this;
|
|
||||||
LHS->setParents();
|
|
||||||
Operator->Parent = this;
|
|
||||||
RHS->Parent = this;
|
|
||||||
RHS->setParents();
|
|
||||||
}
|
|
||||||
|
|
||||||
void UnaryExpression::setParents() {
|
|
||||||
Operator->Parent = this;
|
|
||||||
Argument->Parent = this;
|
|
||||||
Argument->setParents();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExpressionStatement::setParents() {
|
|
||||||
Expression->Parent = this;
|
|
||||||
Expression->setParents();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReturnStatement::setParents() {
|
|
||||||
ReturnKeyword->Parent = this;
|
|
||||||
Expression->Parent = this;
|
|
||||||
Expression->setParents();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IfStatementPart::setParents() {
|
|
||||||
Keyword->Parent = this;
|
|
||||||
if (Test) {
|
|
||||||
Test->Parent = this;
|
|
||||||
Test->setParents();
|
|
||||||
}
|
|
||||||
BlockStart->Parent = this;
|
|
||||||
for (auto Element: Elements) {
|
|
||||||
Element->Parent = this;
|
|
||||||
Element->setParents();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void IfStatement::setParents() {
|
|
||||||
for (auto Part: Parts) {
|
|
||||||
Part->Parent = this;
|
|
||||||
Part->setParents();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TypeAssert::setParents() {
|
|
||||||
Colon->Parent = this;
|
|
||||||
TypeExpression->Parent = this;
|
|
||||||
TypeExpression->setParents();
|
|
||||||
}
|
|
||||||
|
|
||||||
void LetBlockBody::setParents() {
|
|
||||||
BlockStart->Parent = this;
|
|
||||||
for (auto Element: Elements) {
|
|
||||||
Element->Parent = this;
|
|
||||||
Element->setParents();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void LetExprBody::setParents() {
|
|
||||||
Equals->Parent = this;
|
|
||||||
Expression->Parent = this;
|
|
||||||
Expression->setParents();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Param::setParents() {
|
|
||||||
Pattern->Parent = this;
|
|
||||||
Pattern->setParents();
|
|
||||||
if (TypeAssert) {
|
|
||||||
TypeAssert->Parent = this;
|
|
||||||
TypeAssert->setParents();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void LetDeclaration::setParents() {
|
|
||||||
if (PubKeyword) {
|
|
||||||
PubKeyword->Parent = this;
|
|
||||||
}
|
|
||||||
LetKeyword->Parent = this;
|
|
||||||
if (MutKeyword) {
|
|
||||||
MutKeyword->Parent = this;
|
|
||||||
}
|
|
||||||
Pattern->Parent = this;
|
|
||||||
Pattern->setParents();
|
|
||||||
for (auto Param: Params) {
|
|
||||||
Param->Parent = this;
|
|
||||||
Param->setParents();
|
|
||||||
}
|
|
||||||
if (TypeAssert) {
|
|
||||||
TypeAssert->Parent = this;
|
|
||||||
TypeAssert->setParents();
|
|
||||||
}
|
|
||||||
if (Body) {
|
|
||||||
Body->Parent = this;
|
|
||||||
Body->setParents();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StructDeclField::setParents() {
|
|
||||||
Name->Parent = this;
|
|
||||||
Colon->Parent = this;
|
|
||||||
TypeExpression->Parent = this;
|
|
||||||
TypeExpression->setParents();
|
|
||||||
}
|
|
||||||
|
|
||||||
void StructDecl::setParents() {
|
|
||||||
StructKeyword->Parent = this;
|
|
||||||
Name->Parent = this;
|
|
||||||
BlockStart->Parent = this;
|
|
||||||
for (auto Field: Fields) {
|
|
||||||
Field->Parent = this;
|
|
||||||
Field->setParents();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SourceFile::setParents() {
|
|
||||||
for (auto Element: Elements) {
|
|
||||||
Element->Parent = this;
|
|
||||||
Element->setParents();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Node::~Node() {
|
Node::~Node() {
|
||||||
|
|
||||||
|
struct UnrefVisitor : public CSTVisitor<UnrefVisitor> {
|
||||||
|
|
||||||
|
void visit(Node* N) {
|
||||||
|
N->unref();
|
||||||
|
visitEachChild(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
UnrefVisitor V;
|
||||||
|
V.visitEachChild(this);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Token::~Token() {
|
bool Identifier::isTypeVar() const {
|
||||||
}
|
for (auto C: Text) {
|
||||||
|
if (!((C >= 97 && C <= 122) || C == '_')) {
|
||||||
Equals::~Equals() {
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Colon::~Colon() {
|
|
||||||
}
|
|
||||||
|
|
||||||
RArrow::~RArrow() {
|
|
||||||
}
|
|
||||||
|
|
||||||
Dot::~Dot() {
|
|
||||||
}
|
|
||||||
|
|
||||||
DotDot::~DotDot() {
|
|
||||||
}
|
|
||||||
|
|
||||||
LParen::~LParen() {
|
|
||||||
}
|
|
||||||
|
|
||||||
RParen::~RParen() {
|
|
||||||
}
|
|
||||||
|
|
||||||
LBracket::~LBracket() {
|
|
||||||
}
|
|
||||||
|
|
||||||
RBracket::~RBracket() {
|
|
||||||
}
|
|
||||||
|
|
||||||
LBrace::~LBrace() {
|
|
||||||
}
|
|
||||||
|
|
||||||
RBrace::~RBrace() {
|
|
||||||
}
|
|
||||||
|
|
||||||
LetKeyword::~LetKeyword() {
|
|
||||||
}
|
|
||||||
|
|
||||||
MutKeyword::~MutKeyword() {
|
|
||||||
}
|
|
||||||
|
|
||||||
PubKeyword::~PubKeyword() {
|
|
||||||
}
|
|
||||||
|
|
||||||
TypeKeyword::~TypeKeyword() {
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnKeyword::~ReturnKeyword() {
|
|
||||||
}
|
|
||||||
|
|
||||||
IfKeyword::~IfKeyword() {
|
|
||||||
}
|
|
||||||
|
|
||||||
ElifKeyword::~ElifKeyword() {
|
|
||||||
}
|
|
||||||
|
|
||||||
ElseKeyword::~ElseKeyword() {
|
|
||||||
}
|
|
||||||
|
|
||||||
ModKeyword::~ModKeyword() {
|
|
||||||
}
|
|
||||||
|
|
||||||
StructKeyword::~StructKeyword() {
|
|
||||||
}
|
|
||||||
|
|
||||||
Invalid::~Invalid() {
|
|
||||||
}
|
|
||||||
|
|
||||||
EndOfFile::~EndOfFile() {
|
|
||||||
}
|
|
||||||
|
|
||||||
BlockStart::~BlockStart() {
|
|
||||||
}
|
|
||||||
|
|
||||||
BlockEnd::~BlockEnd() {
|
|
||||||
}
|
|
||||||
|
|
||||||
LineFoldEnd::~LineFoldEnd() {
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomOperator::~CustomOperator() {
|
|
||||||
}
|
|
||||||
|
|
||||||
Assignment::~Assignment() {
|
|
||||||
}
|
|
||||||
|
|
||||||
Identifier::~Identifier() {
|
|
||||||
}
|
|
||||||
|
|
||||||
StringLiteral::~StringLiteral() {
|
|
||||||
}
|
|
||||||
|
|
||||||
IntegerLiteral::~IntegerLiteral() {
|
|
||||||
}
|
|
||||||
|
|
||||||
QualifiedName::~QualifiedName() {
|
|
||||||
for (auto& Element: ModulePath){
|
|
||||||
Element->unref();
|
|
||||||
}
|
|
||||||
Name->unref();
|
|
||||||
}
|
|
||||||
|
|
||||||
TypeExpression::~TypeExpression() {
|
|
||||||
}
|
|
||||||
|
|
||||||
ReferenceTypeExpression::~ReferenceTypeExpression() {
|
|
||||||
Name->unref();
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrowTypeExpression::~ArrowTypeExpression() {
|
|
||||||
for (auto ParamType: ParamTypes) {
|
|
||||||
ParamType->unref();
|
|
||||||
}
|
|
||||||
ReturnType->unref();
|
|
||||||
}
|
|
||||||
|
|
||||||
Pattern::~Pattern() {
|
|
||||||
}
|
|
||||||
|
|
||||||
BindPattern::~BindPattern() {
|
|
||||||
Name->unref();
|
|
||||||
}
|
|
||||||
|
|
||||||
Expression::~Expression() {
|
|
||||||
}
|
|
||||||
|
|
||||||
ReferenceExpression::~ReferenceExpression() {
|
|
||||||
Name->unref();
|
|
||||||
}
|
|
||||||
|
|
||||||
NestedExpression::~NestedExpression() {
|
|
||||||
LParen->unref();
|
|
||||||
Inner->unref();
|
|
||||||
RParen->unref();
|
|
||||||
}
|
|
||||||
|
|
||||||
ConstantExpression::~ConstantExpression() {
|
|
||||||
Token->unref();
|
|
||||||
}
|
|
||||||
|
|
||||||
CallExpression::~CallExpression() {
|
|
||||||
Function->unref();
|
|
||||||
for (auto& Element: Args){
|
|
||||||
Element->unref();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
InfixExpression::~InfixExpression() {
|
|
||||||
LHS->unref();
|
|
||||||
Operator->unref();
|
|
||||||
RHS->unref();
|
|
||||||
}
|
|
||||||
|
|
||||||
UnaryExpression::~UnaryExpression() {
|
|
||||||
Operator->unref();
|
|
||||||
Argument->unref();
|
|
||||||
}
|
|
||||||
|
|
||||||
Statement::~Statement() {
|
|
||||||
}
|
|
||||||
|
|
||||||
ExpressionStatement::~ExpressionStatement() {
|
|
||||||
Expression->unref();
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnStatement::~ReturnStatement() {
|
|
||||||
ReturnKeyword->unref();
|
|
||||||
Expression->unref();
|
|
||||||
}
|
|
||||||
|
|
||||||
IfStatementPart::~IfStatementPart() {
|
|
||||||
Keyword->unref();
|
|
||||||
if (Test) {
|
|
||||||
Test->unref();
|
|
||||||
}
|
|
||||||
BlockStart->unref();
|
|
||||||
for (auto Element: Elements) {
|
|
||||||
Element->unref();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IfStatement::~IfStatement() {
|
|
||||||
for (auto Part: Parts) {
|
|
||||||
Part->unref();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TypeAssert::~TypeAssert() {
|
|
||||||
Colon->unref();
|
|
||||||
TypeExpression->unref();
|
|
||||||
}
|
|
||||||
|
|
||||||
Param::~Param() {
|
|
||||||
Pattern->unref();
|
|
||||||
TypeAssert->unref();
|
|
||||||
}
|
|
||||||
|
|
||||||
LetBody::~LetBody() {
|
|
||||||
}
|
|
||||||
|
|
||||||
LetBlockBody::~LetBlockBody() {
|
|
||||||
BlockStart->unref();
|
|
||||||
for (auto& Element: Elements){
|
|
||||||
Element->unref();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LetExprBody::~LetExprBody() {
|
|
||||||
Equals->unref();
|
|
||||||
Expression->unref();
|
|
||||||
}
|
|
||||||
|
|
||||||
LetDeclaration::~LetDeclaration() {
|
|
||||||
if (PubKeyword) {
|
|
||||||
PubKeyword->unref();
|
|
||||||
}
|
|
||||||
LetKeyword->unref();
|
|
||||||
if (MutKeyword) {
|
|
||||||
MutKeyword->unref();
|
|
||||||
}
|
|
||||||
Pattern->unref();
|
|
||||||
for (auto& Element: Params){
|
|
||||||
Element->unref();
|
|
||||||
}
|
|
||||||
if (TypeAssert) {
|
|
||||||
TypeAssert->unref();
|
|
||||||
}
|
|
||||||
if (Body) {
|
|
||||||
Body->unref();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StructDeclField::~StructDeclField() {
|
|
||||||
Name->unref();
|
|
||||||
Colon->unref();
|
|
||||||
TypeExpression->unref();
|
|
||||||
}
|
|
||||||
|
|
||||||
StructDecl::~StructDecl() {
|
|
||||||
StructKeyword->unref();
|
|
||||||
Name->unref();
|
|
||||||
BlockStart->unref();
|
|
||||||
for (auto& Element: Fields){
|
|
||||||
Element->unref();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SourceFile::~SourceFile() {
|
|
||||||
for (auto& Element: Elements){
|
|
||||||
Element->unref();
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Token* QualifiedName::getFirstToken() {
|
Token* QualifiedName::getFirstToken() {
|
||||||
|
@ -537,6 +164,36 @@ namespace bolt {
|
||||||
return Name;
|
return Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Token* TypeclassConstraintExpression::getFirstToken() {
|
||||||
|
return Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
Token* TypeclassConstraintExpression::getLastToken() {
|
||||||
|
if (!TEs.empty()) {
|
||||||
|
return TEs.back()->getLastToken();
|
||||||
|
}
|
||||||
|
return Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
Token* EqualityConstraintExpression::getFirstToken() {
|
||||||
|
return Left->getFirstToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
Token* EqualityConstraintExpression::getLastToken() {
|
||||||
|
return Left->getLastToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
Token* QualifiedTypeExpression::getFirstToken() {
|
||||||
|
if (!Constraints.empty()) {
|
||||||
|
return std::get<0>(Constraints.front())->getFirstToken();
|
||||||
|
}
|
||||||
|
return TE->getFirstToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
Token* QualifiedTypeExpression::getLastToken() {
|
||||||
|
return TE->getLastToken();
|
||||||
|
}
|
||||||
|
|
||||||
Token* ReferenceTypeExpression::getFirstToken() {
|
Token* ReferenceTypeExpression::getFirstToken() {
|
||||||
return Name->getFirstToken();
|
return Name->getFirstToken();
|
||||||
}
|
}
|
||||||
|
@ -556,6 +213,14 @@ namespace bolt {
|
||||||
return ReturnType->getLastToken();
|
return ReturnType->getLastToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Token* VarTypeExpression::getLastToken() {
|
||||||
|
return Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
Token* VarTypeExpression::getFirstToken() {
|
||||||
|
return Name;
|
||||||
|
}
|
||||||
|
|
||||||
Token* BindPattern::getFirstToken() {
|
Token* BindPattern::getFirstToken() {
|
||||||
return Name;
|
return Name;
|
||||||
}
|
}
|
||||||
|
@ -607,11 +272,11 @@ namespace bolt {
|
||||||
return RHS->getLastToken();
|
return RHS->getLastToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
Token* UnaryExpression::getFirstToken() {
|
Token* PrefixExpression::getFirstToken() {
|
||||||
return Operator;
|
return Operator;
|
||||||
}
|
}
|
||||||
|
|
||||||
Token* UnaryExpression::getLastToken() {
|
Token* PrefixExpression::getLastToken() {
|
||||||
return Argument->getLastToken();
|
return Argument->getLastToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -663,11 +328,11 @@ namespace bolt {
|
||||||
return TypeExpression->getLastToken();
|
return TypeExpression->getLastToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
Token* Param::getFirstToken() {
|
Token* Parameter::getFirstToken() {
|
||||||
return Pattern->getFirstToken();
|
return Pattern->getFirstToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
Token* Param::getLastToken() {
|
Token* Parameter::getLastToken() {
|
||||||
if (TypeAssert) {
|
if (TypeAssert) {
|
||||||
return TypeAssert->getLastToken();
|
return TypeAssert->getLastToken();
|
||||||
}
|
}
|
||||||
|
@ -713,28 +378,53 @@ namespace bolt {
|
||||||
return Pattern->getLastToken();
|
return Pattern->getLastToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
Token* StructDeclField::getFirstToken() {
|
Token* StructDeclarationField::getFirstToken() {
|
||||||
return Name;
|
return Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
Token* StructDeclField::getLastToken() {
|
Token* StructDeclarationField::getLastToken() {
|
||||||
return TypeExpression->getLastToken();
|
return TypeExpression->getLastToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
Token* StructDecl::getFirstToken() {
|
Token* StructDeclaration::getFirstToken() {
|
||||||
if (PubKeyword) {
|
if (PubKeyword) {
|
||||||
return PubKeyword;
|
return PubKeyword;
|
||||||
}
|
}
|
||||||
return StructKeyword;
|
return StructKeyword;
|
||||||
}
|
}
|
||||||
|
|
||||||
Token* StructDecl::getLastToken() {
|
Token* StructDeclaration::getLastToken() {
|
||||||
if (Fields.size()) {
|
if (Fields.size()) {
|
||||||
Fields.back()->getLastToken();
|
Fields.back()->getLastToken();
|
||||||
}
|
}
|
||||||
return BlockStart;
|
return BlockStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Token* InstanceDeclaration::getFirstToken() {
|
||||||
|
return InstanceKeyword;
|
||||||
|
}
|
||||||
|
|
||||||
|
Token* InstanceDeclaration::getLastToken() {
|
||||||
|
if (!Elements.empty()) {
|
||||||
|
return Elements.back()->getLastToken();
|
||||||
|
}
|
||||||
|
return BlockStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
Token* ClassDeclaration::getFirstToken() {
|
||||||
|
if (PubKeyword != nullptr) {
|
||||||
|
return PubKeyword;
|
||||||
|
}
|
||||||
|
return ClassKeyword;
|
||||||
|
}
|
||||||
|
|
||||||
|
Token* ClassDeclaration::getLastToken() {
|
||||||
|
if (!Elements.empty()) {
|
||||||
|
return Elements.back()->getLastToken();
|
||||||
|
}
|
||||||
|
return BlockStart;
|
||||||
|
}
|
||||||
|
|
||||||
Token* SourceFile::getFirstToken() {
|
Token* SourceFile::getFirstToken() {
|
||||||
if (Elements.size()) {
|
if (Elements.size()) {
|
||||||
return Elements.front()->getFirstToken();
|
return Elements.front()->getFirstToken();
|
||||||
|
@ -757,10 +447,18 @@ namespace bolt {
|
||||||
return ":";
|
return ":";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Comma::getText() const {
|
||||||
|
return ",";
|
||||||
|
}
|
||||||
|
|
||||||
std::string RArrow::getText() const {
|
std::string RArrow::getText() const {
|
||||||
return "->";
|
return "->";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string RArrowAlt::getText() const {
|
||||||
|
return "=>";
|
||||||
|
}
|
||||||
|
|
||||||
std::string Dot::getText() const {
|
std::string Dot::getText() const {
|
||||||
return ".";
|
return ".";
|
||||||
}
|
}
|
||||||
|
@ -873,6 +571,18 @@ namespace bolt {
|
||||||
return "..";
|
return "..";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Tilde::getText() const {
|
||||||
|
return "~";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ClassKeyword::getText() const {
|
||||||
|
return "class";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string InstanceKeyword::getText() const {
|
||||||
|
return "instance";
|
||||||
|
}
|
||||||
|
|
||||||
SymbolPath QualifiedName::getSymbolPath() const {
|
SymbolPath QualifiedName::getSymbolPath() const {
|
||||||
std::vector<ByteString> ModuleNames;
|
std::vector<ByteString> ModuleNames;
|
||||||
for (auto Ident: ModulePath) {
|
for (auto Ident: ModulePath) {
|
||||||
|
|
825
src/Checker.cc
825
src/Checker.cc
File diff suppressed because it is too large
Load diff
|
@ -44,51 +44,61 @@ namespace bolt {
|
||||||
Diagnostic::Diagnostic(DiagnosticKind Kind):
|
Diagnostic::Diagnostic(DiagnosticKind Kind):
|
||||||
std::runtime_error("a compiler error occurred without being caught"), Kind(Kind) {}
|
std::runtime_error("a compiler error occurred without being caught"), Kind(Kind) {}
|
||||||
|
|
||||||
static std::string describe(NodeType Type) {
|
static std::string describe(NodeKind Type) {
|
||||||
switch (Type) {
|
switch (Type) {
|
||||||
case NodeType::Identifier:
|
case NodeKind::Identifier:
|
||||||
return "an identifier";
|
return "an identifier";
|
||||||
case NodeType::CustomOperator:
|
case NodeKind::CustomOperator:
|
||||||
return "an operator";
|
return "an operator";
|
||||||
case NodeType::IntegerLiteral:
|
case NodeKind::IntegerLiteral:
|
||||||
return "an integer literal";
|
return "an integer literal";
|
||||||
case NodeType::EndOfFile:
|
case NodeKind::EndOfFile:
|
||||||
return "end-of-file";
|
return "end-of-file";
|
||||||
case NodeType::BlockStart:
|
case NodeKind::BlockStart:
|
||||||
return "the start of a new indented block";
|
return "the start of a new indented block";
|
||||||
case NodeType::BlockEnd:
|
case NodeKind::BlockEnd:
|
||||||
return "the end of the current indented block";
|
return "the end of the current indented block";
|
||||||
case NodeType::LineFoldEnd:
|
case NodeKind::LineFoldEnd:
|
||||||
return "the end of the current line-fold";
|
return "the end of the current line-fold";
|
||||||
case NodeType::LParen:
|
case NodeKind::LParen:
|
||||||
return "'('";
|
return "'('";
|
||||||
case NodeType::RParen:
|
case NodeKind::RParen:
|
||||||
return "')'";
|
return "')'";
|
||||||
case NodeType::LBrace:
|
case NodeKind::LBrace:
|
||||||
return "'['";
|
return "'['";
|
||||||
case NodeType::RBrace:
|
case NodeKind::RBrace:
|
||||||
return "']'";
|
return "']'";
|
||||||
case NodeType::LBracket:
|
case NodeKind::LBracket:
|
||||||
return "'{'";
|
return "'{'";
|
||||||
case NodeType::RBracket:
|
case NodeKind::RBracket:
|
||||||
return "'}'";
|
return "'}'";
|
||||||
case NodeType::Colon:
|
case NodeKind::Colon:
|
||||||
return "':'";
|
return "':'";
|
||||||
case NodeType::Equals:
|
case NodeKind::Comma:
|
||||||
|
return "','";
|
||||||
|
case NodeKind::Equals:
|
||||||
return "'='";
|
return "'='";
|
||||||
case NodeType::StringLiteral:
|
case NodeKind::StringLiteral:
|
||||||
return "a string literal";
|
return "a string literal";
|
||||||
case NodeType::Dot:
|
case NodeKind::Dot:
|
||||||
return "'.'";
|
return "'.'";
|
||||||
case NodeType::PubKeyword:
|
case NodeKind::DotDot:
|
||||||
|
return "'..'";
|
||||||
|
case NodeKind::Tilde:
|
||||||
|
return "'~'";
|
||||||
|
case NodeKind::RArrow:
|
||||||
|
return "'->'";
|
||||||
|
case NodeKind::RArrowAlt:
|
||||||
|
return "'=>'";
|
||||||
|
case NodeKind::PubKeyword:
|
||||||
return "'pub'";
|
return "'pub'";
|
||||||
case NodeType::LetKeyword:
|
case NodeKind::LetKeyword:
|
||||||
return "'let'";
|
return "'let'";
|
||||||
case NodeType::MutKeyword:
|
case NodeKind::MutKeyword:
|
||||||
return "'mut'";
|
return "'mut'";
|
||||||
case NodeType::ReturnKeyword:
|
case NodeKind::ReturnKeyword:
|
||||||
return "'return'";
|
return "'return'";
|
||||||
case NodeType::TypeKeyword:
|
case NodeKind::TypeKeyword:
|
||||||
return "'type'";
|
return "'type'";
|
||||||
default:
|
default:
|
||||||
ZEN_UNREACHABLE
|
ZEN_UNREACHABLE
|
||||||
|
@ -97,10 +107,14 @@ namespace bolt {
|
||||||
|
|
||||||
std::string describe(const Type* Ty) {
|
std::string describe(const Type* Ty) {
|
||||||
switch (Ty->getKind()) {
|
switch (Ty->getKind()) {
|
||||||
case TypeKind::Any:
|
|
||||||
return "any";
|
|
||||||
case TypeKind::Var:
|
case TypeKind::Var:
|
||||||
return "a" + std::to_string(static_cast<const TVar*>(Ty)->Id);
|
{
|
||||||
|
auto TV = static_cast<const TVar*>(Ty);
|
||||||
|
if (TV->getVarKind() == VarKind::Rigid) {
|
||||||
|
return static_cast<const TVarRigid*>(TV)->Name;
|
||||||
|
}
|
||||||
|
return "a" + std::to_string(TV->Id);
|
||||||
|
}
|
||||||
case TypeKind::Arrow:
|
case TypeKind::Arrow:
|
||||||
{
|
{
|
||||||
auto Y = static_cast<const TArrow*>(Ty);
|
auto Y = static_cast<const TArrow*>(Ty);
|
||||||
|
@ -342,7 +356,7 @@ namespace bolt {
|
||||||
writeExcerpt(E.Initiator->getSourceFile()->getTextFile(), Range, Range, Color::Red);
|
writeExcerpt(E.Initiator->getSourceFile()->getTextFile(), Range, Range, Color::Red);
|
||||||
Out << "\n";
|
Out << "\n";
|
||||||
}
|
}
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case DiagnosticKind::UnexpectedToken:
|
case DiagnosticKind::UnexpectedToken:
|
||||||
|
@ -366,7 +380,7 @@ namespace bolt {
|
||||||
default:
|
default:
|
||||||
auto Iter = E.Expected.begin();
|
auto Iter = E.Expected.begin();
|
||||||
Out << describe(*Iter++);
|
Out << describe(*Iter++);
|
||||||
NodeType Prev = *Iter++;
|
NodeKind Prev = *Iter++;
|
||||||
while (Iter != E.Expected.end()) {
|
while (Iter != E.Expected.end()) {
|
||||||
Out << ", " << describe(Prev);
|
Out << ", " << describe(Prev);
|
||||||
Prev = *Iter++;
|
Prev = *Iter++;
|
||||||
|
@ -377,7 +391,7 @@ namespace bolt {
|
||||||
Out << " but instead got '" << E.Actual->getText() << "'\n\n";
|
Out << " but instead got '" << E.Actual->getText() << "'\n\n";
|
||||||
writeExcerpt(E.File, E.Actual->getRange(), E.Actual->getRange(), Color::Red);
|
writeExcerpt(E.File, E.Actual->getRange(), E.Actual->getRange(), Color::Red);
|
||||||
Out << "\n";
|
Out << "\n";
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case DiagnosticKind::UnexpectedString:
|
case DiagnosticKind::UnexpectedString:
|
||||||
|
@ -405,7 +419,7 @@ namespace bolt {
|
||||||
TextRange Range { E.Location, E.Location + E.Actual };
|
TextRange Range { E.Location, E.Location + E.Actual };
|
||||||
writeExcerpt(E.File, Range, Range, Color::Red);
|
writeExcerpt(E.File, Range, Range, Color::Red);
|
||||||
Out << "\n";
|
Out << "\n";
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case DiagnosticKind::UnificationError:
|
case DiagnosticKind::UnificationError:
|
||||||
|
@ -423,11 +437,56 @@ namespace bolt {
|
||||||
writeExcerpt(E.Source->getSourceFile()->getTextFile(), Range, Range, Color::Red);
|
writeExcerpt(E.Source->getSourceFile()->getTextFile(), Range, Range, Color::Red);
|
||||||
Out << "\n";
|
Out << "\n";
|
||||||
}
|
}
|
||||||
break;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DiagnosticKind::TypeclassMissing:
|
||||||
|
{
|
||||||
|
auto E = static_cast<const TypeclassMissingDiagnostic&>(D);
|
||||||
|
setForegroundColor(Color::Red);
|
||||||
|
setBold(true);
|
||||||
|
Out << "error: ";
|
||||||
|
resetStyles();
|
||||||
|
Out << "the type class " << ANSI_FG_YELLOW << E.Sig.Id;
|
||||||
|
for (auto TV: E.Sig.Params) {
|
||||||
|
Out << " " << describe(TV);
|
||||||
|
}
|
||||||
|
Out << ANSI_RESET << " is missing from the declaration's type signature\n\n";
|
||||||
|
auto Range = E.Decl->getRange();
|
||||||
|
writeExcerpt(E.Decl->getSourceFile()->getTextFile(), Range, Range, Color::Yellow);
|
||||||
|
Out << "\n\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DiagnosticKind::InstanceNotFound:
|
||||||
|
{
|
||||||
|
auto E = static_cast<const InstanceNotFoundDiagnostic&>(D);
|
||||||
|
setForegroundColor(Color::Red);
|
||||||
|
setBold(true);
|
||||||
|
Out << "error: ";
|
||||||
|
resetStyles();
|
||||||
|
Out << "a type class instance " << ANSI_FG_YELLOW << E.TypeclassName << " " << describe(E.Ty) << ANSI_RESET " was not found.\n\n";
|
||||||
|
auto Range = E.Source->getRange();
|
||||||
|
//std::cerr << Range.Start.Line << ":" << Range.Start.Column << "-" << Range.End.Line << ":" << Range.End.Column << "\n";
|
||||||
|
writeExcerpt(E.Source->getSourceFile()->getTextFile(), Range, Range, Color::Red);
|
||||||
|
Out << "\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DiagnosticKind::ClassNotFound:
|
||||||
|
{
|
||||||
|
auto E = static_cast<const ClassNotFoundDiagnostic&>(D);
|
||||||
|
setForegroundColor(Color::Red);
|
||||||
|
setBold(true);
|
||||||
|
Out << "error: ";
|
||||||
|
resetStyles();
|
||||||
|
Out << "the type class " << ANSI_FG_YELLOW << E.Name << ANSI_RESET " was not found.\n\n";
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ZEN_UNREACHABLE
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,9 @@ namespace bolt {
|
||||||
|
|
||||||
void IPRGraph::populate(Node* X, Node* Decl) {
|
void IPRGraph::populate(Node* X, Node* Decl) {
|
||||||
|
|
||||||
switch (X->Type) {
|
switch (X->getKind()) {
|
||||||
|
|
||||||
case NodeType::SourceFile:
|
case NodeKind::SourceFile:
|
||||||
{
|
{
|
||||||
auto Y = static_cast<SourceFile*>(X);
|
auto Y = static_cast<SourceFile*>(X);
|
||||||
for (auto Element: Y->Elements) {
|
for (auto Element: Y->Elements) {
|
||||||
|
@ -22,7 +22,7 @@ namespace bolt {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case NodeType::IfStatement:
|
case NodeKind::IfStatement:
|
||||||
{
|
{
|
||||||
auto Y = static_cast<IfStatement*>(X);
|
auto Y = static_cast<IfStatement*>(X);
|
||||||
for (auto Part: Y->Parts) {
|
for (auto Part: Y->Parts) {
|
||||||
|
@ -33,12 +33,12 @@ namespace bolt {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case NodeType::LetDeclaration:
|
case NodeKind::LetDeclaration:
|
||||||
{
|
{
|
||||||
auto Y = static_cast<LetDeclaration*>(X);
|
auto Y = static_cast<LetDeclaration*>(X);
|
||||||
if (Y->Body) {
|
if (Y->Body) {
|
||||||
switch (Y->Body->Type) {
|
switch (Y->Body->getKind()) {
|
||||||
case NodeType::LetBlockBody:
|
case NodeKind::LetBlockBody:
|
||||||
{
|
{
|
||||||
auto Z = static_cast<LetBlockBody*>(Y->Body);
|
auto Z = static_cast<LetBlockBody*>(Y->Body);
|
||||||
for (auto Element: Z->Elements) {
|
for (auto Element: Z->Elements) {
|
||||||
|
@ -46,7 +46,7 @@ namespace bolt {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NodeType::LetExprBody:
|
case NodeKind::LetExprBody:
|
||||||
{
|
{
|
||||||
auto Z = static_cast<LetExprBody*>(Y->Body);
|
auto Z = static_cast<LetExprBody*>(Y->Body);
|
||||||
populate(Z->Expression, Y);
|
populate(Z->Expression, Y);
|
||||||
|
@ -59,10 +59,10 @@ namespace bolt {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case NodeType::ConstantExpression:
|
case NodeKind::ConstantExpression:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NodeType::CallExpression:
|
case NodeKind::CallExpression:
|
||||||
{
|
{
|
||||||
auto Y = static_cast<CallExpression*>(X);
|
auto Y = static_cast<CallExpression*>(X);
|
||||||
populate(Y->Function, Decl);
|
populate(Y->Function, Decl);
|
||||||
|
@ -72,7 +72,7 @@ namespace bolt {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case NodeType::ReferenceExpression:
|
case NodeKind::ReferenceExpression:
|
||||||
{
|
{
|
||||||
auto Y = static_cast<ReferenceExpression*>(X);
|
auto Y = static_cast<ReferenceExpression*>(X);
|
||||||
auto Def = Y->getScope()->lookup(Y->Name->getSymbolPath());
|
auto Def = Y->getScope()->lookup(Y->Name->getSymbolPath());
|
||||||
|
|
345
src/Parser.cc
345
src/Parser.cc
|
@ -1,10 +1,13 @@
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "llvm/Support/Casting.h"
|
||||||
|
|
||||||
#include "bolt/CST.hpp"
|
#include "bolt/CST.hpp"
|
||||||
#include "bolt/Scanner.hpp"
|
#include "bolt/Scanner.hpp"
|
||||||
#include "bolt/Parser.hpp"
|
#include "bolt/Parser.hpp"
|
||||||
#include "bolt/Diagnostics.hpp"
|
#include "bolt/Diagnostics.hpp"
|
||||||
#include <exception>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace bolt {
|
namespace bolt {
|
||||||
|
|
||||||
|
@ -57,9 +60,9 @@ namespace bolt {
|
||||||
std::size_t I = 0;
|
std::size_t I = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
auto T0 = Tokens.peek(I++);
|
auto T0 = Tokens.peek(I++);
|
||||||
switch (T0->Type) {
|
switch (T0->getKind()) {
|
||||||
case NodeType::PubKeyword:
|
case NodeKind::PubKeyword:
|
||||||
case NodeType::MutKeyword:
|
case NodeKind::MutKeyword:
|
||||||
continue;
|
continue;
|
||||||
default:
|
default:
|
||||||
return T0;
|
return T0;
|
||||||
|
@ -70,71 +73,141 @@ namespace bolt {
|
||||||
#define BOLT_EXPECT_TOKEN(name) \
|
#define BOLT_EXPECT_TOKEN(name) \
|
||||||
{ \
|
{ \
|
||||||
auto __Token = Tokens.get(); \
|
auto __Token = Tokens.get(); \
|
||||||
if (__Token->Type != NodeType::name) { \
|
if (!llvm::isa<name>(__Token)) { \
|
||||||
throw UnexpectedTokenDiagnostic(File, __Token, std::vector<NodeType> { NodeType::name }); \
|
throw UnexpectedTokenDiagnostic(File, __Token, std::vector<NodeKind> { NodeKind::name }); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
Token* Parser::expectToken(NodeType Type) {
|
Token* Parser::expectToken(NodeKind Kind) {
|
||||||
auto T = Tokens.get();
|
auto T = Tokens.get();
|
||||||
if (T->Type != Type) {
|
if (T->getKind() != Kind) {
|
||||||
throw UnexpectedTokenDiagnostic(File, T, std::vector<NodeType> { Type }); \
|
throw UnexpectedTokenDiagnostic(File, T, std::vector<NodeKind> { Kind }); \
|
||||||
}
|
}
|
||||||
return T;
|
return T;
|
||||||
}
|
}
|
||||||
|
|
||||||
Pattern* Parser::parsePattern() {
|
Pattern* Parser::parsePattern() {
|
||||||
auto T0 = Tokens.peek();
|
auto T0 = Tokens.peek();
|
||||||
switch (T0->Type) {
|
switch (T0->getKind()) {
|
||||||
case NodeType::Identifier:
|
case NodeKind::Identifier:
|
||||||
Tokens.get();
|
Tokens.get();
|
||||||
return new BindPattern(static_cast<Identifier*>(T0));
|
return new BindPattern(static_cast<Identifier*>(T0));
|
||||||
default:
|
default:
|
||||||
throw UnexpectedTokenDiagnostic(File, T0, std::vector { NodeType::Identifier });
|
throw UnexpectedTokenDiagnostic(File, T0, std::vector { NodeKind::Identifier });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QualifiedName* Parser::parseQualifiedName() {
|
QualifiedName* Parser::parseQualifiedName() {
|
||||||
std::vector<Identifier*> ModulePath;
|
std::vector<Identifier*> ModulePath;
|
||||||
auto Name = expectToken(NodeType::Identifier);
|
auto Name = expectToken(NodeKind::Identifier);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
auto T1 = Tokens.peek();
|
auto T1 = Tokens.peek();
|
||||||
if (T1->Type != NodeType::Dot) {
|
if (T1->getKind() != NodeKind::Dot) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Tokens.get();
|
Tokens.get();
|
||||||
ModulePath.push_back(static_cast<Identifier*>(Name));
|
ModulePath.push_back(static_cast<Identifier*>(Name));
|
||||||
Name = Tokens.get();
|
Name = Tokens.get();
|
||||||
if (Name->Type != NodeType::Identifier) {
|
if (Name->getKind() != NodeKind::Identifier) {
|
||||||
throw UnexpectedTokenDiagnostic(File, Name, std::vector { NodeType::Identifier });
|
throw UnexpectedTokenDiagnostic(File, Name, std::vector { NodeKind::Identifier });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new QualifiedName(ModulePath, static_cast<Identifier*>(Name));
|
return new QualifiedName(ModulePath, static_cast<Identifier*>(Name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TypeExpression* Parser::parseTypeExpression() {
|
||||||
|
return parseQualifiedTypeExpression();
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeExpression* Parser::parseQualifiedTypeExpression() {
|
||||||
|
bool HasConstraints = false;
|
||||||
|
auto T0 = Tokens.peek();
|
||||||
|
if (llvm::isa<LParen>(T0)) {
|
||||||
|
std::size_t I = 1;
|
||||||
|
for (;;) {
|
||||||
|
auto T0 = Tokens.peek(I++);
|
||||||
|
switch (T0->getKind()) {
|
||||||
|
case NodeKind::RArrowAlt:
|
||||||
|
HasConstraints = true;
|
||||||
|
goto after_scan;
|
||||||
|
case NodeKind::Equals:
|
||||||
|
case NodeKind::BlockStart:
|
||||||
|
case NodeKind::LineFoldEnd:
|
||||||
|
case NodeKind::EndOfFile:
|
||||||
|
goto after_scan;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
after_scan:
|
||||||
|
if (!HasConstraints) {
|
||||||
|
return parseArrowTypeExpression();
|
||||||
|
}
|
||||||
|
Tokens.get();
|
||||||
|
LParen* LParen = static_cast<class LParen*>(T0);
|
||||||
|
std::vector<std::tuple<ConstraintExpression*, Comma*>> Constraints;
|
||||||
|
RParen* RParen;
|
||||||
|
RArrowAlt* RArrowAlt;
|
||||||
|
for (;;) {
|
||||||
|
ConstraintExpression* C;
|
||||||
|
auto T0 = Tokens.peek();
|
||||||
|
switch (T0->getKind()) {
|
||||||
|
case NodeKind::RParen:
|
||||||
|
Tokens.get();
|
||||||
|
RParen = static_cast<class RParen*>(T0);
|
||||||
|
RArrowAlt = expectToken<class RArrowAlt>();
|
||||||
|
goto after_constraints;
|
||||||
|
default:
|
||||||
|
C = parseConstraintExpression();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Comma* Comma = nullptr;
|
||||||
|
auto T1 = Tokens.get();
|
||||||
|
switch (T1->getKind()) {
|
||||||
|
case NodeKind::Comma:
|
||||||
|
Constraints.push_back(std::make_tuple(C, static_cast<class Comma*>(T1)));
|
||||||
|
continue;
|
||||||
|
case NodeKind::RParen:
|
||||||
|
RArrowAlt = static_cast<class RArrowAlt*>(T1);
|
||||||
|
Constraints.push_back(std::make_tuple(C, nullptr));
|
||||||
|
RArrowAlt = expectToken<class RArrowAlt>();
|
||||||
|
goto after_constraints;
|
||||||
|
default:
|
||||||
|
throw UnexpectedTokenDiagnostic(File, T1, std::vector { NodeKind::Comma, NodeKind::RArrowAlt });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
after_constraints:
|
||||||
|
auto TE = parseArrowTypeExpression();
|
||||||
|
return new QualifiedTypeExpression(Constraints, RArrowAlt, TE);
|
||||||
|
}
|
||||||
|
|
||||||
TypeExpression* Parser::parsePrimitiveTypeExpression() {
|
TypeExpression* Parser::parsePrimitiveTypeExpression() {
|
||||||
auto T0 = Tokens.peek();
|
auto T0 = Tokens.peek();
|
||||||
switch (T0->Type) {
|
switch (T0->getKind()) {
|
||||||
case NodeType::Identifier:
|
case NodeKind::Identifier:
|
||||||
|
if (static_cast<Identifier*>(T0)->isTypeVar()) {
|
||||||
|
return parseVarTypeExpression();
|
||||||
|
}
|
||||||
return new ReferenceTypeExpression(parseQualifiedName());
|
return new ReferenceTypeExpression(parseQualifiedName());
|
||||||
default:
|
default:
|
||||||
throw UnexpectedTokenDiagnostic(File, T0, std::vector { NodeType::Identifier });
|
throw UnexpectedTokenDiagnostic(File, T0, std::vector { NodeKind::Identifier });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeExpression* Parser::parseTypeExpression() {
|
TypeExpression* Parser::parseArrowTypeExpression() {
|
||||||
auto RetType = parsePrimitiveTypeExpression();
|
auto RetType = parsePrimitiveTypeExpression();
|
||||||
std::vector<TypeExpression*> ParamTypes;
|
std::vector<TypeExpression*> ParamTypes;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
auto T1 = Tokens.peek();
|
auto T1 = Tokens.peek();
|
||||||
if (T1->Type != NodeType::RArrow) {
|
if (T1->getKind() != NodeKind::RArrow) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Tokens.get();
|
Tokens.get();
|
||||||
ParamTypes.push_back(RetType);
|
ParamTypes.push_back(RetType);
|
||||||
RetType = parsePrimitiveTypeExpression();
|
RetType = parsePrimitiveTypeExpression();
|
||||||
}
|
}
|
||||||
if (ParamTypes.size()) {
|
if (!ParamTypes.empty()) {
|
||||||
return new ArrowTypeExpression(ParamTypes, RetType);
|
return new ArrowTypeExpression(ParamTypes, RetType);
|
||||||
}
|
}
|
||||||
return RetType;
|
return RetType;
|
||||||
|
@ -142,25 +215,25 @@ namespace bolt {
|
||||||
|
|
||||||
Expression* Parser::parsePrimitiveExpression() {
|
Expression* Parser::parsePrimitiveExpression() {
|
||||||
auto T0 = Tokens.peek();
|
auto T0 = Tokens.peek();
|
||||||
switch (T0->Type) {
|
switch (T0->getKind()) {
|
||||||
case NodeType::Identifier:
|
case NodeKind::Identifier:
|
||||||
{
|
{
|
||||||
auto Name = parseQualifiedName();
|
auto Name = parseQualifiedName();
|
||||||
return new ReferenceExpression(Name);
|
return new ReferenceExpression(Name);
|
||||||
}
|
}
|
||||||
case NodeType::LParen:
|
case NodeKind::LParen:
|
||||||
{
|
{
|
||||||
Tokens.get();
|
Tokens.get();
|
||||||
auto E = parseExpression();
|
auto E = parseExpression();
|
||||||
auto T2 = static_cast<RParen*>(expectToken(NodeType::RParen));
|
auto T2 = static_cast<RParen*>(expectToken(NodeKind::RParen));
|
||||||
return new NestedExpression(static_cast<LParen*>(T0), E, T2);
|
return new NestedExpression(static_cast<LParen*>(T0), E, T2);
|
||||||
}
|
}
|
||||||
case NodeType::IntegerLiteral:
|
case NodeKind::IntegerLiteral:
|
||||||
case NodeType::StringLiteral:
|
case NodeKind::StringLiteral:
|
||||||
Tokens.get();
|
Tokens.get();
|
||||||
return new ConstantExpression(T0);
|
return new ConstantExpression(T0);
|
||||||
default:
|
default:
|
||||||
throw UnexpectedTokenDiagnostic(File, T0, std::vector { NodeType::Identifier, NodeType::IntegerLiteral, NodeType::StringLiteral });
|
throw UnexpectedTokenDiagnostic(File, T0, std::vector { NodeKind::Identifier, NodeKind::IntegerLiteral, NodeKind::StringLiteral });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +242,7 @@ namespace bolt {
|
||||||
std::vector<Expression*> Args;
|
std::vector<Expression*> Args;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
auto T1 = Tokens.peek();
|
auto T1 = Tokens.peek();
|
||||||
if (T1->Type == NodeType::LineFoldEnd || T1->Type == NodeType::RParen || T1->Type == NodeType::BlockStart || ExprOperators.isInfix(T1)) {
|
if (T1->getKind() == NodeKind::LineFoldEnd || T1->getKind() == NodeKind::RParen || T1->getKind() == NodeKind::BlockStart || ExprOperators.isInfix(T1)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Args.push_back(parsePrimitiveExpression());
|
Args.push_back(parsePrimitiveExpression());
|
||||||
|
@ -192,7 +265,7 @@ namespace bolt {
|
||||||
}
|
}
|
||||||
auto E = parseCallExpression();
|
auto E = parseCallExpression();
|
||||||
for (auto Iter = Prefix.rbegin(); Iter != Prefix.rend(); Iter++) {
|
for (auto Iter = Prefix.rbegin(); Iter != Prefix.rend(); Iter++) {
|
||||||
E = new UnaryExpression(*Iter, E);
|
E = new PrefixExpression(*Iter, E);
|
||||||
}
|
}
|
||||||
return E;
|
return E;
|
||||||
}
|
}
|
||||||
|
@ -230,10 +303,10 @@ namespace bolt {
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnStatement* Parser::parseReturnStatement() {
|
ReturnStatement* Parser::parseReturnStatement() {
|
||||||
auto T0 = static_cast<ReturnKeyword*>(expectToken(NodeType::ReturnKeyword));
|
auto T0 = static_cast<ReturnKeyword*>(expectToken(NodeKind::ReturnKeyword));
|
||||||
Expression* Expression = nullptr;
|
Expression* Expression = nullptr;
|
||||||
auto T1 = Tokens.peek();
|
auto T1 = Tokens.peek();
|
||||||
if (T1->Type != NodeType::LineFoldEnd) {
|
if (T1->getKind() != NodeKind::LineFoldEnd) {
|
||||||
Expression = parseExpression();
|
Expression = parseExpression();
|
||||||
}
|
}
|
||||||
BOLT_EXPECT_TOKEN(LineFoldEnd);
|
BOLT_EXPECT_TOKEN(LineFoldEnd);
|
||||||
|
@ -242,13 +315,13 @@ namespace bolt {
|
||||||
|
|
||||||
IfStatement* Parser::parseIfStatement() {
|
IfStatement* Parser::parseIfStatement() {
|
||||||
std::vector<IfStatementPart*> Parts;
|
std::vector<IfStatementPart*> Parts;
|
||||||
auto T0 = expectToken(NodeType::IfKeyword);
|
auto T0 = expectToken(NodeKind::IfKeyword);
|
||||||
auto Test = parseExpression();
|
auto Test = parseExpression();
|
||||||
auto T1 = static_cast<BlockStart*>(expectToken(NodeType::BlockStart));
|
auto T1 = static_cast<BlockStart*>(expectToken(NodeKind::BlockStart));
|
||||||
std::vector<Node*> Then;
|
std::vector<Node*> Then;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
auto T2 = Tokens.peek();
|
auto T2 = Tokens.peek();
|
||||||
if (T2->Type == NodeType::BlockEnd) {
|
if (T2->getKind() == NodeKind::BlockEnd) {
|
||||||
Tokens.get();
|
Tokens.get();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -257,13 +330,13 @@ namespace bolt {
|
||||||
Parts.push_back(new IfStatementPart(T0, Test, T1, Then));
|
Parts.push_back(new IfStatementPart(T0, Test, T1, Then));
|
||||||
BOLT_EXPECT_TOKEN(LineFoldEnd)
|
BOLT_EXPECT_TOKEN(LineFoldEnd)
|
||||||
auto T3 = Tokens.peek();
|
auto T3 = Tokens.peek();
|
||||||
if (T3->Type == NodeType::ElseKeyword) {
|
if (T3->getKind() == NodeKind::ElseKeyword) {
|
||||||
Tokens.get();
|
Tokens.get();
|
||||||
auto T4 = static_cast<BlockStart*>(expectToken(NodeType::BlockStart));
|
auto T4 = static_cast<BlockStart*>(expectToken(NodeKind::BlockStart));
|
||||||
std::vector<Node*> Else;
|
std::vector<Node*> Else;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
auto T5 = Tokens.peek();
|
auto T5 = Tokens.peek();
|
||||||
if (T5->Type == NodeType::BlockEnd) {
|
if (T5->getKind() == NodeKind::BlockEnd) {
|
||||||
Tokens.get();
|
Tokens.get();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -281,41 +354,41 @@ namespace bolt {
|
||||||
LetKeyword* Let;
|
LetKeyword* Let;
|
||||||
MutKeyword* Mut = nullptr;
|
MutKeyword* Mut = nullptr;
|
||||||
auto T0 = Tokens.get();
|
auto T0 = Tokens.get();
|
||||||
if (T0->Type == NodeType::PubKeyword) {
|
if (T0->getKind() == NodeKind::PubKeyword) {
|
||||||
Pub = static_cast<PubKeyword*>(T0);
|
Pub = static_cast<PubKeyword*>(T0);
|
||||||
T0 = Tokens.get();
|
T0 = Tokens.get();
|
||||||
}
|
}
|
||||||
if (T0->Type != NodeType::LetKeyword) {
|
if (T0->getKind() != NodeKind::LetKeyword) {
|
||||||
throw UnexpectedTokenDiagnostic(File, T0, std::vector { NodeType::LetKeyword });
|
throw UnexpectedTokenDiagnostic(File, T0, std::vector { NodeKind::LetKeyword });
|
||||||
}
|
}
|
||||||
Let = static_cast<LetKeyword*>(T0);
|
Let = static_cast<LetKeyword*>(T0);
|
||||||
auto T1 = Tokens.peek();
|
auto T1 = Tokens.peek();
|
||||||
if (T1->Type == NodeType::MutKeyword) {
|
if (T1->getKind() == NodeKind::MutKeyword) {
|
||||||
Mut = static_cast<MutKeyword*>(T1);
|
Mut = static_cast<MutKeyword*>(T1);
|
||||||
Tokens.get();
|
Tokens.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Patt = parsePattern();
|
auto Patt = parsePattern();
|
||||||
|
|
||||||
std::vector<Param*> Params;
|
std::vector<Parameter*> Params;
|
||||||
Token* T2;
|
Token* T2;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
T2 = Tokens.peek();
|
T2 = Tokens.peek();
|
||||||
switch (T2->Type) {
|
switch (T2->getKind()) {
|
||||||
case NodeType::LineFoldEnd:
|
case NodeKind::LineFoldEnd:
|
||||||
case NodeType::BlockStart:
|
case NodeKind::BlockStart:
|
||||||
case NodeType::Equals:
|
case NodeKind::Equals:
|
||||||
case NodeType::Colon:
|
case NodeKind::Colon:
|
||||||
goto after_params;
|
goto after_params;
|
||||||
default:
|
default:
|
||||||
Params.push_back(new Param(parsePattern(), nullptr));
|
Params.push_back(new Parameter(parsePattern(), nullptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
after_params:
|
after_params:
|
||||||
|
|
||||||
TypeAssert* TA = nullptr;
|
TypeAssert* TA = nullptr;
|
||||||
if (T2->Type == NodeType::Colon) {
|
if (T2->getKind() == NodeKind::Colon) {
|
||||||
Tokens.get();
|
Tokens.get();
|
||||||
auto TE = parseTypeExpression();
|
auto TE = parseTypeExpression();
|
||||||
TA = new TypeAssert(static_cast<Colon*>(T2), TE);
|
TA = new TypeAssert(static_cast<Colon*>(T2), TE);
|
||||||
|
@ -323,14 +396,14 @@ after_params:
|
||||||
}
|
}
|
||||||
|
|
||||||
LetBody* Body;
|
LetBody* Body;
|
||||||
switch (T2->Type) {
|
switch (T2->getKind()) {
|
||||||
case NodeType::BlockStart:
|
case NodeKind::BlockStart:
|
||||||
{
|
{
|
||||||
Tokens.get();
|
Tokens.get();
|
||||||
std::vector<Node*> Elements;
|
std::vector<Node*> Elements;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
auto T3 = Tokens.peek();
|
auto T3 = Tokens.peek();
|
||||||
if (T3->Type == NodeType::BlockEnd) {
|
if (T3->getKind() == NodeKind::BlockEnd) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Elements.push_back(parseLetBodyElement());
|
Elements.push_back(parseLetBodyElement());
|
||||||
|
@ -339,20 +412,20 @@ after_params:
|
||||||
Body = new LetBlockBody(static_cast<BlockStart*>(T2), Elements);
|
Body = new LetBlockBody(static_cast<BlockStart*>(T2), Elements);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NodeType::Equals:
|
case NodeKind::Equals:
|
||||||
Tokens.get();
|
Tokens.get();
|
||||||
Body = new LetExprBody(static_cast<Equals*>(T2), parseExpression());
|
Body = new LetExprBody(static_cast<Equals*>(T2), parseExpression());
|
||||||
break;
|
break;
|
||||||
case NodeType::LineFoldEnd:
|
case NodeKind::LineFoldEnd:
|
||||||
Body = nullptr;
|
Body = nullptr;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
std::vector<NodeType> Expected { NodeType::BlockStart, NodeType::LineFoldEnd, NodeType::Equals };
|
std::vector<NodeKind> Expected { NodeKind::BlockStart, NodeKind::LineFoldEnd, NodeKind::Equals };
|
||||||
if (TA == nullptr) {
|
if (TA == nullptr) {
|
||||||
// First tokens of TypeAssert
|
// First tokens of TypeAssert
|
||||||
Expected.push_back(NodeType::Colon);
|
Expected.push_back(NodeKind::Colon);
|
||||||
// First tokens of Pattern
|
// First tokens of Pattern
|
||||||
Expected.push_back(NodeType::Identifier);
|
Expected.push_back(NodeKind::Identifier);
|
||||||
}
|
}
|
||||||
throw UnexpectedTokenDiagnostic(File, T2, Expected);
|
throw UnexpectedTokenDiagnostic(File, T2, Expected);
|
||||||
}
|
}
|
||||||
|
@ -372,25 +445,161 @@ after_params:
|
||||||
|
|
||||||
Node* Parser::parseLetBodyElement() {
|
Node* Parser::parseLetBodyElement() {
|
||||||
auto T0 = peekFirstTokenAfterModifiers();
|
auto T0 = peekFirstTokenAfterModifiers();
|
||||||
switch (T0->Type) {
|
switch (T0->getKind()) {
|
||||||
case NodeType::LetKeyword:
|
case NodeKind::LetKeyword:
|
||||||
return parseLetDeclaration();
|
return parseLetDeclaration();
|
||||||
case NodeType::ReturnKeyword:
|
case NodeKind::ReturnKeyword:
|
||||||
return parseReturnStatement();
|
return parseReturnStatement();
|
||||||
case NodeType::IfKeyword:
|
case NodeKind::IfKeyword:
|
||||||
return parseIfStatement();
|
return parseIfStatement();
|
||||||
default:
|
default:
|
||||||
return parseExpressionStatement();
|
return parseExpressionStatement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConstraintExpression* Parser::parseConstraintExpression() {
|
||||||
|
bool HasTilde = false;
|
||||||
|
for (std::size_t I = 0; ; I++) {
|
||||||
|
auto Tok = Tokens.peek(I);
|
||||||
|
switch (Tok->getKind()) {
|
||||||
|
case NodeKind::Tilde:
|
||||||
|
HasTilde = true;
|
||||||
|
goto after_seek;
|
||||||
|
case NodeKind::RParen:
|
||||||
|
case NodeKind::Comma:
|
||||||
|
case NodeKind::RArrowAlt:
|
||||||
|
case NodeKind::EndOfFile:
|
||||||
|
goto after_seek;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
after_seek:
|
||||||
|
if (HasTilde) {
|
||||||
|
auto Left = parseArrowTypeExpression();
|
||||||
|
auto Tilde = expectToken<class Tilde>();
|
||||||
|
auto Right = parseArrowTypeExpression();
|
||||||
|
return new EqualityConstraintExpression { Left, Tilde, Right };
|
||||||
|
}
|
||||||
|
auto Name = expectToken<Identifier>();
|
||||||
|
std::vector<VarTypeExpression*> TEs;
|
||||||
|
for (;;) {
|
||||||
|
auto T1 = Tokens.peek();
|
||||||
|
switch (T1->getKind()) {
|
||||||
|
case NodeKind::RParen:
|
||||||
|
case NodeKind::RArrowAlt:
|
||||||
|
case NodeKind::Comma:
|
||||||
|
goto after_vars;
|
||||||
|
case NodeKind::Identifier:
|
||||||
|
Tokens.get();
|
||||||
|
TEs.push_back(new VarTypeExpression { static_cast<Identifier*>(T1) });
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw UnexpectedTokenDiagnostic(File, T1, std::vector { NodeKind::RParen, NodeKind::RArrowAlt, NodeKind::Comma, NodeKind::Identifier });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
after_vars:
|
||||||
|
return new TypeclassConstraintExpression { Name, TEs };
|
||||||
|
}
|
||||||
|
|
||||||
|
VarTypeExpression* Parser::parseVarTypeExpression() {
|
||||||
|
auto Name = expectToken<Identifier>();
|
||||||
|
// TODO reject constructor symbols (starting with a capital letter)
|
||||||
|
return new VarTypeExpression { Name };
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceDeclaration* Parser::parseInstanceDeclaration() {
|
||||||
|
auto InstanceKeyword = expectToken<class InstanceKeyword>();
|
||||||
|
auto Name = expectToken<Identifier>();
|
||||||
|
std::vector<TypeExpression*> TypeExps;
|
||||||
|
for (;;) {
|
||||||
|
auto T1 = Tokens.peek();
|
||||||
|
if (T1->is<BlockStart>()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
TypeExps.push_back(parseTypeExpression());
|
||||||
|
}
|
||||||
|
auto BlockStart = expectToken<class BlockStart>();
|
||||||
|
std::vector<Node*> Elements;
|
||||||
|
for (;;) {
|
||||||
|
auto T2 = Tokens.peek();
|
||||||
|
if (T2->is<BlockEnd>()) {
|
||||||
|
Tokens.get();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Elements.push_back(parseClassElement());
|
||||||
|
}
|
||||||
|
expectToken(NodeKind::LineFoldEnd);
|
||||||
|
return new InstanceDeclaration(
|
||||||
|
InstanceKeyword,
|
||||||
|
Name,
|
||||||
|
TypeExps,
|
||||||
|
BlockStart,
|
||||||
|
Elements
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassDeclaration* Parser::parseClassDeclaration() {
|
||||||
|
PubKeyword* PubKeyword = nullptr;
|
||||||
|
auto T0 = Tokens.peek();
|
||||||
|
if (T0->getKind() == NodeKind::PubKeyword) {
|
||||||
|
Tokens.get();
|
||||||
|
PubKeyword = static_cast<class PubKeyword*>(T0);
|
||||||
|
}
|
||||||
|
auto ClassKeyword = expectToken<class ClassKeyword>();
|
||||||
|
auto Name = expectToken<Identifier>();
|
||||||
|
std::vector<VarTypeExpression*> TypeVars;
|
||||||
|
for (;;) {
|
||||||
|
auto T2 = Tokens.peek();
|
||||||
|
if (T2->getKind() == NodeKind::BlockStart) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
TypeVars.push_back(parseVarTypeExpression());
|
||||||
|
}
|
||||||
|
auto BlockStart = expectToken<class BlockStart>();
|
||||||
|
std::vector<Node*> Elements;
|
||||||
|
for (;;) {
|
||||||
|
auto T2 = Tokens.peek();
|
||||||
|
if (T2->is<BlockEnd>()) {
|
||||||
|
Tokens.get();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Elements.push_back(parseClassElement());
|
||||||
|
}
|
||||||
|
expectToken(NodeKind::LineFoldEnd);
|
||||||
|
return new ClassDeclaration(
|
||||||
|
PubKeyword,
|
||||||
|
ClassKeyword,
|
||||||
|
Name,
|
||||||
|
TypeVars,
|
||||||
|
BlockStart,
|
||||||
|
Elements
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node* Parser::parseClassElement() {
|
||||||
|
auto T0 = Tokens.peek();
|
||||||
|
switch (T0->getKind()) {
|
||||||
|
case NodeKind::LetKeyword:
|
||||||
|
return parseLetDeclaration();
|
||||||
|
case NodeKind::TypeKeyword:
|
||||||
|
// TODO
|
||||||
|
default:
|
||||||
|
throw UnexpectedTokenDiagnostic(File, T0, std::vector<NodeKind> { NodeKind::LetKeyword, NodeKind::TypeKeyword });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Node* Parser::parseSourceElement() {
|
Node* Parser::parseSourceElement() {
|
||||||
auto T0 = peekFirstTokenAfterModifiers();
|
auto T0 = peekFirstTokenAfterModifiers();
|
||||||
switch (T0->Type) {
|
switch (T0->getKind()) {
|
||||||
case NodeType::LetKeyword:
|
case NodeKind::LetKeyword:
|
||||||
return parseLetDeclaration();
|
return parseLetDeclaration();
|
||||||
case NodeType::IfKeyword:
|
case NodeKind::IfKeyword:
|
||||||
return parseIfStatement();
|
return parseIfStatement();
|
||||||
|
case NodeKind::ClassKeyword:
|
||||||
|
return parseClassDeclaration();
|
||||||
|
case NodeKind::InstanceKeyword:
|
||||||
|
return parseInstanceDeclaration();
|
||||||
default:
|
default:
|
||||||
return parseExpressionStatement();
|
return parseExpressionStatement();
|
||||||
}
|
}
|
||||||
|
@ -400,7 +609,7 @@ after_params:
|
||||||
std::vector<Node*> Elements;
|
std::vector<Node*> Elements;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
auto T0 = Tokens.peek();
|
auto T0 = Tokens.peek();
|
||||||
if (T0->Type == NodeType::EndOfFile) {
|
if (T0->is<EndOfFile>()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Elements.push_back(parseSourceElement());
|
Elements.push_back(parseSourceElement());
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "zen/config.hpp"
|
#include "zen/config.hpp"
|
||||||
|
|
||||||
|
#include "llvm/Support/Casting.h"
|
||||||
|
|
||||||
#include "bolt/Text.hpp"
|
#include "bolt/Text.hpp"
|
||||||
#include "bolt/Integer.hpp"
|
#include "bolt/Integer.hpp"
|
||||||
#include "bolt/CST.hpp"
|
#include "bolt/CST.hpp"
|
||||||
|
@ -57,16 +59,18 @@ namespace bolt {
|
||||||
return Chr - 48;
|
return Chr - 48;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_map<ByteString, NodeType> Keywords = {
|
std::unordered_map<ByteString, NodeKind> Keywords = {
|
||||||
{ "pub", NodeType::PubKeyword },
|
{ "pub", NodeKind::PubKeyword },
|
||||||
{ "let", NodeType::LetKeyword },
|
{ "let", NodeKind::LetKeyword },
|
||||||
{ "mut", NodeType::MutKeyword },
|
{ "mut", NodeKind::MutKeyword },
|
||||||
{ "return", NodeType::ReturnKeyword },
|
{ "return", NodeKind::ReturnKeyword },
|
||||||
{ "type", NodeType::TypeKeyword },
|
{ "type", NodeKind::TypeKeyword },
|
||||||
{ "mod", NodeType::ModKeyword },
|
{ "mod", NodeKind::ModKeyword },
|
||||||
{ "if", NodeType::IfKeyword },
|
{ "if", NodeKind::IfKeyword },
|
||||||
{ "else", NodeType::ElseKeyword },
|
{ "else", NodeKind::ElseKeyword },
|
||||||
{ "elif", NodeType::ElifKeyword },
|
{ "elif", NodeKind::ElifKeyword },
|
||||||
|
{ "class", NodeKind::ClassKeyword },
|
||||||
|
{ "instance", NodeKind::InstanceKeyword },
|
||||||
};
|
};
|
||||||
|
|
||||||
Scanner::Scanner(TextFile& File, Stream<Char>& Chars):
|
Scanner::Scanner(TextFile& File, Stream<Char>& Chars):
|
||||||
|
@ -202,22 +206,26 @@ digit_finish:
|
||||||
auto Match = Keywords.find(Text);
|
auto Match = Keywords.find(Text);
|
||||||
if (Match != Keywords.end()) {
|
if (Match != Keywords.end()) {
|
||||||
switch (Match->second) {
|
switch (Match->second) {
|
||||||
case NodeType::PubKeyword:
|
case NodeKind::PubKeyword:
|
||||||
return new PubKeyword(StartLoc);
|
return new PubKeyword(StartLoc);
|
||||||
case NodeType::LetKeyword:
|
case NodeKind::LetKeyword:
|
||||||
return new LetKeyword(StartLoc);
|
return new LetKeyword(StartLoc);
|
||||||
case NodeType::MutKeyword:
|
case NodeKind::MutKeyword:
|
||||||
return new MutKeyword(StartLoc);
|
return new MutKeyword(StartLoc);
|
||||||
case NodeType::TypeKeyword:
|
case NodeKind::TypeKeyword:
|
||||||
return new TypeKeyword(StartLoc);
|
return new TypeKeyword(StartLoc);
|
||||||
case NodeType::ReturnKeyword:
|
case NodeKind::ReturnKeyword:
|
||||||
return new ReturnKeyword(StartLoc);
|
return new ReturnKeyword(StartLoc);
|
||||||
case NodeType::IfKeyword:
|
case NodeKind::IfKeyword:
|
||||||
return new IfKeyword(StartLoc);
|
return new IfKeyword(StartLoc);
|
||||||
case NodeType::ElifKeyword:
|
case NodeKind::ElifKeyword:
|
||||||
return new ElifKeyword(StartLoc);
|
return new ElifKeyword(StartLoc);
|
||||||
case NodeType::ElseKeyword:
|
case NodeKind::ElseKeyword:
|
||||||
return new ElseKeyword(StartLoc);
|
return new ElseKeyword(StartLoc);
|
||||||
|
case NodeKind::ClassKeyword:
|
||||||
|
return new ClassKeyword(StartLoc);
|
||||||
|
case NodeKind::InstanceKeyword:
|
||||||
|
return new InstanceKeyword(StartLoc);
|
||||||
default:
|
default:
|
||||||
ZEN_UNREACHABLE
|
ZEN_UNREACHABLE
|
||||||
}
|
}
|
||||||
|
@ -305,6 +313,8 @@ after_string_contents:
|
||||||
}
|
}
|
||||||
if (Text == "->") {
|
if (Text == "->") {
|
||||||
return new RArrow(StartLoc);
|
return new RArrow(StartLoc);
|
||||||
|
} else if (Text == "=>") {
|
||||||
|
return new RArrowAlt(StartLoc);
|
||||||
} else if (Text == "=") {
|
} else if (Text == "=") {
|
||||||
return new Equals(StartLoc);
|
return new Equals(StartLoc);
|
||||||
} else if (Text.back() == '=' && Text[Text.size()-2] != '=') {
|
} else if (Text.back() == '=' && Text[Text.size()-2] != '=') {
|
||||||
|
@ -316,7 +326,7 @@ after_string_contents:
|
||||||
|
|
||||||
#define BOLT_SIMPLE_TOKEN(ch, name) case ch: return new name(StartLoc);
|
#define BOLT_SIMPLE_TOKEN(ch, name) case ch: return new name(StartLoc);
|
||||||
|
|
||||||
//BOLT_SIMPLE_TOKEN(',', Comma)
|
BOLT_SIMPLE_TOKEN(',', Comma)
|
||||||
BOLT_SIMPLE_TOKEN(':', Colon)
|
BOLT_SIMPLE_TOKEN(':', Colon)
|
||||||
BOLT_SIMPLE_TOKEN('(', LParen)
|
BOLT_SIMPLE_TOKEN('(', LParen)
|
||||||
BOLT_SIMPLE_TOKEN(')', RParen)
|
BOLT_SIMPLE_TOKEN(')', RParen)
|
||||||
|
@ -324,6 +334,7 @@ after_string_contents:
|
||||||
BOLT_SIMPLE_TOKEN(']', RBracket)
|
BOLT_SIMPLE_TOKEN(']', RBracket)
|
||||||
BOLT_SIMPLE_TOKEN('{', LBrace)
|
BOLT_SIMPLE_TOKEN('{', LBrace)
|
||||||
BOLT_SIMPLE_TOKEN('}', RBrace)
|
BOLT_SIMPLE_TOKEN('}', RBrace)
|
||||||
|
BOLT_SIMPLE_TOKEN('~', Tilde)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw UnexpectedStringDiagnostic(File, StartLoc, String { static_cast<char>(C0) });
|
throw UnexpectedStringDiagnostic(File, StartLoc, String { static_cast<char>(C0) });
|
||||||
|
@ -342,7 +353,7 @@ after_string_contents:
|
||||||
|
|
||||||
auto T0 = Tokens.peek();
|
auto T0 = Tokens.peek();
|
||||||
|
|
||||||
if (T0->Type == NodeType::EndOfFile) {
|
if (llvm::isa<EndOfFile>(T0)) {
|
||||||
if (Frames.size() == 1) {
|
if (Frames.size() == 1) {
|
||||||
return T0;
|
return T0;
|
||||||
}
|
}
|
||||||
|
@ -366,7 +377,7 @@ after_string_contents:
|
||||||
Locations.pop();
|
Locations.pop();
|
||||||
return new LineFoldEnd(T0->getStartLoc());
|
return new LineFoldEnd(T0->getStartLoc());
|
||||||
}
|
}
|
||||||
if (T0->Type == NodeType::Dot) {
|
if (llvm::isa<Dot>(T0)) {
|
||||||
auto T1 = Tokens.peek(1);
|
auto T1 = Tokens.peek(1);
|
||||||
if (T1->getStartLine() > T0->getEndLine()) {
|
if (T1->getStartLine() > T0->getEndLine()) {
|
||||||
Tokens.get();
|
Tokens.get();
|
||||||
|
|
|
@ -16,18 +16,18 @@ auto checkExpression(std::string Input) {
|
||||||
Scanner S(T, Chars);
|
Scanner S(T, Chars);
|
||||||
Punctuator PT(S);
|
Punctuator PT(S);
|
||||||
Parser P(T, PT);
|
Parser P(T, PT);
|
||||||
|
LanguageConfig Config;
|
||||||
auto SF = P.parseSourceFile();
|
auto SF = P.parseSourceFile();
|
||||||
Checker C(DS);
|
Checker C(Config, DS);
|
||||||
auto Solution = C.check(SF);
|
C.check(SF);
|
||||||
return std::make_tuple(
|
return std::make_tuple(
|
||||||
static_cast<ExpressionStatement*>(SF->Elements[0])->Expression,
|
static_cast<ExpressionStatement*>(SF->Elements[0])->Expression,
|
||||||
C,
|
C
|
||||||
Solution
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CheckerTest, InfersIntFromIntegerLiteral) {
|
TEST(CheckerTest, InfersIntFromIntegerLiteral) {
|
||||||
auto [Expression, Checker, Solution] = checkExpression("1");
|
auto [Expression, Checker] = checkExpression("1");
|
||||||
ASSERT_EQ(Checker.getType(Expression, Solution), Checker.getIntType());
|
ASSERT_EQ(Checker.getType(Expression), Checker.getIntType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ int main(int argc, const char* argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ConsoleDiagnostics DE;
|
ConsoleDiagnostics DE;
|
||||||
|
LanguageConfig Config;
|
||||||
|
|
||||||
auto Text = readFile(argv[1]);
|
auto Text = readFile(argv[1]);
|
||||||
TextFile File { argv[1], Text };
|
TextFile File { argv[1], Text };
|
||||||
|
@ -56,7 +57,7 @@ int main(int argc, const char* argv[]) {
|
||||||
|
|
||||||
SF->setParents();
|
SF->setParents();
|
||||||
|
|
||||||
Checker TheChecker { DE };
|
Checker TheChecker { Config, DE };
|
||||||
TheChecker.check(SF);
|
TheChecker.check(SF);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in a new issue