33 auto program = std::make_unique<Program>();
36 while (match({TokenType::Newline, TokenType::Semicolon})) {
42 int pos_before = current;
43 auto stmt = parseDeclaration();
45 program->statements.push_back(std::move(stmt));
49 if (current == pos_before && !isAtEnd() && !errors.empty()) {
54 return ParseResult{.ast = std::move(program), .errors = std::move(errors)};
57std::unique_ptr<Stmt> Parser::parseDeclaration() {
58 std::unique_ptr<Stmt> stmt;
59 if (peek().type == TokenType::Global) {
60 auto global_decl = parseGlobalDecl();
62 while (match({TokenType::Newline})) {
66 if (peek().type != TokenType::Function) {
67 error(peek(),
"Global declaration must be followed by a function "
70 auto func_def = parseFunctionDef();
72 func_def->global_decl = std::move(global_decl);
74 }
else if (peek().type == TokenType::Function) {
75 auto func_def = parseFunctionDef();
76 stmt = std::make_unique<Stmt>(FunctionDef(std::move(*func_def)));
78 stmt = parseStatement();
90 if (isAtEnd() || peek().type == TokenType::RBrace) {
95 if (peek().type == TokenType::Newline ||
96 peek().type == TokenType::Semicolon) {
101 error(peek(),
"Expected newline or semicolon after statement.");
106std::unique_ptr<Stmt> Parser::parseStatement() {
107 if (peek().type == TokenType::If) {
108 return parseIfStatement();
110 if (peek().type == TokenType::While) {
111 return parseWhileStatement();
113 if (peek().type == TokenType::LBrace) {
114 error(peek(),
"Standalone blocks are not allowed. Braces can only be "
115 "used for function, if, else, or while bodies.");
119 if (peek().type == TokenType::Goto) {
120 return parseGotoStatement();
122 if (peek().type == TokenType::Return) {
123 return parseReturnStatement();
125 if (peek().type == TokenType::Identifier &&
126 peek(1).type == TokenType::Colon) {
127 return parseLabelStatement();
129 return parseExprStatement();
132std::unique_ptr<Stmt> Parser::parseIfStatement() {
133 consume(TokenType::If,
"Expect 'if'.");
134 consume(TokenType::LParen,
"Expect '(' after 'if'.");
135 auto condition = parseTernary();
136 consume(TokenType::RParen,
"Expect ')' after if condition.");
138 if (peek().type != TokenType::LBrace) {
139 error(peek(),
"The body of an if statement must be a block statement "
142 auto then_branch = std::make_unique<Stmt>(std::move(*parseBlock()));
144 std::unique_ptr<Stmt> else_branch =
nullptr;
145 if (match({TokenType::Else})) {
146 if (peek().type == TokenType::If) {
147 else_branch = parseIfStatement();
149 if (peek().type != TokenType::LBrace) {
150 error(peek(),
"The body of an else statement must be a block "
151 "statement enclosed in {}.");
153 else_branch = std::make_unique<Stmt>(std::move(*parseBlock()));
157 std::move(else_branch));
160std::unique_ptr<Stmt> Parser::parseWhileStatement() {
161 consume(TokenType::While,
"Expect 'while'.");
162 consume(TokenType::LParen,
"Expect '(' after 'while'.");
163 auto condition = parseTernary();
164 consume(TokenType::RParen,
"Expect ')' after while condition.");
166 if (peek().type != TokenType::LBrace) {
167 error(peek(),
"The body of a while statement must be a block "
168 "statement enclosed in {}.");
170 auto body = std::make_unique<Stmt>(std::move(*parseBlock()));
175std::unique_ptr<Stmt> Parser::parseGotoStatement() {
176 Token keyword = consume(TokenType::Goto,
"Expect 'goto'.");
178 consume(TokenType::Identifier,
"Expect label name after 'goto'.");
179 if (label.value.starts_with(
"__internal_")) {
180 error(label,
"goto target cannot start with '__internal_'.");
185std::unique_ptr<Stmt> Parser::parseLabelStatement() {
186 Token name = consume(TokenType::Identifier,
"Expect label name.");
187 if (name.value.starts_with(
"__internal_")) {
188 error(name,
"Label name cannot start with '__internal_'.");
190 consume(TokenType::Colon,
"Expect ':' after label name.");
194std::unique_ptr<Stmt> Parser::parseReturnStatement() {
195 Token keyword = consume(TokenType::Return,
"Expect 'return'.");
196 std::unique_ptr<Expr> value =
nullptr;
198 if (peek().type != TokenType::Newline &&
199 peek().type != TokenType::Semicolon &&
200 peek().type != TokenType::EndOfFile &&
201 peek().type != TokenType::RBrace) {
202 value = parseTernary();
207std::unique_ptr<BlockStmt> Parser::parseBlock() {
208 consume(TokenType::LBrace,
"Expect '{' to start a block.");
209 std::vector<std::unique_ptr<Stmt>> statements;
210 while (peek().type != TokenType::RBrace && !isAtEnd()) {
212 while (match({TokenType::Newline, TokenType::Semicolon})) {
214 if (peek().type == TokenType::RBrace || isAtEnd()) {
218 int pos_before = current;
219 auto stmt = parseDeclaration();
221 statements.push_back(std::move(stmt));
225 if (peek().type == TokenType::RBrace || isAtEnd()) {
229 if (current == pos_before && !isAtEnd() &&
230 peek().type != TokenType::RBrace && !errors.empty()) {
234 consume(TokenType::RBrace,
"Expect '}' to end a block.");
235 return std::make_unique<BlockStmt>(BlockStmt(std::move(statements)));
238std::unique_ptr<Stmt> Parser::parseExprStatement() {
239 if (peek().type == TokenType::Identifier &&
240 peek(1).type == TokenType::Assign) {
241 Token name = advance();
242 if (name.value.starts_with(
"__internal_")) {
243 error(name,
"Variable name cannot start with '__internal_'.");
246 auto value = parseTernary();
250 if (peek().type == TokenType::Identifier &&
251 peek(1).type == TokenType::LBracket) {
252 auto left_expr = parsePostfix();
254 if (match({TokenType::Assign})) {
255 auto right_expr = parseTernary();
259 std::move(right_expr));
261 error(peek(),
"Invalid assignment target.");
267 auto expr = parseTernary();
271std::unique_ptr<FunctionDef> Parser::parseFunctionDef() {
272 consume(TokenType::Function,
"Expect 'function'.");
273 Token name = consume(TokenType::Identifier,
"Expect function name.");
274 if (name.value.starts_with(
"__internal_")) {
275 error(name,
"Function name cannot start with '__internal_'.");
280 if ((builtins.contains(name.value)) || name.value.starts_with(
"nth_") ||
281 name.value ==
"new" || name.value ==
"resize") {
284 "Function name '{}' conflicts with a built-in function.",
288 defined_functions.insert(name.value);
290 consume(TokenType::LParen,
"Expect '(' after function name.");
291 std::vector<Parameter> params;
292 if (peek().type != TokenType::RParen) {
298 if (peek().type == TokenType::Identifier &&
299 peek(1).type == TokenType::Identifier) {
300 type_token = advance();
301 if (type_token.value ==
"Value") {
303 }
else if (type_token.value ==
"Clip") {
305 }
else if (type_token.value ==
"Literal") {
307 }
else if (type_token.value ==
"Array") {
311 std::format(
"Unknown type '{}' for parameter.",
315 consume(TokenType::Identifier,
"Expect parameter name.");
316 }
else if (peek().type == TokenType::Identifier) {
319 consume(TokenType::Identifier,
"Expect parameter name.");
320 type_token = {.type = TokenType::Identifier,
322 .range = name_token.range};
325 error(peek(),
"Expect a parameter declaration.");
328 if (name_token.
type == TokenType::Identifier &&
329 name_token.value.starts_with(
"__internal_")) {
331 "Parameter name cannot start with '__internal_'.");
333 params.push_back({type_token, name_token, param_type});
334 }
while (match({TokenType::Comma}));
336 consume(TokenType::RParen,
"Expect ')' after parameters.");
337 auto body = parseBlock();
338 return std::make_unique<FunctionDef>(
339 FunctionDef(name, std::move(params), std::move(body),
nullptr));
342std::unique_ptr<GlobalDecl> Parser::parseGlobalDecl() {
343 Token keyword = consume(TokenType::Global,
"Expect '<global...>'.");
344 std::string content = keyword.value.substr(1, keyword.value.length() - 2);
345 if (content ==
"global.all") {
346 return std::make_unique<GlobalDecl>(
349 if (content ==
"global.none") {
350 return std::make_unique<GlobalDecl>(
355 std::vector<Token> globals;
358 if (content.starts_with(
"global")) {
359 pos = std::string(
"global").length();
361 error(keyword,
"Invalid global declaration format.");
365 while (pos < content.length()) {
366 if (content[pos] !=
'<') {
367 error(keyword,
"Expected '<' in global variable list.");
372 while (pos < content.length() && content[pos] !=
'>') {
376 if (pos >= content.length()) {
377 error(keyword,
"Unclosed '<' in global variable list.");
380 std::string var_name = content.substr(start, pos - start);
382 if (var_name.empty()) {
383 error(keyword,
"Empty variable name in global declaration.");
386 if (var_name.starts_with(
"__internal_")) {
387 error(keyword, std::format(
"Invalid identifier '{}': cannot "
388 "start with '__internal_'.",
392 if ((std::isalpha(var_name[0]) == 0) && var_name[0] !=
'_') {
393 error(keyword, std::format(
"Invalid identifier '{}': must "
394 "start with letter or underscore.",
398 for (
size_t i = 1; i < var_name.length(); i++) {
399 if ((std::isalnum(var_name[i]) == 0) && var_name[i] !=
'_') {
400 error(keyword, std::format(
"Invalid identifier '{}': "
401 "contains invalid character.",
406 globals.push_back({TokenType::Identifier, var_name, keyword.range});
410 if (globals.empty()) {
412 "Global declaration must specify at least one variable.");
415 return std::make_unique<GlobalDecl>(
419std::unique_ptr<Expr> Parser::parseTernary() {
420 auto expr = parseLogicalOr();
421 if (match({TokenType::Question})) {
422 auto then_branch = parseTernary();
423 consume(TokenType::Colon,
"Expect ':' for ternary operator.");
424 auto else_branch = parseTernary();
426 std::move(else_branch));
431template <
typename NextLevel,
typename... TokenTypes>
432std::unique_ptr<Expr> Parser::parseBinary(NextLevel next_level,
433 TokenTypes... token_types) {
434 auto expr = (this->*next_level)();
435 while (match({token_types...})) {
436 Token op = previous();
437 auto right = (this->*next_level)();
443std::unique_ptr<Expr> Parser::parseLogicalOr() {
444 return parseBinary(&Parser::parseLogicalAnd, TokenType::LogicalOr);
447std::unique_ptr<Expr> Parser::parseLogicalAnd() {
448 return parseBinary(&Parser::parseBitwiseOr, TokenType::LogicalAnd);
451std::unique_ptr<Expr> Parser::parseBitwiseOr() {
452 return parseBinary(&Parser::parseBitwiseXor, TokenType::BitOr);
455std::unique_ptr<Expr> Parser::parseBitwiseXor() {
456 return parseBinary(&Parser::parseBitwiseAnd, TokenType::BitXor);
459std::unique_ptr<Expr> Parser::parseBitwiseAnd() {
460 return parseBinary(&Parser::parseEquality, TokenType::BitAnd);
463std::unique_ptr<Expr> Parser::parseEquality() {
464 return parseBinary(&Parser::parseComparison,
TokenType::Eq, TokenType::Ne);
467std::unique_ptr<Expr> Parser::parseComparison() {
472std::unique_ptr<Expr> Parser::parseTerm() {
473 return parseBinary(&Parser::parseFactor, TokenType::Plus, TokenType::Minus);
476std::unique_ptr<Expr> Parser::parseFactor() {
477 return parseBinary(&Parser::parseExponent, TokenType::Star,
478 TokenType::Slash, TokenType::Percent);
481std::unique_ptr<Expr> Parser::parseExponent() {
483 auto expr = parseUnary();
484 if (match({TokenType::StarStar})) {
485 Token op = previous();
486 auto right = parseExponent();
492std::unique_ptr<Expr> Parser::parseUnary() {
493 if (match({
TokenType::Not, TokenType::Minus, TokenType::BitNot})) {
494 Token op = previous();
496 Token number = advance();
497 number.value = std::format(
"-{}", number.value);
498 number.range.start = op.range.start;
501 auto right = parseUnary();
504 return parsePostfix();
507std::unique_ptr<Expr> Parser::parsePostfix() {
508 auto expr = parsePrimary();
510 if (match({TokenType::LParen})) {
511 expr = finishCall(std::move(expr));
512 }
else if (match({TokenType::LBracket})) {
513 auto index1 = parseTernary();
515 if (match({TokenType::Comma})) {
517 auto index2 = parseTernary();
518 consume(TokenType::RBracket,
"Expect ']' after indices");
520 if (match({TokenType::Colon})) {
521 Token s = consume(TokenType::Identifier,
522 "Expect boundary suffix");
523 suffix = std::format(
":{}", s.value);
526 auto get_constant_token = [](
Expr* e) ->
Token* {
531 if (unary->op.type == TokenType::Minus) {
533 unary->right.get())) {
534 static Token neg_token;
535 neg_token = num->value;
537 std::format(
"-{}", neg_token.value);
545 Token* x_tok = get_constant_token(index1.get());
546 Token* y_tok = get_constant_token(index2.get());
548 if ((x_tok !=
nullptr) && (y_tok !=
nullptr)) {
550 var->name, *x_tok, *y_tok, suffix);
553 error(peek(),
"Dynamic pixel access should use dyn().");
556 consume(TokenType::RBracket,
"Expect ']' after array index.");
560 }
else if (match({TokenType::Dot})) {
561 Token prop = consume(TokenType::Identifier,
562 "Expect property name after '.'");
565 if (var->name.value ==
"frame" &&
566 (prop.value ==
"width" || prop.value ==
"height")) {
567 if (match({TokenType::LBracket})) {
568 auto plane_index_expr = parseTernary();
569 consume(TokenType::RBracket,
570 "Expect ']' after plane index");
572 prop, std::move(plane_index_expr));
577 error(prop,
"Invalid property access target.");
585std::unique_ptr<Expr> Parser::finishCall(std::unique_ptr<Expr> callee) {
587 std::vector<std::unique_ptr<Expr>> args;
588 if (peek().type != TokenType::RParen) {
590 args.push_back(parseTernary());
591 }
while (match({TokenType::Comma}));
593 consume(TokenType::RParen,
"Expect ')' after arguments.");
596 error(peek(),
"Invalid call target.");
598 .type = TokenType::Identifier, .value =
"error", .range = peek().range};
600 std::vector<std::unique_ptr<Expr>>{});
603std::unique_ptr<Expr> Parser::parsePrimary() {
607 if (match({TokenType::Identifier})) {
610 if (match({TokenType::LParen})) {
611 auto expr = parseTernary();
612 consume(TokenType::RParen,
"Expect ')' after expression.");
615 error(peek(),
"Expect expression.");
621bool Parser::match(
const std::vector<TokenType>& types) {
622 if (std::ranges::any_of(
623 types, [
this](
TokenType type) {
return peek().type == type; })) {
630Token Parser::consume(
TokenType type,
const std::string& message) {
631 if (peek().type == type) {
634 error(peek(), message);
638Token Parser::advance() {
645Token Parser::peek()
const {
return tokens[current]; }
646Token Parser::peek(
int offset)
const {
647 if (current + offset >=
static_cast<int>(tokens.size())) {
648 return tokens.back();
650 return tokens[current + offset];
652Token Parser::previous()
const {
return tokens[current - 1]; }
653bool Parser::isAtEnd()
const {
return peek().
type == TokenType::EndOfFile; }
655void Parser::reportError(
const Token& token,
const std::string& message) {
660 std::string error_message;
661 if (token.
type == TokenType::EndOfFile) {
662 error_message = std::format(
"at end: {}", message);
664 error_message = std::format(
"at '{}': {}", token.value, message);
667 errors.push_back({error_message, token.range});
670void Parser::error(
const Token& token,
const std::string& message) {
671 reportError(token, message);
677void Parser::synchronize() {
682 TokenType prev = tokens[current - 1].type;
683 if (prev == TokenType::Semicolon || prev == TokenType::Newline) {
684 while (peek().type == TokenType::Semicolon ||
685 peek().type == TokenType::Newline) {
692 switch (peek().type) {
693 case TokenType::Function:
694 case TokenType::Global:
696 case TokenType::While:
697 case TokenType::Return:
698 case TokenType::Goto:
699 case TokenType::RBrace:
700 case TokenType::Semicolon:
701 case TokenType::Newline:
Parser(const std::vector< Token > &tokens)
auto get_if(Wrapper *wrapper) -> decltype(std::get_if< T >(&wrapper->value))
const std::map< std::string, std::vector< BuiltinFunction > > & get_builtin_functions()
preprocessor_detail::Token Token
auto make_node(Args &&... args)