Initial work on the WBT parser and its test suite
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
.idea
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
cmake_minimum_required(VERSION 4.2)
|
||||||
|
project(wb)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 26)
|
||||||
|
|
||||||
|
add_executable(wb main.cpp)
|
||||||
|
target_sources(wb
|
||||||
|
PUBLIC
|
||||||
|
FILE_SET CXX_MODULES FILES
|
||||||
|
wbt/wbt.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test Executables
|
||||||
|
add_executable(test_parse test_parse.cpp)
|
||||||
|
target_sources(test_parse
|
||||||
|
PUBLIC
|
||||||
|
FILE_SET CXX_MODULES FILES
|
||||||
|
wbt/wbt.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
# Copy test files to build folder
|
||||||
|
add_custom_target(copy_test_files ALL
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/test
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/test
|
||||||
|
COMMENT "Copying test files to build directory"
|
||||||
|
)
|
||||||
|
add_dependencies(test_parse copy_test_files)
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 David Gil de Gómez Pérez
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import wbt;
|
||||||
|
|
||||||
|
// WB is a site builder built from scratch
|
||||||
|
int main() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<h1>Hello World</h1>
|
||||||
|
<p>{{ INVALID { EXPRESSION }}</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<h1>Hello World</h1>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<h1>Hello World</h1>
|
||||||
|
<p>{{ VALID EXPRESSION }}</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<h1>Hello World</h1>
|
||||||
|
<p>{{ INVALID EXPRESSION }</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
import wbt;
|
||||||
|
|
||||||
|
void test_parse_no_expressions() {
|
||||||
|
std::ifstream i("test/test_parse_no_expressions.wbt", std::ios_base::in);
|
||||||
|
std::ostream o(std::cout.rdbuf());
|
||||||
|
const WBT_Parser p(i, o);
|
||||||
|
p.parse();
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_parse_single_expression() {
|
||||||
|
std::ifstream i("test/test_parse_single_expression.wbt", std::ios_base::in);
|
||||||
|
std::ostream o(std::cout.rdbuf());
|
||||||
|
const WBT_Parser p(i, o);
|
||||||
|
p.parse();
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_parse_invalid_character_expression() {
|
||||||
|
std::ifstream i("test/test_parse_invalid_character_expression.wbt", std::ios_base::in);
|
||||||
|
std::ostream o(std::cout.rdbuf());
|
||||||
|
const WBT_Parser p(i, o);
|
||||||
|
p.parse();
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_parse_unclosed_expression() {
|
||||||
|
std::ifstream i("test/test_parse_unclosed_expression.wbt", std::ios_base::in);
|
||||||
|
std::ostream o(std::cout.rdbuf());
|
||||||
|
const WBT_Parser p(i, o);
|
||||||
|
p.parse();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
std::cout << std::endl << "-----" << std::endl;
|
||||||
|
test_parse_no_expressions();
|
||||||
|
std::cout << std::endl << "-----" << std::endl;
|
||||||
|
test_parse_single_expression();
|
||||||
|
std::cout << std::endl << "-----" << std::endl;
|
||||||
|
test_parse_invalid_character_expression();
|
||||||
|
std::cout << std::endl << "-----" << std::endl;
|
||||||
|
test_parse_unclosed_expression();
|
||||||
|
std::cout << std::endl << "-----" << std::endl;
|
||||||
|
}
|
||||||
+93
@@ -0,0 +1,93 @@
|
|||||||
|
module;
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
// This module is the transpiler from WBT to HTML for site build
|
||||||
|
export module wbt;
|
||||||
|
|
||||||
|
export enum WBT_States {
|
||||||
|
WBT_STATE_INIT,
|
||||||
|
WBT_STATE_OPEN,
|
||||||
|
WBT_STATE_EXPRESSION,
|
||||||
|
WBT_STATE_CLOSE,
|
||||||
|
};
|
||||||
|
|
||||||
|
export class WBT_Parser {
|
||||||
|
std::istream& input;
|
||||||
|
std::ostream& output;
|
||||||
|
public:
|
||||||
|
explicit WBT_Parser(
|
||||||
|
std::istream& i,
|
||||||
|
std::ostream& o
|
||||||
|
)
|
||||||
|
: input(i), output(o) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void output_char(const char c) const {
|
||||||
|
output << c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void error(const std::string& msg, const int line, const int column) {
|
||||||
|
std::cerr << "Error (" << line << "," << column << "): " << msg << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void eval(const std::string& expr) const {
|
||||||
|
output << "[EXPR: " << expr << "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse() const {
|
||||||
|
auto state = WBT_STATE_INIT;
|
||||||
|
std::string expr;
|
||||||
|
auto line = 1;
|
||||||
|
auto column = 1;
|
||||||
|
while (input.peek() != std::char_traits<char>::eof()) {
|
||||||
|
char c;
|
||||||
|
input.get(c);
|
||||||
|
// State machine
|
||||||
|
switch (state) {
|
||||||
|
case WBT_STATE_INIT:
|
||||||
|
if (c == '{') {
|
||||||
|
state = WBT_STATE_OPEN;
|
||||||
|
} else {
|
||||||
|
output_char(c);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WBT_STATE_OPEN:
|
||||||
|
if (c == '{') {
|
||||||
|
state = WBT_STATE_EXPRESSION;
|
||||||
|
} else {
|
||||||
|
output_char('{');
|
||||||
|
output_char(c);
|
||||||
|
state = WBT_STATE_INIT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WBT_STATE_EXPRESSION:
|
||||||
|
if (c == '}') {
|
||||||
|
state = WBT_STATE_CLOSE;
|
||||||
|
} else if (c == '{') {
|
||||||
|
error("Invalid character inside of expression", line, column);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
expr += c;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WBT_STATE_CLOSE:
|
||||||
|
if (c == '}') {
|
||||||
|
eval(expr);
|
||||||
|
expr.clear();
|
||||||
|
state = WBT_STATE_INIT;
|
||||||
|
} else {
|
||||||
|
error("Unclosed expression", line, column);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c == '\n') {
|
||||||
|
line++;
|
||||||
|
column = 1;
|
||||||
|
} else {
|
||||||
|
column++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user