28 #define C4AUL_Inherited "inherited"
29 #define C4AUL_SafeInherited "_inherited"
30 #define C4AUL_DebugBreak "__debugbreak"
34 enum class ScriptLinkType
43 if (source_host == target_host)
44 return ScriptLinkType::Same;
47 const auto source_script_index = std::find(begin(sources), end(sources), source_host);
48 const auto target_script_index = std::find(begin(sources), end(sources), target_host);
49 assert(source_script_index != target_script_index);
50 if (source_script_index < target_script_index)
51 return ScriptLinkType::Include;
52 else if (source_script_index > target_script_index)
53 return ScriptLinkType::Appendto;
54 return ScriptLinkType::Same;
60 if (func && func->GetFullName())
62 s +=
strprintf(
" (in %s", func->GetFullName().getData());
63 if (source_host && pos)
68 if (source_host && pos)
70 if (!func || !func->GetFullName())
78 if (target_host && source_host != target_host)
80 if (GetScriptLinkType(source_host, target_host) == ScriptLinkType::Include)
88 #pragma GCC diagnostic push
90 #pragma GCC diagnostic ignored "-Wformat-security"
98 #define DIAG(id, msg, enabled) if (warning == C4AulWarningId::id && !enabled) return;
102 else if (target_host && GetScriptLinkType(host, target_host) == ScriptLinkType::Include)
113 std::string message =
sizeof...(T) > 0 ?
strprintf(msg, std::forward<T>(args)...) : msg;
114 message += FormatCodePosition(host, SPos, target_host, func);
126 return Warn(target_host, host, n->loc, func, warning, std::forward<T>(args)...);
131 return Warn(target_host, host,
static_cast<const char*
>(
nullptr), func, warning, std::forward<T>(args)...);
137 std::string message =
sizeof...(T) > 0 ?
strprintf(msg, std::forward<T>(args)...) : msg;
139 message += FormatCodePosition(host, SPos, target_host, func);
146 return Error(target_host, host, n->loc, func, msg, std::forward<T>(args)...);
151 return Error(target_host, host,
static_cast<const char*
>(
nullptr), func, msg, std::forward<T>(args)...);
154 #pragma GCC diagnostic pop
171 using DefaultRecursiveVisitor::visit;
172 void visit(const ::aul::ast::RangeLoop *n)
override;
173 void visit(const ::aul::ast::VarDecl *n)
override;
174 void visit(const ::aul::ast::FunctionDecl *n)
override;
175 void visit(const ::aul::ast::CallExpr *n)
override;
176 void visit(const ::aul::ast::ParExpr *n)
override;
177 void visit(const ::aul::ast::AppendtoPragma *n)
override;
178 void visit(const ::aul::ast::IncludePragma *n)
override;
179 void visit(const ::aul::ast::Script *n)
override;
190 int32_t stack_height = 0;
191 bool at_jump_target =
false;
195 explicit Loop(
int stack_height) : stack_height(stack_height) {}
197 int stack_height = 0;
198 std::vector<int> continues;
199 std::vector<int> breaks;
208 std::stack<Loop> active_loops;
212 std::set<std::string> variables;
214 std::deque<Scope> scopes;
226 void UpdateJump(
int jump,
int target);
228 void PopLoop(
int continue_target);
229 void AddLoopControl(
const char *loc, Loop::Control c);
231 int AddVarAccess(
const char *TokenSPos,
C4AulBCCType eType, intptr_t varnum);
232 int AddBCC(
const char *TokenSPos,
C4AulBCCType eType, intptr_t
X = 0);
233 int AddBCC(
const char *SPos,
const C4AulBCC &bcc);
236 void MaybePopValueOf(
const std::unique_ptr<T> &n)
239 if (!n->has_value())
return;
244 void RemoveLastBCC();
245 C4AulBCC MakeSetter(
const char *SPos,
bool fLeaveValue);
260 bool SafeVisit(
const T &node)
281 const int32_t target_stack_height;
283 explicit StackGuard(
CodegenAstVisitor *parent, int32_t offset = 0) : parent(parent), target_stack_height(parent->stack_height + offset)
287 assert(parent->stack_height == target_stack_height);
288 if (parent->stack_height != target_stack_height)
290 parent->HandleError(Error(parent->target_host, parent->host,
nullptr, parent->Fn,
"internal error: value stack left unbalanced"));
291 parent->AddBCC(
nullptr,
AB_STACK, target_stack_height - parent->stack_height);
303 parent->scopes.emplace_front();
307 parent->scopes.pop_front();
311 ScopeGuard(ScopeGuard &&rhs) =
default;
312 ScopeGuard &operator=(ScopeGuard &&) =
default;
314 ScopeGuard(
const ScopeGuard &) =
delete;
315 ScopeGuard &operator=(
const ScopeGuard &) =
delete;
317 ScopeGuard enterScope() {
return ScopeGuard(
this); }
323 Warn(target_host, host, n.get(), Fn, C4AulWarningId::suspicious_assignment);
333 using DefaultRecursiveVisitor::visit;
334 void visit(const ::aul::ast::Noop *)
override;
335 void visit(const ::aul::ast::StringLit *n)
override;
336 void visit(const ::aul::ast::IntLit *n)
override;
337 void visit(const ::aul::ast::BoolLit *n)
override;
338 void visit(const ::aul::ast::ArrayLit *n)
override;
339 void visit(const ::aul::ast::ProplistLit *n)
override;
340 void visit(const ::aul::ast::NilLit *n)
override;
341 void visit(const ::aul::ast::ThisLit *n)
override;
342 void visit(const ::aul::ast::VarExpr *n)
override;
343 void visit(const ::aul::ast::UnOpExpr *n)
override;
344 void visit(const ::aul::ast::BinOpExpr *n)
override;
345 void visit(const ::aul::ast::AssignmentExpr *n)
override;
346 void visit(const ::aul::ast::SubscriptExpr *n)
override;
347 void visit(const ::aul::ast::SliceExpr *n)
override;
348 void visit(const ::aul::ast::CallExpr *n)
override;
349 void visit(const ::aul::ast::ParExpr *n)
override;
350 void visit(const ::aul::ast::Block *n)
override;
351 void visit(const ::aul::ast::Return *n)
override;
352 void visit(const ::aul::ast::ForLoop *n)
override;
353 void visit(const ::aul::ast::RangeLoop *n)
override;
354 void visit(const ::aul::ast::DoLoop *n)
override;
355 void visit(const ::aul::ast::WhileLoop *n)
override;
356 void visit(const ::aul::ast::Break *n)
override;
357 void visit(const ::aul::ast::Continue *n)
override;
358 void visit(const ::aul::ast::If *n)
override;
359 void visit(const ::aul::ast::VarDecl *n)
override;
360 void visit(const ::aul::ast::FunctionDecl *n)
override;
361 void visit(const ::aul::ast::FunctionExpr *n)
override;
362 void visit(const ::aul::ast::Script *n)
override;
375 void EmitFunctionCode(const ::aul::ast::Function *f, const ::aul::ast::Node *n);
402 bool ignore_unset_values =
false;
411 ProplistMagic() =
default;
412 ProplistMagic(
bool active,
C4PropListStatic *parent, std::string key) : active(active), parent(parent), key(
std::move(key)) {}
415 explicit ConstexprEvaluator(
C4ScriptHost *host) : host(host) {}
417 template<
typename... T>
418 NORETURN void nonconst(const ::aul::ast::Node *n,
const char *msg, T&&...args)
const
420 throw ExpressionNotConstant(host, n, msg, std::forward<T>(args)...);
423 void AssertValueType(
const C4Value &v,
C4V_Type Type1,
const char *opname, const ::aul::ast::Node *n)
427 throw Error(host, host, n,
nullptr, R
"(operator "%s": got %s, but expected %s)", opname, v.GetTypeName(), GetC4VName(Type1));
433 template<
typename... T>
438 using AstVisitor::visit;
439 void visit(const ::aul::ast::StringLit *n)
override;
440 void visit(const ::aul::ast::IntLit *n)
override;
441 void visit(const ::aul::ast::BoolLit *n)
override;
442 void visit(const ::aul::ast::ArrayLit *n)
override;
443 void visit(const ::aul::ast::ProplistLit *n)
override;
444 void visit(const ::aul::ast::NilLit *)
override;
445 void visit(const ::aul::ast::ThisLit *n)
override;
446 void visit(const ::aul::ast::VarExpr *n)
override;
447 void visit(const ::aul::ast::UnOpExpr *n)
override;
448 void visit(const ::aul::ast::BinOpExpr *n)
override;
449 void visit(const ::aul::ast::AssignmentExpr *n)
override;
450 void visit(const ::aul::ast::SubscriptExpr *n)
override;
451 void visit(const ::aul::ast::SliceExpr *n)
override;
452 void visit(const ::aul::ast::CallExpr *n)
override;
453 void visit(const ::aul::ast::FunctionExpr *n)
override;
486 using DefaultRecursiveVisitor::visit;
487 void visit(const ::aul::ast::Script *n)
override;
488 void visit(const ::aul::ast::VarDecl *n)
override;
513 def->body->accept(&v);
521 #define ENSURE_COND(cond, failmsg) do { if (!(cond)) throw Error(target_host, host, n, Fn, failmsg); } while (0)
525 const char *cname = n->var.c_str();
536 Warn(target_host, host, n, Fn, C4AulWarningId::implicit_range_loop_var_decl, cname);
540 DefaultRecursiveVisitor::visit(n);
547 Warn(target_host, host, n, Fn, C4AulWarningId::non_global_var_is_never_const);
549 for (
const auto &var : n->decls)
551 const char *cname = var.name.c_str();
554 case ::aul::ast::VarDecl::Scope::Func:
556 assert(Fn &&
"function-local var declaration outside of function");
558 throw Error(target_host, host, n, Fn,
"internal error: function-local var declaration outside of function");
565 Warn(target_host, host, n, Fn, C4AulWarningId::variable_shadows_variable,
"local variable", cname,
"global variable");
568 Warn(target_host, host, n, Fn, C4AulWarningId::variable_shadows_variable,
"local variable", cname,
"object-local variable");
569 if (Fn->ParNamed.GetItemNr(cname) != -1)
576 Warn(target_host, host, n, Fn, C4AulWarningId::variable_shadows_variable,
"parameter", cname,
"local variable");
579 Fn->VarNamed.AddName(cname);
585 Warn(target_host, host, n, Fn, C4AulWarningId::variable_shadows_variable,
"object-local variable", cname,
"global variable");
588 Warn(target_host, host, n, Fn, C4AulWarningId::redeclaration,
"object-local variable", cname);
593 case ::aul::ast::VarDecl::Scope::Global:
594 assert(!Fn &&
"global var declaration inside function");
596 throw Error(target_host, host, n, Fn,
"internal error: global var declaration inside function");
599 Warn(target_host, host, n, Fn, C4AulWarningId::redeclaration,
"global variable", cname);
613 DefaultRecursiveVisitor::visit(n);
621 const char *cname = n->name.c_str();
630 for (
const auto ¶m : n->params)
632 Fn->AddPar(param.name.c_str(), param.type);
634 if (n->has_unnamed_params)
638 Fn->SetOverloaded(parent_func);
643 DefaultRecursiveVisitor::visit(n);
659 DefaultRecursiveVisitor::visit(n);
666 Warn(target_host, host, n, Fn, C4AulWarningId::undeclared_varargs,
"Par()");
669 DefaultRecursiveVisitor::visit(n);
675 host->
Appends.emplace_back(
"*");
677 host->
Appends.emplace_back(n->what.c_str());
682 host->
Includes.emplace_back(n->what.c_str());
687 for (
const auto &d : n->declarations)
700 int C4AulCompiler::CodegenAstVisitor::GetStackValue(
C4AulBCCType eType, intptr_t
X)
749 return -
reinterpret_cast<C4AulFunc *
>(
X)->GetParCount() + 1;
788 assert(0 &&
"GetStackValue: unexpected bytecode not handled");
792 int C4AulCompiler::CodegenAstVisitor::AddVarAccess(
const char *TokenSPos,
C4AulBCCType eType, intptr_t varnum)
794 return AddBCC(TokenSPos, eType, 1 + varnum - (stack_height + Fn->VarNamed.iSize));
797 int C4AulCompiler::CodegenAstVisitor::AddBCC(
const char *TokenSPos,
C4AulBCCType eType, intptr_t
X)
800 stack_height += GetStackValue(eType,
X);
812 if (!at_jump_target && Fn->GetLastCode())
814 C4AulBCC *pCPos1 = Fn->GetLastCode();
819 return Fn->GetCodePos() - 1;
824 (X <= 0 || pCPos1->Par.i >= 0))
832 return Fn->GetCodePos() - 1;
842 return Fn->GetCodePos() - 1;
857 return Fn->GetCodePos() - 1;
864 return Fn->GetCodePos() - 1;
870 (pCPos1->
Par.i == 1 || pCPos1->
Par.i == -1))
872 if ((pCPos1->
Par.i > 0) == (eType ==
AB_Sum))
877 return Fn->GetCodePos() - 1;
884 pCPos1->
Par.i =
X + 1;
885 return Fn->GetCodePos() - 1;
892 return Fn->GetCodePos() - 1;
899 return Fn->GetCodePos() - 1;
904 Fn->AddBCC(eType,
X, TokenSPos);
907 at_jump_target =
false;
909 return Fn->GetCodePos() - 1;
912 void C4AulCompiler::CodegenAstVisitor::RemoveLastBCC()
918 stack_height -= GetStackValue(pBCC->
bccType, pBCC->
Par.X);
923 int C4AulCompiler::CodegenAstVisitor::AddBCC(
const char *SPos,
const C4AulBCC &bcc)
928 C4AulBCC C4AulCompiler::CodegenAstVisitor::MakeSetter(
const char *SPos,
bool fLeaveValue)
931 C4AulBCC Value = *(Fn->GetLastCode()), Setter = Value;
951 throw Error(target_host, host, SPos, Fn,
"assignment to a constant");
956 int iParCount = 1 - GetStackValue(Value.
bccType, Value.
Par.X);
967 else if (!fLeaveValue || iParCount)
970 at_jump_target =
true;
972 if (fLeaveValue && iParCount)
974 for (
int i = 0; i < iParCount; i++)
975 AddBCC(SPos,
AB_DUP, 1 - iParCount);
980 assert(iParCount == -GetStackValue(Setter.bccType, Setter.Par.X));
984 int C4AulCompiler::CodegenAstVisitor::AddJumpTarget()
986 assert(Fn &&
"Jump target outside of function");
988 throw C4AulParseError(host,
"internal error: jump target outside of function");
990 at_jump_target =
true;
991 return Fn->GetCodePos();
994 void C4AulCompiler::CodegenAstVisitor::UpdateJump(
int jump,
int target)
996 C4AulBCC *code = Fn->GetCodeByPos(jump);
998 code->
Par.i = target - jump;
1001 void C4AulCompiler::CodegenAstVisitor::AddJumpTo(
const char *loc,
C4AulBCCType type,
int target)
1003 AddBCC(loc,
type, target - Fn->GetCodePos());
1006 void C4AulCompiler::CodegenAstVisitor::PushLoop()
1008 active_loops.emplace(stack_height);
1011 void C4AulCompiler::CodegenAstVisitor::PopLoop(
int continue_target)
1013 assert(!active_loops.empty());
1014 assert(stack_height == active_loops.top().stack_height);
1016 const auto &loop = active_loops.top();
1017 for (
auto &c : loop.continues)
1018 UpdateJump(c, continue_target);
1019 int loop_exit = AddJumpTarget();
1020 for (
auto &
b : loop.breaks)
1021 UpdateJump(
b, loop_exit);
1025 void C4AulCompiler::CodegenAstVisitor::AddLoopControl(
const char *loc,
Loop::Control c)
1027 assert(!active_loops.empty());
1028 if (active_loops.empty())
1029 throw C4AulParseError(host,
"internal error: loop control code emitted outside of loop");
1031 assert(active_loops.top().stack_height == stack_height);
1032 if (active_loops.top().stack_height - stack_height > 0)
1033 AddBCC(loc,
AB_STACK, active_loops.top().stack_height - stack_height);
1034 int jump = AddBCC(loc,
AB_JUMP, 0);
1037 case Loop::Control::Continue:
1038 active_loops.top().continues.push_back(jump);
1040 case Loop::Control::Break:
1041 active_loops.top().breaks.push_back(jump);
1050 StackGuard g(
this, 1);
1057 StackGuard g(
this, 1);
1058 AddBCC(n->loc,
AB_INT, n->value);
1064 StackGuard g(
this, 1);
1065 AddBCC(n->loc,
AB_BOOL, n->value);
1071 StackGuard g(
this, 1);
1072 for (
const auto &e : n->values)
1082 StackGuard g(
this, 1);
1083 for (
const auto &e : n->values)
1085 StackGuard g(
this, 2);
1087 SafeVisit(e.second);
1095 StackGuard g(
this, 1);
1102 StackGuard g(
this, 1);
1109 StackGuard g(
this, 1);
1111 assert(!scopes.empty());
1113 const char *cname = n->identifier.c_str();
1125 if (Fn->ParNamed.GetItemNr(cname) != -1)
1127 int pos = Fn->ParNamed.GetItemNr(cname);
1128 AddVarAccess(n->loc,
AB_DUP, -Fn->GetParCount() + pos);
1129 type_of_stack_top = Fn->GetParType()[pos];
1131 else if (Fn->VarNamed.GetItemNr(cname) != -1)
1133 const bool in_scope = end(scopes) != std::find_if(begin(scopes), end(scopes), [n](
const Scope &scope) {
1134 return scope.variables.find(n->identifier) != scope.variables.end();
1138 Warn(target_host, host, n, Fn, C4AulWarningId::variable_out_of_scope, cname);
1140 AddVarAccess(n->loc,
AB_DUP, Fn->VarNamed.GetItemNr(cname));
1144 else if (Fn->Parent && interned && Fn->Parent->GetPropertyByS(interned, &dummy))
1146 AddBCC(n->loc,
AB_LOCALN, (intptr_t)interned);
1180 throw Error(target_host, host, n, Fn,
"internal error: global constant of unexpected type: %s (of type %s)", cname, v.
GetTypeName());
1182 type_of_stack_top = v.
GetType();
1187 throw Error(target_host, host, n, Fn,
"symbol not found in any symbol table: %s", cname);
1193 StackGuard g(
this, 1);
1195 n->operand->accept(
this);
1199 C4AulBCC setter = MakeSetter(n->loc,
true);
1200 AddBCC(n->loc, op.Code, 0);
1201 AddBCC(n->loc, setter);
1203 if (op.Postfix && (op.Code ==
AB_Inc || op.Code ==
AB_Dec))
1210 AddBCC(n->loc, op.Code);
1212 type_of_stack_top = op.RetType;
1217 StackGuard g(
this, 1);
1227 int jump = AddBCC(n->loc, op.Code);
1229 UpdateJump(jump, AddJumpTarget());
1231 else if (op.Changer)
1235 C4AulBCC setter = MakeSetter(n->loc,
true);
1237 AddBCC(n->loc, op.Code);
1238 AddBCC(n->loc, setter);
1248 AddBCC(n->loc, op.Code, 0);
1251 type_of_stack_top = op.RetType;
1256 StackGuard g(
this, 1);
1260 C4AulBCC setter = MakeSetter(n->loc,
false);
1262 AddBCC(n->loc, setter);
1273 StackGuard g(
this, 1);
1274 SafeVisit(n->object);
1275 SafeVisit(n->index);
1284 StackGuard g(
this, 1);
1285 SafeVisit(n->object);
1286 SafeVisit(n->start);
1295 const char *cname = n->callee.c_str();
1300 throw Error(target_host, host, n, Fn, R
"("%s" can't be called in a different context)", cname);
1301 if (!n->args.empty())
1302 throw Error(target_host, host, n, Fn, R
"("%s" must not have any arguments)", cname);
1316 throw Error(target_host, host, n, Fn, R
"("%s" can't be called in a different context)", cname);
1322 throw Error(target_host, host, n, Fn,
"inherited function not found (use " C4AUL_SafeInherited " to disable this message)");
1325 const auto pre_call_stack = stack_height;
1328 SafeVisit(n->context);
1330 std::vector<C4V_Type> known_par_types;
1331 known_par_types.reserve(n->args.size());
1333 for (
const auto &arg : n->args)
1336 known_par_types.push_back(type_of_stack_top);
1344 callee = Fn->OwnerOverloaded;
1353 if (!callee && target_host)
1363 if (!n->args.empty())
1364 AddBCC(n->loc,
AB_STACK, -(intptr_t)n->args.size());
1371 HandleError(Error(target_host, host, n, Fn,
"called function not found: %s", cname));
1377 if (n->args.size() > fn_argc)
1380 Warn(target_host, host, n->args[fn_argc].get(), Fn, C4AulWarningId::arg_count_mismatch,
1381 cname, (
unsigned)n->args.size(), fn_argc);
1382 AddBCC(n->loc,
AB_STACK, fn_argc - n->args.size());
1384 else if (n->args.size() < fn_argc)
1386 if (n->append_unnamed_pars)
1389 int missing_par_count = fn_argc - n->args.size();
1390 int available_par_count = Fn->GetParCount() - Fn->ParNamed.iSize;
1391 for (
int i = 0; i < std::min(missing_par_count, available_par_count); ++i)
1393 AddVarAccess(n->loc,
AB_DUP, -Fn->GetParCount() + Fn->ParNamed.iSize + i);
1396 if (available_par_count < missing_par_count)
1397 AddBCC(n->loc,
AB_STACK, missing_par_count - available_par_count);
1399 else if (fn_argc > n->args.size())
1402 AddBCC(n->loc,
AB_STACK, fn_argc - n->args.size());
1407 std::vector<C4V_Type> expected_par_types;
1420 if (candidate->
GetParCount() > expected_par_types.size())
1424 for (
size_t i = 0; i < expected_par_types.size(); ++i)
1432 if (implicit_a_to_b && !implicit_b_to_a)
1433 expected_par_types[i] =
b;
1434 else if (implicit_b_to_a && !implicit_a_to_b)
1435 expected_par_types[i] =
a;
1439 else if (!implicit_a_to_b && !implicit_b_to_a)
1440 expected_par_types[i] =
C4V_Any;
1449 AddBCC(n->loc,
AB_FUNC, (intptr_t)callee);
1450 expected_par_types.assign(callee->GetParType(), callee->GetParType() + callee->GetParCount());
1451 type_of_stack_top = callee->GetRetType();
1455 for (
size_t i = 0; i < std::min(known_par_types.size(), expected_par_types.size()); ++i)
1457 C4V_Type from = known_par_types[i];
1458 C4V_Type to = expected_par_types[i];
1461 Warn(target_host, host, n->args[i].get(), Fn, C4AulWarningId::arg_type_mismatch, (
unsigned)i, cname,
GetC4VName(from),
GetC4VName(to));
1466 assert(pre_call_stack + 1 == stack_height);
1471 StackGuard g(
this, 1);
1480 auto scope = enterScope();
1481 for (
const auto &
s : n->children)
1483 StackGuard g(
this, 0);
1494 StackGuard g(
this, 0);
1496 WarnOnAssignment(n->value);
1497 SafeVisit(n->value);
1515 auto scope = enterScope();
1518 if (SafeVisit(n->init))
1519 MaybePopValueOf(n->init);
1529 cond = AddJumpTarget();
1531 active_loops.top().breaks.push_back(AddBCC(n->cond->loc,
AB_CONDN));
1534 int body = AddJumpTarget();
1537 if (SafeVisit(n->body))
1538 MaybePopValueOf(n->body);
1543 incr = AddJumpTarget();
1544 if (SafeVisit(n->incr))
1545 MaybePopValueOf(n->incr);
1553 AddJumpTo(n->loc,
AB_JUMP, cond);
1571 auto scope = enterScope();
1572 scopes.front().variables.insert(n->var);
1574 const char *cname = n->var.c_str();
1575 int var_id = Fn->VarNamed.GetItemNr(cname);
1576 assert(var_id != -1 &&
"CodegenAstVisitor: unable to find variable in foreach");
1578 throw Error(target_host, host, n, Fn,
"internal error: unable to find variable in foreach: %s", cname);
1582 AddBCC(n->loc,
AB_INT, 0);
1583 int cond = AddJumpTarget();
1586 AddLoopControl(n->loc, Loop::Control::Break);
1589 if (SafeVisit(n->body))
1590 MaybePopValueOf(n->body);
1592 AddLoopControl(n->loc, Loop::Control::Continue);
1600 assert(Fn !=
nullptr);
1601 assert(scopes.empty());
1606 if (Fn->VarNamed.iSize > 0)
1607 AddBCC(n->loc,
AB_STACK, Fn->VarNamed.iSize);
1610 auto scope = enterScope();
1613 f->body->accept(
this);
1621 if (f->body->children.empty() || !
dynamic_cast<::
aul::ast::Return*
>(f->body->children.rbegin()->get()))
1633 assert(stack_height == 0);
1638 auto scope = enterScope();
1639 int body = AddJumpTarget();
1641 if (SafeVisit(n->body))
1642 MaybePopValueOf(n->body);
1643 int cond = AddJumpTarget();
1649 AddJumpTo(n->loc,
AB_COND, body);
1655 auto scope = enterScope();
1656 int cond = AddJumpTarget();
1663 active_loops.top().breaks.push_back(AddBCC(n->cond->loc,
AB_CONDN));
1664 if (SafeVisit(n->body))
1665 MaybePopValueOf(n->body);
1667 AddLoopControl(n->loc, Loop::Control::Continue);
1673 ENSURE_COND(!active_loops.empty(),
"'break' outside loop");
1674 AddLoopControl(n->loc, Loop::Control::Break);
1679 ENSURE_COND(!active_loops.empty(),
"'continue' outside loop");
1680 AddLoopControl(n->loc, Loop::Control::Continue);
1685 auto scope = enterScope();
1686 WarnOnAssignment(n->cond);
1688 int jump = AddBCC(n->loc,
AB_CONDN);
1692 Warn(target_host, host, n->iftrue->loc, Fn, C4AulWarningId::empty_if);
1694 if (SafeVisit(n->iftrue))
1695 MaybePopValueOf(n->iftrue);
1699 Warn(target_host, host, n->iffalse->loc, Fn, C4AulWarningId::empty_if);
1704 int jumpout = AddBCC(n->loc,
AB_JUMP);
1705 UpdateJump(jump, AddJumpTarget());
1707 if (SafeVisit(n->iffalse))
1708 MaybePopValueOf(n->iffalse);
1710 UpdateJump(jump, AddJumpTarget());
1715 for (
const auto &dec : n->decls)
1717 const char *cname = dec.name.c_str();
1720 case ::aul::ast::VarDecl::Scope::Func:
1721 scopes.front().variables.insert(dec.name);
1725 SafeVisit(dec.init);
1726 int var_idx = Fn->VarNamed.GetItemNr(cname);
1727 assert(var_idx >= 0 &&
"CodegenAstVisitor: var not found in variable table");
1731 throw Error(target_host, host, n, Fn,
"internal error: var not found in variable table: %s", cname);
1733 AddVarAccess(n->loc,
AB_POP_TO, var_idx);
1737 case ::aul::ast::VarDecl::Scope::Global:
1746 assert(!Fn &&
"CodegenAstVisitor: function declaration encountered within active function");
1748 throw Error(target_host, host, n, Fn,
"internal error: function declaration for '%s' encountered within active function", n->name.c_str());
1759 Warn(target_host, host, n, Fn, C4AulWarningId::redeclaration,
"function", f->
GetName());
1767 throw Error(target_host, host, n, Fn,
"declaration of '%s': cannot override local variable via 'func %s'", n->name.c_str(), n->name.c_str());
1770 assert(Fn &&
"CodegenAstVisitor: unable to find function definition");
1772 throw Error(target_host, host, n, Fn,
"internal error: unable to find function definition for %s", n->name.c_str());
1777 if (!n->is_global && !Fn->OwnerOverloaded)
1781 Fn->SetOverloaded(global_parent);
1786 EmitFunctionCode(n);
1799 throw Error(target_host, host, n, Fn,
"can't define a function in a function-scoped proplist");
1804 for (
const auto &d : n->declarations)
1811 #define ENSURE_COND(cond, failmsg) do { if (!(cond)) throw Error(host, host, n, nullptr, failmsg); } while (0)
1819 ce.ignore_unset_values = (flags & IgnoreUnset) == IgnoreUnset;
1827 if ((flags & SuppressErrors) == 0)
1836 ce.proplist_magic = ConstexprEvaluator::ProplistMagic{
true, parent, parent_key };
1837 ce.ignore_unset_values = (flags & IgnoreUnset) == IgnoreUnset;
1845 if ((flags & SuppressErrors) == 0)
1859 auto a = std::make_unique<C4ValueArray>(n->values.size());
1860 for (
size_t i = 0; i < n->values.size(); ++i)
1862 n->values[i]->accept(
this);
1870 std::unique_ptr<C4PropList> new_proplist;
1873 bool first_pass =
true;
1875 if (proplist_magic.active)
1880 if (proplist_magic.parent)
1882 proplist_magic.parent->GetPropertyByS(key, &old);
1897 new_proplist.reset(p);
1903 new_proplist.reset(p);
1911 for (
const auto &kv : n->values)
1917 auto saved_magic = std::move(proplist_magic);
1918 for (
const auto &kv : n->values)
1920 proplist_magic = ProplistMagic { saved_magic.active, p->
IsStatic(), kv.first };
1921 kv.second->accept(
this);
1924 proplist_magic = std::move(saved_magic);
1926 new_proplist.release();
1935 const char *cname = n->identifier.c_str();
1942 if (ignore_unset_values)
1948 nonconst(n,
"the variable \"%s\" is not a global constant", cname);
1953 n->operand->accept(
this);
1957 nonconst(n,
"unary operator %s is applied in a non-const fashion", op.Identifier);
1958 AssertValueType(v, op.Type1, op.Identifier, n);
1971 assert(!
"ConstexprEvaluator: Unexpected unary operator");
1972 throw Error(host, host, n,
nullptr,
"internal error: unary operator not found in operator table");
1981 nonconst(n,
"binary operator %s is applied in a non-const fashion", op.Identifier);
1983 n->lhs->accept(
this);
1991 n->rhs->accept(
this);
1994 AssertValueType(lhs, op.Type1, op.Identifier, n);
1995 AssertValueType(rhs, op.Type2, op.Identifier, n);
2015 #define INT_BINOP(code, op) case code: v.SetInt(lhs._getInt() op rhs._getInt()); break
2024 #define BOOL_BINOP(code, op) case code: v.SetBool(lhs._getInt() op rhs._getInt()); break
2043 assert(!
"ConstexprEvaluator: Unexpected binary operator");
2044 throw Error(host, host, n,
nullptr,
"internal error: binary operator not found in operator table");
2051 nonconst(n,
"updating assignment used in a non-const fashion");
2056 n->object->accept(
this);
2058 n->index->accept(
this);
2080 n->object->accept(
this);
2082 n->start->accept(
this);
2084 n->end->accept(
this);
2097 nonconst(n,
"call to function (%s) not supported in constant expressions", n->callee.c_str());
2103 ENSURE_COND(proplist_magic.active,
"internal error: function expression outside of static proplist");
2106 bool first_pass =
true;
2108 if (
auto func = proplist_magic.parent->GetFunc(proplist_magic.key.c_str()))
2110 sfunc = func->
SFunc();
2115 sfunc =
new C4AulScriptFunc(proplist_magic.parent, host, proplist_magic.key.c_str(), n->loc);
2118 ENSURE_COND(sfunc !=
nullptr,
"internal error: function expression target resolved to non-function value");
2122 for (
const auto ¶m : n->params)
2124 sfunc->
AddPar(param.name.c_str());
2126 if (n->has_unnamed_params)
2130 preparser.
visit(n->body.get());
2143 for (
const auto &d : n->declarations)
2159 for (
const auto &dec : n->decls)
2161 const char *cname = dec.name.c_str();
2165 case ::aul::ast::VarDecl::Scope::Func:
2186 case ::aul::ast::VarDecl::Scope::Global:
2187 if ((dec.init !=
nullptr) != n->constant)
2190 host->
Engine->
ErrorHandler->
OnError(Error(host, host, n->loc,
nullptr,
"global variable must be either constant or uninitialized: %s", cname).
what());
2196 assert(n->constant &&
"CodegenAstVisitor: initialized global variable isn't const");
2198 assert(v &&
"CodegenAstVisitor: global constant not found in variable table");
2200 throw Error(host, host, n->loc,
nullptr,
"internal error: global constant not found in variable table: %s", cname);
const char * C4AulWarningIDs[]
const char * C4AulWarningMessages[]
#define INT_BINOP(code, op)
#define C4AUL_SafeInherited
#define ENSURE_COND(cond, failmsg)
#define BOOL_BINOP(code, op)
C4Object * Object(C4PropList *_this)
const C4ScriptOpDef C4ScriptOpMap[]
C4AulScriptEngine ScriptEngine
const char * GetC4VName(const C4V_Type Type)
C4Value C4VFunction(C4AulFunc *pFn)
C4Value C4VArray(C4ValueArray *pArray)
C4Value C4VInt(int32_t i)
C4Value C4VPropList(C4PropList *p)
C4Value C4VString(C4String *pStr)
int SGetLine(const char *szText, const char *cpPosition)
int Pow(int base, int exponent)
int SLineGetCharacters(const char *szText, const char *cpPosition)
std::string strprintf(const char *format,...)
StdStrBuf FormatString(const char *szFmt,...)
void EmitFunctionCode(const T *n)
CodegenAstVisitor(C4AulScriptFunc *func)
CodegenAstVisitor(C4ScriptHost *host, C4ScriptHost *source_host)
~CodegenAstVisitor() override=default
void visit(const ::aul::ast::Noop *) override
static void resolve(C4ScriptHost *host, const ::aul::ast::Script *script)
static void resolve_quiet(C4ScriptHost *host, const ::aul::ast::Script *script)
void visit(const ::aul::ast::Script *n) override
~ConstantResolver() override=default
ExpressionNotConstant(const C4ScriptHost *host, const ::aul::ast::Node *n, const char *reason, T &&...args)
void visit(const ::aul::ast::StringLit *n) override
static C4Value eval_static(C4ScriptHost *host, C4PropListStatic *parent, const std::string &parent_key, const ::aul::ast::Expr *e, EvalFlags flags=0)
static C4Value eval(C4ScriptHost *host, const ::aul::ast::Expr *e, EvalFlags flags=0)
PreparseAstVisitor(C4AulScriptFunc *func)
void visit(const ::aul::ast::RangeLoop *n) override
PreparseAstVisitor(C4ScriptHost *host, C4ScriptHost *source_host, C4AulScriptFunc *func=nullptr)
~PreparseAstVisitor() override=default
static void Preparse(C4ScriptHost *out, C4ScriptHost *source, const ::aul::ast::Script *s)
static void Compile(C4AulScriptFunc *out, const ::aul::ast::Function *f)
virtual void OnError(const char *msg)=0
virtual void OnWarning(const char *msg)=0
const char * what() const noexcept override
const char * GetName() const
virtual C4AulScriptFunc * SFunc()
C4PropListStatic * Parent
virtual const C4V_Type * GetParType() const =0
virtual int GetParCount() const
bool GetGlobalConstant(const char *szName, C4Value *pTargetValue)
C4AulErrorHandler * GetErrorHandler() const
C4ValueMapNames GlobalConstNames
C4AulFunc * GetNextSNFunc(const C4AulFunc *After)
C4PropListStatic * GetPropList()
C4ValueMapNames GlobalNamedNames
C4ValueMapData GlobalConsts
C4AulErrorHandler * ErrorHandler
C4AulFunc * GetFirstFunc(const char *Name)
void AddPar(const char *Idtf, C4V_Type type=C4V_Any)
C4AulFunc * OwnerOverloaded
C4AulScriptFunc * SFunc() override
C4ScriptHost * pOrgScript
const char * GetFilePath() const
C4AulFunc * GetFunc(C4PropertyName k) const
virtual class C4PropListStatic * IsStatic()
virtual bool GetPropertyByS(const C4String *k, C4Value *pResult) const
bool HasProperty(C4String *k) const
virtual void SetPropertyByS(C4String *k, const C4Value &to)
static C4PropList * New(C4PropList *prototype=nullptr)
static C4PropListStatic * NewStatic(C4PropList *prototype, const C4PropListStatic *parent, C4String *key)
C4PropListStatic * IsStatic() override
std::vector< C4Value > ownedFunctions
C4AulScriptEngine * Engine
bool IsWarningEnabled(const char *pos, C4AulWarningId warning) const
std::list< StdCopyStrBuf > Appends
std::list< StdCopyStrBuf > Includes
virtual C4PropListStatic * GetPropList()
std::deque< C4ScriptHost * > SourceScripts
const char * GetScript() const
const char * GetCStr() const
C4String * FindString(const char *strString) const
C4String * RegString(StdStrBuf String)
const C4Value & GetItem(int32_t iElem) const
C4ValueArray * GetSlice(int32_t startIndex, int32_t endIndex)
C4ValueArray * getArray() const
ALWAYS_INLINE bool CheckConversion(C4V_Type vtToType) const
C4PropList * _getPropList() const
C4String * getStr() const
static bool WarnAboutConversion(C4V_Type Type, C4V_Type vtToType)
ALWAYS_INLINE bool CheckParConversion(C4V_Type vtToType) const
C4AulFunc * _getFunction() const
void SetArray(C4ValueArray *Array)
C4ValueArray * _getArray() const
bool IsIdenticalTo(const C4Value &cmp) const
C4String * _getStr() const
C4PropList * getPropList() const
const char * GetTypeName() const
void SetFunction(C4AulFunc *Fn)
C4Value * GetItem(const char *strName)
int32_t AddName(const char *pnName)
int32_t GetItemNr(const char *strName) const
const char * getData() const
virtual void visit(const ::aul::ast::Noop *)
std::unique_ptr< Expr > ExprPtr