Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | 172x 172x 526x 177x 172x 701x 696x 5x 5x 1x 4x 4x 4x 4x 1x 3x 3x 140x 140x 129x 96x 96x 69x | /**
* Parser utilities specific to code generation.
*
* These utilities depend on ANTLR parser types and are used by CodeGenerator.
* Separated from src/utils/ParserUtils.ts to avoid circular dependencies.
*/
import { ParserRuleContext, TerminalNode } from "antlr4ng";
import * as Parser from "../../../logic/parser/grammar/CNextParser";
import ExpressionUnwrapper from "./ExpressionUnwrapper";
/**
* Static utility methods for parser context operations in code generation.
*/
class CodegenParserUtils {
/**
* Extract operators from parse tree children in order.
*
* When parsing expressions like "a + b - c", ANTLR creates children
* with operands interleaved: [a, +, b, -, c]. This method extracts
* just the operators as terminal nodes.
*
* Note: Using children.filter() loses operator ordering when operators
* are detected using text.includes(), so we iterate explicitly.
*
* @param ctx - The parser rule context containing operands and operators
* @returns Array of operator strings in the order they appear
*/
static getOperatorsFromChildren(ctx: ParserRuleContext): string[] {
const operators: string[] = [];
for (const child of ctx.children) {
if (child instanceof TerminalNode) {
operators.push(child.getText());
}
}
return operators;
}
/**
* Check if this is the main function with command-line args parameter.
* Supports: u8 args[][] (legacy) or string args[] (preferred)
*
* @param name - Function name
* @param paramList - Parameter list context
* @returns true if this is main with args parameter
*/
static isMainFunctionWithArgs(
name: string,
paramList: Parser.ParameterListContext | null,
): boolean {
if (name !== "main" || !paramList) {
return false;
}
const params = paramList.parameter();
if (params.length !== 1) {
return false;
}
const param = params[0];
const typeCtx = param.type();
const dims = param.arrayDimension();
// Check for string args[] (preferred - array of strings)
if (typeCtx.stringType() && dims.length === 1) {
return true;
}
// Check for u8 args[][] (legacy - 2D array of bytes)
const type = typeCtx.getText();
return (type === "u8" || type === "i8") && dims.length === 2;
}
/**
* Extract a simple identifier from an expression, if it is one.
* Returns null for complex expressions (binary ops, function calls, etc.)
*
* A "simple identifier" is an expression that is just a variable name
* with no operators, member access, or array indexing.
*
* @param ctx - The expression context to analyze
* @returns The identifier string, or null if not a simple identifier
*/
static getSimpleIdentifier(ctx: Parser.ExpressionContext): string | null {
const postfix = ExpressionUnwrapper.getPostfixExpression(ctx);
if (!postfix) return null;
// Has postfix operators like . or [] - not a simple identifier
if (postfix.postfixOp().length !== 0) return null;
const primary = postfix.primaryExpression();
if (!primary.IDENTIFIER()) return null;
return primary.IDENTIFIER()!.getText();
}
}
export default CodegenParserUtils;
|