From 43c229fc7233a9735e6c79d1b165c81256320d52 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Tue, 4 Jun 2024 00:49:01 +0800 Subject: [PATCH] :sparkles: add parse process for `??` & `?.` --- src/ast_dumper.cpp | 8 ++++++++ src/ast_dumper.h | 1 + src/ast_visitor.cpp | 4 ++++ src/ast_visitor.h | 1 + src/nasal_ast.cpp | 4 ++++ src/nasal_ast.h | 17 ++++++++++++++++- src/nasal_parse.cpp | 30 ++++++++++++++++++++++++++++-- src/nasal_parse.h | 2 ++ 8 files changed, 64 insertions(+), 3 deletions(-) diff --git a/src/ast_dumper.cpp b/src/ast_dumper.cpp index 03fbb71..0690068 100644 --- a/src/ast_dumper.cpp +++ b/src/ast_dumper.cpp @@ -185,6 +185,7 @@ bool ast_dumper::visit_binary_operator(binary_operator* node) { case binary_operator::binary_type::leq: std::cout << "<="; break; case binary_operator::binary_type::condition_and: std::cout << "and"; break; case binary_operator::binary_type::condition_or: std::cout << "or"; break; + case binary_operator::binary_type::nullchain: std::cout << "??"; break; } std::cout << "\"" << format_location(node); push_indent(); @@ -241,6 +242,13 @@ bool ast_dumper::visit_call_hash(call_hash* node) { return true; } +bool ast_dumper::visit_null_access(null_access* node) { + dump_indent(); + std::cout << "null_access " << node->get_field(); + std::cout << format_location(node); + return true; +} + bool ast_dumper::visit_call_vector(call_vector* node) { dump_indent(); std::cout << "call_vector"; diff --git a/src/ast_dumper.h b/src/ast_dumper.h index 2af89fd..1586d0b 100644 --- a/src/ast_dumper.h +++ b/src/ast_dumper.h @@ -70,6 +70,7 @@ public: 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; diff --git a/src/ast_visitor.cpp b/src/ast_visitor.cpp index f438b4b..dacd80b 100644 --- a/src/ast_visitor.cpp +++ b/src/ast_visitor.cpp @@ -116,6 +116,10 @@ bool ast_visitor::visit_call_hash(call_hash* node) { return true; } +bool ast_visitor::visit_null_access(null_access* node) { + return true; +} + bool ast_visitor::visit_call_vector(call_vector* node) { for(auto i : node->get_slices()) { i->accept(this); diff --git a/src/ast_visitor.h b/src/ast_visitor.h index 4235541..e6a5abd 100644 --- a/src/ast_visitor.h +++ b/src/ast_visitor.h @@ -26,6 +26,7 @@ public: virtual bool visit_unary_operator(unary_operator*); virtual bool visit_call_expr(call_expr*); virtual bool visit_call_hash(call_hash*); + virtual bool visit_null_access(null_access*); virtual bool visit_call_vector(call_vector*); virtual bool visit_call_function(call_function*); virtual bool visit_slice_vector(slice_vector*); diff --git a/src/nasal_ast.cpp b/src/nasal_ast.cpp index b1c27e1..2ab1d62 100644 --- a/src/nasal_ast.cpp +++ b/src/nasal_ast.cpp @@ -173,6 +173,10 @@ void call_hash::accept(ast_visitor* visitor) { visitor->visit_call_hash(this); } +void null_access::accept(ast_visitor* visitor) { + visitor->visit_null_access(this); +} + call_vector::~call_vector() { for(auto i : calls) { delete i; diff --git a/src/nasal_ast.h b/src/nasal_ast.h index 3913ff9..f0b885b 100644 --- a/src/nasal_ast.h +++ b/src/nasal_ast.h @@ -23,6 +23,7 @@ enum class expr_type { ast_pair, // pair of key and value in hashmap ast_call, // mark a sub-tree of calling an identifier ast_callh, // id.name + ast_nullaccess, // id?.name ast_callv, // id[index] ast_callf, // id() ast_subvec, // id[index:index] @@ -302,7 +303,8 @@ public: bitwise_xor, bitwise_and, condition_and, - condition_or + condition_or, + nullchain }; private: @@ -389,6 +391,19 @@ public: void accept(ast_visitor*) override; }; +class null_access: public call { +private: + std::string field; + +public: + null_access(const span& location, const std::string& name): + call(location, expr_type::ast_nullaccess), + field(name) {} + ~null_access() override = default; + const std::string& get_field() const {return field;} + void accept(ast_visitor*) override; +}; + class call_vector: public call { private: std::vector calls; diff --git a/src/nasal_parse.cpp b/src/nasal_parse.cpp index 5b8ec1a..f43e4d2 100644 --- a/src/nasal_parse.cpp +++ b/src/nasal_parse.cpp @@ -98,7 +98,8 @@ bool parse::lookahead(tok type) { } bool parse::is_call(tok type) { - return type==tok::tk_lcurve || type==tok::tk_lbracket || type==tok::tk_dot; + return type==tok::tk_lcurve || type==tok::tk_lbracket || + type==tok::tk_dot || type==tok::tk_quesdot; } bool parse::check_comma(const tok* panic_set) { @@ -568,7 +569,7 @@ expr* parse::and_expr() { } expr* parse::cmp_expr() { - auto node = additive_expr(); + auto node = null_chain_expr(); while(tok::tk_cmpeq<=toks[ptr].type && toks[ptr].type<=tok::tk_geq) { auto tmp = new binary_operator(toks[ptr].loc); switch(toks[ptr].type) { @@ -582,6 +583,21 @@ expr* parse::cmp_expr() { } tmp->set_left(node); match(toks[ptr].type); + tmp->set_right(null_chain_expr()); + update_location(tmp); + node = tmp; + } + update_location(node); + return node; +} + +expr* parse::null_chain_expr() { + auto node = additive_expr(); + while(lookahead(tok::tk_quesques)) { + auto tmp = new binary_operator(toks[ptr].loc); + tmp->set_operator_type(binary_operator::binary_type::nullchain); + tmp->set_left(node); + match(tok::tk_quesques); tmp->set_right(additive_expr()); update_location(tmp); node = tmp; @@ -722,6 +738,7 @@ call* parse::call_scalar() { case tok::tk_lcurve: return callf(); break; case tok::tk_lbracket: return callv(); break; case tok::tk_dot: return callh(); break; + case tok::tk_quesdot: return null_access_call(); break; default: break; } // unreachable @@ -737,6 +754,15 @@ call_hash* parse::callh() { return node; } +null_access* parse::null_access_call() { + const auto& begin_loc = toks[ptr].loc; + match(tok::tk_quesdot); + auto node = new null_access(begin_loc, toks[ptr].str); + update_location(node); + match(tok::tk_id, "expected hashmap key"); // get key + return node; +} + call_vector* parse::callv() { // panic set for this token is not ',' // this is the FIRST set of subvec diff --git a/src/nasal_parse.h b/src/nasal_parse.h index 612585b..f589d63 100644 --- a/src/nasal_parse.h +++ b/src/nasal_parse.h @@ -119,12 +119,14 @@ private: expr* or_expr(); expr* and_expr(); expr* cmp_expr(); + expr* null_chain_expr(); expr* additive_expr(); expr* multive_expr(); unary_operator* unary(); expr* scalar(); call* call_scalar(); call_hash* callh(); + null_access* null_access_call(); call_vector* callv(); call_function* callf(); slice_vector* subvec();