25 #ifndef DEBUG_BYTECODE_DUMP
26 #define DEBUG_BYTECODE_DUMP 0
30 #define C4AUL_Include "#include"
31 #define C4AUL_Append "#appendto"
32 #define C4AUL_Warning "#warning"
34 #define C4Aul_Warning_enable "enable"
35 #define C4Aul_Warning_disable "disable"
37 #define C4AUL_Func "func"
39 #define C4AUL_Private "private"
40 #define C4AUL_Protected "protected"
41 #define C4AUL_Public "public"
42 #define C4AUL_Global "global"
43 #define C4AUL_Const "const"
46 #define C4AUL_Else "else"
48 #define C4AUL_While "while"
49 #define C4AUL_For "for"
51 #define C4AUL_Return "return"
52 #define C4AUL_Var "Var"
53 #define C4AUL_Par "Par"
54 #define C4AUL_Break "break"
55 #define C4AUL_Continue "continue"
56 #define C4AUL_this "this"
58 #define C4AUL_GlobalNamed "static"
59 #define C4AUL_LocalNamed "local"
60 #define C4AUL_VarNamed "var"
62 #define C4AUL_TypeInt "int"
63 #define C4AUL_TypeBool "bool"
64 #define C4AUL_TypeC4ID "id"
65 #define C4AUL_TypeDef "def"
66 #define C4AUL_TypeEffect "effect"
67 #define C4AUL_TypeC4Object "object"
68 #define C4AUL_TypePropList "proplist"
69 #define C4AUL_TypeString "string"
70 #define C4AUL_TypeArray "array"
71 #define C4AUL_TypeFunction "func"
72 #define C4AUL_TypeAny "any"
74 #define C4AUL_True "true"
75 #define C4AUL_False "false"
76 #define C4AUL_Nil "nil"
77 #define C4AUL_New "new"
106 Fn(nullptr), Host(
a), pOrgScript(
a), Engine(
a->Engine),
107 SPos(
a->Script.getData()), TokenSPos(SPos),
109 ContextToExecIn(nullptr)
113 Fn(Fn), Host(nullptr), pOrgScript(nullptr), Engine(Engine),
114 SPos(Fn->Script), TokenSPos(SPos),
116 ContextToExecIn(context)
126 va_list args; va_start(args, pMsg);
135 if (!IsWarningEnabled(TokenSPos, warning))
137 va_list args; va_start(args, warning);
145 bool C4AulParse::IsWarningEnabled(
const char *pos,
C4AulWarningId warning)
const
151 #define DIAG(id, text, enabled) case C4AulWarningId::id: return enabled;
154 default:
return false;
158 void C4AulParse::Error(
const char *pMsg, ...)
160 va_list args; va_start(args, pMsg);
167 void C4AulParse::AppendPosition(
StdStrBuf & Buf)
192 if (pOrgScript != Host && Host)
196 C4AulParseError::C4AulParseError(
C4AulParse * state,
const char *pMsg)
203 C4AulParseError::C4AulParseError(
C4ScriptHost *pScript,
const char *pMsg)
215 C4AulParseError::C4AulParseError(
C4AulScriptFunc * Fn,
const char *SPos,
const char *pMsg)
236 bool C4AulParse::AdvanceSpaces()
248 while (*SPos && *SPos != 13 && *SPos != 10)
252 else if (SPos[1] ==
'*')
255 while (*SPos && (*SPos !=
'*' || SPos[1] !=
'/'))
263 else if (*SPos ==
'\xEF' && SPos[1] ==
'\xBB' && SPos[2] ==
'\xBF')
265 else if ((
unsigned)*SPos > 32)
328 int C4AulParse::GetOperator(
const char* pScript)
336 if (!*pScript)
return 0;
338 if ((*pScript >=
'a' && *pScript <=
'z') ||
339 (*pScript >=
'A' && *pScript <=
'Z'))
345 int len = 0;
int maxfound = -1;
361 void C4AulParse::ClearToken()
376 if (!AdvanceSpaces())
return ATT_EOF;
384 if (
Inside(C,
'a',
'z') ||
Inside(C,
'A',
'Z') || C ==
'_' || C ==
'#')
400 while (*SPos !=
'\n' && *SPos !=
'\0') ++SPos;
401 Parse_WarningPragma();
403 return GetNextToken();
407 SCopy(TokenSPos, Idtf, Len);
414 else if (
Inside(C,
'0',
'9'))
417 if (C ==
'0' && *SPos ==
'x')
420 cInt =
StrToI32(SPos + 1, 16, &SPos);
426 cInt =
StrToI32(TokenSPos, 10, &SPos);
430 else if (C ==
'-' && *SPos ==
'>' && *(SPos + 1) ==
'~')
432 else if (C ==
'-' && *SPos ==
'>')
434 else if ((cInt = GetOperator(SPos - 1)) != -1)
439 else if (C ==
'=')
return ATT_SET;
455 case '"': ++SPos; strbuf.push_back(
'"');
break;
456 case '\\': ++SPos; strbuf.push_back(
'\\');
break;
457 case 'n': ++SPos; strbuf.push_back(
'\n');
break;
458 case 't': ++SPos; strbuf.push_back(
'\t');
break;
464 if (!std::isxdigit(*SPos))
466 Warn(C4AulWarningId::invalid_hex_escape);
467 strbuf.push_back(
'\\'); strbuf.push_back(
'x');
472 while (std::isxdigit(*SPos))
475 if (*SPos >=
'0' && *SPos <=
'9')
477 else if (*SPos >=
'a' && *SPos <=
'f')
478 ch += *SPos -
'a' + 10;
479 else if (*SPos >=
'A' && *SPos <=
'F')
480 ch += *SPos -
'A' + 10;
483 strbuf.push_back(ch);
487 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
491 while (SPos[0] >=
'0' && SPos[0] <=
'7')
496 strbuf.push_back(ch);
502 strbuf.push_back(
'\\');
504 Warn(C4AulWarningId::invalid_escape_sequence, *(SPos + 1));
507 else if (C == 0 || C == 10 || C == 13)
521 else if (C ==
'.' && *SPos ==
'.' && *(SPos + 1) ==
'.')
523 else if (C ==
'.')
return ATT_DOT;
528 if (C >=
'!' && C <=
'~')
550 case AB_PAR:
return "PAR";
555 case AB_Inc:
return "Inc";
556 case AB_Dec:
return "Dec";
558 case AB_Not:
return "Not";
559 case AB_Neg:
return "Neg";
562 case AB_Pow:
return "Pow";
563 case AB_Div:
return "Div";
564 case AB_Mul:
return "Mul";
565 case AB_Mod:
return "Mod";
566 case AB_Sub:
return "Sub";
567 case AB_Sum:
return "Sum";
583 case AB_INT:
return "INT";
589 case AB_NIL:
return "NIL";
591 case AB_DUP:
return "DUP";
603 case AB_ERR:
return "ERR";
607 assert(
false);
return "UNKNOWN";
614 fprintf(stderr,
"%s:\n",
GetName());
615 std::map<C4AulBCC *, int> labels;
617 for (
auto & bcc:
Code)
622 labels[&bcc + bcc.Par.i] = ++labeln;
break;
626 for (
auto & bcc:
Code)
629 if (labels.find(&bcc) != labels.end())
630 fprintf(stderr,
"%d:\n", labels[&bcc]);
631 fprintf(stderr,
"\t%d\t%-20s",
GetLineOfCode(&bcc), GetTTName(eType));
635 fprintf(stderr,
"\t%s\n", bcc.Par.f->GetFullName().getData());
break;
639 fprintf(stderr,
"\t%s\n", bcc.Par.s->GetCStr());
break;
644 std::for_each(
s.getData(),
s.getData() +
s.getLength(), [&es](
char c) {
645 if (std::isgraph((unsigned char)c))
653 case
'\'': es.append(R
"(\')"); break;
654 case '\"': es.append(R
"(\")"); break;
655 case '\\': es.append(R
"(\\)"); break;
656 case '\a': es.append(R
"(\a)"); break;
657 case '\b': es.append(R
"(\b)"); break;
658 case '\f': es.append(R
"(\f)"); break;
659 case '\n': es.append(R
"(\n)"); break;
660 case '\r': es.append(R
"(\r)"); break;
661 case '\t': es.append(R
"(\t)"); break;
662 case '\v': es.append(R
"(\v)"); break;
665 std::stringstream hex;
666 hex << R"(\x)" << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>((unsigned char)c);
667 es.append(hex.str());
673 fprintf(stderr,
"\t\"%s\"\n", es.c_str());
break;
679 assert(!bcc.Par.X); fprintf(stderr,
"\n");
break;
685 fprintf(stderr,
"\t% -d\n", labels[&bcc + bcc.Par.i]);
break;
687 fprintf(stderr,
"\t% -d\n", bcc.Par.i);
break;
709 assert(enabledWarnings.empty());
711 #define DIAG(id, text, enabled) warnings.set(static_cast<size_t>(C4AulWarningId::id), enabled);
736 case ATT_DIR:
return "directive";
738 case ATT_INT:
return "integer constant";
755 case ATT_EOF:
return "end of file";
756 default:
return "unrecognized token";
762 TokenType = GetNextToken();
764 void C4AulParse::Check(
C4AulTokenType RefTokenType,
const char * Expected)
766 if (TokenType != RefTokenType)
767 UnexpectedToken(Expected ? Expected : GetTokenName(RefTokenType));
769 void C4AulParse::Match(
C4AulTokenType RefTokenType,
const char * Expected)
771 Check(RefTokenType, Expected);
774 void C4AulParse::UnexpectedToken(
const char * Expected)
779 void C4AulParse::Parse_WarningPragma()
784 std::string line(TokenSPos +
sizeof(
C4AUL_Warning) - 1, SPos);
785 auto end = line.end();
786 auto cursor = std::find_if_not(begin(line), end,
IsWhiteSpace);
794 bool enable_warning =
false;
797 enable_warning =
true;
801 enable_warning =
false;
815 #define DIAG(id, text, enabled) pOrgScript->EnableWarning(TokenSPos, C4AulWarningId::id, enable_warning);
822 static const std::map<std::string, C4AulWarningId> warnings{
823 #define DIAG(id, text, enabled) std::make_pair(#id, C4AulWarningId::id),
827 while (cursor != end)
831 auto entry = warnings.find(std::string(start, cursor));
832 if (entry != warnings.end())
834 pOrgScript->
EnableWarning(TokenSPos, entry->second, enable_warning);
862 std::unique_ptr<::aul::ast::FunctionDecl> func;
870 func = std::make_unique<::aul::ast::FunctionDecl>(
"$internal$eval");
871 func->body = std::make_unique<::aul::ast::Block>();
872 func->body->children.push_back(std::make_unique<::aul::ast::Return>(std::move(expr)));
880 pOrgScript = scripthost;
882 const char * SPos0 = SPos;
883 bool first_error =
true;
884 auto script = ::aul::ast::Script::New(SPos0);
902 script->declarations.push_back(::aul::ast::IncludePragma::New(TokenSPos, Idtf));
914 script->declarations.push_back(::aul::ast::AppendtoPragma::New(TokenSPos, Idtf));
919 script->declarations.push_back(::aul::ast::AppendtoPragma::New(TokenSPos));
925 UnexpectedToken(
"identifier or '*'");
931 Error(
"unknown directive: %s", Idtf);
939 script->declarations.push_back(
Parse_Var());
949 UnexpectedToken(
"declaration");
966 const char *NodeStart = TokenSPos;
979 Error(
"Declaration expected, but found identifier: %s", Idtf);
984 auto func = ::aul::ast::FunctionDecl::New(NodeStart, Idtf);
985 func->is_global = is_global;
987 Parse_Function(func.get());
999 throw C4AulParseError(
this,
"'func' parameter list: too many parameters (max 10)");
1008 Check(
ATT_IDTF,
"parameter, '...', or ')'");
1025 std::string par_name;
1029 Warn(C4AulWarningId::type_name_used_as_par_name, Idtf);
1037 func->
params.emplace_back(par_name, parameter_type);
1052 auto block = ::aul::ast::Block::New(TokenSPos);
1064 const char *NodeStart = TokenSPos;
1065 std::unique_ptr<::aul::ast::Stmt> stmt;
1085 return ::aul::ast::Noop::New(NodeStart);
1148 stmt = ::aul::ast::Return::New(NodeStart, ::aul::ast::NilLit::New(NodeStart));
1159 stmt = ::aul::ast::Break::New(NodeStart);
1164 stmt = ::aul::ast::Continue::New(NodeStart);
1174 UnexpectedToken(
"statement");
1180 assert(call !=
nullptr);
1181 assert(call->
args.empty());
1185 while(TokenType !=
ATT_BCLOSE)
switch(TokenType)
1189 Warn(C4AulWarningId::empty_parameter_in_call, (
unsigned)call->
args.size(), call->
callee.c_str());
1190 call->
args.push_back(::aul::ast::NilLit::New(TokenSPos));
1213 auto arr = ::aul::ast::ArrayLit::New(TokenSPos);
1222 Warn(C4AulWarningId::empty_parameter_in_array, (
unsigned)arr->values.size());
1223 arr->values.emplace_back(::aul::ast::NilLit::New(TokenSPos));
1233 Warn(C4AulWarningId::empty_parameter_in_array, (
unsigned)arr->values.size());
1234 arr->values.emplace_back(::aul::ast::NilLit::New(TokenSPos));
1243 auto proplist = ::aul::ast::ProplistLit::New(TokenSPos);
1263 else UnexpectedToken(
"string or identifier");
1265 UnexpectedToken(
"':' or '='");
1271 UnexpectedToken(
"'}' or ','");
1279 auto loop = ::aul::ast::DoLoop::New(TokenSPos);
1284 UnexpectedToken(
"'while'");
1294 auto loop = ::aul::ast::WhileLoop::New(TokenSPos);
1307 auto stmt = ::aul::ast::If::New(TokenSPos);
1325 auto loop = ::aul::ast::ForLoop::New(TokenSPos);
1358 auto loop = ::aul::ast::RangeLoop::New(TokenSPos);
1362 loop->scoped_var =
true;
1370 UnexpectedToken(
"'in'");
1382 const char *NodeStart = TokenSPos;
1383 std::unique_ptr<::aul::ast::Expr> expr;
1396 expr = ::aul::ast::BoolLit::New(NodeStart,
true);
1401 expr = ::aul::ast::BoolLit::New(NodeStart,
false);
1406 expr = ::aul::ast::NilLit::New(NodeStart);
1417 expr = ::aul::ast::ThisLit::New(NodeStart);
1424 Error(
"reserved identifier not allowed in expressions: %s", Idtf);
1457 auto func = ::aul::ast::FunctionExpr::New(NodeStart);
1458 Parse_Function(func.get());
1459 expr = std::move(func);
1471 std::string identifier = Idtf;
1476 auto func = ::aul::ast::CallExpr::New(NodeStart);
1477 func->callee = identifier;
1478 Parse_CallParams(func.get());
1479 expr = std::move(func);
1484 expr = ::aul::ast::VarExpr::New(NodeStart, identifier);
1489 expr = ::aul::ast::IntLit::New(NodeStart, cInt);
1493 expr = ::aul::ast::StringLit::New(NodeStart, cStr->
GetCStr());
1502 throw C4AulParseError(
this,
"postfix operator without first expression");
1512 expr = ::aul::ast::UnOpExpr::New(NodeStart, op -
C4ScriptOpMap, std::move(expr));
1527 UnexpectedToken(
"expression");
1534 NodeStart = TokenSPos;
1541 if (iParentPrio > 1)
1544 expr = ::aul::ast::AssignmentExpr::New(NodeStart, std::move(expr),
Parse_Expression(1));
1556 for (postfixop = op + 1; postfixop->
Identifier; ++postfixop)
1563 Error(
"unexpected prefix operator: %s", op->
Identifier);
1576 expr = ::aul::ast::UnOpExpr::New(NodeStart, op -
C4ScriptOpMap, std::move(expr));
1590 start = ::aul::ast::IntLit::New(TokenSPos, 0);
1596 expr = ::aul::ast::SubscriptExpr::New(NodeStart, std::move(expr), std::move(start));
1604 end = ::aul::ast::IntLit::New(TokenSPos, std::numeric_limits<int32_t>::max());
1610 expr = ::aul::ast::SliceExpr::New(NodeStart, std::move(expr), std::move(start), std::move(end));
1614 UnexpectedToken(
"']' or ':'");
1622 expr = ::aul::ast::SubscriptExpr::New(NodeStart, std::move(expr), ::aul::ast::StringLit::New(TokenSPos, Idtf));
1627 auto call = ::aul::ast::CallExpr::New(NodeStart);
1628 call->
context = std::move(expr);
1631 Check(
ATT_IDTF,
"function name after '->'");
1634 Parse_CallParams(call.get());
1635 expr = std::move(call);
1646 auto decl = ::aul::ast::VarDecl::New(TokenSPos);
1661 assert(0 &&
"C4AulParse::Parse_Var called with invalid parse state (current token should be scope of variable)");
1663 Error(
"internal error: C4AulParse::Parse_Var called with invalid parse state (current token should be scope of variable, but is '%s')", Idtf);
1668 decl->constant =
true;
1675 std::string identifier = Idtf;
1683 decl->decls.push_back({ identifier, std::move(init) });
1735 prop = from.
Next(prop);
1756 if (SourceScript ==
this)
1778 auto entry = enabledWarnings.emplace(pos, decltype(enabledWarnings)::mapped_type{});
1783 assert(entry.first != enabledWarnings.begin());
1784 auto previous = entry.first;
1786 entry.first->second = previous->second;
1788 entry.first->second.set(
static_cast<size_t>(warning), enable);
1793 assert(!enabledWarnings.empty());
1794 if (enabledWarnings.empty())
1798 auto entry = enabledWarnings.upper_bound(pos);
1799 assert(entry != enabledWarnings.begin());
1800 if (entry != enabledWarnings.begin())
1805 return entry->second.test(
static_cast<size_t>(warning));
1808 void C4AulParse::PushParsePos()
1810 parse_pos_stack.push(TokenSPos);
1813 void C4AulParse::PopParsePos()
1815 assert(!parse_pos_stack.empty());
1816 SPos = parse_pos_stack.top();
1821 void C4AulParse::DiscardParsePos()
1823 assert(!parse_pos_stack.empty());
1824 parse_pos_stack.pop();
const char * C4AulWarningIDs[]
const char * C4AulWarningMessages[]
#define C4AUL_MAX_Identifier
#define C4AUL_TypePropList
#define C4AUL_TypeC4Object
#define C4AUL_GlobalNamed
#define C4AUL_TypeFunction
#define C4Aul_Warning_enable
#define DEBUG_BYTECODE_DUMP
const C4ScriptOpDef C4ScriptOpMap[]
#define C4Aul_Warning_disable
C4AulScriptEngine ScriptEngine
C4Value C4VFunction(C4AulFunc *pFn)
C4Value C4VArray(C4ValueArray *pArray)
C4Value C4VPropList(C4PropList *p)
bool SEqual2(const char *szStr1, const char *szStr2)
void SCopy(const char *szSource, char *sTarget, size_t iMaxL)
int SGetLine(const char *szText, const char *cpPosition)
int32_t StrToI32(const char *str, int base, const char **scan_end)
int SLineGetCharacters(const char *szText, const char *cpPosition)
bool IsWhiteSpace(char cChar)
bool SEqual(const char *szStr1, const char *szStr2)
bool Inside(T ival, U lbound, V rbound)
size_t SLen(const char *sptr)
StdStrBuf FormatString(const char *szFmt,...)
StdStrBuf FormatStringV(const char *szFmt, va_list args)
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
C4RefCntPointer< C4String > Name
const char * GetName() const
virtual C4AulScriptFunc * SFunc()
std::unique_ptr<::aul::ast::If > Parse_If()
std::unique_ptr<::aul::ast::Expr > Parse_Expression(int iParentPrio=-1)
std::unique_ptr<::aul::ast::Script > Parse_Script(C4ScriptHost *)
std::unique_ptr<::aul::ast::ForLoop > Parse_For()
std::unique_ptr<::aul::ast::WhileLoop > Parse_While()
std::unique_ptr<::aul::ast::FunctionDecl > Parse_DirectExec(const char *code, bool whole_function)
friend class C4AulParseError
std::unique_ptr<::aul::ast::Stmt > Parse_Statement()
std::unique_ptr<::aul::ast::FunctionDecl > Parse_ToplevelFunctionDecl()
std::unique_ptr<::aul::ast::VarDecl > Parse_Var()
C4AulParse(class C4ScriptHost *host)
std::unique_ptr<::aul::ast::Block > Parse_Block()
std::unique_ptr<::aul::ast::RangeLoop > Parse_ForEach()
std::unique_ptr<::aul::ast::ProplistLit > Parse_PropList()
std::unique_ptr<::aul::ast::DoLoop > Parse_DoWhile()
std::unique_ptr<::aul::ast::ArrayLit > Parse_Array()
C4AulErrorHandler * GetErrorHandler() const
C4PropListStatic * GetPropList()
C4AulErrorHandler * ErrorHandler
std::vector< C4AulBCC > Code
void ParseDirectExecStatement(C4AulScriptEngine *Engine, C4AulScriptContext *context=nullptr)
void ParseDirectExecFunc(C4AulScriptEngine *Engine, C4AulScriptContext *context=nullptr)
int GetLineOfCode(C4AulBCC *bcc)
void SetOverloaded(C4AulFunc *)
C4ScriptHost * pOrgScript
void IncludeDefinition(C4Def *pIncludeDef)
C4AulFunc * GetFunc(C4PropertyName k) const
virtual class C4PropListStatic * IsStatic()
virtual C4Def const * GetDef() const
virtual void SetPropertyByS(C4String *k, const C4Value &to)
void SetProperty(C4PropertyName k, const C4Value &to)
static C4PropListStatic * NewStatic(C4PropList *prototype, const C4PropListStatic *parent, C4String *key)
const C4PropListStatic * GetParent() const
C4Set< C4Property > LocalValues
C4AulScriptEngine * Engine
friend class C4AulScriptFunc
bool IsWarningEnabled(const char *pos, C4AulWarningId warning) const
virtual void AddEngineFunctions()
void CopyPropList(C4Set< C4Property > &from, C4PropListStatic *to)
std::list< StdCopyStrBuf > Appends
std::list< StdCopyStrBuf > Includes
virtual C4PropListStatic * GetPropList()
void EnableWarning(const char *pos, C4AulWarningId warning, bool enable=true)
std::deque< C4ScriptHost * > SourceScripts
void Warn(const char *pMsg,...) GNUC_FORMAT_ATTRIBUTE_O
const char * GetScript() const
T const * Next(T const *p) const
const char * GetCStr() const
C4String * RegString(StdStrBuf String)
StdStrBuf GetDataString(int depth=10, const class C4PropListStatic *ignore_reference_parent=nullptr) const
C4PropList * _getPropList() const
C4AulFunc * getFunction() const
void AppendFormat(const char *szFmt,...) GNUC_FORMAT_ATTRIBUTE_O
void FormatV(const char *szFmt, va_list args)
const char * getData() const
void AppendChar(char cChar)
void Append(const char *pnData, size_t iChars)
const char * getPtr(size_t i) const
std::vector< ExprPtr > args
std::vector< Parameter > params
std::unique_ptr< Block > body
std::unique_ptr< Expr > ExprPtr