✨ add demo format executable
This commit is contained in:
parent
c228dcc149
commit
277ddb9c0f
|
@ -50,7 +50,9 @@ cmake-windows-*
|
||||||
*.out
|
*.out
|
||||||
*.app
|
*.app
|
||||||
nasal
|
nasal
|
||||||
|
nasal-format
|
||||||
nasal.exe
|
nasal.exe
|
||||||
|
nasal-format.exe
|
||||||
|
|
||||||
# Visual Studio specific
|
# Visual Studio specific
|
||||||
*.sln
|
*.sln
|
||||||
|
|
|
@ -41,6 +41,7 @@ set(NASAL_OBJECT_SOURCE_FILE
|
||||||
${CMAKE_SOURCE_DIR}/src/util/fs.cpp
|
${CMAKE_SOURCE_DIR}/src/util/fs.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/util/util.cpp
|
${CMAKE_SOURCE_DIR}/src/util/util.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/ast_dumper.cpp
|
${CMAKE_SOURCE_DIR}/src/ast_dumper.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/src/ast_format.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/ast_visitor.cpp
|
${CMAKE_SOURCE_DIR}/src/ast_visitor.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/nasal_ast.cpp
|
${CMAKE_SOURCE_DIR}/src/nasal_ast.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/nasal_codegen.cpp
|
${CMAKE_SOURCE_DIR}/src/nasal_codegen.cpp
|
||||||
|
@ -62,12 +63,18 @@ target_include_directories(nasal-object PRIVATE ${CMAKE_SOURCE_DIR}/src)
|
||||||
add_executable(nasal ${CMAKE_SOURCE_DIR}/src/main.cpp)
|
add_executable(nasal ${CMAKE_SOURCE_DIR}/src/main.cpp)
|
||||||
target_link_libraries(nasal nasal-object)
|
target_link_libraries(nasal nasal-object)
|
||||||
|
|
||||||
|
# build nasal-format
|
||||||
|
add_executable(nasal-format ${CMAKE_SOURCE_DIR}/src/format.cpp)
|
||||||
|
target_link_libraries(nasal-format nasal-object)
|
||||||
|
|
||||||
# link ldl and lpthread
|
# link ldl and lpthread
|
||||||
if(NOT CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
|
if(NOT CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
|
||||||
target_link_libraries(nasal dl)
|
target_link_libraries(nasal dl)
|
||||||
target_link_libraries(nasal pthread)
|
target_link_libraries(nasal pthread)
|
||||||
|
target_link_libraries(nasal-format pthread)
|
||||||
endif()
|
endif()
|
||||||
target_include_directories(nasal PRIVATE ${CMAKE_SOURCE_DIR}/src)
|
target_include_directories(nasal PRIVATE ${CMAKE_SOURCE_DIR}/src)
|
||||||
|
target_include_directories(nasal-format PRIVATE ${CMAKE_SOURCE_DIR}/src)
|
||||||
|
|
||||||
# copy nasal from build dir to the outside dir
|
# copy nasal from build dir to the outside dir
|
||||||
if(NOT CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
|
if(NOT CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
|
||||||
|
@ -77,6 +84,12 @@ if(NOT CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
|
||||||
${CMAKE_SOURCE_DIR}/build/nasal
|
${CMAKE_SOURCE_DIR}/build/nasal
|
||||||
${CMAKE_SOURCE_DIR}/nasal
|
${CMAKE_SOURCE_DIR}/nasal
|
||||||
)
|
)
|
||||||
|
add_custom_command(
|
||||||
|
TARGET nasal-format POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy
|
||||||
|
${CMAKE_SOURCE_DIR}/build/nasal-format
|
||||||
|
${CMAKE_SOURCE_DIR}/nasal-format
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# build module
|
# build module
|
||||||
|
|
|
@ -38,7 +38,7 @@ private:
|
||||||
if (indent.size() && indent.back()=="│ ") {
|
if (indent.size() && indent.back()=="│ ") {
|
||||||
indent.back() = "├──";
|
indent.back() = "├──";
|
||||||
}
|
}
|
||||||
for(const auto& i : indent) {
|
for (const auto& i : indent) {
|
||||||
std::cout << i;
|
std::cout << i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,412 @@
|
||||||
|
#include "ast_format.h"
|
||||||
|
#include "util/util.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace nasal {
|
||||||
|
|
||||||
|
bool ast_format::visit_use_stmt(use_stmt* node) {
|
||||||
|
dump_formating_node_info(node, "use statement");
|
||||||
|
out << "use ";
|
||||||
|
for(auto i : node->get_path()) {
|
||||||
|
i->accept(this);
|
||||||
|
if (i != node->get_path().back()) {
|
||||||
|
out << ".";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_null_expr(null_expr* node) {
|
||||||
|
dump_formating_node_info(node, "null expression");
|
||||||
|
out << "null";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_nil_expr(nil_expr* node) {
|
||||||
|
dump_formating_node_info(node, "nil expression");
|
||||||
|
out << "nil";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_number_literal(number_literal* node) {
|
||||||
|
dump_formating_node_info(node, "number expression");
|
||||||
|
out << node->get_number();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_string_literal(string_literal* node) {
|
||||||
|
dump_formating_node_info(node, "string expression");
|
||||||
|
out << "\"" << util::rawstr(node->get_content()) << "\"";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_identifier(identifier* node) {
|
||||||
|
dump_formating_node_info(node, "identifier");
|
||||||
|
out << node->get_name();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_bool_literal(bool_literal* node) {
|
||||||
|
dump_formating_node_info(node, "bool expression");
|
||||||
|
out << (node->get_flag()? "true" : "false");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_vector_expr(vector_expr* node) {
|
||||||
|
dump_formating_node_info(node, "vector expression");
|
||||||
|
out << "[";
|
||||||
|
for(auto i : node->get_elements()) {
|
||||||
|
i->accept(this);
|
||||||
|
if (i != node->get_elements().back()) {
|
||||||
|
out << ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out << "]";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_hash_expr(hash_expr* node) {
|
||||||
|
dump_formating_node_info(node, "hash expression");
|
||||||
|
out << "{";
|
||||||
|
for(auto i : node->get_members()) {
|
||||||
|
i->accept(this);
|
||||||
|
if (i != node->get_members().back()) {
|
||||||
|
out << ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out << "}";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_hash_pair(hash_pair* node) {
|
||||||
|
dump_formating_node_info(node, "hash pair");
|
||||||
|
out << node->get_name();
|
||||||
|
if (node->get_value()) {
|
||||||
|
out << " : ";
|
||||||
|
node->get_value()->accept(this);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_function(function* node) {
|
||||||
|
dump_formating_node_info(node, "function");
|
||||||
|
out << "func(";
|
||||||
|
for(auto i : node->get_parameter_list()) {
|
||||||
|
i->accept(this);
|
||||||
|
if (i != node->get_parameter_list().back()) {
|
||||||
|
out << ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out << ") ";
|
||||||
|
node->get_code_block()->accept(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_code_block(code_block* node) {
|
||||||
|
dump_formating_node_info(node, "code block");
|
||||||
|
out << "{\n";
|
||||||
|
push_indent();
|
||||||
|
for(auto i : node->get_expressions()) {
|
||||||
|
dump_indent();
|
||||||
|
i->accept(this);
|
||||||
|
if (need_dump_semi(i)) {
|
||||||
|
out << ";\n";
|
||||||
|
} else {
|
||||||
|
out << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pop_indent();
|
||||||
|
dump_indent();
|
||||||
|
out << "}";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_parameter(parameter* node) {
|
||||||
|
dump_formating_node_info(node, "parameter");
|
||||||
|
out << node->get_parameter_name();
|
||||||
|
switch (node->get_parameter_type()) {
|
||||||
|
case parameter::kind::normal_parameter: break;
|
||||||
|
case parameter::kind::dynamic_parameter: out << "..."; break;
|
||||||
|
case parameter::kind::default_parameter: out << " = "; break;
|
||||||
|
}
|
||||||
|
if (node->get_default_value()) {
|
||||||
|
node->get_default_value()->accept(this);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_ternary_operator(ternary_operator* node) {
|
||||||
|
dump_formating_node_info(node, "ternary operator");
|
||||||
|
node->get_condition()->accept(this);
|
||||||
|
out << " ? ";
|
||||||
|
node->get_left()->accept(this);
|
||||||
|
out << " : ";
|
||||||
|
node->get_right()->accept(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_binary_operator(binary_operator* node) {
|
||||||
|
dump_formating_node_info(node, "binary operator");
|
||||||
|
out << "(";
|
||||||
|
node->get_left()->accept(this);
|
||||||
|
switch(node->get_operator_type()) {
|
||||||
|
case binary_operator::kind::add: out << " + "; break;
|
||||||
|
case binary_operator::kind::sub: out << " - "; break;
|
||||||
|
case binary_operator::kind::mult: out << " * "; break;
|
||||||
|
case binary_operator::kind::div: out << " / "; break;
|
||||||
|
case binary_operator::kind::concat: out << " ~ "; break;
|
||||||
|
case binary_operator::kind::bitwise_and: out << " & "; break;
|
||||||
|
case binary_operator::kind::bitwise_or: out << " | "; break;
|
||||||
|
case binary_operator::kind::bitwise_xor: out << " ^ "; break;
|
||||||
|
case binary_operator::kind::cmpeq: out << " == "; break;
|
||||||
|
case binary_operator::kind::cmpneq: out << " != "; break;
|
||||||
|
case binary_operator::kind::grt: out << " > "; break;
|
||||||
|
case binary_operator::kind::geq: out << " >= "; break;
|
||||||
|
case binary_operator::kind::less: out << " < "; break;
|
||||||
|
case binary_operator::kind::leq: out << " <= "; break;
|
||||||
|
case binary_operator::kind::condition_and: out << " and "; break;
|
||||||
|
case binary_operator::kind::condition_or: out << " or "; break;
|
||||||
|
case binary_operator::kind::null_chain: out << " ?? "; break;
|
||||||
|
}
|
||||||
|
node->get_right()->accept(this);
|
||||||
|
out << ")";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_unary_operator(unary_operator* node) {
|
||||||
|
dump_formating_node_info(node, "unary operator");
|
||||||
|
switch(node->get_operator_type()) {
|
||||||
|
case unary_operator::kind::negative: out << "-"; break;
|
||||||
|
case unary_operator::kind::logical_not: out << "!"; break;
|
||||||
|
case unary_operator::kind::bitwise_not: out << "~"; break;
|
||||||
|
}
|
||||||
|
node->get_value()->accept(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_call_expr(call_expr* node) {
|
||||||
|
dump_formating_node_info(node, "call expression");
|
||||||
|
node->get_first()->accept(this);
|
||||||
|
for(auto i : node->get_calls()) {
|
||||||
|
i->accept(this);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_call_hash(call_hash* node) {
|
||||||
|
dump_formating_node_info(node, "call hash");
|
||||||
|
out << "." << node->get_field();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_null_access(null_access* node) {
|
||||||
|
dump_formating_node_info(node, "null access operator(?.)");
|
||||||
|
out << "?." << node->get_field();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_call_vector(call_vector* node) {
|
||||||
|
dump_formating_node_info(node, "call vector");
|
||||||
|
out << "[";
|
||||||
|
for(auto i : node->get_slices()) {
|
||||||
|
i->accept(this);
|
||||||
|
if (i != node->get_slices().back()) {
|
||||||
|
out << ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out << "]";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_call_function(call_function* node) {
|
||||||
|
dump_formating_node_info(node, "call function");
|
||||||
|
out << "(";
|
||||||
|
for(auto i : node->get_argument()) {
|
||||||
|
i->accept(this);
|
||||||
|
if (i != node->get_argument().back()) {
|
||||||
|
out << ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out << ")";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_slice_vector(slice_vector* node) {
|
||||||
|
dump_formating_node_info(node, "slice vector");
|
||||||
|
node->get_begin()->accept(this);
|
||||||
|
if (node->get_end()) {
|
||||||
|
out << " : ";
|
||||||
|
node->get_end()->accept(this);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_definition_expr(definition_expr* node) {
|
||||||
|
dump_formating_node_info(node, "definition");
|
||||||
|
out << "var ";
|
||||||
|
if (node->get_variable_name()) {
|
||||||
|
node->get_variable_name()->accept(this);
|
||||||
|
} else {
|
||||||
|
node->get_variables()->accept(this);
|
||||||
|
}
|
||||||
|
out << " = ";
|
||||||
|
if (node->get_tuple()) {
|
||||||
|
node->get_tuple()->accept(this);
|
||||||
|
} else {
|
||||||
|
node->get_value()->accept(this);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_assignment_expr(assignment_expr* node) {
|
||||||
|
dump_formating_node_info(node, "assignment");
|
||||||
|
node->get_left()->accept(this);
|
||||||
|
switch(node->get_assignment_type()) {
|
||||||
|
case assignment_expr::kind::add_equal: out << " += "; break;
|
||||||
|
case assignment_expr::kind::sub_equal: out << " -= "; break;
|
||||||
|
case assignment_expr::kind::mult_equal: out << " *= "; break;
|
||||||
|
case assignment_expr::kind::div_equal: out << " /= "; break;
|
||||||
|
case assignment_expr::kind::concat_equal: out << " ~= "; break;
|
||||||
|
case assignment_expr::kind::equal: out << " = "; break;
|
||||||
|
case assignment_expr::kind::bitwise_and_equal: out << " &= "; break;
|
||||||
|
case assignment_expr::kind::bitwise_or_equal: out << " |= "; break;
|
||||||
|
case assignment_expr::kind::bitwise_xor_equal: out << " ^= "; break;
|
||||||
|
}
|
||||||
|
node->get_right()->accept(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_multi_identifier(multi_identifier* node) {
|
||||||
|
dump_formating_node_info(node, "multi identifier");
|
||||||
|
out << "(";
|
||||||
|
for(auto i : node->get_variables()) {
|
||||||
|
i->accept(this);
|
||||||
|
if (i != node->get_variables().back()) {
|
||||||
|
out << ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out << ")";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_tuple_expr(tuple_expr* node) {
|
||||||
|
dump_formating_node_info(node, "tuple expression");
|
||||||
|
out << "(";
|
||||||
|
for(auto i : node->get_elements()) {
|
||||||
|
i->accept(this);
|
||||||
|
if (i != node->get_elements().back()) {
|
||||||
|
out << ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out << ")";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_multi_assign(multi_assign* node) {
|
||||||
|
dump_formating_node_info(node, "multi assign");
|
||||||
|
node->get_tuple()->accept(this);
|
||||||
|
out << " = ";
|
||||||
|
node->get_value()->accept(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_while_expr(while_expr* node) {
|
||||||
|
dump_formating_node_info(node, "while statement");
|
||||||
|
out << "while (";
|
||||||
|
node->get_condition()->accept(this);
|
||||||
|
out << ") ";
|
||||||
|
node->get_code_block()->accept(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_for_expr(for_expr* node) {
|
||||||
|
dump_formating_node_info(node, "for statement");
|
||||||
|
out << "for (";
|
||||||
|
node->get_initial()->accept(this);
|
||||||
|
out << "; ";
|
||||||
|
node->get_condition()->accept(this);
|
||||||
|
out << "; ";
|
||||||
|
node->get_step()->accept(this);
|
||||||
|
out << ") ";
|
||||||
|
node->get_code_block()->accept(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_iter_expr(iter_expr* node) {
|
||||||
|
dump_formating_node_info(node, "iteration expression");
|
||||||
|
if (node->is_definition()) {
|
||||||
|
out << "var ";
|
||||||
|
}
|
||||||
|
if (node->get_name()) {
|
||||||
|
node->get_name()->accept(this);
|
||||||
|
} else {
|
||||||
|
node->get_call()->accept(this);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_forei_expr(forei_expr* node) {
|
||||||
|
dump_formating_node_info(node, "forindex/foreach statement");
|
||||||
|
if (node->get_loop_type()==forei_expr::kind::foreach) {
|
||||||
|
out << "foreach ";
|
||||||
|
} else {
|
||||||
|
out << "forindex ";
|
||||||
|
}
|
||||||
|
out << "(";
|
||||||
|
node->get_iterator()->accept(this);
|
||||||
|
out << "; ";
|
||||||
|
node->get_value()->accept(this);
|
||||||
|
out << ") ";
|
||||||
|
node->get_code_block()->accept(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_condition_expr(condition_expr* node) {
|
||||||
|
dump_formating_node_info(node, "condition statement");
|
||||||
|
out << "if ";
|
||||||
|
node->get_if_statement()->accept(this);
|
||||||
|
for (auto i : node->get_elsif_stataments()) {
|
||||||
|
out << " elsif ";
|
||||||
|
i->accept(this);
|
||||||
|
}
|
||||||
|
if (node->get_else_statement()) {
|
||||||
|
out << " else ";
|
||||||
|
node->get_else_statement()->accept(this);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_if_expr(if_expr* node) {
|
||||||
|
dump_formating_node_info(node, "if statement");
|
||||||
|
if (node->get_condition()) {
|
||||||
|
out << "(";
|
||||||
|
node->get_condition()->accept(this);
|
||||||
|
out << ") ";
|
||||||
|
}
|
||||||
|
node->get_code_block()->accept(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_continue_expr(continue_expr* node) {
|
||||||
|
dump_formating_node_info(node, "continue statement");
|
||||||
|
out << "continue";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_break_expr(break_expr* node) {
|
||||||
|
dump_formating_node_info(node, "break statement");
|
||||||
|
out << "break";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_return_expr(return_expr* node) {
|
||||||
|
dump_formating_node_info(node, "return statement");
|
||||||
|
out << "return ";
|
||||||
|
if (node->get_value()) {
|
||||||
|
node->get_value()->accept(this);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,144 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ast_visitor.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <fstream>
|
||||||
|
#include <cstring>
|
||||||
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace nasal {
|
||||||
|
|
||||||
|
class ast_format: public ast_visitor {
|
||||||
|
private:
|
||||||
|
std::ofstream out;
|
||||||
|
std::vector<std::string> indent;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void push_indent() {
|
||||||
|
indent.push_back(" ");
|
||||||
|
}
|
||||||
|
void pop_indent() {
|
||||||
|
if (indent.size()) {
|
||||||
|
indent.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void dump_indent() {
|
||||||
|
for (const auto& i : indent) {
|
||||||
|
out << i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void dump_formating_node_info(expr* n, const char* name) {
|
||||||
|
std::cout << " formating " << name << " @ 0x";
|
||||||
|
std::cout << std::hex << n << std::dec << "\n";
|
||||||
|
}
|
||||||
|
bool need_dump_semi(expr* n) {
|
||||||
|
switch (n->get_type()) {
|
||||||
|
case expr_type::ast_use:
|
||||||
|
case expr_type::ast_null:
|
||||||
|
case expr_type::ast_nil:
|
||||||
|
case expr_type::ast_num:
|
||||||
|
case expr_type::ast_str:
|
||||||
|
case expr_type::ast_bool:
|
||||||
|
case expr_type::ast_vec:
|
||||||
|
case expr_type::ast_hash:
|
||||||
|
case expr_type::ast_call: return true;
|
||||||
|
case expr_type::ast_def: {
|
||||||
|
auto dn = reinterpret_cast<definition_expr*>(n);
|
||||||
|
if (dn->get_value() &&
|
||||||
|
dn->get_value()->get_type() == expr_type::ast_func) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case expr_type::ast_assign: {
|
||||||
|
auto dn = reinterpret_cast<assignment_expr*>(n);
|
||||||
|
if (dn->get_right() &&
|
||||||
|
dn->get_right()->get_type() == expr_type::ast_func) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case expr_type::ast_ret: {
|
||||||
|
auto dn = reinterpret_cast<return_expr*>(n);
|
||||||
|
if (dn->get_value() &&
|
||||||
|
dn->get_value()->get_type() == expr_type::ast_func) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool visit_use_stmt(use_stmt*) override;
|
||||||
|
bool visit_null_expr(null_expr*) override;
|
||||||
|
bool visit_nil_expr(nil_expr*) override;
|
||||||
|
bool visit_number_literal(number_literal*) override;
|
||||||
|
bool visit_string_literal(string_literal*) override;
|
||||||
|
bool visit_identifier(identifier*) override;
|
||||||
|
bool visit_bool_literal(bool_literal*) override;
|
||||||
|
bool visit_vector_expr(vector_expr*) override;
|
||||||
|
bool visit_hash_expr(hash_expr*) override;
|
||||||
|
bool visit_hash_pair(hash_pair*) override;
|
||||||
|
bool visit_function(function*) override;
|
||||||
|
bool visit_code_block(code_block*) override;
|
||||||
|
bool visit_parameter(parameter*) override;
|
||||||
|
bool visit_ternary_operator(ternary_operator*) override;
|
||||||
|
bool visit_binary_operator(binary_operator*) override;
|
||||||
|
bool visit_unary_operator(unary_operator*) override;
|
||||||
|
bool visit_call_expr(call_expr*) override;
|
||||||
|
bool visit_call_hash(call_hash*) override;
|
||||||
|
bool visit_null_access(null_access*) override;
|
||||||
|
bool visit_call_vector(call_vector*) override;
|
||||||
|
bool visit_call_function(call_function*) override;
|
||||||
|
bool visit_slice_vector(slice_vector*) override;
|
||||||
|
bool visit_definition_expr(definition_expr*) override;
|
||||||
|
bool visit_assignment_expr(assignment_expr*) override;
|
||||||
|
bool visit_multi_identifier(multi_identifier*) override;
|
||||||
|
bool visit_tuple_expr(tuple_expr*) override;
|
||||||
|
bool visit_multi_assign(multi_assign*) override;
|
||||||
|
bool visit_while_expr(while_expr*) override;
|
||||||
|
bool visit_for_expr(for_expr*) override;
|
||||||
|
bool visit_iter_expr(iter_expr*) override;
|
||||||
|
bool visit_forei_expr(forei_expr*) override;
|
||||||
|
bool visit_condition_expr(condition_expr*) override;
|
||||||
|
bool visit_if_expr(if_expr*) override;
|
||||||
|
bool visit_continue_expr(continue_expr*) override;
|
||||||
|
bool visit_break_expr(break_expr*) override;
|
||||||
|
bool visit_return_expr(return_expr*) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ast_format(const std::string output_file): out(output_file) {
|
||||||
|
if (out.fail()) {
|
||||||
|
throw std::runtime_error("can't open file: " + output_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_format(code_block* root) {
|
||||||
|
std::cout << "nasal-format is not stable right now, ";
|
||||||
|
std::cout << "take care of source code!\n";
|
||||||
|
dump_formating_node_info(root, "program root");
|
||||||
|
bool is_use_statement = true;
|
||||||
|
for (auto i : root->get_expressions()) {
|
||||||
|
if (is_use_statement && i->get_type() != expr_type::ast_use) {
|
||||||
|
is_use_statement = false;
|
||||||
|
out << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
i->accept(this);
|
||||||
|
if (need_dump_semi(i)) {
|
||||||
|
out << ";\n";
|
||||||
|
} else {
|
||||||
|
out << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,6 +1,12 @@
|
||||||
|
#include "nasal.h"
|
||||||
#include "cli/cli.h"
|
#include "cli/cli.h"
|
||||||
|
#include "util/util.h"
|
||||||
|
#include "nasal_parse.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
namespace nasal::cli {
|
namespace nasal::cli {
|
||||||
|
|
||||||
|
@ -59,4 +65,75 @@ std::ostream& help(std::ostream& out) {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::ostream& nasal_format_help(std::ostream& out) {
|
||||||
|
out
|
||||||
|
<< "\n"
|
||||||
|
<< " ,--#-,\n"
|
||||||
|
<< "<3 / \\____\\ <3\n"
|
||||||
|
<< " |_|__A_|\n"
|
||||||
|
<< "\nnasal-format <option>\n"
|
||||||
|
<< "option:\n"
|
||||||
|
<< " -h, --help | get help.\n"
|
||||||
|
<< " -v, --version | get version.\n"
|
||||||
|
<< "\nnasal-format <file>\n"
|
||||||
|
<< "file:\n"
|
||||||
|
<< " <filename> | file to be formatted.\n"
|
||||||
|
<< "\n";
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& logo(std::ostream& out) {
|
||||||
|
out
|
||||||
|
<< "\n"
|
||||||
|
<< " __ _\n"
|
||||||
|
<< " /\\ \\ \\__ _ ___ __ _| |\n"
|
||||||
|
<< " / \\/ / _` / __|/ _` | |\n"
|
||||||
|
<< " / /\\ / (_| \\__ \\ (_| | |\n"
|
||||||
|
<< " \\_\\ \\/ \\__,_|___/\\__,_|_|\n"
|
||||||
|
<< "\n"
|
||||||
|
<< "ver : " << __nasver__
|
||||||
|
<< " " << nasal::util::get_platform()
|
||||||
|
<< " " << nasal::util::get_arch()
|
||||||
|
<< " (" << __DATE__ << " " << __TIME__ << ")\n"
|
||||||
|
<< "std : c++ " << __cplusplus << "\n"
|
||||||
|
<< "core : " << std::thread::hardware_concurrency() << " core(s)\n"
|
||||||
|
<< "repo : https://github.com/ValKmjolnir/Nasal-Interpreter\n"
|
||||||
|
<< "repo : https://gitee.com/valkmjolnir/Nasal-Interpreter\n"
|
||||||
|
<< "wiki : https://wiki.flightgear.org/Nasal_scripting_language\n"
|
||||||
|
<< "\n"
|
||||||
|
<< "presented by fgprc members:\n"
|
||||||
|
<< " - http://fgprc.org\n"
|
||||||
|
<< " - http://fgprc.org.cn\n"
|
||||||
|
<< "\n"
|
||||||
|
<< "input <nasal-format -h> to get help.\n\n";
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& version(std::ostream& out) {
|
||||||
|
std::srand(static_cast<u32>(std::time(nullptr)));
|
||||||
|
|
||||||
|
f64 num = 0;
|
||||||
|
for(u32 i = 0; i<5; ++i) {
|
||||||
|
num = (num+rand())*(1.0/(RAND_MAX+1.0));
|
||||||
|
}
|
||||||
|
// give you 5% to see this easter egg
|
||||||
|
if (num<0.05) {
|
||||||
|
nasal::parse::easter_egg();
|
||||||
|
}
|
||||||
|
|
||||||
|
out << "nasal version " << __nasver__;
|
||||||
|
out << " " << nasal::util::get_platform();
|
||||||
|
out << " " << nasal::util::get_arch();
|
||||||
|
out << " (" << __DATE__ << " " << __TIME__ << ")\n";
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& nasal_format_version(std::ostream& out) {
|
||||||
|
out << "nasal-format version " << __nasver__ << "-beta";
|
||||||
|
out << " " << nasal::util::get_platform();
|
||||||
|
out << " " << nasal::util::get_arch();
|
||||||
|
out << " (" << __DATE__ << " " << __TIME__ << ")\n";
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -69,5 +69,10 @@ const std::unordered_map<std::string, option> cli_options = {
|
||||||
cli_config parse(const std::vector<std::string>&);
|
cli_config parse(const std::vector<std::string>&);
|
||||||
|
|
||||||
std::ostream& help(std::ostream&);
|
std::ostream& help(std::ostream&);
|
||||||
|
std::ostream& nasal_format_help(std::ostream&);
|
||||||
|
|
||||||
|
std::ostream& logo(std::ostream&);
|
||||||
|
std::ostream& version(std::ostream&);
|
||||||
|
std::ostream& nasal_format_version(std::ostream&);
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
#include "nasal.h"
|
||||||
|
#include "nasal_lexer.h"
|
||||||
|
#include "nasal_ast.h"
|
||||||
|
#include "nasal_parse.h"
|
||||||
|
#include "util/util.h"
|
||||||
|
#include "cli/cli.h"
|
||||||
|
#include "ast_format.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
[[noreturn]]
|
||||||
|
void err() {
|
||||||
|
std::cerr << "invalid argument(s), use <nasal-format -h> to get help.\n";
|
||||||
|
std::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void execute(const nasal::cli::cli_config& config) {
|
||||||
|
nasal::lexer lex;
|
||||||
|
nasal::parse parse;
|
||||||
|
|
||||||
|
// lexer scans file to get tokens
|
||||||
|
lex.scan(config.input_file_path).chkerr();
|
||||||
|
|
||||||
|
// parser gets lexer's token list to compile
|
||||||
|
parse.compile(lex).chkerr();
|
||||||
|
|
||||||
|
nasal::ast_format("nasal-format-out.nas").do_format(parse.tree());
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(i32 argc, const char* argv[]) {
|
||||||
|
// output version info
|
||||||
|
if (argc <= 1) {
|
||||||
|
err();
|
||||||
|
} else if (argc > 2) {
|
||||||
|
err();
|
||||||
|
}
|
||||||
|
|
||||||
|
// the first argument is the executable itself, ignore it
|
||||||
|
const auto config = nasal::cli::parse({argv+1, argv+argc});
|
||||||
|
|
||||||
|
// run directly or show help
|
||||||
|
if (argc == 2) {
|
||||||
|
if (config.has(nasal::cli::option::cli_help)) {
|
||||||
|
std::clog << nasal::cli::nasal_format_help;
|
||||||
|
} else if (config.has(nasal::cli::option::cli_version)) {
|
||||||
|
std::clog << nasal::cli::nasal_format_version;
|
||||||
|
} else if (config.input_file_path.size()) {
|
||||||
|
execute(config);
|
||||||
|
} else {
|
||||||
|
err();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
55
src/main.cpp
55
src/main.cpp
|
@ -18,55 +18,8 @@
|
||||||
#include "repl/repl.h"
|
#include "repl/repl.h"
|
||||||
#include "cli/cli.h"
|
#include "cli/cli.h"
|
||||||
|
|
||||||
#include <thread>
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
std::ostream& logo(std::ostream& out) {
|
|
||||||
out
|
|
||||||
<< "\n"
|
|
||||||
<< " __ _\n"
|
|
||||||
<< " /\\ \\ \\__ _ ___ __ _| |\n"
|
|
||||||
<< " / \\/ / _` / __|/ _` | |\n"
|
|
||||||
<< " / /\\ / (_| \\__ \\ (_| | |\n"
|
|
||||||
<< " \\_\\ \\/ \\__,_|___/\\__,_|_|\n"
|
|
||||||
<< "\n"
|
|
||||||
<< "ver : " << __nasver__
|
|
||||||
<< " " << nasal::util::get_platform()
|
|
||||||
<< " " << nasal::util::get_arch()
|
|
||||||
<< " (" << __DATE__ << " " << __TIME__ << ")\n"
|
|
||||||
<< "std : c++ " << __cplusplus << "\n"
|
|
||||||
<< "core : " << std::thread::hardware_concurrency() << " core(s)\n"
|
|
||||||
<< "repo : https://github.com/ValKmjolnir/Nasal-Interpreter\n"
|
|
||||||
<< "repo : https://gitee.com/valkmjolnir/Nasal-Interpreter\n"
|
|
||||||
<< "wiki : https://wiki.flightgear.org/Nasal_scripting_language\n"
|
|
||||||
<< "\n"
|
|
||||||
<< "presented by fgprc members:\n"
|
|
||||||
<< " - http://fgprc.org\n"
|
|
||||||
<< " - http://fgprc.org.cn\n"
|
|
||||||
<< "\n"
|
|
||||||
<< "input <nasal -h> to get help.\n\n";
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream& version(std::ostream& out) {
|
|
||||||
std::srand(static_cast<u32>(std::time(nullptr)));
|
|
||||||
|
|
||||||
f64 num = 0;
|
|
||||||
for(u32 i = 0; i<5; ++i) {
|
|
||||||
num = (num+rand())*(1.0/(RAND_MAX+1.0));
|
|
||||||
}
|
|
||||||
// give you 5% to see this easter egg
|
|
||||||
if (num<0.05) {
|
|
||||||
nasal::parse::easter_egg();
|
|
||||||
}
|
|
||||||
|
|
||||||
out << "nasal version " << __nasver__;
|
|
||||||
out << " " << nasal::util::get_platform();
|
|
||||||
out << " " << nasal::util::get_arch();
|
|
||||||
out << " (" << __DATE__ << " " << __TIME__ << ")\n";
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[noreturn]]
|
[[noreturn]]
|
||||||
void err() {
|
void err() {
|
||||||
std::cerr << "invalid argument(s), use <nasal -h> to get help.\n";
|
std::cerr << "invalid argument(s), use <nasal -h> to get help.\n";
|
||||||
|
@ -157,8 +110,8 @@ void execute(const nasal::cli::cli_config& config) {
|
||||||
|
|
||||||
i32 main(i32 argc, const char* argv[]) {
|
i32 main(i32 argc, const char* argv[]) {
|
||||||
// output version info
|
// output version info
|
||||||
if (argc<=1) {
|
if (argc <= 1) {
|
||||||
std::clog << logo;
|
std::clog << nasal::cli::logo;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,11 +119,11 @@ i32 main(i32 argc, const char* argv[]) {
|
||||||
const auto config = nasal::cli::parse({argv+1, argv+argc});
|
const auto config = nasal::cli::parse({argv+1, argv+argc});
|
||||||
|
|
||||||
// run directly or show help
|
// run directly or show help
|
||||||
if (argc==2) {
|
if (argc == 2) {
|
||||||
if (config.has(nasal::cli::option::cli_help)) {
|
if (config.has(nasal::cli::option::cli_help)) {
|
||||||
std::clog << nasal::cli::help;
|
std::clog << nasal::cli::help;
|
||||||
} else if (config.has(nasal::cli::option::cli_version)) {
|
} else if (config.has(nasal::cli::option::cli_version)) {
|
||||||
std::clog << version;
|
std::clog << nasal::cli::version;
|
||||||
} else if (config.has(nasal::cli::option::cli_repl_mode)) {
|
} else if (config.has(nasal::cli::option::cli_repl_mode)) {
|
||||||
auto repl = std::make_unique<nasal::repl::repl>();
|
auto repl = std::make_unique<nasal::repl::repl>();
|
||||||
repl->execute();
|
repl->execute();
|
||||||
|
|
Loading…
Reference in New Issue