diff --git a/athena/README.md b/athena/README.md index c846159..349cb6d 100644 --- a/athena/README.md +++ b/athena/README.md @@ -20,7 +20,7 @@ Both classes live in `namespace athena`, are declared in the same header * 1.The execution process of the entire program is determined by each statement, with each statement ending with a semicolon ";". -* 2.The format of a statement must be constructed as follows: {ID} = {Expression}, where ID is understood as a variable name and Expression is an expression. Of course, you can also use just an expression without an ID, and it is still valid. +* 2.The format of a statement must be constructed as follows: {ID} = {Expression}, where ID is understood as a variable name and Expression is an expression. Of course, you can also use just an expression without an ID, and it is still valid. You can also use `let` to declare a constant variable: `let {ID} = {Expression}`. A `let`-declared variable cannot be reassigned later (including inside `when` branches). Attempting to reassign a `let` variable or redeclare an existing variable with `let` will result in a compile-time error. * 3.In addition to supporting various operations, expressions also support several types of special syntax. Function syntax: {function_name}({arg1}, {arg2}, ...). It also supports switch statements and if statements. Following the principle of simplicity, the syntax for switch and if statements is similar to function syntax: if({condition}, {true_expression}, {false_expression}), switch({case1}, {value1}, {case2}, {value2}..., {default_value}). diff --git a/athena/ast_builder.cc b/athena/ast_builder.cc index f593f71..81a9440 100644 --- a/athena/ast_builder.cc +++ b/athena/ast_builder.cc @@ -36,7 +36,7 @@ Status ProgramAstBuilder::BuildExpression(const std::string& code, std::unique_p } Status ProgramAstBuilder::BuildPipeline(const std::string& code, std::unique_ptr* result) { - std::vector names; + std::vector var_infos; std::vector> args; statements_.clear(); var2index_.clear(); @@ -51,13 +51,13 @@ Status ProgramAstBuilder::BuildPipeline(const std::string& code, std::unique_ptr if (!custom_error_message_.empty()) { return Status::ParseError(custom_error_message_); } - names.reserve(statements_.size()); + var_infos.reserve(statements_.size()); args.reserve(statements_.size()); for (auto& statement : statements_) { - names.emplace_back(std::move(statement.var_name)); + var_infos.emplace_back(std::move(statement.var_name), statement.is_const); args.emplace_back(std::move(statement.expression)); } - auto root = std::unique_ptr(new NoOPNode(std::move(names), std::move(args))); + auto root = std::unique_ptr(new NoOPNode(std::move(var_infos), std::move(args))); *result = std::move(root); return Status::OK(); } @@ -102,15 +102,15 @@ void ProgramAstBuilder::EnterBlock() { } std::unique_ptr ProgramAstBuilder::LeaveBlock() { - std::vector names; + std::vector var_infos; std::vector> args; - names.reserve(statements_.size()); + var_infos.reserve(statements_.size()); args.reserve(statements_.size()); for (auto& stmt : statements_) { - names.emplace_back(std::move(stmt.var_name)); + var_infos.emplace_back(std::move(stmt.var_name), stmt.is_const); args.emplace_back(std::move(stmt.expression)); } - auto block_node = std::unique_ptr(new NoOPNode(std::move(names), std::move(args))); + auto block_node = std::unique_ptr(new NoOPNode(std::move(var_infos), std::move(args))); auto& outer = block_stack_.back(); statements_ = std::move(outer.statements); diff --git a/athena/ast_builder.h b/athena/ast_builder.h index 9a773da..8792579 100644 --- a/athena/ast_builder.h +++ b/athena/ast_builder.h @@ -25,6 +25,8 @@ struct Statement { Statement() = default; Statement(std::string vname, std::unique_ptr exp) : var_name(std::move(vname)), expression(std::move(exp)) {} + Statement(std::string vname, std::unique_ptr exp, bool is_const_var) + : var_name(std::move(vname)), expression(std::move(exp)), is_const(is_const_var) {} explicit Statement(std::unique_ptr exp) : expression(std::move(exp)) {} ~Statement() = default; Statement(Statement&& s) = default; @@ -32,6 +34,7 @@ struct Statement { std::string var_name; std::unique_ptr expression; + bool is_const{false}; }; class ProgramAstBuilder { diff --git a/athena/parser.cc b/athena/parser.cc index 2156511..033d5f1 100644 --- a/athena/parser.cc +++ b/athena/parser.cc @@ -1117,7 +1117,7 @@ namespace athena { switch (yyn) { case 2: // program: statement -#line 180 "parser.yy" +#line 181 "parser.yy" { builder.AddStatement(std::move(yystack_[0].value.as < Statement > ())); yylhs.value.as < void* > () = nullptr; @@ -1126,7 +1126,7 @@ namespace athena { break; case 3: // program: program statement -#line 184 "parser.yy" +#line 185 "parser.yy" { builder.AddStatement(std::move(yystack_[0].value.as < Statement > ())); yylhs.value.as < void* > () = nullptr; @@ -1135,563 +1135,569 @@ namespace athena { break; case 4: // statement: "identifier" "=" expr ";" -#line 190 "parser.yy" +#line 191 "parser.yy" { yylhs.value.as < Statement > () = Statement(std::move(yystack_[3].value.as < std::string > ()), std::move(yystack_[1].value.as < std::unique_ptr > ())); } #line 1141 "parser.cc" break; - case 5: // statement: expr ";" -#line 191 "parser.yy" - { yylhs.value.as < Statement > () = Statement(std::move(yystack_[1].value.as < std::unique_ptr > ())); } + case 5: // statement: "let" "identifier" "=" expr ";" +#line 192 "parser.yy" + { yylhs.value.as < Statement > () = Statement(std::move(yystack_[3].value.as < std::string > ()), std::move(yystack_[1].value.as < std::unique_ptr > ()), true); } #line 1147 "parser.cc" break; - case 6: // statement: when_block -#line 192 "parser.yy" - { yylhs.value.as < Statement > () = Statement(std::move(yystack_[0].value.as < std::unique_ptr > ())); } + case 6: // statement: expr ";" +#line 193 "parser.yy" + { yylhs.value.as < Statement > () = Statement(std::move(yystack_[1].value.as < std::unique_ptr > ())); } #line 1153 "parser.cc" break; - case 7: // expr: term + case 7: // statement: when_block #line 194 "parser.yy" - { yylhs.value.as < std::unique_ptr > () = std::move(yystack_[0].value.as < std::unique_ptr > ());} + { yylhs.value.as < Statement > () = Statement(std::move(yystack_[0].value.as < std::unique_ptr > ())); } #line 1159 "parser.cc" break; - case 8: // term: literal -#line 198 "parser.yy" - { yylhs.value.as < std::unique_ptr > () = std::move(yystack_[0].value.as < std::unique_ptr > ()); } + case 8: // expr: term +#line 196 "parser.yy" + { yylhs.value.as < std::unique_ptr > () = std::move(yystack_[0].value.as < std::unique_ptr > ());} #line 1165 "parser.cc" break; - case 9: // term: function -#line 199 "parser.yy" - { yylhs.value.as < std::unique_ptr > () = std::move(yystack_[0].value.as < std::unique_ptr > ()); } + case 9: // term: literal +#line 200 "parser.yy" + { yylhs.value.as < std::unique_ptr > () = std::move(yystack_[0].value.as < std::unique_ptr > ()); } #line 1171 "parser.cc" break; - case 10: // term: boolean -#line 200 "parser.yy" - { yylhs.value.as < std::unique_ptr > () = std::move(yystack_[0].value.as < std::unique_ptr > ()); } + case 10: // term: function +#line 201 "parser.yy" + { yylhs.value.as < std::unique_ptr > () = std::move(yystack_[0].value.as < std::unique_ptr > ()); } #line 1177 "parser.cc" break; - case 11: // term: "(" term ")" -#line 201 "parser.yy" - { yylhs.value.as < std::unique_ptr > () = std::move(yystack_[1].value.as < std::unique_ptr > ()); } + case 11: // term: boolean +#line 202 "parser.yy" + { yylhs.value.as < std::unique_ptr > () = std::move(yystack_[0].value.as < std::unique_ptr > ()); } #line 1183 "parser.cc" break; - case 12: // term: "identifier" -#line 202 "parser.yy" + case 12: // term: "(" term ")" +#line 203 "parser.yy" + { yylhs.value.as < std::unique_ptr > () = std::move(yystack_[1].value.as < std::unique_ptr > ()); } +#line 1189 "parser.cc" + break; + + case 13: // term: "identifier" +#line 204 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(builder.MakeRefNode(std::move(yystack_[0].value.as < std::string > ()), static_cast(yylhs.location.begin.line), static_cast(yylhs.location.begin.column), static_cast(yylhs.location.end.line), static_cast(yylhs.location.end.column)), yylhs.location, builder.GetSourceCode()); } -#line 1191 "parser.cc" +#line 1197 "parser.cc" break; - case 13: // term: "entry_arg" -#line 205 "parser.yy" + case 14: // term: "entry_arg" +#line 207 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::unique_ptr(new jitfusion::EntryArgumentNode), yylhs.location, builder.GetSourceCode()); } -#line 1197 "parser.cc" +#line 1203 "parser.cc" break; - case 14: // term: "exec_ctx" -#line 206 "parser.yy" + case 15: // term: "exec_ctx" +#line 208 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::unique_ptr(new jitfusion::ExecContextNode), yylhs.location, builder.GetSourceCode()); } -#line 1203 "parser.cc" +#line 1209 "parser.cc" break; - case 15: // term: "output" -#line 207 "parser.yy" + case 16: // term: "output" +#line 209 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::unique_ptr(new jitfusion::OutputNode), yylhs.location, builder.GetSourceCode()); } -#line 1209 "parser.cc" +#line 1215 "parser.cc" break; - case 16: // literal: "int8" -#line 211 "parser.yy" + case 17: // literal: "int8" +#line 213 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(yystack_[0].value.as < int8_t > ()), yylhs.location, builder.GetSourceCode()); } -#line 1215 "parser.cc" +#line 1221 "parser.cc" break; - case 17: // literal: "int16" -#line 212 "parser.yy" + case 18: // literal: "int16" +#line 214 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(yystack_[0].value.as < int16_t > ()), yylhs.location, builder.GetSourceCode()); } -#line 1221 "parser.cc" +#line 1227 "parser.cc" break; - case 18: // literal: "int32" -#line 213 "parser.yy" + case 19: // literal: "int32" +#line 215 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(yystack_[0].value.as < int32_t > ()), yylhs.location, builder.GetSourceCode()); } -#line 1227 "parser.cc" +#line 1233 "parser.cc" break; - case 19: // literal: "int64" -#line 214 "parser.yy" + case 20: // literal: "int64" +#line 216 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(yystack_[0].value.as < int64_t > ()), yylhs.location, builder.GetSourceCode()); } -#line 1233 "parser.cc" +#line 1239 "parser.cc" break; - case 20: // literal: "uint8" -#line 215 "parser.yy" + case 21: // literal: "uint8" +#line 217 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(yystack_[0].value.as < uint8_t > ()), yylhs.location, builder.GetSourceCode()); } -#line 1239 "parser.cc" +#line 1245 "parser.cc" break; - case 21: // literal: "uint16" -#line 216 "parser.yy" + case 22: // literal: "uint16" +#line 218 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(yystack_[0].value.as < uint16_t > ()), yylhs.location, builder.GetSourceCode()); } -#line 1245 "parser.cc" +#line 1251 "parser.cc" break; - case 22: // literal: "uint32" -#line 217 "parser.yy" + case 23: // literal: "uint32" +#line 219 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(yystack_[0].value.as < uint32_t > ()), yylhs.location, builder.GetSourceCode()); } -#line 1251 "parser.cc" +#line 1257 "parser.cc" break; - case 23: // literal: "uint64" -#line 218 "parser.yy" + case 24: // literal: "uint64" +#line 220 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(yystack_[0].value.as < uint64_t > ()), yylhs.location, builder.GetSourceCode()); } -#line 1257 "parser.cc" +#line 1263 "parser.cc" break; - case 24: // literal: "float" -#line 219 "parser.yy" + case 25: // literal: "float" +#line 221 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(yystack_[0].value.as < float > ()), yylhs.location, builder.GetSourceCode()); } -#line 1263 "parser.cc" +#line 1269 "parser.cc" break; - case 25: // literal: "double" -#line 220 "parser.yy" + case 26: // literal: "double" +#line 222 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(yystack_[0].value.as < double > ()), yylhs.location, builder.GetSourceCode()); } -#line 1269 "parser.cc" +#line 1275 "parser.cc" break; - case 26: // literal: "string" -#line 221 "parser.yy" + case 27: // literal: "string" +#line 223 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(yystack_[0].value.as < std::string > ()), yylhs.location, builder.GetSourceCode()); } -#line 1275 "parser.cc" +#line 1281 "parser.cc" break; - case 27: // literal: list -#line 222 "parser.yy" + case 28: // literal: list +#line 224 "parser.yy" { yylhs.value.as < std::unique_ptr > () = std::move(yystack_[0].value.as < std::unique_ptr > ()); } -#line 1281 "parser.cc" +#line 1287 "parser.cc" break; - case 28: // literal: "true" -#line 223 "parser.yy" + case 29: // literal: "true" +#line 225 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(uint8_t(1)), yylhs.location, builder.GetSourceCode()); } -#line 1287 "parser.cc" +#line 1293 "parser.cc" break; - case 29: // literal: "false" -#line 224 "parser.yy" + case 30: // literal: "false" +#line 226 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(uint8_t(0)), yylhs.location, builder.GetSourceCode()); } -#line 1293 "parser.cc" +#line 1299 "parser.cc" break; - case 30: // list: "[" i8_list "]" -#line 228 "parser.yy" + case 31: // list: "[" i8_list "]" +#line 230 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(yystack_[1].value.as < std::vector > ()), yylhs.location, builder.GetSourceCode()); } -#line 1299 "parser.cc" +#line 1305 "parser.cc" break; - case 31: // list: "[" i16_list "]" -#line 229 "parser.yy" + case 32: // list: "[" i16_list "]" +#line 231 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(yystack_[1].value.as < std::vector > ()), yylhs.location, builder.GetSourceCode()); } -#line 1305 "parser.cc" +#line 1311 "parser.cc" break; - case 32: // list: "[" i32_list "]" -#line 230 "parser.yy" + case 33: // list: "[" i32_list "]" +#line 232 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(yystack_[1].value.as < std::vector > ()), yylhs.location, builder.GetSourceCode()); } -#line 1311 "parser.cc" +#line 1317 "parser.cc" break; - case 33: // list: "[" i64_list "]" -#line 231 "parser.yy" + case 34: // list: "[" i64_list "]" +#line 233 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(yystack_[1].value.as < std::vector > ()), yylhs.location, builder.GetSourceCode()); } -#line 1317 "parser.cc" +#line 1323 "parser.cc" break; - case 34: // list: "[" u8_list "]" -#line 232 "parser.yy" + case 35: // list: "[" u8_list "]" +#line 234 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(yystack_[1].value.as < std::vector > ()), yylhs.location, builder.GetSourceCode()); } -#line 1323 "parser.cc" +#line 1329 "parser.cc" break; - case 35: // list: "[" u16_list "]" -#line 233 "parser.yy" + case 36: // list: "[" u16_list "]" +#line 235 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(yystack_[1].value.as < std::vector > ()), yylhs.location, builder.GetSourceCode()); } -#line 1329 "parser.cc" +#line 1335 "parser.cc" break; - case 36: // list: "[" u32_list "]" -#line 234 "parser.yy" + case 37: // list: "[" u32_list "]" +#line 236 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(yystack_[1].value.as < std::vector > ()), yylhs.location, builder.GetSourceCode()); } -#line 1335 "parser.cc" +#line 1341 "parser.cc" break; - case 37: // list: "[" u64_list "]" -#line 235 "parser.yy" + case 38: // list: "[" u64_list "]" +#line 237 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(yystack_[1].value.as < std::vector > ()), yylhs.location, builder.GetSourceCode()); } -#line 1341 "parser.cc" +#line 1347 "parser.cc" break; - case 38: // list: "[" f32_list "]" -#line 236 "parser.yy" + case 39: // list: "[" f32_list "]" +#line 238 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(yystack_[1].value.as < std::vector > ()), yylhs.location, builder.GetSourceCode()); } -#line 1347 "parser.cc" +#line 1353 "parser.cc" break; - case 39: // list: "[" f64_list "]" -#line 237 "parser.yy" + case 40: // list: "[" f64_list "]" +#line 239 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(yystack_[1].value.as < std::vector > ()), yylhs.location, builder.GetSourceCode()); } -#line 1353 "parser.cc" +#line 1359 "parser.cc" break; - case 40: // list: "[" string_list "]" -#line 238 "parser.yy" + case 41: // list: "[" string_list "]" +#line 240 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(yystack_[1].value.as < std::vector > ()), yylhs.location, builder.GetSourceCode()); } -#line 1359 "parser.cc" +#line 1365 "parser.cc" break; - case 41: // i8_list: "int8" -#line 242 "parser.yy" + case 42: // i8_list: "int8" +#line 244 "parser.yy" { yylhs.value.as < std::vector > () = std::vector{yystack_[0].value.as < int8_t > ()}; } -#line 1365 "parser.cc" +#line 1371 "parser.cc" break; - case 42: // i8_list: i8_list "," "int8" -#line 243 "parser.yy" + case 43: // i8_list: i8_list "," "int8" +#line 245 "parser.yy" { yystack_[2].value.as < std::vector > ().emplace_back(std::move(yystack_[0].value.as < int8_t > ())); yylhs.value.as < std::vector > () = std::move(yystack_[2].value.as < std::vector > ()); } -#line 1374 "parser.cc" +#line 1380 "parser.cc" break; - case 43: // i16_list: "int16" -#line 250 "parser.yy" + case 44: // i16_list: "int16" +#line 252 "parser.yy" { yylhs.value.as < std::vector > () = std::vector{yystack_[0].value.as < int16_t > ()}; } -#line 1380 "parser.cc" +#line 1386 "parser.cc" break; - case 44: // i16_list: i16_list "," "int16" -#line 251 "parser.yy" + case 45: // i16_list: i16_list "," "int16" +#line 253 "parser.yy" { yystack_[2].value.as < std::vector > ().emplace_back(std::move(yystack_[0].value.as < int16_t > ())); yylhs.value.as < std::vector > () = std::move(yystack_[2].value.as < std::vector > ()); } -#line 1389 "parser.cc" +#line 1395 "parser.cc" break; - case 45: // i32_list: "int32" -#line 258 "parser.yy" + case 46: // i32_list: "int32" +#line 260 "parser.yy" { yylhs.value.as < std::vector > () = std::vector{yystack_[0].value.as < int32_t > ()}; } -#line 1395 "parser.cc" +#line 1401 "parser.cc" break; - case 46: // i32_list: i32_list "," "int32" -#line 259 "parser.yy" + case 47: // i32_list: i32_list "," "int32" +#line 261 "parser.yy" { yystack_[2].value.as < std::vector > ().emplace_back(std::move(yystack_[0].value.as < int32_t > ())); yylhs.value.as < std::vector > () = std::move(yystack_[2].value.as < std::vector > ()); } -#line 1404 "parser.cc" +#line 1410 "parser.cc" break; - case 47: // i64_list: "int64" -#line 266 "parser.yy" + case 48: // i64_list: "int64" +#line 268 "parser.yy" { yylhs.value.as < std::vector > () = std::vector{yystack_[0].value.as < int64_t > ()}; } -#line 1410 "parser.cc" +#line 1416 "parser.cc" break; - case 48: // i64_list: i64_list "," "int64" -#line 267 "parser.yy" + case 49: // i64_list: i64_list "," "int64" +#line 269 "parser.yy" { yystack_[2].value.as < std::vector > ().emplace_back(std::move(yystack_[0].value.as < int64_t > ())); yylhs.value.as < std::vector > () = std::move(yystack_[2].value.as < std::vector > ()); } -#line 1419 "parser.cc" +#line 1425 "parser.cc" break; - case 49: // u8_list: "uint8" -#line 274 "parser.yy" + case 50: // u8_list: "uint8" +#line 276 "parser.yy" { yylhs.value.as < std::vector > () = std::vector{yystack_[0].value.as < uint8_t > ()}; } -#line 1425 "parser.cc" +#line 1431 "parser.cc" break; - case 50: // u8_list: u8_list "," "uint8" -#line 275 "parser.yy" + case 51: // u8_list: u8_list "," "uint8" +#line 277 "parser.yy" { yystack_[2].value.as < std::vector > ().emplace_back(std::move(yystack_[0].value.as < uint8_t > ())); yylhs.value.as < std::vector > () = std::move(yystack_[2].value.as < std::vector > ()); } -#line 1434 "parser.cc" +#line 1440 "parser.cc" break; - case 51: // u16_list: "uint16" -#line 282 "parser.yy" + case 52: // u16_list: "uint16" +#line 284 "parser.yy" { yylhs.value.as < std::vector > () = std::vector{yystack_[0].value.as < uint16_t > ()}; } -#line 1440 "parser.cc" +#line 1446 "parser.cc" break; - case 52: // u16_list: u16_list "," "uint16" -#line 283 "parser.yy" + case 53: // u16_list: u16_list "," "uint16" +#line 285 "parser.yy" { yystack_[2].value.as < std::vector > ().emplace_back(std::move(yystack_[0].value.as < uint16_t > ())); yylhs.value.as < std::vector > () = std::move(yystack_[2].value.as < std::vector > ()); } -#line 1449 "parser.cc" +#line 1455 "parser.cc" break; - case 53: // u32_list: "uint32" -#line 290 "parser.yy" + case 54: // u32_list: "uint32" +#line 292 "parser.yy" { yylhs.value.as < std::vector > () = std::vector{yystack_[0].value.as < uint32_t > ()}; } -#line 1455 "parser.cc" +#line 1461 "parser.cc" break; - case 54: // u32_list: u32_list "," "uint32" -#line 291 "parser.yy" + case 55: // u32_list: u32_list "," "uint32" +#line 293 "parser.yy" { yystack_[2].value.as < std::vector > ().emplace_back(std::move(yystack_[0].value.as < uint32_t > ())); yylhs.value.as < std::vector > () = std::move(yystack_[2].value.as < std::vector > ()); } -#line 1464 "parser.cc" +#line 1470 "parser.cc" break; - case 55: // u64_list: "uint64" -#line 298 "parser.yy" + case 56: // u64_list: "uint64" +#line 300 "parser.yy" { yylhs.value.as < std::vector > () = std::vector{yystack_[0].value.as < uint64_t > ()}; } -#line 1470 "parser.cc" +#line 1476 "parser.cc" break; - case 56: // u64_list: u64_list "," "uint64" -#line 299 "parser.yy" + case 57: // u64_list: u64_list "," "uint64" +#line 301 "parser.yy" { yystack_[2].value.as < std::vector > ().emplace_back(std::move(yystack_[0].value.as < uint64_t > ())); yylhs.value.as < std::vector > () = std::move(yystack_[2].value.as < std::vector > ()); } -#line 1479 "parser.cc" +#line 1485 "parser.cc" break; - case 57: // f32_list: "float" -#line 306 "parser.yy" + case 58: // f32_list: "float" +#line 308 "parser.yy" { yylhs.value.as < std::vector > () = std::vector{yystack_[0].value.as < float > ()}; } -#line 1485 "parser.cc" +#line 1491 "parser.cc" break; - case 58: // f32_list: f32_list "," "float" -#line 307 "parser.yy" + case 59: // f32_list: f32_list "," "float" +#line 309 "parser.yy" { yystack_[2].value.as < std::vector > ().emplace_back(std::move(yystack_[0].value.as < float > ())); yylhs.value.as < std::vector > () = std::move(yystack_[2].value.as < std::vector > ()); } -#line 1494 "parser.cc" +#line 1500 "parser.cc" break; - case 59: // f64_list: "double" -#line 314 "parser.yy" + case 60: // f64_list: "double" +#line 316 "parser.yy" { yylhs.value.as < std::vector > () = std::vector{yystack_[0].value.as < double > ()}; } -#line 1500 "parser.cc" +#line 1506 "parser.cc" break; - case 60: // f64_list: f64_list "," "double" -#line 315 "parser.yy" + case 61: // f64_list: f64_list "," "double" +#line 317 "parser.yy" { yystack_[2].value.as < std::vector > ().emplace_back(std::move(yystack_[0].value.as < double > ())); yylhs.value.as < std::vector > () = std::move(yystack_[2].value.as < std::vector > ()); } -#line 1509 "parser.cc" +#line 1515 "parser.cc" break; - case 61: // string_list: "string" -#line 322 "parser.yy" + case 62: // string_list: "string" +#line 324 "parser.yy" { yylhs.value.as < std::vector > () = std::vector{yystack_[0].value.as < std::string > ()}; } -#line 1515 "parser.cc" +#line 1521 "parser.cc" break; - case 62: // string_list: string_list "," "string" -#line 323 "parser.yy" + case 63: // string_list: string_list "," "string" +#line 325 "parser.yy" { yystack_[2].value.as < std::vector > ().emplace_back(std::move(yystack_[0].value.as < std::string > ())); yylhs.value.as < std::vector > () = std::move(yystack_[2].value.as < std::vector > ()); } -#line 1524 "parser.cc" +#line 1530 "parser.cc" break; - case 63: // function: infix_function -#line 330 "parser.yy" + case 64: // function: infix_function +#line 332 "parser.yy" { yylhs.value.as < std::unique_ptr > () = std::move(yystack_[0].value.as < std::unique_ptr > ()); } -#line 1530 "parser.cc" +#line 1536 "parser.cc" break; - case 64: // function: named_function -#line 331 "parser.yy" + case 65: // function: named_function +#line 333 "parser.yy" { yylhs.value.as < std::unique_ptr > () = std::move(yystack_[0].value.as < std::unique_ptr > ()); } -#line 1536 "parser.cc" +#line 1542 "parser.cc" break; - case 65: // infix_function: "-" term -#line 336 "parser.yy" + case 66: // infix_function: "-" term +#line 338 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(jitfusion::UnaryOPType::kMinus, std::move(yystack_[0].value.as < std::unique_ptr > ())), yylhs.location, builder.GetSourceCode()); } -#line 1542 "parser.cc" +#line 1548 "parser.cc" break; - case 66: // infix_function: "not" term -#line 337 "parser.yy" + case 67: // infix_function: "not" term +#line 339 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(jitfusion::UnaryOPType::kNot, std::move(yystack_[0].value.as < std::unique_ptr > ())), yylhs.location, builder.GetSourceCode()); } -#line 1548 "parser.cc" +#line 1554 "parser.cc" break; - case 67: // infix_function: "+" term -#line 338 "parser.yy" + case 68: // infix_function: "+" term +#line 340 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(jitfusion::UnaryOPType::kPlus, std::move(yystack_[0].value.as < std::unique_ptr > ())), yylhs.location, builder.GetSourceCode()); } -#line 1554 "parser.cc" +#line 1560 "parser.cc" break; - case 68: // infix_function: "~" term -#line 339 "parser.yy" + case 69: // infix_function: "~" term +#line 341 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(jitfusion::UnaryOPType::kBitwiseNot, std::move(yystack_[0].value.as < std::unique_ptr > ())), yylhs.location, builder.GetSourceCode()); } -#line 1560 "parser.cc" +#line 1566 "parser.cc" break; - case 69: // infix_function: term "+" term -#line 340 "parser.yy" + case 70: // infix_function: term "+" term +#line 342 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(jitfusion::BinaryOPType::kAdd, std::move(yystack_[2].value.as < std::unique_ptr > ()), std::move(yystack_[0].value.as < std::unique_ptr > ())), yylhs.location, builder.GetSourceCode()); } -#line 1566 "parser.cc" +#line 1572 "parser.cc" break; - case 70: // infix_function: term "-" term -#line 341 "parser.yy" + case 71: // infix_function: term "-" term +#line 343 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(jitfusion::BinaryOPType::kSub, std::move(yystack_[2].value.as < std::unique_ptr > ()), std::move(yystack_[0].value.as < std::unique_ptr > ())), yylhs.location, builder.GetSourceCode()); } -#line 1572 "parser.cc" +#line 1578 "parser.cc" break; - case 71: // infix_function: term "*" term -#line 342 "parser.yy" + case 72: // infix_function: term "*" term +#line 344 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(jitfusion::BinaryOPType::kMul, std::move(yystack_[2].value.as < std::unique_ptr > ()), std::move(yystack_[0].value.as < std::unique_ptr > ())), yylhs.location, builder.GetSourceCode()); } -#line 1578 "parser.cc" +#line 1584 "parser.cc" break; - case 72: // infix_function: term "/" term -#line 343 "parser.yy" + case 73: // infix_function: term "/" term +#line 345 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(jitfusion::BinaryOPType::kDiv, std::move(yystack_[2].value.as < std::unique_ptr > ()), std::move(yystack_[0].value.as < std::unique_ptr > ())), yylhs.location, builder.GetSourceCode()); } -#line 1584 "parser.cc" +#line 1590 "parser.cc" break; - case 73: // infix_function: term "%" term -#line 344 "parser.yy" + case 74: // infix_function: term "%" term +#line 346 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(jitfusion::BinaryOPType::kMod, std::move(yystack_[2].value.as < std::unique_ptr > ()), std::move(yystack_[0].value.as < std::unique_ptr > ())), yylhs.location, builder.GetSourceCode()); } -#line 1590 "parser.cc" +#line 1596 "parser.cc" break; - case 74: // infix_function: term "&" term -#line 345 "parser.yy" + case 75: // infix_function: term "&" term +#line 347 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(jitfusion::BinaryOPType::kBitwiseAnd, std::move(yystack_[2].value.as < std::unique_ptr > ()), std::move(yystack_[0].value.as < std::unique_ptr > ())), yylhs.location, builder.GetSourceCode()); } -#line 1596 "parser.cc" +#line 1602 "parser.cc" break; - case 75: // infix_function: term "|" term -#line 346 "parser.yy" + case 76: // infix_function: term "|" term +#line 348 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(jitfusion::BinaryOPType::kBitwiseOr, std::move(yystack_[2].value.as < std::unique_ptr > ()), std::move(yystack_[0].value.as < std::unique_ptr > ())), yylhs.location, builder.GetSourceCode()); } -#line 1602 "parser.cc" +#line 1608 "parser.cc" break; - case 76: // infix_function: term "^" term -#line 347 "parser.yy" + case 77: // infix_function: term "^" term +#line 349 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(jitfusion::BinaryOPType::kBitwiseXor, std::move(yystack_[2].value.as < std::unique_ptr > ()), std::move(yystack_[0].value.as < std::unique_ptr > ())), yylhs.location, builder.GetSourceCode()); } -#line 1608 "parser.cc" +#line 1614 "parser.cc" break; - case 77: // infix_function: term "==" term -#line 348 "parser.yy" + case 78: // infix_function: term "==" term +#line 350 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(jitfusion::BinaryOPType::kEqual, std::move(yystack_[2].value.as < std::unique_ptr > ()), std::move(yystack_[0].value.as < std::unique_ptr > ())), yylhs.location, builder.GetSourceCode()); } -#line 1614 "parser.cc" +#line 1620 "parser.cc" break; - case 78: // infix_function: term "!=" term -#line 349 "parser.yy" + case 79: // infix_function: term "!=" term +#line 351 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(jitfusion::BinaryOPType::kNotEqual, std::move(yystack_[2].value.as < std::unique_ptr > ()), std::move(yystack_[0].value.as < std::unique_ptr > ())), yylhs.location, builder.GetSourceCode()); } -#line 1620 "parser.cc" +#line 1626 "parser.cc" break; - case 79: // infix_function: term ">" term -#line 350 "parser.yy" + case 80: // infix_function: term ">" term +#line 352 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(jitfusion::BinaryOPType::kLarge, std::move(yystack_[2].value.as < std::unique_ptr > ()), std::move(yystack_[0].value.as < std::unique_ptr > ())), yylhs.location, builder.GetSourceCode()); } -#line 1626 "parser.cc" +#line 1632 "parser.cc" break; - case 80: // infix_function: term ">=" term -#line 351 "parser.yy" + case 81: // infix_function: term ">=" term +#line 353 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(jitfusion::BinaryOPType::kLargeEqual, std::move(yystack_[2].value.as < std::unique_ptr > ()), std::move(yystack_[0].value.as < std::unique_ptr > ())), yylhs.location, builder.GetSourceCode()); } -#line 1632 "parser.cc" +#line 1638 "parser.cc" break; - case 81: // infix_function: term "<" term -#line 352 "parser.yy" + case 82: // infix_function: term "<" term +#line 354 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(jitfusion::BinaryOPType::kLess, std::move(yystack_[2].value.as < std::unique_ptr > ()), std::move(yystack_[0].value.as < std::unique_ptr > ())), yylhs.location, builder.GetSourceCode()); } -#line 1638 "parser.cc" +#line 1644 "parser.cc" break; - case 82: // infix_function: term "<=" term -#line 353 "parser.yy" + case 83: // infix_function: term "<=" term +#line 355 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(jitfusion::BinaryOPType::kLessEqual, std::move(yystack_[2].value.as < std::unique_ptr > ()), std::move(yystack_[0].value.as < std::unique_ptr > ())), yylhs.location, builder.GetSourceCode()); } -#line 1644 "parser.cc" +#line 1650 "parser.cc" break; - case 83: // infix_function: term "<<" term -#line 354 "parser.yy" + case 84: // infix_function: term "<<" term +#line 356 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(jitfusion::BinaryOPType::kBitwiseShiftLeft, std::move(yystack_[2].value.as < std::unique_ptr > ()), std::move(yystack_[0].value.as < std::unique_ptr > ())), yylhs.location, builder.GetSourceCode()); } -#line 1650 "parser.cc" +#line 1656 "parser.cc" break; - case 84: // infix_function: term ">>" term -#line 355 "parser.yy" + case 85: // infix_function: term ">>" term +#line 357 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(jitfusion::BinaryOPType::kBitwiseShiftRight, std::move(yystack_[2].value.as < std::unique_ptr > ()), std::move(yystack_[0].value.as < std::unique_ptr > ())), yylhs.location, builder.GetSourceCode()); } -#line 1656 "parser.cc" +#line 1662 "parser.cc" break; - case 85: // named_function: "if" "(" args ")" -#line 359 "parser.yy" + case 86: // named_function: "if" "(" args ")" +#line 361 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(std::move(yystack_[1].value.as < std::vector> > ())), yylhs.location, builder.GetSourceCode()); } -#line 1662 "parser.cc" +#line 1668 "parser.cc" break; - case 86: // named_function: "identifier" "(" args ")" -#line 360 "parser.yy" + case 87: // named_function: "identifier" "(" args ")" +#line 362 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(std::move(yystack_[3].value.as < std::string > ()), std::move(yystack_[1].value.as < std::vector> > ())), yylhs.location, builder.GetSourceCode()); } -#line 1668 "parser.cc" +#line 1674 "parser.cc" break; - case 87: // named_function: "identifier" "(" ")" -#line 361 "parser.yy" + case 88: // named_function: "identifier" "(" ")" +#line 363 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(std::move(yystack_[2].value.as < std::string > ()), std::vector>{}), yylhs.location, builder.GetSourceCode());} -#line 1674 "parser.cc" +#line 1680 "parser.cc" break; - case 88: // named_function: term "in" term -#line 362 "parser.yy" + case 89: // named_function: term "in" term +#line 364 "parser.yy" { auto node = std::make_unique("in", std::vector>()); node->AppendArgs(std::move(yystack_[2].value.as < std::unique_ptr > ())); node->AppendArgs(std::move(yystack_[0].value.as < std::unique_ptr > ())); yylhs.value.as < std::unique_ptr > () = WithLoc(std::move(node), yylhs.location, builder.GetSourceCode()); } -#line 1685 "parser.cc" +#line 1691 "parser.cc" break; - case 89: // named_function: "switch" "(" args ")" -#line 368 "parser.yy" + case 90: // named_function: "switch" "(" args ")" +#line 370 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(std::move(yystack_[1].value.as < std::vector> > ())), yylhs.location, builder.GetSourceCode()); } -#line 1691 "parser.cc" +#line 1697 "parser.cc" break; - case 90: // when_block: "when" expr "{" block "}" elif_chain -#line 372 "parser.yy" + case 91: // when_block: "when" expr "{" block "}" elif_chain +#line 374 "parser.yy" { if (builder.IsExpressionMode()) { error(yystack_[5].location, "when block is not allowed in expression mode"); @@ -1704,84 +1710,84 @@ namespace athena { args.insert(args.end(), std::make_move_iterator(yystack_[0].value.as < std::vector> > ().begin()), std::make_move_iterator(yystack_[0].value.as < std::vector> > ().end())); yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(std::move(args)), yylhs.location, builder.GetSourceCode()); } -#line 1708 "parser.cc" +#line 1714 "parser.cc" break; - case 91: // elif_chain: %empty -#line 387 "parser.yy" + case 92: // elif_chain: %empty +#line 389 "parser.yy" { yylhs.value.as < std::vector> > () = std::vector>{}; } -#line 1714 "parser.cc" +#line 1720 "parser.cc" break; - case 92: // elif_chain: elif_chain "elif" expr "{" block "}" -#line 388 "parser.yy" + case 93: // elif_chain: elif_chain "elif" expr "{" block "}" +#line 390 "parser.yy" { yylhs.value.as < std::vector> > () = std::move(yystack_[5].value.as < std::vector> > ()); yylhs.value.as < std::vector> > ().emplace_back(std::move(yystack_[3].value.as < std::unique_ptr > ())); yylhs.value.as < std::vector> > ().emplace_back(std::move(yystack_[1].value.as < std::unique_ptr > ())); } -#line 1724 "parser.cc" +#line 1730 "parser.cc" break; - case 93: // elif_chain: elif_chain "else" "{" block "}" -#line 393 "parser.yy" + case 94: // elif_chain: elif_chain "else" "{" block "}" +#line 395 "parser.yy" { yylhs.value.as < std::vector> > () = std::move(yystack_[4].value.as < std::vector> > ()); yylhs.value.as < std::vector> > ().emplace_back(std::move(yystack_[1].value.as < std::unique_ptr > ())); } -#line 1733 "parser.cc" +#line 1739 "parser.cc" break; - case 94: // $@1: %empty -#line 400 "parser.yy" + case 95: // $@1: %empty +#line 402 "parser.yy" { builder.EnterBlock(); } -#line 1739 "parser.cc" +#line 1745 "parser.cc" break; - case 95: // block: $@1 program -#line 400 "parser.yy" + case 96: // block: $@1 program +#line 402 "parser.yy" { yylhs.value.as < std::unique_ptr > () = builder.LeaveBlock(); } -#line 1745 "parser.cc" +#line 1751 "parser.cc" break; - case 96: // args: arg -#line 404 "parser.yy" + case 97: // args: arg +#line 406 "parser.yy" { yylhs.value.as < std::vector> > () = std::vector>{}; yylhs.value.as < std::vector> > ().emplace_back(std::move(yystack_[0].value.as < std::unique_ptr > ())); } -#line 1754 "parser.cc" +#line 1760 "parser.cc" break; - case 97: // args: args "," arg -#line 408 "parser.yy" + case 98: // args: args "," arg +#line 410 "parser.yy" { yystack_[2].value.as < std::vector> > ().emplace_back(std::move(yystack_[0].value.as < std::unique_ptr > ())); yylhs.value.as < std::vector> > () = std::move(yystack_[2].value.as < std::vector> > ()); } -#line 1763 "parser.cc" +#line 1769 "parser.cc" break; - case 98: // arg: term -#line 415 "parser.yy" + case 99: // arg: term +#line 417 "parser.yy" { yylhs.value.as < std::unique_ptr > () = std::move(yystack_[0].value.as < std::unique_ptr > ()); } -#line 1769 "parser.cc" +#line 1775 "parser.cc" break; - case 99: // boolean: term "and" term -#line 419 "parser.yy" + case 100: // boolean: term "and" term +#line 421 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(jitfusion::BinaryOPType::kAnd, std::move(yystack_[2].value.as < std::unique_ptr > ()), std::move(yystack_[0].value.as < std::unique_ptr > ())), yylhs.location, builder.GetSourceCode()); } -#line 1775 "parser.cc" +#line 1781 "parser.cc" break; - case 100: // boolean: term "or" term -#line 420 "parser.yy" + case 101: // boolean: term "or" term +#line 422 "parser.yy" { yylhs.value.as < std::unique_ptr > () = WithLoc(std::make_unique(jitfusion::BinaryOPType::kOr, std::move(yystack_[2].value.as < std::unique_ptr > ()), std::move(yystack_[0].value.as < std::unique_ptr > ())), yylhs.location, builder.GetSourceCode()); } -#line 1781 "parser.cc" +#line 1787 "parser.cc" break; -#line 1785 "parser.cc" +#line 1791 "parser.cc" default: break; @@ -1965,17 +1971,17 @@ namespace athena { { static const char *const yy_sname[] = { - "end of file", "error", "invalid token", "when", "if", "elif", "else", - "switch", "in", "not", "and", "or", "true", "false", "-", "+", "*", "/", - "(", ")", "%", "|", "^", "&", "~", "<<", ">>", "==", "=", "!=", "<", - "<=", ">", ">=", ",", "[", "]", ";", "{", "}", "entry_arg", "exec_ctx", - "output", "identifier", "int8", "int16", "int32", "int64", "uint8", - "uint16", "uint32", "uint64", "float", "double", "string", "NEG", - "$accept", "program", "statement", "expr", "term", "literal", "list", - "i8_list", "i16_list", "i32_list", "i64_list", "u8_list", "u16_list", - "u32_list", "u64_list", "f32_list", "f64_list", "string_list", - "function", "infix_function", "named_function", "when_block", - "elif_chain", "block", "$@1", "args", "arg", "boolean", YY_NULLPTR + "end of file", "error", "invalid token", "let", "when", "if", "elif", + "else", "switch", "in", "not", "and", "or", "true", "false", "-", "+", + "*", "/", "(", ")", "%", "|", "^", "&", "~", "<<", ">>", "==", "=", "!=", + "<", "<=", ">", ">=", ",", "[", "]", ";", "{", "}", "entry_arg", + "exec_ctx", "output", "identifier", "int8", "int16", "int32", "int64", + "uint8", "uint16", "uint32", "uint64", "float", "double", "string", + "NEG", "$accept", "program", "statement", "expr", "term", "literal", + "list", "i8_list", "i16_list", "i32_list", "i64_list", "u8_list", + "u16_list", "u32_list", "u64_list", "f32_list", "f64_list", + "string_list", "function", "infix_function", "named_function", + "when_block", "elif_chain", "block", "$@1", "args", "arg", "boolean", YY_NULLPTR }; return yy_sname[yysymbol]; } @@ -2244,223 +2250,225 @@ namespace athena { } - const signed char Parser::yypact_ninf_ = -68; + const signed char Parser::yypact_ninf_ = -83; const signed char Parser::yytable_ninf_ = -1; const short Parser::yypact_[] = { - 104, 207, 0, 9, 207, -68, -68, 207, 207, 207, - 207, 46, -68, -68, -68, 1, -68, -68, -68, -68, - -68, -68, -68, -68, -68, -68, -68, 8, -68, -7, - 280, -68, -68, -68, -68, -68, -68, -68, 23, 27, - 207, 207, -68, -68, -68, 254, -68, -68, -68, -68, - -68, -68, -68, -68, -68, -68, -68, -68, -20, 6, - 34, 76, 87, 90, 91, 95, 96, 99, 100, 156, - 207, -68, -68, -68, 207, 207, 207, 207, 207, 207, - 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, - 207, 207, 207, -68, 280, -10, -68, -9, -68, 70, - -68, 75, -68, 69, -68, 93, -68, 94, -68, 92, - -68, 88, -68, 108, -68, 109, -68, 113, -68, 118, - -68, -68, -6, 125, 346, 326, 306, 47, 47, -68, - -68, -68, 366, 386, 406, 89, 89, 162, 162, 19, - 19, 19, 19, 128, 104, -68, 207, -68, -68, -68, - -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, - -68, -68, 104, -68, 41, 207, 135, 143, -68, -68, - 144, 145, -68, -68 + 106, -35, 208, 1, 93, 208, -83, -83, 208, 208, + 208, 208, 49, -83, -83, -83, 13, -83, -83, -83, + -83, -83, -83, -83, -83, -83, -83, -83, 8, -83, + 28, 281, -83, -83, -83, -83, -83, -83, -83, 88, + 104, 79, 208, 208, -83, -83, -83, 255, -83, -83, + -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, + -18, -9, 6, 34, 70, 71, 78, 98, 99, 102, + 103, 157, 208, -83, -83, -83, 208, 208, 208, 208, + 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, + 208, 208, 208, 208, 208, 208, -83, 281, -10, -83, + -6, -83, 85, -83, 97, -83, 77, -83, 96, -83, + 114, -83, 95, -83, 113, -83, 117, -83, 121, -83, + 112, -83, 120, -83, -83, -5, 145, 347, 327, 307, + 47, 47, -83, -83, -83, 367, 387, 407, 111, 111, + 163, 163, 19, 19, 19, 19, 147, 146, 106, -83, + 208, -83, -83, -83, -83, -83, -83, -83, -83, -83, + -83, -83, -83, -83, -83, -83, -83, 106, -83, 41, + 208, 148, 149, -83, -83, 151, 152, -83, -83 }; const signed char Parser::yydefact_[] = { - 0, 0, 0, 0, 0, 28, 29, 0, 0, 0, - 0, 0, 13, 14, 15, 12, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 0, 2, 0, - 7, 8, 27, 9, 63, 64, 6, 10, 12, 0, - 0, 0, 66, 65, 67, 0, 68, 41, 43, 45, - 47, 49, 51, 53, 55, 57, 59, 61, 0, 0, + 0, 0, 0, 0, 0, 0, 29, 30, 0, 0, + 0, 0, 0, 14, 15, 16, 13, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 0, 2, + 0, 8, 9, 28, 10, 64, 65, 7, 11, 0, + 13, 0, 0, 0, 67, 66, 68, 0, 69, 42, + 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 3, 5, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 3, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 94, 98, 0, 96, 0, 11, 0, - 30, 0, 31, 0, 32, 0, 33, 0, 34, 0, - 35, 0, 36, 0, 37, 0, 38, 0, 39, 0, - 40, 87, 0, 0, 88, 99, 100, 70, 69, 71, - 72, 73, 75, 76, 74, 83, 84, 77, 78, 81, - 82, 79, 80, 0, 0, 85, 0, 89, 42, 44, - 46, 48, 50, 52, 54, 56, 58, 60, 62, 86, - 4, 91, 95, 97, 90, 0, 0, 0, 94, 94, - 0, 0, 93, 92 + 0, 0, 0, 0, 0, 0, 95, 99, 0, 97, + 0, 12, 0, 31, 0, 32, 0, 33, 0, 34, + 0, 35, 0, 36, 0, 37, 0, 38, 0, 39, + 0, 40, 0, 41, 88, 0, 0, 89, 100, 101, + 71, 70, 72, 73, 74, 76, 77, 75, 84, 85, + 78, 79, 82, 83, 80, 81, 0, 0, 0, 86, + 0, 90, 43, 45, 47, 49, 51, 53, 55, 57, + 59, 61, 63, 87, 4, 5, 92, 96, 98, 91, + 0, 0, 0, 95, 95, 0, 0, 94, 93 }; const signed char Parser::yypgoto_[] = { - -68, 42, -25, -1, -3, -68, -68, -68, -68, -68, - -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, - -68, -68, -68, -67, -68, -38, 39, -68 + -83, 66, -26, -2, -4, -83, -83, -83, -83, -83, + -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, + -83, -83, -83, -82, -83, -40, 65, -83 }; const unsigned char Parser::yydefgoto_[] = { - 0, 27, 28, 29, 30, 31, 32, 58, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 33, 34, - 35, 36, 164, 143, 144, 95, 96, 37 + 0, 28, 29, 30, 31, 32, 33, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 34, 35, + 36, 37, 169, 147, 148, 98, 99, 38 }; const unsigned char Parser::yytable_[] = { - 39, 42, 72, 97, 43, 44, 45, 46, 71, 145, - 147, 1, 2, 159, 99, 3, 100, 4, 40, 69, - 5, 6, 7, 8, 146, 146, 9, 41, 146, 70, - 73, 122, 10, 77, 78, 79, 80, 94, 94, 81, - 101, 69, 102, 11, 85, 86, 165, 166, 12, 13, + 41, 44, 74, 100, 45, 46, 47, 48, 73, 39, + 149, 1, 2, 3, 151, 163, 4, 102, 5, 103, + 42, 6, 7, 8, 9, 150, 104, 10, 105, 150, + 150, 125, 71, 11, 79, 80, 81, 82, 97, 97, + 83, 106, 72, 107, 12, 87, 88, 170, 171, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 79, 80, 93, 94, 81, 103, 123, - 104, 124, 125, 126, 127, 128, 129, 130, 131, 132, - 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 170, 171, 77, 78, 79, 80, 1, 2, 81, - 105, 3, 106, 4, 148, 150, 5, 6, 7, 8, - 149, 107, 9, 108, 109, 111, 110, 112, 10, 113, - 115, 114, 116, 117, 119, 118, 120, 72, 154, 11, - 151, 153, 152, 94, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 155, - 2, 156, 160, 3, 167, 4, 157, 161, 5, 6, - 7, 8, 158, 168, 9, 121, 77, 78, 79, 80, - 10, 169, 81, 172, 173, 163, 162, 85, 86, 0, - 0, 11, 89, 90, 91, 92, 12, 13, 14, 38, + 24, 25, 26, 27, 81, 82, 75, 97, 83, 108, + 126, 109, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 175, 176, 146, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 110, 112, 111, 113, 1, + 2, 3, 43, 114, 4, 115, 5, 95, 96, 6, + 7, 8, 9, 71, 154, 10, 79, 80, 81, 82, + 152, 11, 83, 116, 118, 117, 119, 120, 122, 121, + 123, 74, 12, 153, 155, 157, 97, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 2, 0, 0, 3, 0, 4, 0, 0, 5, - 6, 7, 8, 0, 0, 9, 0, 0, 0, 0, - 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 11, 0, 0, 0, 0, 12, 13, 14, - 38, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 74, 0, 75, 76, 0, 0, 77, 78, - 79, 80, 0, 98, 81, 82, 83, 84, 0, 85, - 86, 87, 0, 88, 89, 90, 91, 92, 74, 0, - 75, 76, 0, 0, 77, 78, 79, 80, 0, 0, - 81, 82, 83, 84, 0, 85, 86, 87, 0, 88, - 89, 90, 91, 92, 74, 0, 75, 0, 0, 0, - 77, 78, 79, 80, 0, 0, 81, 82, 83, 84, - 0, 85, 86, 87, 74, 88, 89, 90, 91, 92, - 77, 78, 79, 80, 0, 0, 81, 82, 83, 84, - 0, 85, 86, 87, 0, 88, 89, 90, 91, 92, - 77, 78, 79, 80, 0, 0, 81, 82, 83, 84, - 0, 85, 86, 87, 0, 88, 89, 90, 91, 92, - 77, 78, 79, 80, 0, 0, 81, 0, 83, 84, - 0, 85, 86, 87, 0, 88, 89, 90, 91, 92, - 77, 78, 79, 80, 0, 0, 81, 0, 0, 84, - 0, 85, 86, 87, 0, 88, 89, 90, 91, 92, - 77, 78, 79, 80, 0, 0, 81, 0, 0, 0, - 0, 85, 86, 87, 0, 88, 89, 90, 91, 92 + 26, 27, 3, 156, 158, 4, 161, 5, 172, 159, + 6, 7, 8, 9, 160, 162, 10, 124, 79, 80, + 81, 82, 11, 164, 83, 165, 166, 173, 174, 87, + 88, 177, 178, 12, 91, 92, 93, 94, 13, 14, + 15, 40, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 3, 167, 168, 4, 0, 5, 0, + 0, 6, 7, 8, 9, 0, 0, 10, 0, 0, + 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 12, 0, 0, 0, 0, 13, + 14, 15, 40, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 76, 0, 77, 78, 0, 0, + 79, 80, 81, 82, 0, 101, 83, 84, 85, 86, + 0, 87, 88, 89, 0, 90, 91, 92, 93, 94, + 76, 0, 77, 78, 0, 0, 79, 80, 81, 82, + 0, 0, 83, 84, 85, 86, 0, 87, 88, 89, + 0, 90, 91, 92, 93, 94, 76, 0, 77, 0, + 0, 0, 79, 80, 81, 82, 0, 0, 83, 84, + 85, 86, 0, 87, 88, 89, 76, 90, 91, 92, + 93, 94, 79, 80, 81, 82, 0, 0, 83, 84, + 85, 86, 0, 87, 88, 89, 0, 90, 91, 92, + 93, 94, 79, 80, 81, 82, 0, 0, 83, 84, + 85, 86, 0, 87, 88, 89, 0, 90, 91, 92, + 93, 94, 79, 80, 81, 82, 0, 0, 83, 0, + 85, 86, 0, 87, 88, 89, 0, 90, 91, 92, + 93, 94, 79, 80, 81, 82, 0, 0, 83, 0, + 0, 86, 0, 87, 88, 89, 0, 90, 91, 92, + 93, 94, 79, 80, 81, 82, 0, 0, 83, 0, + 0, 0, 0, 87, 88, 89, 0, 90, 91, 92, + 93, 94 }; const short Parser::yycheck_[] = { - 1, 4, 27, 41, 7, 8, 9, 10, 0, 19, - 19, 3, 4, 19, 34, 7, 36, 9, 18, 18, - 12, 13, 14, 15, 34, 34, 18, 18, 34, 28, - 37, 69, 24, 14, 15, 16, 17, 40, 41, 20, - 34, 18, 36, 35, 25, 26, 5, 6, 40, 41, + 2, 5, 28, 43, 8, 9, 10, 11, 0, 44, + 20, 3, 4, 5, 20, 20, 8, 35, 10, 37, + 19, 13, 14, 15, 16, 35, 35, 19, 37, 35, + 35, 71, 19, 25, 15, 16, 17, 18, 42, 43, + 21, 35, 29, 37, 36, 26, 27, 6, 7, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 16, 17, 38, 69, 20, 34, 70, - 36, 74, 75, 76, 77, 78, 79, 80, 81, 82, - 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 52, 53, 54, 55, 17, 18, 38, 71, 21, 35, + 72, 37, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 173, 174, 95, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 35, 35, 37, 37, 3, + 4, 5, 19, 35, 8, 37, 10, 29, 39, 13, + 14, 15, 16, 19, 47, 19, 15, 16, 17, 18, + 45, 25, 21, 35, 35, 37, 37, 35, 35, 37, + 37, 167, 36, 46, 48, 50, 150, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 168, 169, 14, 15, 16, 17, 3, 4, 20, - 34, 7, 36, 9, 44, 46, 12, 13, 14, 15, - 45, 34, 18, 36, 34, 34, 36, 36, 24, 34, - 34, 36, 36, 34, 34, 36, 36, 162, 50, 35, - 47, 49, 48, 146, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 51, - 4, 52, 37, 7, 165, 9, 53, 39, 12, 13, - 14, 15, 54, 38, 18, 19, 14, 15, 16, 17, - 24, 38, 20, 39, 39, 146, 144, 25, 26, -1, - -1, 35, 30, 31, 32, 33, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 4, -1, -1, 7, -1, 9, -1, -1, 12, - 13, 14, 15, -1, -1, 18, -1, -1, -1, -1, - -1, 24, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 35, -1, -1, -1, -1, 40, 41, 42, + 54, 55, 5, 49, 51, 8, 54, 10, 170, 52, + 13, 14, 15, 16, 53, 55, 19, 20, 15, 16, + 17, 18, 25, 38, 21, 38, 40, 39, 39, 26, + 27, 40, 40, 36, 31, 32, 33, 34, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - 53, 54, 8, -1, 10, 11, -1, -1, 14, 15, - 16, 17, -1, 19, 20, 21, 22, 23, -1, 25, - 26, 27, -1, 29, 30, 31, 32, 33, 8, -1, - 10, 11, -1, -1, 14, 15, 16, 17, -1, -1, - 20, 21, 22, 23, -1, 25, 26, 27, -1, 29, - 30, 31, 32, 33, 8, -1, 10, -1, -1, -1, - 14, 15, 16, 17, -1, -1, 20, 21, 22, 23, - -1, 25, 26, 27, 8, 29, 30, 31, 32, 33, - 14, 15, 16, 17, -1, -1, 20, 21, 22, 23, - -1, 25, 26, 27, -1, 29, 30, 31, 32, 33, - 14, 15, 16, 17, -1, -1, 20, 21, 22, 23, - -1, 25, 26, 27, -1, 29, 30, 31, 32, 33, - 14, 15, 16, 17, -1, -1, 20, -1, 22, 23, - -1, 25, 26, 27, -1, 29, 30, 31, 32, 33, - 14, 15, 16, 17, -1, -1, 20, -1, -1, 23, - -1, 25, 26, 27, -1, 29, 30, 31, 32, 33, - 14, 15, 16, 17, -1, -1, 20, -1, -1, -1, - -1, 25, 26, 27, -1, 29, 30, 31, 32, 33 + 53, 54, 55, 5, 148, 150, 8, -1, 10, -1, + -1, 13, 14, 15, 16, -1, -1, 19, -1, -1, + -1, -1, -1, 25, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 36, -1, -1, -1, -1, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 9, -1, 11, 12, -1, -1, + 15, 16, 17, 18, -1, 20, 21, 22, 23, 24, + -1, 26, 27, 28, -1, 30, 31, 32, 33, 34, + 9, -1, 11, 12, -1, -1, 15, 16, 17, 18, + -1, -1, 21, 22, 23, 24, -1, 26, 27, 28, + -1, 30, 31, 32, 33, 34, 9, -1, 11, -1, + -1, -1, 15, 16, 17, 18, -1, -1, 21, 22, + 23, 24, -1, 26, 27, 28, 9, 30, 31, 32, + 33, 34, 15, 16, 17, 18, -1, -1, 21, 22, + 23, 24, -1, 26, 27, 28, -1, 30, 31, 32, + 33, 34, 15, 16, 17, 18, -1, -1, 21, 22, + 23, 24, -1, 26, 27, 28, -1, 30, 31, 32, + 33, 34, 15, 16, 17, 18, -1, -1, 21, -1, + 23, 24, -1, 26, 27, 28, -1, 30, 31, 32, + 33, 34, 15, 16, 17, 18, -1, -1, 21, -1, + -1, 24, -1, 26, 27, 28, -1, 30, 31, 32, + 33, 34, 15, 16, 17, 18, -1, -1, 21, -1, + -1, -1, -1, 26, 27, 28, -1, 30, 31, 32, + 33, 34 }; const signed char Parser::yystos_[] = { - 0, 3, 4, 7, 9, 12, 13, 14, 15, 18, - 24, 35, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 57, 58, 59, - 60, 61, 62, 74, 75, 76, 77, 83, 43, 59, - 18, 18, 60, 60, 60, 60, 60, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 63, 64, - 65, 66, 67, 68, 69, 70, 71, 72, 73, 18, - 28, 0, 58, 37, 8, 10, 11, 14, 15, 16, - 17, 20, 21, 22, 23, 25, 26, 27, 29, 30, - 31, 32, 33, 38, 60, 81, 82, 81, 19, 34, - 36, 34, 36, 34, 36, 34, 36, 34, 36, 34, - 36, 34, 36, 34, 36, 34, 36, 34, 36, 34, - 36, 19, 81, 59, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 79, 80, 19, 34, 19, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 19, - 37, 39, 57, 82, 78, 5, 6, 59, 38, 38, - 79, 79, 39, 39 + 0, 3, 4, 5, 8, 10, 13, 14, 15, 16, + 19, 25, 36, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 58, 59, + 60, 61, 62, 63, 75, 76, 77, 78, 84, 44, + 44, 60, 19, 19, 61, 61, 61, 61, 61, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 19, 29, 0, 59, 38, 9, 11, 12, 15, + 16, 17, 18, 21, 22, 23, 24, 26, 27, 28, + 30, 31, 32, 33, 34, 29, 39, 61, 82, 83, + 82, 20, 35, 37, 35, 37, 35, 37, 35, 37, + 35, 37, 35, 37, 35, 37, 35, 37, 35, 37, + 35, 37, 35, 37, 20, 82, 60, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 60, 80, 81, 20, + 35, 20, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 20, 38, 38, 40, 58, 83, 79, + 6, 7, 60, 39, 39, 80, 80, 40, 40 }; const signed char Parser::yyr1_[] = { - 0, 56, 57, 57, 58, 58, 58, 59, 60, 60, - 60, 60, 60, 60, 60, 60, 61, 61, 61, 61, - 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 0, 57, 58, 58, 59, 59, 59, 59, 60, 61, + 61, 61, 61, 61, 61, 61, 61, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 63, 63, 64, 64, 65, 65, 66, 66, 67, - 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, - 72, 73, 73, 74, 74, 75, 75, 75, 75, 75, - 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, - 75, 75, 75, 75, 75, 76, 76, 76, 76, 76, - 77, 78, 78, 78, 80, 79, 81, 81, 82, 83, - 83 + 62, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 64, 64, 65, 65, 66, 66, 67, 67, + 68, 68, 69, 69, 70, 70, 71, 71, 72, 72, + 73, 73, 74, 74, 75, 75, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 77, 77, 77, 77, + 77, 78, 79, 79, 79, 81, 80, 82, 82, 83, + 84, 84 }; const signed char Parser::yyr2_[] = { - 0, 2, 1, 2, 4, 2, 1, 1, 1, 1, - 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 2, 1, 2, 4, 5, 2, 1, 1, 1, + 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 1, 3, 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, - 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, - 3, 1, 3, 1, 1, 2, 2, 2, 2, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 4, 4, 3, 3, 4, - 6, 0, 6, 5, 0, 2, 1, 3, 1, 3, - 3 + 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, + 4, 6, 0, 6, 5, 0, 2, 1, 3, 1, + 3, 3 }; @@ -2470,17 +2478,17 @@ namespace athena { const short Parser::yyrline_[] = { - 0, 180, 180, 184, 190, 191, 192, 194, 198, 199, - 200, 201, 202, 205, 206, 207, 211, 212, 213, 214, - 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, - 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, - 238, 242, 243, 250, 251, 258, 259, 266, 267, 274, - 275, 282, 283, 290, 291, 298, 299, 306, 307, 314, - 315, 322, 323, 330, 331, 336, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, - 351, 352, 353, 354, 355, 359, 360, 361, 362, 368, - 372, 387, 388, 393, 400, 400, 404, 408, 415, 419, - 420 + 0, 181, 181, 185, 191, 192, 193, 194, 196, 200, + 201, 202, 203, 204, 207, 208, 209, 213, 214, 215, + 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, + 226, 230, 231, 232, 233, 234, 235, 236, 237, 238, + 239, 240, 244, 245, 252, 253, 260, 261, 268, 269, + 276, 277, 284, 285, 292, 293, 300, 301, 308, 309, + 316, 317, 324, 325, 332, 333, 338, 339, 340, 341, + 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, + 352, 353, 354, 355, 356, 357, 361, 362, 363, 364, + 370, 374, 389, 390, 395, 402, 402, 406, 410, 417, + 421, 422 }; void @@ -2513,9 +2521,9 @@ namespace athena { #line 10 "parser.yy" } // athena -#line 2517 "parser.cc" +#line 2525 "parser.cc" -#line 422 "parser.yy" +#line 424 "parser.yy" void athena::Parser::error(const location_type &l, const std::string &m) { diff --git a/athena/parser.hh b/athena/parser.hh index bd072dc..8037ed6 100644 --- a/athena/parser.hh +++ b/athena/parser.hh @@ -578,59 +578,60 @@ namespace athena { TOK_YYEOF = 0, // "end of file" TOK_YYerror = 1, // error TOK_YYUNDEF = 2, // "invalid token" - TOK_WHEN = 3, // "when" - TOK_IF = 4, // "if" - TOK_ELIF = 5, // "elif" - TOK_ELSE = 6, // "else" - TOK_SWITCH = 7, // "switch" - TOK_IN = 8, // "in" - TOK_NOT = 9, // "not" - TOK_AND = 10, // "and" - TOK_OR = 11, // "or" - TOK_TRUE = 12, // "true" - TOK_FALSE = 13, // "false" - TOK_MINUS = 14, // "-" - TOK_PLUS = 15, // "+" - TOK_STAR = 16, // "*" - TOK_SLASH = 17, // "/" - TOK_LPAREN = 18, // "(" - TOK_RPAREN = 19, // ")" - TOK_MODOLO = 20, // "%" - TOK_BITWISE_OR = 21, // "|" - TOK_BITWISE_XOR = 22, // "^" - TOK_BITWISE_AND = 23, // "&" - TOK_BITWISE_NOT = 24, // "~" - TOK_BITWISE_LEFT = 25, // "<<" - TOK_BITWISE_RIGHT = 26, // ">>" - TOK_EQUAL = 27, // "==" - TOK_ASSIGNMENT = 28, // "=" - TOK_NOT_EQUAL = 29, // "!=" - TOK_LESS_THAN = 30, // "<" - TOK_LESS_THAN_OR_EQUAL_TO = 31, // "<=" - TOK_GREATER_THAN = 32, // ">" - TOK_GREATER_THAN_OR_EQUAL_TO = 33, // ">=" - TOK_COMMA = 34, // "," - TOK_LBRACKET = 35, // "[" - TOK_RBRACKET = 36, // "]" - TOK_SEMI = 37, // ";" - TOK_LBRACE = 38, // "{" - TOK_RBRACE = 39, // "}" - TOK_ENTRY_ARG = 40, // "entry_arg" - TOK_EXEC_CTX = 41, // "exec_ctx" - TOK_OUTPUT = 42, // "output" - TOK_IDENTIFIER = 43, // "identifier" - TOK_I8 = 44, // "int8" - TOK_I16 = 45, // "int16" - TOK_I32 = 46, // "int32" - TOK_I64 = 47, // "int64" - TOK_U8 = 48, // "uint8" - TOK_U16 = 49, // "uint16" - TOK_U32 = 50, // "uint32" - TOK_U64 = 51, // "uint64" - TOK_F32 = 52, // "float" - TOK_F64 = 53, // "double" - TOK_STRING = 54, // "string" - TOK_NEG = 55 // NEG + TOK_LET = 3, // "let" + TOK_WHEN = 4, // "when" + TOK_IF = 5, // "if" + TOK_ELIF = 6, // "elif" + TOK_ELSE = 7, // "else" + TOK_SWITCH = 8, // "switch" + TOK_IN = 9, // "in" + TOK_NOT = 10, // "not" + TOK_AND = 11, // "and" + TOK_OR = 12, // "or" + TOK_TRUE = 13, // "true" + TOK_FALSE = 14, // "false" + TOK_MINUS = 15, // "-" + TOK_PLUS = 16, // "+" + TOK_STAR = 17, // "*" + TOK_SLASH = 18, // "/" + TOK_LPAREN = 19, // "(" + TOK_RPAREN = 20, // ")" + TOK_MODOLO = 21, // "%" + TOK_BITWISE_OR = 22, // "|" + TOK_BITWISE_XOR = 23, // "^" + TOK_BITWISE_AND = 24, // "&" + TOK_BITWISE_NOT = 25, // "~" + TOK_BITWISE_LEFT = 26, // "<<" + TOK_BITWISE_RIGHT = 27, // ">>" + TOK_EQUAL = 28, // "==" + TOK_ASSIGNMENT = 29, // "=" + TOK_NOT_EQUAL = 30, // "!=" + TOK_LESS_THAN = 31, // "<" + TOK_LESS_THAN_OR_EQUAL_TO = 32, // "<=" + TOK_GREATER_THAN = 33, // ">" + TOK_GREATER_THAN_OR_EQUAL_TO = 34, // ">=" + TOK_COMMA = 35, // "," + TOK_LBRACKET = 36, // "[" + TOK_RBRACKET = 37, // "]" + TOK_SEMI = 38, // ";" + TOK_LBRACE = 39, // "{" + TOK_RBRACE = 40, // "}" + TOK_ENTRY_ARG = 41, // "entry_arg" + TOK_EXEC_CTX = 42, // "exec_ctx" + TOK_OUTPUT = 43, // "output" + TOK_IDENTIFIER = 44, // "identifier" + TOK_I8 = 45, // "int8" + TOK_I16 = 46, // "int16" + TOK_I32 = 47, // "int32" + TOK_I64 = 48, // "int64" + TOK_U8 = 49, // "uint8" + TOK_U16 = 50, // "uint16" + TOK_U32 = 51, // "uint32" + TOK_U64 = 52, // "uint64" + TOK_F32 = 53, // "float" + TOK_F64 = 54, // "double" + TOK_STRING = 55, // "string" + TOK_NEG = 56 // NEG }; /// Backward compatibility alias (Bison 3.6). typedef token_kind_type yytokentype; @@ -647,92 +648,93 @@ namespace athena { { enum symbol_kind_type { - YYNTOKENS = 56, ///< Number of tokens. + YYNTOKENS = 57, ///< Number of tokens. S_YYEMPTY = -2, S_YYEOF = 0, // "end of file" S_YYerror = 1, // error S_YYUNDEF = 2, // "invalid token" - S_WHEN = 3, // "when" - S_IF = 4, // "if" - S_ELIF = 5, // "elif" - S_ELSE = 6, // "else" - S_SWITCH = 7, // "switch" - S_IN = 8, // "in" - S_NOT = 9, // "not" - S_AND = 10, // "and" - S_OR = 11, // "or" - S_TRUE = 12, // "true" - S_FALSE = 13, // "false" - S_MINUS = 14, // "-" - S_PLUS = 15, // "+" - S_STAR = 16, // "*" - S_SLASH = 17, // "/" - S_LPAREN = 18, // "(" - S_RPAREN = 19, // ")" - S_MODOLO = 20, // "%" - S_BITWISE_OR = 21, // "|" - S_BITWISE_XOR = 22, // "^" - S_BITWISE_AND = 23, // "&" - S_BITWISE_NOT = 24, // "~" - S_BITWISE_LEFT = 25, // "<<" - S_BITWISE_RIGHT = 26, // ">>" - S_EQUAL = 27, // "==" - S_ASSIGNMENT = 28, // "=" - S_NOT_EQUAL = 29, // "!=" - S_LESS_THAN = 30, // "<" - S_LESS_THAN_OR_EQUAL_TO = 31, // "<=" - S_GREATER_THAN = 32, // ">" - S_GREATER_THAN_OR_EQUAL_TO = 33, // ">=" - S_COMMA = 34, // "," - S_LBRACKET = 35, // "[" - S_RBRACKET = 36, // "]" - S_SEMI = 37, // ";" - S_LBRACE = 38, // "{" - S_RBRACE = 39, // "}" - S_ENTRY_ARG = 40, // "entry_arg" - S_EXEC_CTX = 41, // "exec_ctx" - S_OUTPUT = 42, // "output" - S_IDENTIFIER = 43, // "identifier" - S_I8 = 44, // "int8" - S_I16 = 45, // "int16" - S_I32 = 46, // "int32" - S_I64 = 47, // "int64" - S_U8 = 48, // "uint8" - S_U16 = 49, // "uint16" - S_U32 = 50, // "uint32" - S_U64 = 51, // "uint64" - S_F32 = 52, // "float" - S_F64 = 53, // "double" - S_STRING = 54, // "string" - S_NEG = 55, // NEG - S_YYACCEPT = 56, // $accept - S_program = 57, // program - S_statement = 58, // statement - S_expr = 59, // expr - S_term = 60, // term - S_literal = 61, // literal - S_list = 62, // list - S_i8_list = 63, // i8_list - S_i16_list = 64, // i16_list - S_i32_list = 65, // i32_list - S_i64_list = 66, // i64_list - S_u8_list = 67, // u8_list - S_u16_list = 68, // u16_list - S_u32_list = 69, // u32_list - S_u64_list = 70, // u64_list - S_f32_list = 71, // f32_list - S_f64_list = 72, // f64_list - S_string_list = 73, // string_list - S_function = 74, // function - S_infix_function = 75, // infix_function - S_named_function = 76, // named_function - S_when_block = 77, // when_block - S_elif_chain = 78, // elif_chain - S_block = 79, // block - S_80_1 = 80, // $@1 - S_args = 81, // args - S_arg = 82, // arg - S_boolean = 83 // boolean + S_LET = 3, // "let" + S_WHEN = 4, // "when" + S_IF = 5, // "if" + S_ELIF = 6, // "elif" + S_ELSE = 7, // "else" + S_SWITCH = 8, // "switch" + S_IN = 9, // "in" + S_NOT = 10, // "not" + S_AND = 11, // "and" + S_OR = 12, // "or" + S_TRUE = 13, // "true" + S_FALSE = 14, // "false" + S_MINUS = 15, // "-" + S_PLUS = 16, // "+" + S_STAR = 17, // "*" + S_SLASH = 18, // "/" + S_LPAREN = 19, // "(" + S_RPAREN = 20, // ")" + S_MODOLO = 21, // "%" + S_BITWISE_OR = 22, // "|" + S_BITWISE_XOR = 23, // "^" + S_BITWISE_AND = 24, // "&" + S_BITWISE_NOT = 25, // "~" + S_BITWISE_LEFT = 26, // "<<" + S_BITWISE_RIGHT = 27, // ">>" + S_EQUAL = 28, // "==" + S_ASSIGNMENT = 29, // "=" + S_NOT_EQUAL = 30, // "!=" + S_LESS_THAN = 31, // "<" + S_LESS_THAN_OR_EQUAL_TO = 32, // "<=" + S_GREATER_THAN = 33, // ">" + S_GREATER_THAN_OR_EQUAL_TO = 34, // ">=" + S_COMMA = 35, // "," + S_LBRACKET = 36, // "[" + S_RBRACKET = 37, // "]" + S_SEMI = 38, // ";" + S_LBRACE = 39, // "{" + S_RBRACE = 40, // "}" + S_ENTRY_ARG = 41, // "entry_arg" + S_EXEC_CTX = 42, // "exec_ctx" + S_OUTPUT = 43, // "output" + S_IDENTIFIER = 44, // "identifier" + S_I8 = 45, // "int8" + S_I16 = 46, // "int16" + S_I32 = 47, // "int32" + S_I64 = 48, // "int64" + S_U8 = 49, // "uint8" + S_U16 = 50, // "uint16" + S_U32 = 51, // "uint32" + S_U64 = 52, // "uint64" + S_F32 = 53, // "float" + S_F64 = 54, // "double" + S_STRING = 55, // "string" + S_NEG = 56, // NEG + S_YYACCEPT = 57, // $accept + S_program = 58, // program + S_statement = 59, // statement + S_expr = 60, // expr + S_term = 61, // term + S_literal = 62, // literal + S_list = 63, // list + S_i8_list = 64, // i8_list + S_i16_list = 65, // i16_list + S_i32_list = 66, // i32_list + S_i64_list = 67, // i64_list + S_u8_list = 68, // u8_list + S_u16_list = 69, // u16_list + S_u32_list = 70, // u32_list + S_u64_list = 71, // u64_list + S_f32_list = 72, // f32_list + S_f64_list = 73, // f64_list + S_string_list = 74, // string_list + S_function = 75, // function + S_infix_function = 76, // infix_function + S_named_function = 77, // named_function + S_when_block = 78, // when_block + S_elif_chain = 79, // elif_chain + S_block = 80, // block + S_81_1 = 81, // $@1 + S_args = 82, // args + S_arg = 83, // arg + S_boolean = 84 // boolean }; }; @@ -2006,6 +2008,21 @@ switch (yykind) return symbol_type (token::TOK_YYUNDEF, l); } #endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_LET (location_type l) + { + return symbol_type (token::TOK_LET, std::move (l)); + } +#else + static + symbol_type + make_LET (const location_type& l) + { + return symbol_type (token::TOK_LET, l); + } +#endif #if 201103L <= YY_CPLUSPLUS static symbol_type @@ -3145,9 +3162,9 @@ switch (yykind) /// Constants. enum { - yylast_ = 439, ///< Last index in yytable_. + yylast_ = 441, ///< Last index in yytable_. yynnts_ = 28, ///< Number of nonterminal symbols. - yyfinal_ = 71 ///< Termination state number. + yyfinal_ = 73 ///< Termination state number. }; @@ -3520,7 +3537,7 @@ switch (yykind) #line 10 "parser.yy" } // athena -#line 3524 "parser.hh" +#line 3541 "parser.hh" // "%code provides" blocks. @@ -3531,7 +3548,7 @@ switch (yykind) // ... and declare it for the parser's sake. YY_DECL; -#line 3535 "parser.hh" +#line 3552 "parser.hh" #endif // !YY_YY_PARSER_HH_INCLUDED diff --git a/athena/parser.yy b/athena/parser.yy index c57e72f..deb48f7 100644 --- a/athena/parser.yy +++ b/athena/parser.yy @@ -63,6 +63,7 @@ YY_DECL; %define api.token.prefix {TOK_} %token + LET "let" WHEN "when" IF "if" ELIF "elif" @@ -188,6 +189,7 @@ program: statement: IDENTIFIER "=" expr ";" { $$ = Statement(std::move($1), std::move($3)); } +| "let" IDENTIFIER "=" expr ";" { $$ = Statement(std::move($2), std::move($4), true); } | expr ";" { $$ = Statement(std::move($1)); } | when_block { $$ = Statement(std::move($1)); } diff --git a/athena/pipeline_grouper.h b/athena/pipeline_grouper.h index 69f146b..ea481b2 100644 --- a/athena/pipeline_grouper.h +++ b/athena/pipeline_grouper.h @@ -31,7 +31,7 @@ using jitfusion::Visitor; class PipelineGrouper : jitfusion::Visitor { public: PipelineGrouper() = default; - ~PipelineGrouper() = default; + ~PipelineGrouper() override = default; // Merge the pipeline ASTs by category into new pipeline ASTs, where the root node of each new pipeline is a NoOp // node, and the original pipeline ASTs will be cleared. diff --git a/athena/test/const_var_test.cc b/athena/test/const_var_test.cc new file mode 100644 index 0000000..f9d0252 --- /dev/null +++ b/athena/test/const_var_test.cc @@ -0,0 +1,449 @@ +/* + * @Author: victorika + * @Date: 2026-07-15 10:30:00 + * @Last Modified by: victorika + * @Last Modified time: 2026-07-15 10:30:00 + */ +#include "gtest/gtest.h" +#include "test_helper.h" + +using athena::AthenaExpression; +using athena::AthenaPipeline; +using athena::FunctionRegistry; +using athena::FunctionRegistryFactory; +using athena::FunctionSignature; +using athena::RetType; +using athena::ValueType; +using test::LoadF32; +using test::StoreF32; + +TEST(ConstVarTest, BasicLetDeclaration) { + AthenaPipeline athena; + std::unique_ptr func_registry; + EXPECT_TRUE(FunctionRegistryFactory::CreateFunctionRegistry(&func_registry).ok()); + { + FunctionSignature sign("load", {ValueType::kPtr, ValueType::kI32}, ValueType::kF32); + EXPECT_TRUE(func_registry->RegisterReadOnlyCFunc(sign, reinterpret_cast(LoadF32)).ok()); + } + { + FunctionSignature sign("store", {ValueType::kPtr, ValueType::kI32, ValueType::kF32}, ValueType::kVoid); + EXPECT_TRUE(func_registry->RegisterStoreCFunc(sign, reinterpret_cast(StoreF32), 1).ok()); + } + + std::string code = R"( + let a = load(entry_arg, 0); + let b = load(entry_arg, 1); + let c = a + b; + store(output, 0, c); + )"; + + std::vector codes = {code}; + ASSERT_TRUE(athena.Compile(codes, func_registry).ok()); + + std::vector value = {10, 3}; + std::vector output = {0}; + ASSERT_TRUE(athena.Execute(value.data(), output.data()).ok()); + + EXPECT_EQ(output[0], 13.0F); +} + +TEST(ConstVarTest, ReassignConstVarShouldFail) { + AthenaPipeline athena; + std::unique_ptr func_registry; + EXPECT_TRUE(FunctionRegistryFactory::CreateFunctionRegistry(&func_registry).ok()); + { + FunctionSignature sign("load", {ValueType::kPtr, ValueType::kI32}, ValueType::kF32); + EXPECT_TRUE(func_registry->RegisterReadOnlyCFunc(sign, reinterpret_cast(LoadF32)).ok()); + } + + std::string code = R"( + let a = load(entry_arg, 0); + a = load(entry_arg, 1); + )"; + + std::vector codes = {code}; + auto st = athena.Compile(codes, func_registry); + EXPECT_FALSE(st.ok()); + EXPECT_NE(st.ToString().find("cannot reassign const variable 'a'"), std::string::npos) << st.ToString(); +} + +TEST(ConstVarTest, ReassignMutableVarShouldSucceed) { + AthenaPipeline athena; + std::unique_ptr func_registry; + EXPECT_TRUE(FunctionRegistryFactory::CreateFunctionRegistry(&func_registry).ok()); + { + FunctionSignature sign("load", {ValueType::kPtr, ValueType::kI32}, ValueType::kF32); + EXPECT_TRUE(func_registry->RegisterReadOnlyCFunc(sign, reinterpret_cast(LoadF32)).ok()); + } + { + FunctionSignature sign("store", {ValueType::kPtr, ValueType::kI32, ValueType::kF32}, ValueType::kVoid); + EXPECT_TRUE(func_registry->RegisterStoreCFunc(sign, reinterpret_cast(StoreF32), 1).ok()); + } + + std::string code = R"( + a = load(entry_arg, 0); + a = a + 1.0f32; + store(output, 0, a); + )"; + + std::vector codes = {code}; + ASSERT_TRUE(athena.Compile(codes, func_registry).ok()); + + std::vector value = {10}; + std::vector output = {0}; + ASSERT_TRUE(athena.Execute(value.data(), output.data()).ok()); + + EXPECT_EQ(output[0], 11.0F); +} + +TEST(ConstVarTest, ModifyConstVarInWhenShouldFail) { + AthenaPipeline athena; + std::unique_ptr func_registry; + EXPECT_TRUE(FunctionRegistryFactory::CreateFunctionRegistry(&func_registry).ok()); + { + FunctionSignature sign("load", {ValueType::kPtr, ValueType::kI32}, ValueType::kF32); + EXPECT_TRUE(func_registry->RegisterReadOnlyCFunc(sign, reinterpret_cast(LoadF32)).ok()); + } + + std::string code = R"( + let a = load(entry_arg, 0); + when a > 0.0f32 { + a = 1.0f32; + } + )"; + + std::vector codes = {code}; + auto st = athena.Compile(codes, func_registry); + EXPECT_FALSE(st.ok()); + EXPECT_NE(st.ToString().find("cannot reassign const variable 'a'"), std::string::npos) << st.ToString(); +} + +TEST(ConstVarTest, MixedConstAndMutableVars) { + AthenaPipeline athena; + std::unique_ptr func_registry; + EXPECT_TRUE(FunctionRegistryFactory::CreateFunctionRegistry(&func_registry).ok()); + { + FunctionSignature sign("load", {ValueType::kPtr, ValueType::kI32}, ValueType::kF32); + EXPECT_TRUE(func_registry->RegisterReadOnlyCFunc(sign, reinterpret_cast(LoadF32)).ok()); + } + { + FunctionSignature sign("store", {ValueType::kPtr, ValueType::kI32, ValueType::kF32}, ValueType::kVoid); + EXPECT_TRUE(func_registry->RegisterStoreCFunc(sign, reinterpret_cast(StoreF32), 1).ok()); + } + + std::string code = R"( + let a = load(entry_arg, 0); + b = a + 1.0f32; + b = b * 2.0f32; + store(output, 0, b); + )"; + + std::vector codes = {code}; + ASSERT_TRUE(athena.Compile(codes, func_registry).ok()); + + std::vector value = {5}; + std::vector output = {0}; + ASSERT_TRUE(athena.Execute(value.data(), output.data()).ok()); + + EXPECT_EQ(output[0], 12.0F); // (5 + 1) * 2 = 12 +} + +TEST(ConstVarTest, ModifyMutableVarInWhenShouldSucceed) { + AthenaPipeline athena; + std::unique_ptr func_registry; + EXPECT_TRUE(FunctionRegistryFactory::CreateFunctionRegistry(&func_registry).ok()); + { + FunctionSignature sign("load", {ValueType::kPtr, ValueType::kI32}, ValueType::kF32); + EXPECT_TRUE(func_registry->RegisterReadOnlyCFunc(sign, reinterpret_cast(LoadF32)).ok()); + } + { + FunctionSignature sign("store", {ValueType::kPtr, ValueType::kI32, ValueType::kF32}, ValueType::kVoid); + EXPECT_TRUE(func_registry->RegisterStoreCFunc(sign, reinterpret_cast(StoreF32), 1).ok()); + } + + std::string code = R"( + let a = load(entry_arg, 0); + b = 0.0f32; + when a > 0.0f32 { + b = a + 1.0f32; + } else { + b = a - 1.0f32; + } + store(output, 0, b); + )"; + + std::vector codes = {code}; + ASSERT_TRUE(athena.Compile(codes, func_registry).ok()); + + std::vector value = {5}; + std::vector output = {0}; + ASSERT_TRUE(athena.Execute(value.data(), output.data()).ok()); + + EXPECT_EQ(output[0], 6.0F); +} + +TEST(ConstVarTest, LetRedeclareExistingMutableVar) { + AthenaPipeline athena; + std::unique_ptr func_registry; + EXPECT_TRUE(FunctionRegistryFactory::CreateFunctionRegistry(&func_registry).ok()); + { + FunctionSignature sign("load", {ValueType::kPtr, ValueType::kI32}, ValueType::kF32); + EXPECT_TRUE(func_registry->RegisterReadOnlyCFunc(sign, reinterpret_cast(LoadF32)).ok()); + } + + std::string code = R"( + a = load(entry_arg, 0); + let a = a + 1.0f32; + )"; + + std::vector codes = {code}; + auto st = athena.Compile(codes, func_registry); + EXPECT_FALSE(st.ok()); + EXPECT_NE(st.ToString().find("cannot redeclare variable 'a' with let"), std::string::npos) << st.ToString(); +} + +TEST(ConstVarTest, LetRedeclareThenReassignShouldFail) { + AthenaPipeline athena; + std::unique_ptr func_registry; + EXPECT_TRUE(FunctionRegistryFactory::CreateFunctionRegistry(&func_registry).ok()); + { + FunctionSignature sign("load", {ValueType::kPtr, ValueType::kI32}, ValueType::kF32); + EXPECT_TRUE(func_registry->RegisterReadOnlyCFunc(sign, reinterpret_cast(LoadF32)).ok()); + } + + std::string code = R"( + a = load(entry_arg, 0); + let a = a + 1.0f32; + a = a + 2.0f32; + )"; + + std::vector codes = {code}; + auto st = athena.Compile(codes, func_registry); + EXPECT_FALSE(st.ok()); + EXPECT_NE(st.ToString().find("cannot redeclare variable 'a' with let"), std::string::npos) << st.ToString(); +} + +TEST(ConstVarTest, NestedWhenThirdLayerReadFirstLayerConst) { + AthenaPipeline athena; + std::unique_ptr func_registry; + EXPECT_TRUE(FunctionRegistryFactory::CreateFunctionRegistry(&func_registry).ok()); + { + FunctionSignature sign("load", {ValueType::kPtr, ValueType::kI32}, ValueType::kF32); + EXPECT_TRUE(func_registry->RegisterReadOnlyCFunc(sign, reinterpret_cast(LoadF32)).ok()); + } + { + FunctionSignature sign("store", {ValueType::kPtr, ValueType::kI32, ValueType::kF32}, ValueType::kVoid); + EXPECT_TRUE(func_registry->RegisterStoreCFunc(sign, reinterpret_cast(StoreF32), 1).ok()); + } + + std::string code = R"( + let a = load(entry_arg, 0); + b = 0.0f32; + when a > 0.0f32 { + when a > 5.0f32 { + when a > 10.0f32 { + b = a + 100.0f32; + } + } + } + store(output, 0, b); + )"; + + std::vector codes = {code}; + ASSERT_TRUE(athena.Compile(codes, func_registry).ok()); + + std::vector value = {15}; + std::vector output = {0}; + ASSERT_TRUE(athena.Execute(value.data(), output.data()).ok()); + + EXPECT_EQ(output[0], 115.0F); // 15 + 100 = 115 +} + +TEST(ConstVarTest, NestedWhenThirdLayerReadSecondLayerConst) { + AthenaPipeline athena; + std::unique_ptr func_registry; + EXPECT_TRUE(FunctionRegistryFactory::CreateFunctionRegistry(&func_registry).ok()); + { + FunctionSignature sign("load", {ValueType::kPtr, ValueType::kI32}, ValueType::kF32); + EXPECT_TRUE(func_registry->RegisterReadOnlyCFunc(sign, reinterpret_cast(LoadF32)).ok()); + } + { + FunctionSignature sign("store", {ValueType::kPtr, ValueType::kI32, ValueType::kF32}, ValueType::kVoid); + EXPECT_TRUE(func_registry->RegisterStoreCFunc(sign, reinterpret_cast(StoreF32), 1).ok()); + } + + std::string code = R"( + let a = load(entry_arg, 0); + b = 0.0f32; + when a > 0.0f32 { + let c = a * 2.0f32; + when c > 10.0f32 { + when c > 20.0f32 { + b = c + 1.0f32; + } + } + } + store(output, 0, b); + )"; + + std::vector codes = {code}; + ASSERT_TRUE(athena.Compile(codes, func_registry).ok()); + + std::vector value = {15}; + std::vector output = {0}; + ASSERT_TRUE(athena.Execute(value.data(), output.data()).ok()); + + EXPECT_EQ(output[0], 31.0F); // 15 * 2 + 1 = 31 +} + +TEST(ConstVarTest, NestedWhenSecondLayerReadFirstLayerConst) { + AthenaPipeline athena; + std::unique_ptr func_registry; + EXPECT_TRUE(FunctionRegistryFactory::CreateFunctionRegistry(&func_registry).ok()); + { + FunctionSignature sign("load", {ValueType::kPtr, ValueType::kI32}, ValueType::kF32); + EXPECT_TRUE(func_registry->RegisterReadOnlyCFunc(sign, reinterpret_cast(LoadF32)).ok()); + } + { + FunctionSignature sign("store", {ValueType::kPtr, ValueType::kI32, ValueType::kF32}, ValueType::kVoid); + EXPECT_TRUE(func_registry->RegisterStoreCFunc(sign, reinterpret_cast(StoreF32), 1).ok()); + } + + std::string code = R"( + let a = load(entry_arg, 0); + let b = load(entry_arg, 1); + result = 0.0f32; + when a > 0.0f32 { + let c = a + b; + when c > 10.0f32 { + result = c * a; + } + } + store(output, 0, result); + )"; + + std::vector codes = {code}; + ASSERT_TRUE(athena.Compile(codes, func_registry).ok()); + + std::vector value = {5, 8}; + std::vector output = {0}; + ASSERT_TRUE(athena.Execute(value.data(), output.data()).ok()); + + EXPECT_EQ(output[0], 65.0F); // c = 5 + 8 = 13, result = 13 * 5 = 65 +} + +TEST(ConstVarTest, NestedWhenThirdLayerModifyFirstLayerConstShouldFail) { + AthenaPipeline athena; + std::unique_ptr func_registry; + EXPECT_TRUE(FunctionRegistryFactory::CreateFunctionRegistry(&func_registry).ok()); + { + FunctionSignature sign("load", {ValueType::kPtr, ValueType::kI32}, ValueType::kF32); + EXPECT_TRUE(func_registry->RegisterReadOnlyCFunc(sign, reinterpret_cast(LoadF32)).ok()); + } + + std::string code = R"( + let a = load(entry_arg, 0); + when a > 0.0f32 { + when a > 5.0f32 { + when a > 10.0f32 { + a = 999.0f32; + } + } + } + )"; + + std::vector codes = {code}; + auto st = athena.Compile(codes, func_registry); + EXPECT_FALSE(st.ok()); + EXPECT_NE(st.ToString().find("cannot reassign const variable 'a'"), std::string::npos) << st.ToString(); +} + +TEST(ConstVarTest, NestedWhenThirdLayerModifySecondLayerConstShouldFail) { + AthenaPipeline athena; + std::unique_ptr func_registry; + EXPECT_TRUE(FunctionRegistryFactory::CreateFunctionRegistry(&func_registry).ok()); + { + FunctionSignature sign("load", {ValueType::kPtr, ValueType::kI32}, ValueType::kF32); + EXPECT_TRUE(func_registry->RegisterReadOnlyCFunc(sign, reinterpret_cast(LoadF32)).ok()); + } + + std::string code = R"( + let a = load(entry_arg, 0); + when a > 0.0f32 { + let b = a + 1.0f32; + when b > 5.0f32 { + when b > 10.0f32 { + b = 999.0f32; + } + } + } + )"; + + std::vector codes = {code}; + auto st = athena.Compile(codes, func_registry); + EXPECT_FALSE(st.ok()); + EXPECT_NE(st.ToString().find("cannot reassign const variable 'b'"), std::string::npos) << st.ToString(); +} + +TEST(ConstVarTest, NestedWhenSecondLayerModifyFirstLayerConstShouldFail) { + AthenaPipeline athena; + std::unique_ptr func_registry; + EXPECT_TRUE(FunctionRegistryFactory::CreateFunctionRegistry(&func_registry).ok()); + { + FunctionSignature sign("load", {ValueType::kPtr, ValueType::kI32}, ValueType::kF32); + EXPECT_TRUE(func_registry->RegisterReadOnlyCFunc(sign, reinterpret_cast(LoadF32)).ok()); + } + + std::string code = R"( + let a = load(entry_arg, 0); + when a > 0.0f32 { + when a > 5.0f32 { + a = 999.0f32; + } + } + )"; + + std::vector codes = {code}; + auto st = athena.Compile(codes, func_registry); + EXPECT_FALSE(st.ok()); + EXPECT_NE(st.ToString().find("cannot reassign const variable 'a'"), std::string::npos) << st.ToString(); +} + +TEST(ConstVarTest, NestedWhenMixedConstAndMutableComplex) { + AthenaPipeline athena; + std::unique_ptr func_registry; + EXPECT_TRUE(FunctionRegistryFactory::CreateFunctionRegistry(&func_registry).ok()); + { + FunctionSignature sign("load", {ValueType::kPtr, ValueType::kI32}, ValueType::kF32); + EXPECT_TRUE(func_registry->RegisterReadOnlyCFunc(sign, reinterpret_cast(LoadF32)).ok()); + } + { + FunctionSignature sign("store", {ValueType::kPtr, ValueType::kI32, ValueType::kF32}, ValueType::kVoid); + EXPECT_TRUE(func_registry->RegisterStoreCFunc(sign, reinterpret_cast(StoreF32), 1).ok()); + } + + std::string code = R"( + let a = load(entry_arg, 0); + result = 0.0f32; + when a > 0.0f32 { + let b = a * 3.0f32; + result = b; + when b > 10.0f32 { + let c = a + b; + when c > 50.0f32 { + result = c + a + b; + } + } + } + store(output, 0, result); + )"; + + std::vector codes = {code}; + ASSERT_TRUE(athena.Compile(codes, func_registry).ok()); + + std::vector value = {20}; + std::vector output = {0}; + ASSERT_TRUE(athena.Execute(value.data(), output.data()).ok()); + + EXPECT_EQ(output[0], 160.0F); +} diff --git a/athena/test/diagnostic_test.cc b/athena/test/diagnostic_test.cc index f213729..8812fde 100644 --- a/athena/test/diagnostic_test.cc +++ b/athena/test/diagnostic_test.cc @@ -468,5 +468,5 @@ store(output, 0, r); ASSERT_FALSE(st.ok()); const std::string msg = st.ToString(); EXPECT_NE(msg.find("variable 'r'"), std::string::npos) << msg; - EXPECT_NE(msg.find("incompatible types across if block"), std::string::npos) << msg; + EXPECT_NE(msg.find("cannot assign"), std::string::npos) << msg; } diff --git a/athena/test/when_test.cc b/athena/test/when_test.cc index f602e1d..4af9eae 100644 --- a/athena/test/when_test.cc +++ b/athena/test/when_test.cc @@ -1431,7 +1431,7 @@ TEST(WhenTest, VariableTypeMismatchInWhenBranch) { std::vector codes = {code}; auto status = athena.Compile(codes, func_registry); EXPECT_FALSE(status.ok()); - EXPECT_NE(status.ToString().find("incompatible types"), std::string::npos); + EXPECT_NE(status.ToString().find("cannot assign"), std::string::npos); } TEST(WhenTest, VariableTypeMismatchInElseBranch) { @@ -1461,7 +1461,7 @@ TEST(WhenTest, VariableTypeMismatchInElseBranch) { std::vector codes = {code}; auto status = athena.Compile(codes, func_registry); EXPECT_FALSE(status.ok()); - EXPECT_NE(status.ToString().find("incompatible types"), std::string::npos); + EXPECT_NE(status.ToString().find("cannot assign"), std::string::npos); } TEST(WhenTest, StringConditionReject) { diff --git a/athena/token.cc b/athena/token.cc index 7a9bd53..7eae7a9 100644 --- a/athena/token.cc +++ b/athena/token.cc @@ -550,8 +550,8 @@ static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); yyg->yy_hold_char = *yy_cp; \ *yy_cp = '\0'; \ yyg->yy_c_buf_p = yy_cp; -#define YY_NUM_RULES 62 -#define YY_END_OF_BUFFER 63 +#define YY_NUM_RULES 63 +#define YY_END_OF_BUFFER 64 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -559,24 +559,24 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static const flex_int16_t yy_accept[143] = +static const flex_int16_t yy_accept[146] = { 0, - 0, 0, 63, 62, 1, 2, 14, 62, 25, 28, - 62, 23, 24, 21, 20, 37, 19, 62, 22, 46, - 12, 33, 31, 35, 45, 38, 39, 27, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 10, 26, 11, - 29, 1, 2, 32, 0, 60, 0, 15, 0, 61, - 0, 55, 0, 3, 55, 46, 0, 0, 0, 40, - 34, 30, 36, 41, 45, 45, 45, 45, 45, 45, - 6, 13, 45, 16, 45, 45, 45, 45, 16, 0, - 0, 0, 3, 55, 0, 0, 0, 0, 0, 51, - 0, 0, 0, 47, 15, 45, 45, 45, 45, 45, - - 14, 45, 45, 45, 45, 0, 0, 4, 58, 59, - 52, 53, 54, 48, 49, 50, 7, 8, 45, 45, - 45, 45, 45, 17, 5, 56, 57, 45, 45, 18, - 45, 45, 45, 45, 44, 9, 45, 45, 45, 43, - 42, 0 + 0, 0, 64, 63, 1, 2, 15, 63, 26, 29, + 63, 24, 25, 22, 21, 38, 20, 63, 23, 47, + 13, 34, 32, 36, 46, 39, 40, 28, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 46, 11, 27, + 12, 30, 1, 2, 33, 0, 61, 0, 16, 0, + 62, 0, 56, 0, 3, 56, 47, 0, 0, 0, + 41, 35, 31, 37, 42, 46, 46, 46, 46, 46, + 46, 7, 14, 46, 46, 17, 46, 46, 46, 46, + 17, 0, 0, 0, 3, 56, 0, 0, 0, 0, + 0, 52, 0, 0, 0, 48, 16, 46, 46, 46, + + 46, 46, 5, 15, 46, 46, 46, 46, 0, 0, + 4, 59, 60, 53, 54, 55, 49, 50, 51, 8, + 9, 46, 46, 46, 46, 46, 18, 6, 57, 58, + 46, 46, 19, 46, 46, 46, 46, 45, 10, 46, + 46, 46, 44, 43, 0 } ; static const YY_CHAR yy_ec[256] = @@ -621,81 +621,83 @@ static const YY_CHAR yy_meta[57] = 5, 5, 1, 1, 1, 1 } ; -static const flex_int16_t yy_base[149] = +static const flex_int16_t yy_base[152] = { 0, - 0, 0, 217, 218, 214, 212, 188, 52, 218, 206, - 50, 218, 218, 218, 218, 218, 218, 42, 55, 52, - 218, 43, 186, 46, 0, 218, 218, 218, 168, 32, - 176, 38, 165, 38, 158, 161, 166, 218, 151, 218, - 218, 202, 200, 218, 72, 218, 199, 218, 70, 218, - 198, 86, 189, 0, 93, 79, 66, 103, 112, 218, - 218, 218, 218, 218, 0, 163, 38, 150, 160, 154, - 0, 0, 147, 0, 146, 152, 143, 154, 218, 69, - 179, 81, 0, 119, 170, 167, 165, 167, 164, 218, - 162, 164, 161, 218, 0, 140, 119, 109, 119, 106, - - 0, 107, 103, 113, 106, 129, 126, 218, 218, 218, - 218, 218, 218, 218, 218, 218, 0, 0, 94, 112, - 107, 94, 98, 0, 0, 218, 218, 96, 92, 0, - 74, 79, 84, 51, 0, 0, 52, 45, 56, 0, - 0, 218, 157, 162, 165, 166, 171, 176 + 0, 0, 219, 220, 216, 214, 190, 52, 220, 208, + 50, 220, 220, 220, 220, 220, 220, 42, 55, 52, + 220, 43, 188, 46, 0, 220, 220, 220, 170, 32, + 178, 38, 174, 166, 38, 159, 162, 167, 220, 152, + 220, 220, 203, 201, 220, 72, 220, 200, 220, 70, + 220, 199, 86, 190, 0, 93, 79, 66, 103, 112, + 220, 220, 220, 220, 220, 0, 164, 38, 151, 161, + 155, 0, 0, 148, 147, 0, 146, 152, 143, 154, + 220, 69, 179, 81, 0, 119, 170, 167, 165, 167, + 164, 220, 162, 164, 161, 220, 0, 140, 119, 109, + + 119, 106, 0, 0, 107, 103, 113, 106, 129, 126, + 220, 220, 220, 220, 220, 220, 220, 220, 220, 0, + 0, 94, 112, 107, 94, 98, 0, 0, 220, 220, + 96, 92, 0, 74, 79, 84, 51, 0, 0, 52, + 45, 56, 0, 0, 220, 157, 162, 165, 166, 171, + 176 } ; -static const flex_int16_t yy_def[149] = +static const flex_int16_t yy_def[152] = { 0, - 142, 1, 142, 142, 142, 142, 142, 143, 142, 142, - 144, 142, 142, 142, 142, 142, 142, 142, 142, 145, - 142, 142, 142, 142, 146, 142, 142, 142, 146, 146, - 146, 146, 146, 146, 146, 146, 146, 142, 142, 142, - 142, 142, 142, 142, 143, 142, 143, 142, 144, 142, - 144, 142, 147, 148, 142, 145, 142, 142, 142, 142, - 142, 142, 142, 142, 146, 146, 146, 146, 146, 146, - 146, 146, 146, 146, 146, 146, 146, 146, 142, 142, - 147, 147, 148, 142, 142, 142, 142, 142, 142, 142, - 142, 142, 142, 142, 146, 146, 146, 146, 146, 146, - - 146, 146, 146, 146, 146, 142, 142, 142, 142, 142, - 142, 142, 142, 142, 142, 142, 146, 146, 146, 146, - 146, 146, 146, 146, 146, 142, 142, 146, 146, 146, - 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, - 146, 0, 142, 142, 142, 142, 142, 142 + 145, 1, 145, 145, 145, 145, 145, 146, 145, 145, + 147, 145, 145, 145, 145, 145, 145, 145, 145, 148, + 145, 145, 145, 145, 149, 145, 145, 145, 149, 149, + 149, 149, 149, 149, 149, 149, 149, 149, 145, 145, + 145, 145, 145, 145, 145, 146, 145, 146, 145, 147, + 145, 147, 145, 150, 151, 145, 148, 145, 145, 145, + 145, 145, 145, 145, 145, 149, 149, 149, 149, 149, + 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, + 145, 145, 150, 150, 151, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 149, 149, 149, 149, + + 149, 149, 149, 149, 149, 149, 149, 149, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 149, + 149, 149, 149, 149, 149, 149, 149, 149, 145, 145, + 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, + 149, 149, 149, 149, 0, 145, 145, 145, 145, 145, + 145 } ; -static const flex_int16_t yy_nxt[275] = +static const flex_int16_t yy_nxt[277] = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 20, 20, 20, 20, 20, 20, 21, 22, 23, 24, 25, 26, 4, 27, 28, 4, 29, 25, 25, 30, 31, 25, 25, - 32, 25, 33, 34, 25, 25, 35, 36, 25, 37, - 25, 25, 38, 39, 40, 41, 46, 50, 52, 52, - 52, 52, 52, 52, 52, 53, 55, 60, 61, 44, - 54, 63, 64, 67, 68, 71, 46, 50, 96, 51, - 72, 47, 69, 74, 97, 85, 75, 86, 106, 57, - 107, 82, 58, 55, 141, 140, 108, 139, 138, 51, - - 59, 47, 52, 52, 52, 52, 52, 52, 52, 84, - 84, 84, 84, 84, 84, 84, 57, 137, 136, 58, - 87, 135, 88, 80, 89, 90, 134, 59, 133, 91, - 80, 92, 132, 93, 94, 84, 84, 84, 84, 84, - 84, 84, 131, 130, 129, 128, 127, 126, 125, 124, - 123, 122, 121, 120, 119, 118, 80, 45, 45, 45, - 45, 45, 49, 49, 49, 49, 49, 56, 56, 65, - 65, 81, 81, 81, 81, 81, 83, 117, 83, 83, - 83, 116, 115, 114, 113, 112, 111, 110, 109, 82, - 105, 104, 103, 102, 101, 100, 99, 98, 95, 82, - - 142, 142, 43, 42, 79, 78, 77, 76, 73, 70, - 66, 62, 48, 44, 43, 42, 142, 3, 142, 142, - 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, - 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, - 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, - 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, - 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, - 142, 142, 142, 142 + 32, 33, 34, 35, 25, 25, 36, 37, 25, 38, + 25, 25, 39, 40, 41, 42, 47, 51, 53, 53, + 53, 53, 53, 53, 53, 54, 56, 61, 62, 45, + 55, 64, 65, 68, 69, 72, 47, 51, 98, 52, + 73, 48, 70, 76, 99, 87, 77, 88, 109, 58, + 110, 84, 59, 56, 144, 143, 111, 142, 141, 52, + + 60, 48, 53, 53, 53, 53, 53, 53, 53, 86, + 86, 86, 86, 86, 86, 86, 58, 140, 139, 59, + 89, 138, 90, 82, 91, 92, 137, 60, 136, 93, + 82, 94, 135, 95, 96, 86, 86, 86, 86, 86, + 86, 86, 134, 133, 132, 131, 130, 129, 128, 127, + 126, 125, 124, 123, 122, 121, 82, 46, 46, 46, + 46, 46, 50, 50, 50, 50, 50, 57, 57, 66, + 66, 83, 83, 83, 83, 83, 85, 120, 85, 85, + 85, 119, 118, 117, 116, 115, 114, 113, 112, 84, + 108, 107, 106, 105, 104, 103, 102, 101, 100, 97, + + 84, 145, 145, 44, 43, 81, 80, 79, 78, 75, + 74, 71, 67, 63, 49, 45, 44, 43, 145, 3, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145 } ; -static const flex_int16_t yy_chk[275] = +static const flex_int16_t yy_chk[277] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -704,29 +706,29 @@ static const flex_int16_t yy_chk[275] = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 11, 18, 18, 18, 18, 18, 18, 18, 19, 20, 22, 22, 22, - 19, 24, 24, 30, 30, 32, 45, 49, 67, 11, - 32, 8, 30, 34, 67, 57, 34, 57, 80, 20, - 80, 82, 20, 56, 139, 138, 82, 137, 134, 49, - - 20, 45, 52, 52, 52, 52, 52, 52, 52, 55, - 55, 55, 55, 55, 55, 55, 56, 133, 132, 56, - 58, 131, 58, 52, 58, 58, 129, 56, 128, 59, - 55, 59, 123, 59, 59, 84, 84, 84, 84, 84, - 84, 84, 122, 121, 120, 119, 107, 106, 105, 104, - 103, 102, 100, 99, 98, 97, 84, 143, 143, 143, - 143, 143, 144, 144, 144, 144, 144, 145, 145, 146, - 146, 147, 147, 147, 147, 147, 148, 96, 148, 148, - 148, 93, 92, 91, 89, 88, 87, 86, 85, 81, - 78, 77, 76, 75, 73, 70, 69, 68, 66, 53, - - 51, 47, 43, 42, 39, 37, 36, 35, 33, 31, - 29, 23, 10, 7, 6, 5, 3, 142, 142, 142, - 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, - 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, - 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, - 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, - 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, - 142, 142, 142, 142 + 19, 24, 24, 30, 30, 32, 46, 50, 68, 11, + 32, 8, 30, 35, 68, 58, 35, 58, 82, 20, + 82, 84, 20, 57, 142, 141, 84, 140, 137, 50, + + 20, 46, 53, 53, 53, 53, 53, 53, 53, 56, + 56, 56, 56, 56, 56, 56, 57, 136, 135, 57, + 59, 134, 59, 53, 59, 59, 132, 57, 131, 60, + 56, 60, 126, 60, 60, 86, 86, 86, 86, 86, + 86, 86, 125, 124, 123, 122, 110, 109, 108, 107, + 106, 105, 102, 101, 100, 99, 86, 146, 146, 146, + 146, 146, 147, 147, 147, 147, 147, 148, 148, 149, + 149, 150, 150, 150, 150, 150, 151, 98, 151, 151, + 151, 95, 94, 93, 91, 90, 89, 88, 87, 83, + 80, 79, 78, 77, 75, 74, 71, 70, 69, 67, + + 54, 52, 48, 44, 43, 40, 38, 37, 36, 34, + 33, 31, 29, 23, 10, 7, 6, 5, 3, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145 } ; /* The intent behind this definition is that it'll catch @@ -745,7 +747,7 @@ static const flex_int16_t yy_chk[275] = #include #include #include -#line 748 "token.cc" +#line 750 "token.cc" #line 15 "token.ll" #if defined __clang__ # define CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) @@ -816,13 +818,13 @@ static const flex_int16_t yy_chk[275] = #if defined GCC_VERSION && 900 <= GCC_VERSION # pragma GCC diagnostic ignored "-Wuseless-cast" #endif -#line 819 "token.cc" +#line 821 "token.cc" #define YY_NO_INPUT 1 #line 94 "token.ll" // Code run each time a pattern is matched. # define YY_USER_ACTION loc.columns (yyleng); -#line 824 "token.cc" -#line 825 "token.cc" +#line 826 "token.cc" +#line 827 "token.cc" #define INITIAL 0 @@ -1089,7 +1091,7 @@ YY_DECL // Code run each time yylex is called. loc.step (); -#line 1092 "token.cc" +#line 1094 "token.cc" while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { @@ -1116,13 +1118,13 @@ YY_DECL while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 143 ) + if ( yy_current_state >= 146 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; ++yy_cp; } - while ( yy_current_state != 142 ); + while ( yy_current_state != 145 ); yy_cp = yyg->yy_last_accepting_cpos; yy_current_state = yyg->yy_last_accepting_state; @@ -1172,300 +1174,305 @@ YY_RULE_SETUP case 5: YY_RULE_SETUP #line 116 "token.ll" -return athena::Parser::make_WHEN (loc); +return athena::Parser::make_LET (loc); YY_BREAK case 6: YY_RULE_SETUP #line 117 "token.ll" -return athena::Parser::make_IF (loc); +return athena::Parser::make_WHEN (loc); YY_BREAK case 7: YY_RULE_SETUP #line 118 "token.ll" -return athena::Parser::make_ELIF (loc); +return athena::Parser::make_IF (loc); YY_BREAK case 8: YY_RULE_SETUP #line 119 "token.ll" -return athena::Parser::make_ELSE (loc); +return athena::Parser::make_ELIF (loc); YY_BREAK case 9: YY_RULE_SETUP #line 120 "token.ll" -return athena::Parser::make_SWITCH (loc); +return athena::Parser::make_ELSE (loc); YY_BREAK case 10: YY_RULE_SETUP #line 121 "token.ll" -return athena::Parser::make_LBRACE (loc); +return athena::Parser::make_SWITCH (loc); YY_BREAK case 11: YY_RULE_SETUP #line 122 "token.ll" -return athena::Parser::make_RBRACE (loc); +return athena::Parser::make_LBRACE (loc); YY_BREAK case 12: YY_RULE_SETUP #line 123 "token.ll" -return athena::Parser::make_SEMI (loc); +return athena::Parser::make_RBRACE (loc); YY_BREAK case 13: YY_RULE_SETUP -#line 125 "token.ll" -return athena::Parser::make_IN (loc); +#line 124 "token.ll" +return athena::Parser::make_SEMI (loc); YY_BREAK case 14: YY_RULE_SETUP #line 126 "token.ll" -return athena::Parser::make_NOT (loc); +return athena::Parser::make_IN (loc); YY_BREAK case 15: YY_RULE_SETUP #line 127 "token.ll" -return athena::Parser::make_AND (loc); +return athena::Parser::make_NOT (loc); YY_BREAK case 16: YY_RULE_SETUP #line 128 "token.ll" -return athena::Parser::make_OR (loc); +return athena::Parser::make_AND (loc); YY_BREAK case 17: YY_RULE_SETUP #line 129 "token.ll" -return athena::Parser::make_TRUE (loc); +return athena::Parser::make_OR (loc); YY_BREAK case 18: YY_RULE_SETUP #line 130 "token.ll" -return athena::Parser::make_FALSE (loc); +return athena::Parser::make_TRUE (loc); YY_BREAK case 19: YY_RULE_SETUP #line 131 "token.ll" -return athena::Parser::make_MINUS (loc); +return athena::Parser::make_FALSE (loc); YY_BREAK case 20: YY_RULE_SETUP #line 132 "token.ll" -return athena::Parser::make_PLUS (loc); +return athena::Parser::make_MINUS (loc); YY_BREAK case 21: YY_RULE_SETUP #line 133 "token.ll" -return athena::Parser::make_STAR (loc); +return athena::Parser::make_PLUS (loc); YY_BREAK case 22: YY_RULE_SETUP #line 134 "token.ll" -return athena::Parser::make_SLASH (loc); +return athena::Parser::make_STAR (loc); YY_BREAK case 23: YY_RULE_SETUP #line 135 "token.ll" -return athena::Parser::make_LPAREN (loc); +return athena::Parser::make_SLASH (loc); YY_BREAK case 24: YY_RULE_SETUP #line 136 "token.ll" -return athena::Parser::make_RPAREN (loc); +return athena::Parser::make_LPAREN (loc); YY_BREAK case 25: YY_RULE_SETUP #line 137 "token.ll" -return athena::Parser::make_MODOLO (loc); +return athena::Parser::make_RPAREN (loc); YY_BREAK case 26: YY_RULE_SETUP #line 138 "token.ll" -return athena::Parser::make_BITWISE_OR (loc); +return athena::Parser::make_MODOLO (loc); YY_BREAK case 27: YY_RULE_SETUP #line 139 "token.ll" -return athena::Parser::make_BITWISE_XOR (loc); +return athena::Parser::make_BITWISE_OR (loc); YY_BREAK case 28: YY_RULE_SETUP #line 140 "token.ll" -return athena::Parser::make_BITWISE_AND (loc); +return athena::Parser::make_BITWISE_XOR (loc); YY_BREAK case 29: YY_RULE_SETUP #line 141 "token.ll" -return athena::Parser::make_BITWISE_NOT (loc); +return athena::Parser::make_BITWISE_AND (loc); YY_BREAK case 30: YY_RULE_SETUP #line 142 "token.ll" -return athena::Parser::make_EQUAL (loc); +return athena::Parser::make_BITWISE_NOT (loc); YY_BREAK case 31: YY_RULE_SETUP #line 143 "token.ll" -return athena::Parser::make_ASSIGNMENT (loc); +return athena::Parser::make_EQUAL (loc); YY_BREAK case 32: YY_RULE_SETUP #line 144 "token.ll" -return athena::Parser::make_NOT_EQUAL (loc); +return athena::Parser::make_ASSIGNMENT (loc); YY_BREAK case 33: YY_RULE_SETUP #line 145 "token.ll" -return athena::Parser::make_LESS_THAN (loc); +return athena::Parser::make_NOT_EQUAL (loc); YY_BREAK case 34: YY_RULE_SETUP #line 146 "token.ll" -return athena::Parser::make_LESS_THAN_OR_EQUAL_TO (loc); +return athena::Parser::make_LESS_THAN (loc); YY_BREAK case 35: YY_RULE_SETUP #line 147 "token.ll" -return athena::Parser::make_GREATER_THAN (loc); +return athena::Parser::make_LESS_THAN_OR_EQUAL_TO (loc); YY_BREAK case 36: YY_RULE_SETUP #line 148 "token.ll" -return athena::Parser::make_GREATER_THAN_OR_EQUAL_TO (loc); +return athena::Parser::make_GREATER_THAN (loc); YY_BREAK case 37: YY_RULE_SETUP #line 149 "token.ll" -return athena::Parser::make_COMMA (loc); +return athena::Parser::make_GREATER_THAN_OR_EQUAL_TO (loc); YY_BREAK case 38: YY_RULE_SETUP #line 150 "token.ll" -return athena::Parser::make_LBRACKET (loc); +return athena::Parser::make_COMMA (loc); YY_BREAK case 39: YY_RULE_SETUP #line 151 "token.ll" -return athena::Parser::make_RBRACKET (loc); +return athena::Parser::make_LBRACKET (loc); YY_BREAK case 40: YY_RULE_SETUP #line 152 "token.ll" -return athena::Parser::make_BITWISE_LEFT (loc); +return athena::Parser::make_RBRACKET (loc); YY_BREAK case 41: YY_RULE_SETUP #line 153 "token.ll" -return athena::Parser::make_BITWISE_RIGHT (loc); +return athena::Parser::make_BITWISE_LEFT (loc); YY_BREAK case 42: YY_RULE_SETUP -#line 155 "token.ll" -return athena::Parser::make_ENTRY_ARG (loc); +#line 154 "token.ll" +return athena::Parser::make_BITWISE_RIGHT (loc); YY_BREAK case 43: YY_RULE_SETUP #line 156 "token.ll" -return athena::Parser::make_EXEC_CTX (loc); +return athena::Parser::make_ENTRY_ARG (loc); YY_BREAK case 44: YY_RULE_SETUP #line 157 "token.ll" -return athena::Parser::make_OUTPUT (loc); +return athena::Parser::make_EXEC_CTX (loc); YY_BREAK case 45: YY_RULE_SETUP -#line 159 "token.ll" -return athena::Parser::make_IDENTIFIER (std::string(yytext), loc); +#line 158 "token.ll" +return athena::Parser::make_OUTPUT (loc); YY_BREAK case 46: YY_RULE_SETUP -#line 161 "token.ll" -return athena::Parser::make_I32 (std::stoull(yytext), loc); +#line 160 "token.ll" +return athena::Parser::make_IDENTIFIER (std::string(yytext), loc); YY_BREAK case 47: YY_RULE_SETUP #line 162 "token.ll" -return athena::Parser::make_U8 (std::stoull(yytext), loc); +return athena::Parser::make_I32 (std::stoull(yytext), loc); YY_BREAK case 48: YY_RULE_SETUP #line 163 "token.ll" -return athena::Parser::make_U16 (std::stoull(yytext), loc); +return athena::Parser::make_U8 (std::stoull(yytext), loc); YY_BREAK case 49: YY_RULE_SETUP #line 164 "token.ll" -return athena::Parser::make_U32 (std::stoull(yytext), loc); +return athena::Parser::make_U16 (std::stoull(yytext), loc); YY_BREAK case 50: YY_RULE_SETUP #line 165 "token.ll" -return athena::Parser::make_U64 (std::stoull(yytext), loc); +return athena::Parser::make_U32 (std::stoull(yytext), loc); YY_BREAK case 51: YY_RULE_SETUP #line 166 "token.ll" -return athena::Parser::make_I8 (std::stoull(yytext), loc); +return athena::Parser::make_U64 (std::stoull(yytext), loc); YY_BREAK case 52: YY_RULE_SETUP #line 167 "token.ll" -return athena::Parser::make_I16 (std::stoull(yytext), loc); +return athena::Parser::make_I8 (std::stoull(yytext), loc); YY_BREAK case 53: YY_RULE_SETUP #line 168 "token.ll" -return athena::Parser::make_I32 (std::stoull(yytext), loc); +return athena::Parser::make_I16 (std::stoull(yytext), loc); YY_BREAK case 54: YY_RULE_SETUP #line 169 "token.ll" -return athena::Parser::make_I64 (std::stoull(yytext), loc); +return athena::Parser::make_I32 (std::stoull(yytext), loc); YY_BREAK case 55: YY_RULE_SETUP -#line 171 "token.ll" -return athena::Parser::make_F64 (std::stod(yytext), loc); +#line 170 "token.ll" +return athena::Parser::make_I64 (std::stoull(yytext), loc); YY_BREAK case 56: YY_RULE_SETUP #line 172 "token.ll" -return athena::Parser::make_F32 (std::stof(yytext), loc); +return athena::Parser::make_F64 (std::stod(yytext), loc); YY_BREAK case 57: YY_RULE_SETUP #line 173 "token.ll" -return athena::Parser::make_F64 (std::stod(yytext), loc); +return athena::Parser::make_F32 (std::stof(yytext), loc); YY_BREAK case 58: YY_RULE_SETUP #line 174 "token.ll" -return athena::Parser::make_F32 (std::stof(yytext), loc); +return athena::Parser::make_F64 (std::stod(yytext), loc); YY_BREAK case 59: YY_RULE_SETUP #line 175 "token.ll" -return athena::Parser::make_F64 (std::stod(yytext), loc); +return athena::Parser::make_F32 (std::stof(yytext), loc); YY_BREAK case 60: -/* rule 60 can match eol */ YY_RULE_SETUP -#line 178 "token.ll" -return athena::Parser::make_STRING (std::string(yytext + 1, yyleng - 2), loc); +#line 176 "token.ll" +return athena::Parser::make_F64 (std::stod(yytext), loc); YY_BREAK case 61: /* rule 61 can match eol */ YY_RULE_SETUP #line 179 "token.ll" +return athena::Parser::make_STRING (std::string(yytext + 1, yyleng - 2), loc); + YY_BREAK +case 62: +/* rule 62 can match eol */ +YY_RULE_SETUP +#line 180 "token.ll" return athena::Parser::make_STRING (std::string(yytext + 1, yyleng - 2), loc); YY_BREAK case YY_STATE_EOF(INITIAL): -#line 181 "token.ll" +#line 182 "token.ll" return athena::Parser::make_YYEOF (loc); YY_BREAK -case 62: +case 63: YY_RULE_SETUP -#line 182 "token.ll" +#line 183 "token.ll" ECHO; YY_BREAK -#line 1468 "token.cc" +#line 1475 "token.cc" case YY_END_OF_BUFFER: { @@ -1763,7 +1770,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 143 ) + if ( yy_current_state >= 146 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; @@ -1792,11 +1799,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 143 ) + if ( yy_current_state >= 146 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; - yy_is_jam = (yy_current_state == 142); + yy_is_jam = (yy_current_state == 145); (void)yyg; return yy_is_jam ? 0 : yy_current_state; @@ -2595,7 +2602,7 @@ void yyfree (void * ptr , yyscan_t yyscanner) #define YYTABLES_NAME "yytables" -#line 182 "token.ll" +#line 183 "token.ll" jitfusion::Status athena::ProgramAstBuilder::Scan(const std::string &code) { diff --git a/athena/token.ll b/athena/token.ll index 777a285..3c19b09 100644 --- a/athena/token.ll +++ b/athena/token.ll @@ -112,6 +112,7 @@ blank [ \t\r] loc.step(); } +"let" return athena::Parser::make_LET (loc); "when" return athena::Parser::make_WHEN (loc); "if" return athena::Parser::make_IF (loc); "elif" return athena::Parser::make_ELIF (loc); diff --git a/benchmark/bench_execute_core.cc b/benchmark/bench_execute_core.cc index a99a3ce..ec8f9e0 100644 --- a/benchmark/bench_execute_core.cc +++ b/benchmark/bench_execute_core.cc @@ -11,11 +11,6 @@ namespace { -using ::jitfusion::bench::CompileOrDie; -using ::jitfusion::bench::MakeLinearAddChain; -using ::jitfusion::bench::MakeRegistry; -using ::jitfusion::bench::MakeRegistryWithStore; -using ::jitfusion::bench::MakeStoreI32; using ::jitfusion::BinaryOPNode; using ::jitfusion::BinaryOPType; using ::jitfusion::ConstantValueNode; @@ -28,6 +23,11 @@ using ::jitfusion::NoOPNode; using ::jitfusion::RefNode; using ::jitfusion::RetType; using ::jitfusion::SwitchNode; +using ::jitfusion::bench::CompileOrDie; +using ::jitfusion::bench::MakeLinearAddChain; +using ::jitfusion::bench::MakeRegistry; +using ::jitfusion::bench::MakeRegistryWithStore; +using ::jitfusion::bench::MakeStoreI32; // ============================================================================= // B. Execute @@ -162,7 +162,7 @@ void BM_Execute_IfBlock(benchmark::State& state) { auto reg = MakeRegistryWithStore(); auto make_block = [](int32_t v) { - auto block = std::unique_ptr(new NoOPNode({}, {})); + auto block = std::unique_ptr(new NoOPNode(std::vector>{})); static_cast(block.get())->AppendArgs("result", std::unique_ptr(new ConstantValueNode(v))); return block; }; @@ -179,7 +179,7 @@ void BM_Execute_IfBlock(benchmark::State& state) { // `result` must be declared in the outer scope so RefNode("result") can // resolve it after the IfBlock; this matches the pattern used in // test/if_block_test.cc. - auto root = std::unique_ptr(new NoOPNode({}, {})); + auto root = std::unique_ptr(new NoOPNode(std::vector>{})); static_cast(root.get()) ->AppendArgs("result", std::unique_ptr(new ConstantValueNode(static_cast(0)))); static_cast(root.get())->AppendArgs(std::move(if_block)); @@ -217,11 +217,11 @@ void BM_Execute_RefNode(benchmark::State& state) { auto product = std::unique_ptr(new BinaryOPNode( BinaryOPType::kMul, std::unique_ptr(new RefNode("x")), std::unique_ptr(new RefNode("x")))); - std::vector names = {"x", ""}; + std::vector var_infos = {{"x", false}, {"", false}}; std::vector> items; items.emplace_back(std::move(inner)); items.emplace_back(MakeStoreI32(0, std::move(product))); - std::unique_ptr node(new NoOPNode(std::move(names), std::move(items))); + std::unique_ptr node(new NoOPNode(std::move(var_infos), std::move(items))); auto engine = CompileOrDie(std::move(node), reg); ExecContext ctx(4096); diff --git a/include/exec_node.h b/include/exec_node.h index 0261632..f71e0df 100644 --- a/include/exec_node.h +++ b/include/exec_node.h @@ -10,6 +10,7 @@ #include #include #include +#include #include "status.h" #include "type.h" @@ -175,23 +176,31 @@ class FunctionNode : public ExecNode { std::vector> args_; }; +struct VarInfo { + VarInfo() = default; + VarInfo(std::string name, bool is_const) : name(std::move(name)), is_const(is_const) {} + std::string name; + bool is_const{false}; +}; + class NoOPNode : public ExecNode { public: NoOPNode() = delete; - explicit NoOPNode(std::vector> args) : names_(args.size()), args_(std::move(args)) {} + explicit NoOPNode(std::vector> args) : var_infos_(args.size()), args_(std::move(args)) {} NoOPNode(std::vector> args, bool isolated) - : names_(args.size()), args_(std::move(args)), isolated_(isolated) {} - NoOPNode(std::vector names, std::vector> args) - : names_(std::move(names)), args_(std::move(args)) {} - NoOPNode(std::vector names, std::vector> args, bool isolated) - : names_(std::move(names)), args_(std::move(args)), isolated_(isolated) {} + : var_infos_(args.size()), args_(std::move(args)), isolated_(isolated) {} + NoOPNode(std::vector var_infos, std::vector> args) + : var_infos_(std::move(var_infos)), args_(std::move(args)) {} + NoOPNode(std::vector var_infos, std::vector> args, bool isolated) + : var_infos_(std::move(var_infos)), args_(std::move(args)), isolated_(isolated) {} Status Accept(Visitor* visitor) override; ExecNodeType GetExecNodeType() override; void AppendArgs(std::unique_ptr&& arg); void AppendArgs(std::string name, std::unique_ptr&& arg); + void AppendArgs(std::string name, std::unique_ptr&& arg, bool is_const); [[nodiscard]] const std::vector>& GetArgs() const { return args_; } - [[nodiscard]] const std::vector& GetNames() const { return names_; } + [[nodiscard]] const std::vector& GetVarInfos() const { return var_infos_; } [[nodiscard]] bool IsIsolated() const { return isolated_; } @@ -199,7 +208,7 @@ class NoOPNode : public ExecNode { std::string ToStringImpl(const std::string& prefix) override; std::unique_ptr CloneImpl() override; - std::vector names_; + std::vector var_infos_; std::vector> args_; bool isolated_{false}; }; diff --git a/src/codegen/if_block_codegen.cc b/src/codegen/if_block_codegen.cc index 9599be2..9a09732 100644 --- a/src/codegen/if_block_codegen.cc +++ b/src/codegen/if_block_codegen.cc @@ -113,7 +113,7 @@ Status CodeGen::Visit(IfBlockNode &if_block_node) { } for (const auto &var_name : all_modified_vars) { - llvm::Value *original_value = scope_stack_.Lookup(var_name); + llvm::Value *original_value = *scope_stack_.Lookup(var_name); llvm::PHINode *phi = ctx_.builder.CreatePHI(original_value->getType(), num_incoming, var_name + ".phi"); for (const auto &info : branch_infos) { auto it = info.modified.find(var_name); diff --git a/src/codegen/no_op_codegen.cc b/src/codegen/no_op_codegen.cc index 74388cd..50bc52c 100644 --- a/src/codegen/no_op_codegen.cc +++ b/src/codegen/no_op_codegen.cc @@ -10,7 +10,7 @@ namespace jitfusion { Status CodeGen::Visit(NoOPNode& no_op_node) { - const auto& names = no_op_node.GetNames(); + const auto& var_infos = no_op_node.GetVarInfos(); const auto& args = no_op_node.GetArgs(); const bool isolated = no_op_node.IsIsolated(); for (size_t i = 0; i < args.size(); ++i) { @@ -26,8 +26,8 @@ Status CodeGen::Visit(NoOPNode& no_op_node) { } llvm::Value* args_value; JF_RETURN_NOT_OK(GetValue(args[i].get(), &args_value)); - if (!names[i].empty()) { - scope_stack_.Set(names[i], args_value); + if (!var_infos[i].name.empty()) { + scope_stack_.Set(var_infos[i].name, args_value); } if (isolated) { scope_stack_.PopScope(); diff --git a/src/codegen/ref_node_codegen.cc b/src/codegen/ref_node_codegen.cc index 958b401..405e9cd 100644 --- a/src/codegen/ref_node_codegen.cc +++ b/src/codegen/ref_node_codegen.cc @@ -10,12 +10,12 @@ namespace jitfusion { Status CodeGen::Visit(RefNode& ref_node) { - llvm::Value* val = scope_stack_.Lookup(ref_node.GetName()); - if (nullptr == val) { + auto val = scope_stack_.Lookup(ref_node.GetName()); + if (!val.has_value()) { return Status::RuntimeError("[internal] variable not found in codegen scope: ", ref_node.GetName(), " (should be caught by validator)"); } - value_ = val; + value_ = *val; return Status::OK(); } diff --git a/src/exec_node.cc b/src/exec_node.cc index 963a8ea..7aeb7eb 100644 --- a/src/exec_node.cc +++ b/src/exec_node.cc @@ -125,8 +125,14 @@ std::unique_ptr FunctionNode::CloneImpl() { std::string NoOPNode::ToStringImpl(const std::string& prefix) { std::string result = prefix + "|--no_op\n"; for (size_t i = 0; i < args_.size(); ++i) { - if (!names_[i].empty()) { - result += prefix + "| |--[" + names_[i] + "]\n"; + if (!var_infos_[i].name.empty()) { + result += prefix; + result += "| |--["; + if (var_infos_[i].is_const) { + result += "let "; + } + result += var_infos_[i].name; + result += "]\n"; } result += args_[i]->ToString(prefix + "| "); } @@ -136,11 +142,15 @@ std::string NoOPNode::ToStringImpl(const std::string& prefix) { Status NoOPNode::Accept(Visitor* visitor) { return visitor->Visit(*this); } ExecNodeType NoOPNode::GetExecNodeType() { return ExecNodeType::kNoOPNode; } void NoOPNode::AppendArgs(std::unique_ptr&& arg) { - names_.emplace_back(); + var_infos_.emplace_back(); args_.emplace_back(std::move(arg)); } void NoOPNode::AppendArgs(std::string name, std::unique_ptr&& arg) { - names_.emplace_back(std::move(name)); + var_infos_.emplace_back(std::move(name), false); + args_.emplace_back(std::move(arg)); +} +void NoOPNode::AppendArgs(std::string name, std::unique_ptr&& arg, bool is_const) { + var_infos_.emplace_back(std::move(name), is_const); args_.emplace_back(std::move(arg)); } @@ -150,7 +160,7 @@ std::unique_ptr NoOPNode::CloneImpl() { for (const auto& arg : args_) { args.emplace_back(arg->Clone()); } - return std::make_unique(names_, std::move(args), isolated_); + return std::make_unique(var_infos_, std::move(args), isolated_); } std::string IfNode::ToStringImpl(const std::string& prefix) { diff --git a/src/scope_stack.h b/src/scope_stack.h index 386c44f..6b51226 100644 --- a/src/scope_stack.h +++ b/src/scope_stack.h @@ -6,8 +6,8 @@ */ #pragma once +#include #include -#include #include #include @@ -23,17 +23,13 @@ class ScopeStack { void Set(const std::string& name, V value) { stack_.back()[name] = std::move(value); } - V Lookup(const std::string& name) const { + std::optional Lookup(const std::string& name) const { for (auto it = stack_.rbegin(); it != stack_.rend(); ++it) { if (auto found = it->find(name); found != it->end()) { return found->second; } } - if constexpr (std::is_pointer_v) { - return nullptr; - } else { - return V{}; - } + return std::nullopt; } std::unordered_map GetShadowed() const { diff --git a/src/validator.cc b/src/validator.cc index 1bf2b3a..60e8d54 100644 --- a/src/validator.cc +++ b/src/validator.cc @@ -24,10 +24,32 @@ Status MakeParseError(const ExecNode& node, std::string message, Notes&&... note return Status::ParseError(diag.Render()); } +std::string TypeMismatchMessage(const std::string& name, ValueType old_type, ValueType new_type) { + return "cannot assign " + TypeHelper::TypeToString(new_type) + " to variable '" + name + "' of type " + + TypeHelper::TypeToString(old_type); +} + } // namespace Status Validator::Validate(ExecNode* node) { return node->Accept(this); } +SetVarResult Validator::TrySetVar(const std::string& name, ValueType type, bool is_const) { + auto entry = type_scope_stack_.Lookup(name); + if (entry.has_value()) { + if (entry->is_const) { + return SetVarResult::kConstReassign; + } + if (is_const) { + return SetVarResult::kRedeclare; + } + if (entry->type != type) { + return SetVarResult::kTypeMismatch; + } + } + type_scope_stack_.Set(name, {type, is_const}); + return SetVarResult::kOk; +} + Status Validator::Visit(EntryArgumentNode& entry_argument_node) { entry_argument_node.SetReturnType(ValueType::kPtr); return Status::OK(); @@ -267,7 +289,7 @@ Status Validator::Visit(FunctionNode& function_node) { } Status Validator::Visit(NoOPNode& no_op_node) { - const auto& names = no_op_node.GetNames(); + const auto& var_infos = no_op_node.GetVarInfos(); const auto& args = no_op_node.GetArgs(); const bool isolated = no_op_node.IsIsolated(); for (size_t i = 0; i < args.size(); ++i) { @@ -282,8 +304,19 @@ Status Validator::Visit(NoOPNode& no_op_node) { type_scope_stack_.PushScope(); } JF_RETURN_NOT_OK(args[i]->Accept(this)); - if (!names[i].empty()) { - type_scope_stack_.Set(names[i], args[i]->GetReturnType()); + if (!var_infos[i].name.empty()) { + auto result = TrySetVar(var_infos[i].name, args[i]->GetReturnType(), var_infos[i].is_const); + if (result == SetVarResult::kConstReassign) { + return MakeParseError(*args[i], "cannot reassign const variable '" + var_infos[i].name + "'"); + } + if (result == SetVarResult::kRedeclare) { + return MakeParseError(*args[i], "cannot redeclare variable '" + var_infos[i].name + "' with let"); + } + if (result == SetVarResult::kTypeMismatch) { + auto old_entry = type_scope_stack_.Lookup(var_infos[i].name); + return MakeParseError(*args[i], + TypeMismatchMessage(var_infos[i].name, old_entry->type, args[i]->GetReturnType())); + } } if (isolated) { type_scope_stack_.PopScope(); @@ -409,15 +442,8 @@ Status Validator::Visit(IfBlockNode& if_block_node) { } auto shadowed = type_scope_stack_.GetShadowed(); type_scope_stack_.PopScope(); - for (const auto& [name, new_type] : shadowed) { - ValueType original_type = type_scope_stack_.Lookup(name); - if (original_type != ValueType::kUnknown && original_type != new_type) { - return MakeParseError( - if_block_node, - "variable '" + name + "' has incompatible types across if block branches: original type is " + - TypeHelper::TypeToString(original_type) + ", but assigned " + TypeHelper::TypeToString(new_type)); - } - all_shadowed[name] = new_type; + for (const auto& [name, new_entry] : shadowed) { + all_shadowed[name] = new_entry.type; } } @@ -432,20 +458,13 @@ Status Validator::Visit(IfBlockNode& if_block_node) { } auto shadowed = type_scope_stack_.GetShadowed(); type_scope_stack_.PopScope(); - for (const auto& [name, new_type] : shadowed) { - ValueType original_type = type_scope_stack_.Lookup(name); - if (original_type != ValueType::kUnknown && original_type != new_type) { - return MakeParseError( - if_block_node, - "variable '" + name + "' has incompatible types across if block else branch: original type is " + - TypeHelper::TypeToString(original_type) + ", but assigned " + TypeHelper::TypeToString(new_type)); - } - all_shadowed[name] = new_type; + for (const auto& [name, new_entry] : shadowed) { + all_shadowed[name] = new_entry.type; } } for (const auto& [name, type] : all_shadowed) { - type_scope_stack_.Set(name, type); + type_scope_stack_.Set(name, {type, false}); } if_block_node.SetReturnType(ValueType::kVoid); @@ -453,11 +472,11 @@ Status Validator::Visit(IfBlockNode& if_block_node) { } Status Validator::Visit(RefNode& ref_node) { - ValueType type = type_scope_stack_.Lookup(ref_node.GetName()); - if (type == ValueType::kUnknown) { + auto entry = type_scope_stack_.Lookup(ref_node.GetName()); + if (!entry.has_value()) { return MakeParseError(ref_node, "variable '" + ref_node.GetName() + "' is not defined"); } - ref_node.SetReturnType(type); + ref_node.SetReturnType(entry->type); return Status::OK(); } diff --git a/src/validator.h b/src/validator.h index 4f67da2..0d51b06 100644 --- a/src/validator.h +++ b/src/validator.h @@ -13,6 +13,13 @@ namespace jitfusion { +struct VarEntry { + ValueType type{ValueType::kUnknown}; + bool is_const{false}; +}; + +enum class SetVarResult : uint8_t { kOk, kConstReassign, kRedeclare, kTypeMismatch }; + class Validator : public Visitor { public: explicit Validator(const std::unique_ptr& func_registry) : func_registry_(func_registry) {} @@ -34,8 +41,10 @@ class Validator : public Visitor { Status Visit(RefNode& ref_node) override; private: + SetVarResult TrySetVar(const std::string& name, ValueType type, bool is_const); + const std::unique_ptr& func_registry_; - ScopeStack type_scope_stack_; + ScopeStack type_scope_stack_; }; } // namespace jitfusion \ No newline at end of file diff --git a/test/if_block_test.cc b/test/if_block_test.cc index 18c6740..416cbff 100644 --- a/test/if_block_test.cc +++ b/test/if_block_test.cc @@ -76,10 +76,10 @@ TEST(IfBlockTest, WhenElseModifyAndStore) { { auto cond = MakeBinaryOP(BinaryOPType::kLarge, MakeRef("a"), MakeConstF32(0.0F)); auto body_expr = MakeBinaryOP(BinaryOPType::kAdd, MakeRef("a"), MakeConstF32(1.0F)); - auto body_noop = std::unique_ptr(new NoOPNode({}, {})); + auto body_noop = std::unique_ptr(new NoOPNode(std::vector>{})); static_cast(body_noop.get())->AppendArgs("result", std::move(body_expr)); auto else_expr = MakeBinaryOP(BinaryOPType::kSub, MakeRef("a"), MakeConstF32(1.0F)); - auto else_noop = std::unique_ptr(new NoOPNode({}, {})); + auto else_noop = std::unique_ptr(new NoOPNode(std::vector>{})); static_cast(else_noop.get())->AppendArgs("result", std::move(else_expr)); std::vector> if_args; if_args.emplace_back(std::move(cond)); @@ -87,7 +87,7 @@ TEST(IfBlockTest, WhenElseModifyAndStore) { if_args.emplace_back(std::move(else_noop)); auto if_block = std::unique_ptr(new IfBlockNode(std::move(if_args))); auto store_node = MakeStoreF32(0, MakeRef("result")); - auto root = std::unique_ptr(new NoOPNode({}, {})); + auto root = std::unique_ptr(new NoOPNode(std::vector>{})); static_cast(root.get())->AppendArgs("a", std::move(load_a)); static_cast(root.get())->AppendArgs("result", std::move(init_result)); static_cast(root.get())->AppendArgs(std::move(if_block)); @@ -117,14 +117,14 @@ TEST(IfBlockTest, WhenElifElseModifyAndStore) { auto init_result = MakeConstF32(0.0f); auto cond1 = MakeBinaryOP(BinaryOPType::kLarge, MakeRef("a"), MakeConstF32(100.0F)); - auto body1 = std::unique_ptr(new NoOPNode({}, {})); + auto body1 = std::unique_ptr(new NoOPNode(std::vector>{})); static_cast(body1.get())->AppendArgs("result", MakeConstF32(3.0F)); auto cond2 = MakeBinaryOP(BinaryOPType::kLarge, MakeRef("a"), MakeConstF32(10.0F)); - auto body2 = std::unique_ptr(new NoOPNode({}, {})); + auto body2 = std::unique_ptr(new NoOPNode(std::vector>{})); static_cast(body2.get())->AppendArgs("result", MakeConstF32(2.0F)); - auto else_body = std::unique_ptr(new NoOPNode({}, {})); + auto else_body = std::unique_ptr(new NoOPNode(std::vector>{})); static_cast(else_body.get())->AppendArgs("result", MakeConstF32(1.0F)); std::vector> if_args; @@ -137,7 +137,7 @@ TEST(IfBlockTest, WhenElifElseModifyAndStore) { auto store_node = MakeStoreF32(0, MakeRef("result")); - auto root = std::unique_ptr(new NoOPNode({}, {})); + auto root = std::unique_ptr(new NoOPNode(std::vector>{})); static_cast(root.get())->AppendArgs("a", std::move(load_a)); static_cast(root.get())->AppendArgs("result", std::move(init_result)); static_cast(root.get())->AppendArgs(std::move(if_block)); @@ -175,7 +175,7 @@ TEST(IfBlockTest, WhenWithoutElsePartialModify) { auto init_result = MakeConstF32(99.0F); auto cond = MakeBinaryOP(BinaryOPType::kLarge, MakeRef("a"), MakeConstF32(10.0F)); - auto body = std::unique_ptr(new NoOPNode({}, {})); + auto body = std::unique_ptr(new NoOPNode(std::vector>{})); static_cast(body.get()) ->AppendArgs("result", MakeBinaryOP(BinaryOPType::kMul, MakeRef("a"), MakeConstF32(2.0F))); @@ -186,7 +186,7 @@ TEST(IfBlockTest, WhenWithoutElsePartialModify) { auto store_node = MakeStoreF32(0, MakeRef("result")); - auto root = std::unique_ptr(new NoOPNode({}, {})); + auto root = std::unique_ptr(new NoOPNode(std::vector>{})); static_cast(root.get())->AppendArgs("a", std::move(load_a)); static_cast(root.get())->AppendArgs("result", std::move(init_result)); static_cast(root.get())->AppendArgs(std::move(if_block)); @@ -220,11 +220,11 @@ TEST(IfBlockTest, MultipleVarsModifyAndStore) { auto cond = MakeBinaryOP(BinaryOPType::kLarge, MakeRef("a"), MakeConstF32(0.0F)); - auto body = std::unique_ptr(new NoOPNode({}, {})); + auto body = std::unique_ptr(new NoOPNode(std::vector>{})); static_cast(body.get())->AppendArgs("r1", MakeBinaryOP(BinaryOPType::kAdd, MakeRef("a"), MakeRef("b"))); static_cast(body.get())->AppendArgs("r2", MakeBinaryOP(BinaryOPType::kMul, MakeRef("a"), MakeRef("b"))); - auto else_body = std::unique_ptr(new NoOPNode({}, {})); + auto else_body = std::unique_ptr(new NoOPNode(std::vector>{})); static_cast(else_body.get()) ->AppendArgs("r1", MakeBinaryOP(BinaryOPType::kSub, MakeRef("a"), MakeRef("b"))); static_cast(else_body.get()) @@ -239,7 +239,7 @@ TEST(IfBlockTest, MultipleVarsModifyAndStore) { auto store_r1 = MakeStoreF32(0, MakeRef("r1")); auto store_r2 = MakeStoreF32(1, MakeRef("r2")); - auto root = std::unique_ptr(new NoOPNode({}, {})); + auto root = std::unique_ptr(new NoOPNode(std::vector>{})); static_cast(root.get())->AppendArgs("a", std::move(load_a)); static_cast(root.get())->AppendArgs("b", std::move(load_b)); static_cast(root.get())->AppendArgs("r1", std::move(init_r1)); @@ -275,10 +275,10 @@ TEST(IfBlockTest, StoreInsideWhenBlock) { auto cond = MakeBinaryOP(BinaryOPType::kLarge, MakeRef("a"), MakeConstF32(0.0F)); - auto body = std::unique_ptr(new NoOPNode({}, {})); + auto body = std::unique_ptr(new NoOPNode(std::vector>{})); static_cast(body.get()) ->AppendArgs(MakeStoreF32(0, MakeBinaryOP(BinaryOPType::kMul, MakeRef("a"), MakeConstF32(2.0F)))); - auto else_body = std::unique_ptr(new NoOPNode({}, {})); + auto else_body = std::unique_ptr(new NoOPNode(std::vector>{})); static_cast(else_body.get()) ->AppendArgs(MakeStoreF32(0, MakeBinaryOP(BinaryOPType::kMul, MakeRef("a"), MakeConstF32(-1.0F)))); @@ -288,7 +288,7 @@ TEST(IfBlockTest, StoreInsideWhenBlock) { if_args.emplace_back(std::move(else_body)); auto if_block = std::unique_ptr(new IfBlockNode(std::move(if_args))); - auto root = std::unique_ptr(new NoOPNode({}, {})); + auto root = std::unique_ptr(new NoOPNode(std::vector>{})); static_cast(root.get())->AppendArgs("a", std::move(load_a)); static_cast(root.get())->AppendArgs(std::move(if_block)); @@ -318,13 +318,13 @@ TEST(IfBlockTest, PartialModifyAndStore) { auto init_r2 = MakeConstF32(100.0F); auto cond = MakeBinaryOP(BinaryOPType::kLarge, MakeRef("a"), MakeConstF32(0.0F)); - auto body = std::unique_ptr(new NoOPNode({}, {})); + auto body = std::unique_ptr(new NoOPNode(std::vector>{})); static_cast(body.get()) ->AppendArgs("r1", MakeBinaryOP(BinaryOPType::kAdd, MakeRef("a"), MakeConstF32(1.0F))); static_cast(body.get()) ->AppendArgs("r2", MakeBinaryOP(BinaryOPType::kAdd, MakeRef("a"), MakeConstF32(2.0F))); - auto else_body = std::unique_ptr(new NoOPNode({}, {})); + auto else_body = std::unique_ptr(new NoOPNode(std::vector>{})); static_cast(else_body.get()) ->AppendArgs("r1", MakeBinaryOP(BinaryOPType::kSub, MakeRef("a"), MakeConstF32(1.0F))); @@ -337,7 +337,7 @@ TEST(IfBlockTest, PartialModifyAndStore) { auto store_r1 = MakeStoreF32(0, MakeRef("r1")); auto store_r2 = MakeStoreF32(1, MakeRef("r2")); - auto root = std::unique_ptr(new NoOPNode({}, {})); + auto root = std::unique_ptr(new NoOPNode(std::vector>{})); static_cast(root.get())->AppendArgs("a", std::move(load_a)); static_cast(root.get())->AppendArgs("r1", std::move(init_r1)); static_cast(root.get())->AppendArgs("r2", std::move(init_r2));