Token ast_token(Ast *node) { switch (node->kind) { case Ast_Ident: return node->Ident.token; case Ast_Implicit: return node->Implicit; case Ast_Undef: return node->Undef; case Ast_BasicLit: return node->BasicLit.token; case Ast_BasicDirective: return node->BasicDirective.token; case Ast_ProcGroup: return node->ProcGroup.token; case Ast_ProcLit: return ast_token(node->ProcLit.type); case Ast_CompoundLit: if (node->CompoundLit.type != nullptr) { return ast_token(node->CompoundLit.type); } return node->CompoundLit.open; case Ast_TagExpr: return node->TagExpr.token; case Ast_BadExpr: return node->BadExpr.begin; case Ast_UnaryExpr: return node->UnaryExpr.op; case Ast_BinaryExpr: return ast_token(node->BinaryExpr.left); case Ast_ParenExpr: return node->ParenExpr.open; case Ast_CallExpr: return ast_token(node->CallExpr.proc); case Ast_SelectorExpr: if (node->SelectorExpr.selector != nullptr) { return ast_token(node->SelectorExpr.selector); } return node->SelectorExpr.token; case Ast_SelectorCallExpr: if (node->SelectorCallExpr.expr != nullptr) { return ast_token(node->SelectorCallExpr.expr); } return node->SelectorCallExpr.token; case Ast_ImplicitSelectorExpr: if (node->ImplicitSelectorExpr.selector != nullptr) { return ast_token(node->ImplicitSelectorExpr.selector); } return node->ImplicitSelectorExpr.token; case Ast_IndexExpr: return node->IndexExpr.open; case Ast_SliceExpr: return node->SliceExpr.open; case Ast_Ellipsis: return node->Ellipsis.token; case Ast_FieldValue: return node->FieldValue.eq; case Ast_DerefExpr: return node->DerefExpr.op; case Ast_TernaryIfExpr: return ast_token(node->TernaryIfExpr.x); case Ast_TernaryWhenExpr: return ast_token(node->TernaryWhenExpr.x); case Ast_TypeAssertion: return ast_token(node->TypeAssertion.expr); case Ast_TypeCast: return node->TypeCast.token; case Ast_AutoCast: return node->AutoCast.token; case Ast_InlineAsmExpr: return node->InlineAsmExpr.token; case Ast_BadStmt: return node->BadStmt.begin; case Ast_EmptyStmt: return node->EmptyStmt.token; case Ast_ExprStmt: return ast_token(node->ExprStmt.expr); case Ast_TagStmt: return node->TagStmt.token; case Ast_AssignStmt: return node->AssignStmt.op; case Ast_BlockStmt: return node->BlockStmt.open; case Ast_IfStmt: return node->IfStmt.token; case Ast_WhenStmt: return node->WhenStmt.token; case Ast_ReturnStmt: return node->ReturnStmt.token; case Ast_ForStmt: return node->ForStmt.token; case Ast_RangeStmt: return node->RangeStmt.token; case Ast_UnrollRangeStmt: return node->UnrollRangeStmt.unroll_token; case Ast_CaseClause: return node->CaseClause.token; case Ast_SwitchStmt: return node->SwitchStmt.token; case Ast_TypeSwitchStmt: return node->TypeSwitchStmt.token; case Ast_DeferStmt: return node->DeferStmt.token; case Ast_BranchStmt: return node->BranchStmt.token; case Ast_UsingStmt: return node->UsingStmt.token; case Ast_BadDecl: return node->BadDecl.begin; case Ast_Label: return node->Label.token; case Ast_ValueDecl: return ast_token(node->ValueDecl.names[0]); case Ast_PackageDecl: return node->PackageDecl.token; case Ast_ImportDecl: return node->ImportDecl.token; case Ast_ForeignImportDecl: return node->ForeignImportDecl.token; case Ast_ForeignBlockDecl: return node->ForeignBlockDecl.token; case Ast_Attribute: return node->Attribute.token; case Ast_Field: if (node->Field.names.count > 0) { return ast_token(node->Field.names[0]); } return ast_token(node->Field.type); case Ast_FieldList: return node->FieldList.token; case Ast_TypeidType: return node->TypeidType.token; case Ast_HelperType: return node->HelperType.token; case Ast_DistinctType: return node->DistinctType.token; case Ast_PolyType: return node->PolyType.token; case Ast_ProcType: return node->ProcType.token; case Ast_RelativeType: return ast_token(node->RelativeType.tag); case Ast_PointerType: return node->PointerType.token; case Ast_ArrayType: return node->ArrayType.token; case Ast_DynamicArrayType: return node->DynamicArrayType.token; case Ast_StructType: return node->StructType.token; case Ast_UnionType: return node->UnionType.token; case Ast_EnumType: return node->EnumType.token; case Ast_BitSetType: return node->BitSetType.token; case Ast_MapType: return node->MapType.token; } return empty_token; } TokenPos token_pos_end(Token const &token) { TokenPos pos = token.pos; pos.offset += cast(i32)token.string.len; for (isize i = 0; i < token.string.len; i++) { // TODO(bill): This assumes ASCII char c = token.string[i]; if (c == '\n') { pos.line += 1; pos.column = 1; } else { pos.column += 1; } } return pos; } Token ast_end_token(Ast *node) { GB_ASSERT(node != nullptr); switch (node->kind) { case Ast_Invalid: return empty_token; case Ast_Ident: return node->Ident.token; case Ast_Implicit: return node->Implicit; case Ast_Undef: return node->Undef; case Ast_BasicLit: return node->BasicLit.token; case Ast_BasicDirective: return node->BasicDirective.token; case Ast_ProcGroup: return node->ProcGroup.close; case Ast_ProcLit: if (node->ProcLit.body) { return ast_end_token(node->ProcLit.body); } return ast_end_token(node->ProcLit.type); case Ast_CompoundLit: return node->CompoundLit.close; case Ast_BadExpr: return node->BadExpr.end; case Ast_TagExpr: if (node->TagExpr.expr) { return ast_end_token(node->TagExpr.expr); } return node->TagExpr.name; case Ast_UnaryExpr: if (node->UnaryExpr.expr) { return ast_end_token(node->UnaryExpr.expr); } return node->UnaryExpr.op; case Ast_BinaryExpr: return ast_end_token(node->BinaryExpr.right); case Ast_ParenExpr: return node->ParenExpr.close; case Ast_CallExpr: return node->CallExpr.close; case Ast_SelectorExpr: return ast_end_token(node->SelectorExpr.selector); case Ast_SelectorCallExpr: return ast_end_token(node->SelectorCallExpr.call); case Ast_ImplicitSelectorExpr: if (node->ImplicitSelectorExpr.selector) { return ast_end_token(node->ImplicitSelectorExpr.selector); } return node->ImplicitSelectorExpr.token; case Ast_IndexExpr: return node->IndexExpr.close; case Ast_SliceExpr: return node->SliceExpr.close; case Ast_Ellipsis: if (node->Ellipsis.expr) { return ast_end_token(node->Ellipsis.expr); } return node->Ellipsis.token; case Ast_FieldValue: return ast_end_token(node->FieldValue.value); case Ast_DerefExpr: return node->DerefExpr.op; case Ast_TernaryIfExpr: return ast_end_token(node->TernaryIfExpr.y); case Ast_TernaryWhenExpr: return ast_end_token(node->TernaryWhenExpr.y); case Ast_TypeAssertion: return ast_end_token(node->TypeAssertion.type); case Ast_TypeCast: return ast_end_token(node->TypeCast.expr); case Ast_AutoCast: return ast_end_token(node->AutoCast.expr); case Ast_InlineAsmExpr: return node->InlineAsmExpr.close; case Ast_BadStmt: return node->BadStmt.end; case Ast_EmptyStmt: return node->EmptyStmt.token; case Ast_ExprStmt: return ast_end_token(node->ExprStmt.expr); case Ast_TagStmt: return ast_end_token(node->TagStmt.stmt); case Ast_AssignStmt: if (node->AssignStmt.rhs.count > 0) { return ast_end_token(node->AssignStmt.rhs[node->AssignStmt.rhs.count-1]); } return node->AssignStmt.op; case Ast_BlockStmt: return node->BlockStmt.close; case Ast_IfStmt: if (node->IfStmt.else_stmt) { return ast_end_token(node->IfStmt.else_stmt); } return ast_end_token(node->IfStmt.body); case Ast_WhenStmt: if (node->WhenStmt.else_stmt) { return ast_end_token(node->WhenStmt.else_stmt); } return ast_end_token(node->WhenStmt.body); case Ast_ReturnStmt: if (node->ReturnStmt.results.count > 0) { return ast_end_token(node->ReturnStmt.results[node->ReturnStmt.results.count-1]); } return node->ReturnStmt.token; case Ast_ForStmt: return ast_end_token(node->ForStmt.body); case Ast_RangeStmt: return ast_end_token(node->RangeStmt.body); case Ast_UnrollRangeStmt: return ast_end_token(node->UnrollRangeStmt.body); case Ast_CaseClause: if (node->CaseClause.stmts.count) { return ast_end_token(node->CaseClause.stmts[node->CaseClause.stmts.count-1]); } else if (node->CaseClause.list.count) { return ast_end_token(node->CaseClause.list[node->CaseClause.list.count-1]); } return node->CaseClause.token; case Ast_SwitchStmt: return ast_end_token(node->SwitchStmt.body); case Ast_TypeSwitchStmt: return ast_end_token(node->TypeSwitchStmt.body); case Ast_DeferStmt: return ast_end_token(node->DeferStmt.stmt); case Ast_BranchStmt: if (node->BranchStmt.label) { return ast_end_token(node->BranchStmt.label); } return node->BranchStmt.token; case Ast_UsingStmt: if (node->UsingStmt.list.count > 0) { return ast_end_token(node->UsingStmt.list[node->UsingStmt.list.count-1]); } return node->UsingStmt.token; case Ast_BadDecl: return node->BadDecl.end; case Ast_Label: if (node->Label.name) { return ast_end_token(node->Label.name); } return node->Label.token; case Ast_ValueDecl: if (node->ValueDecl.values.count > 0) { return ast_end_token(node->ValueDecl.values[node->ValueDecl.values.count-1]); } if (node->ValueDecl.type) { return ast_end_token(node->ValueDecl.type); } if (node->ValueDecl.names.count > 0) { return ast_end_token(node->ValueDecl.names[node->ValueDecl.names.count-1]); } return {}; case Ast_PackageDecl: return node->PackageDecl.name; case Ast_ImportDecl: return node->ImportDecl.relpath; case Ast_ForeignImportDecl: if (node->ForeignImportDecl.filepaths.count > 0) { return node->ForeignImportDecl.filepaths[node->ForeignImportDecl.filepaths.count-1]; } if (node->ForeignImportDecl.library_name.kind != Token_Invalid) { return node->ForeignImportDecl.library_name; } return node->ForeignImportDecl.token; case Ast_ForeignBlockDecl: return ast_end_token(node->ForeignBlockDecl.body); case Ast_Attribute: if (node->Attribute.close.kind != Token_Invalid) { return node->Attribute.close; } return ast_end_token(node->Attribute.elems[node->Attribute.elems.count-1]); case Ast_Field: if (node->Field.tag.kind != Token_Invalid) { return node->Field.tag; } if (node->Field.default_value) { return ast_end_token(node->Field.default_value); } if (node->Field.type) { return ast_end_token(node->Field.type); } return ast_end_token(node->Field.names[node->Field.names.count-1]); case Ast_FieldList: if (node->FieldList.list.count > 0) { return ast_end_token(node->FieldList.list[node->FieldList.list.count-1]); } return node->FieldList.token; case Ast_TypeidType: if (node->TypeidType.specialization) { return ast_end_token(node->TypeidType.specialization); } return node->TypeidType.token; case Ast_HelperType: return ast_end_token(node->HelperType.type); case Ast_DistinctType: return ast_end_token(node->DistinctType.type); case Ast_PolyType: if (node->PolyType.specialization) { return ast_end_token(node->PolyType.specialization); } return ast_end_token(node->PolyType.type); case Ast_ProcType: if (node->ProcType.results) { return ast_end_token(node->ProcType.results); } if (node->ProcType.params) { return ast_end_token(node->ProcType.params); } return node->ProcType.token; case Ast_RelativeType: return ast_end_token(node->RelativeType.type); case Ast_PointerType: return ast_end_token(node->PointerType.type); case Ast_ArrayType: return ast_end_token(node->ArrayType.elem); case Ast_DynamicArrayType: return ast_end_token(node->DynamicArrayType.elem); case Ast_StructType: if (node->StructType.fields.count > 0) { return ast_end_token(node->StructType.fields[node->StructType.fields.count-1]); } return node->StructType.token; case Ast_UnionType: if (node->UnionType.variants.count > 0) { return ast_end_token(node->UnionType.variants[node->UnionType.variants.count-1]); } return node->UnionType.token; case Ast_EnumType: if (node->EnumType.fields.count > 0) { return ast_end_token(node->EnumType.fields[node->EnumType.fields.count-1]); } if (node->EnumType.base_type) { return ast_end_token(node->EnumType.base_type); } return node->EnumType.token; case Ast_BitSetType: if (node->BitSetType.underlying) { return ast_end_token(node->BitSetType.underlying); } return ast_end_token(node->BitSetType.elem); case Ast_MapType: return ast_end_token(node->MapType.value); } return empty_token; } TokenPos ast_end_pos(Ast *node) { return token_pos_end(ast_end_token(node)); }